2000-04-26 18:34:17 +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
|
|
|
*
|
2021-06-03 08:37:05 +02:00
|
|
|
* SPDX-License-Identifier: MPL-2.0
|
|
|
|
*
|
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.
|
2000-04-26 18:34:17 +00:00
|
|
|
*/
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*! \file
|
|
|
|
* \note
|
2000-05-08 22:51:08 +00:00
|
|
|
* Notice to programmers: Do not use this code as an example of how to
|
|
|
|
* use the ISC library to perform DNS lookups. Dig and Host both operate
|
|
|
|
* on the request level, since they allow fine-tuning of output and are
|
|
|
|
* intended as debugging tools. As a result, they perform many of the
|
|
|
|
* functions which could be better handled using the dns_resolver
|
|
|
|
* functions in most applications.
|
|
|
|
*/
|
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
#include <errno.h>
|
2018-03-28 14:19:37 +02:00
|
|
|
#include <inttypes.h>
|
2020-02-12 13:59:18 +01:00
|
|
|
#include <limits.h>
|
2021-06-22 13:05:15 +02:00
|
|
|
#include <locale.h>
|
2018-04-17 08:29:14 -07:00
|
|
|
#include <stdbool.h>
|
2000-04-26 18:34:17 +00:00
|
|
|
#include <stdlib.h>
|
2000-06-15 19:05:30 +00:00
|
|
|
#include <string.h>
|
2020-02-12 13:59:18 +01:00
|
|
|
#include <unistd.h>
|
2000-04-26 18:34:17 +00:00
|
|
|
|
Rework libidn2 detection
Clean up the parts of configure.in responsible for handling libidn2
detection and adjust other pieces of the build system to match these
cleanups:
- use pkg-config when --with-libidn2 is used without an explicit path,
- look for idn2_to_ascii_lz() rather than idn2_to_ascii_8z() as the
former is used in BIND while the latter is not,
- do not look for idn2_to_unicode_8zlz() as it is present in all
libidn2 versions which have idn2_to_ascii_lz(),
- check whether the <idn2.h> header is usable,
- set LDFLAGS in the Makefile for dig so that, if specified, the
requested libidn2 path is used when linking with libidn2,
- override CPPFLAGS when looking for libidn2 components so that the
configure script does not produce warnings when libidn2 is not
installed system-wide,
- merge the AS_CASE() call into the AS_IF() call below it to simplify
code,
- indicate the default value of --with-libidn2 in "./configure --help"
output,
- use $with_libidn2 rather than $use_libidn2 to better match the name
of the configure script argument,
- stop differentiating between IDN "in" and "out" support, i.e. make
dig either support libidn2 or not; remove WITH_* Autoconf macros and
use a new one, HAVE_LIBIDN2, to determine whether libidn2 support
should be enabled.
2018-07-10 14:34:35 +02:00
|
|
|
#ifdef HAVE_LIBIDN2
|
2015-09-23 16:47:37 +02:00
|
|
|
#include <idn2.h>
|
Rework libidn2 detection
Clean up the parts of configure.in responsible for handling libidn2
detection and adjust other pieces of the build system to match these
cleanups:
- use pkg-config when --with-libidn2 is used without an explicit path,
- look for idn2_to_ascii_lz() rather than idn2_to_ascii_8z() as the
former is used in BIND while the latter is not,
- do not look for idn2_to_unicode_8zlz() as it is present in all
libidn2 versions which have idn2_to_ascii_lz(),
- check whether the <idn2.h> header is usable,
- set LDFLAGS in the Makefile for dig so that, if specified, the
requested libidn2 path is used when linking with libidn2,
- override CPPFLAGS when looking for libidn2 components so that the
configure script does not produce warnings when libidn2 is not
installed system-wide,
- merge the AS_CASE() call into the AS_IF() call below it to simplify
code,
- indicate the default value of --with-libidn2 in "./configure --help"
output,
- use $with_libidn2 rather than $use_libidn2 to better match the name
of the configure script argument,
- stop differentiating between IDN "in" and "out" support, i.e. make
dig either support libidn2 or not; remove WITH_* Autoconf macros and
use a new one, HAVE_LIBIDN2, to determine whether libidn2 support
should be enabled.
2018-07-10 14:34:35 +02:00
|
|
|
#endif /* HAVE_LIBIDN2 */
|
2015-09-23 14:37:16 +02:00
|
|
|
|
2000-06-21 17:48:32 +00:00
|
|
|
#include <isc/app.h>
|
|
|
|
#include <isc/base64.h>
|
2005-09-01 02:25:06 +00:00
|
|
|
#include <isc/file.h>
|
2014-02-19 12:53:42 +11:00
|
|
|
#include <isc/hex.h>
|
2000-06-21 17:48:32 +00:00
|
|
|
#include <isc/lang.h>
|
2009-09-15 03:13:44 +00:00
|
|
|
#include <isc/log.h>
|
2021-04-27 00:07:43 +02:00
|
|
|
#include <isc/managers.h>
|
2000-10-23 23:13:21 +00:00
|
|
|
#include <isc/netaddr.h>
|
2004-04-13 02:39:35 +00:00
|
|
|
#include <isc/netdb.h>
|
2018-05-28 15:22:23 +02:00
|
|
|
#include <isc/nonce.h>
|
2009-09-15 03:13:44 +00:00
|
|
|
#include <isc/parseint.h>
|
2000-11-20 13:02:18 +00:00
|
|
|
#include <isc/print.h>
|
2004-04-08 01:21:16 +00:00
|
|
|
#include <isc/random.h>
|
2000-06-23 20:57:19 +00:00
|
|
|
#include <isc/result.h>
|
2015-08-17 18:26:44 -07:00
|
|
|
#include <isc/safe.h>
|
2011-12-01 00:53:58 +00:00
|
|
|
#include <isc/serial.h>
|
2014-02-19 15:51:02 -08:00
|
|
|
#include <isc/sockaddr.h>
|
2000-06-21 17:48:32 +00:00
|
|
|
#include <isc/string.h>
|
|
|
|
#include <isc/task.h>
|
|
|
|
#include <isc/timer.h>
|
|
|
|
#include <isc/types.h>
|
|
|
|
#include <isc/util.h>
|
2000-06-12 19:33:30 +00:00
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
#include <dns/byaddr.h>
|
|
|
|
#include <dns/fixedname.h>
|
|
|
|
#include <dns/log.h>
|
|
|
|
#include <dns/message.h>
|
|
|
|
#include <dns/name.h>
|
2020-03-11 13:55:14 +11:00
|
|
|
#include <dns/opcode.h>
|
2020-02-12 13:59:18 +01:00
|
|
|
#include <dns/rcode.h>
|
|
|
|
#include <dns/rdata.h>
|
|
|
|
#include <dns/rdataclass.h>
|
|
|
|
#include <dns/rdatalist.h>
|
|
|
|
#include <dns/rdataset.h>
|
|
|
|
#include <dns/rdatastruct.h>
|
|
|
|
#include <dns/rdatatype.h>
|
|
|
|
#include <dns/tsig.h>
|
2016-08-19 08:02:51 +10:00
|
|
|
|
2020-03-09 16:17:26 +01:00
|
|
|
#include <dst/dst.h>
|
|
|
|
|
2009-09-15 03:13:44 +00:00
|
|
|
#include <isccfg/namedconf.h>
|
|
|
|
|
2020-03-09 16:17:26 +01:00
|
|
|
#include <irs/resconf.h>
|
|
|
|
|
2001-11-14 22:08:38 +00:00
|
|
|
#include <bind9/getaddresses.h>
|
2020-03-09 16:17:26 +01:00
|
|
|
|
2018-08-07 16:46:53 +02:00
|
|
|
#include "dighost.h"
|
2001-01-18 22:21:31 +00:00
|
|
|
|
2021-06-22 13:05:15 +02:00
|
|
|
#define systemlocale(l) (void)setlocale(l, "")
|
|
|
|
#define resetlocale(l) (void)setlocale(l, "C")
|
|
|
|
|
2020-02-13 14:44:37 -08:00
|
|
|
dig_lookuplist_t lookup_list;
|
|
|
|
dig_serverlist_t server_list;
|
2005-07-04 03:03:21 +00:00
|
|
|
dig_searchlistlist_t search_list;
|
2000-04-26 18:34:17 +00:00
|
|
|
|
2022-03-08 23:55:10 +01:00
|
|
|
static atomic_bool cancel_now = false;
|
2020-11-05 15:22:38 +01:00
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
bool check_ra = false, have_ipv4 = false, have_ipv6 = false,
|
2020-11-05 15:22:38 +01:00
|
|
|
specified_source = false, free_now = false, usesearch = false,
|
|
|
|
showsearch = false, is_dst_up = false, keep_open = false, verbose = false,
|
|
|
|
yaml = false;
|
2020-02-13 14:44:37 -08:00
|
|
|
in_port_t port = 53;
|
2020-07-22 08:59:42 +02:00
|
|
|
bool port_set = false;
|
2020-02-13 14:44:37 -08:00
|
|
|
unsigned int timeout = 0;
|
|
|
|
unsigned int extrabytes;
|
|
|
|
isc_mem_t *mctx = NULL;
|
|
|
|
isc_log_t *lctx = NULL;
|
2021-04-27 00:07:43 +02:00
|
|
|
isc_nm_t *netmgr = NULL;
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_taskmgr_t *taskmgr = NULL;
|
|
|
|
isc_task_t *global_task = NULL;
|
2020-09-05 16:37:24 -07:00
|
|
|
isc_sockaddr_t localaddr;
|
2022-03-08 23:55:10 +01:00
|
|
|
isc_refcount_t sendcount = 0;
|
|
|
|
isc_refcount_t recvcount = 0;
|
2020-02-13 14:44:37 -08:00
|
|
|
int ndots = -1;
|
2021-06-22 16:35:46 +02:00
|
|
|
int tries = -1;
|
2020-02-13 14:44:37 -08:00
|
|
|
int lookup_counter = 0;
|
2001-01-18 05:12:44 +00:00
|
|
|
|
2015-07-06 09:44:24 +10:00
|
|
|
static char servercookie[256];
|
2015-04-06 23:13:35 -07:00
|
|
|
|
Rework libidn2 detection
Clean up the parts of configure.in responsible for handling libidn2
detection and adjust other pieces of the build system to match these
cleanups:
- use pkg-config when --with-libidn2 is used without an explicit path,
- look for idn2_to_ascii_lz() rather than idn2_to_ascii_8z() as the
former is used in BIND while the latter is not,
- do not look for idn2_to_unicode_8zlz() as it is present in all
libidn2 versions which have idn2_to_ascii_lz(),
- check whether the <idn2.h> header is usable,
- set LDFLAGS in the Makefile for dig so that, if specified, the
requested libidn2 path is used when linking with libidn2,
- override CPPFLAGS when looking for libidn2 components so that the
configure script does not produce warnings when libidn2 is not
installed system-wide,
- merge the AS_CASE() call into the AS_IF() call below it to simplify
code,
- indicate the default value of --with-libidn2 in "./configure --help"
output,
- use $with_libidn2 rather than $use_libidn2 to better match the name
of the configure script argument,
- stop differentiating between IDN "in" and "out" support, i.e. make
dig either support libidn2 or not; remove WITH_* Autoconf macros and
use a new one, HAVE_LIBIDN2, to determine whether libidn2 support
should be enabled.
2018-07-10 14:34:35 +02:00
|
|
|
#ifdef HAVE_LIBIDN2
|
2020-02-14 08:14:03 +01:00
|
|
|
static void
|
|
|
|
idn_locale_to_ace(const char *src, char *dst, size_t dstlen);
|
|
|
|
static void
|
|
|
|
idn_ace_to_locale(const char *src, char **dst);
|
|
|
|
static isc_result_t
|
|
|
|
idn_output_filter(isc_buffer_t *buffer, unsigned int used_org);
|
Rework libidn2 detection
Clean up the parts of configure.in responsible for handling libidn2
detection and adjust other pieces of the build system to match these
cleanups:
- use pkg-config when --with-libidn2 is used without an explicit path,
- look for idn2_to_ascii_lz() rather than idn2_to_ascii_8z() as the
former is used in BIND while the latter is not,
- do not look for idn2_to_unicode_8zlz() as it is present in all
libidn2 versions which have idn2_to_ascii_lz(),
- check whether the <idn2.h> header is usable,
- set LDFLAGS in the Makefile for dig so that, if specified, the
requested libidn2 path is used when linking with libidn2,
- override CPPFLAGS when looking for libidn2 components so that the
configure script does not produce warnings when libidn2 is not
installed system-wide,
- merge the AS_CASE() call into the AS_IF() call below it to simplify
code,
- indicate the default value of --with-libidn2 in "./configure --help"
output,
- use $with_libidn2 rather than $use_libidn2 to better match the name
of the configure script argument,
- stop differentiating between IDN "in" and "out" support, i.e. make
dig either support libidn2 or not; remove WITH_* Autoconf macros and
use a new one, HAVE_LIBIDN2, to determine whether libidn2 support
should be enabled.
2018-07-10 14:34:35 +02:00
|
|
|
#endif /* HAVE_LIBIDN2 */
|
2005-09-09 06:17:03 +00:00
|
|
|
|
2020-09-05 16:37:24 -07:00
|
|
|
isc_nmhandle_t *keep = NULL;
|
2013-11-07 10:50:01 +11:00
|
|
|
isc_sockaddr_t keepaddr;
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
2000-08-03 17:43:06 +00:00
|
|
|
* Exit Codes:
|
2005-04-27 04:57:32 +00:00
|
|
|
*
|
2005-08-25 00:56:08 +00:00
|
|
|
*\li 0 Everything went well, including things like NXDOMAIN
|
|
|
|
*\li 1 Usage error
|
|
|
|
*\li 7 Got too many RR's or Names
|
|
|
|
*\li 8 Couldn't open batch file
|
|
|
|
*\li 9 No reply from server
|
|
|
|
*\li 10 Internal error
|
2000-08-03 17:43:06 +00:00
|
|
|
*/
|
2020-02-13 14:44:37 -08:00
|
|
|
int exitcode = 0;
|
|
|
|
int fatalexit = 0;
|
|
|
|
char keynametext[MXNAME];
|
|
|
|
char keyfile[MXNAME] = "";
|
|
|
|
char keysecret[MXNAME] = "";
|
|
|
|
unsigned char cookie_secret[33];
|
|
|
|
unsigned char cookie[8];
|
2016-12-30 15:45:08 +11:00
|
|
|
const dns_name_t *hmacname = NULL;
|
2020-02-13 14:44:37 -08:00
|
|
|
unsigned int digestbits = 0;
|
|
|
|
isc_buffer_t *namebuf = NULL;
|
|
|
|
dns_tsigkey_t *tsigkey = NULL;
|
|
|
|
bool validated = true;
|
|
|
|
bool debugging = false;
|
|
|
|
bool debugtiming = false;
|
|
|
|
bool memdebugging = false;
|
|
|
|
char *progname = NULL;
|
|
|
|
isc_mutex_t lookup_lock;
|
|
|
|
dig_lookup_t *current_lookup = NULL;
|
2000-07-14 17:57:27 +00:00
|
|
|
|
2004-09-06 01:24:44 +00:00
|
|
|
#define DIG_MAX_ADDRESSES 20
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
2000-07-14 17:57:27 +00:00
|
|
|
* Apply and clear locks at the event level in global task.
|
2000-08-01 00:53:20 +00:00
|
|
|
* Can I get rid of these using shutdown events? XXX
|
2000-07-14 17:57:27 +00:00
|
|
|
*/
|
2022-07-13 13:19:32 +02:00
|
|
|
#define LOCK_LOOKUP \
|
|
|
|
{ \
|
|
|
|
debug("lock_lookup %s:%d", __FILE__, __LINE__); \
|
|
|
|
isc_mutex_lock((&lookup_lock)); \
|
|
|
|
debug("success"); \
|
2020-02-12 13:59:18 +01:00
|
|
|
}
|
2022-07-13 13:19:32 +02:00
|
|
|
#define UNLOCK_LOOKUP \
|
|
|
|
{ \
|
|
|
|
debug("unlock_lookup %s:%d", __FILE__, __LINE__); \
|
|
|
|
isc_mutex_unlock((&lookup_lock)); \
|
2020-02-12 13:59:18 +01:00
|
|
|
}
|
2000-06-06 22:50:44 +00:00
|
|
|
|
2019-08-30 14:23:29 +10:00
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
default_warnerr(const char *format, ...) {
|
2019-08-30 14:23:29 +10:00
|
|
|
va_list args;
|
|
|
|
|
|
|
|
printf(";; ");
|
|
|
|
va_start(args, format);
|
|
|
|
vprintf(format, args);
|
|
|
|
va_end(args);
|
|
|
|
printf("\n");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2019-08-30 14:23:29 +10:00
|
|
|
|
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
default_comments(dig_lookup_t *lookup, const char *format, ...) {
|
2019-08-30 14:23:29 +10:00
|
|
|
va_list args;
|
|
|
|
|
|
|
|
if (lookup->comments) {
|
|
|
|
printf(";; ");
|
|
|
|
va_start(args, format);
|
|
|
|
vprintf(format, args);
|
|
|
|
va_end(args);
|
|
|
|
printf("\n");
|
|
|
|
}
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2019-08-30 14:23:29 +10:00
|
|
|
|
2017-08-10 22:51:24 -07:00
|
|
|
/* dynamic callbacks */
|
|
|
|
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_result_t (*dighost_printmessage)(dig_query_t *query,
|
2020-02-12 13:59:18 +01:00
|
|
|
const isc_buffer_t *msgbuf,
|
|
|
|
dns_message_t *msg, bool headers);
|
2017-08-10 22:51:24 -07:00
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
void (*dighost_error)(const char *format, ...) = default_warnerr;
|
2019-08-30 14:23:29 +10:00
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
void (*dighost_warning)(const char *format, ...) = default_warnerr;
|
2019-08-30 14:23:29 +10:00
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
void (*dighost_comments)(dig_lookup_t *lookup, const char *format,
|
|
|
|
...) = default_comments;
|
2019-07-16 23:44:20 -07:00
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
void (*dighost_received)(unsigned int bytes, isc_sockaddr_t *from,
|
|
|
|
dig_query_t *query);
|
2017-08-10 22:51:24 -07:00
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
void (*dighost_trying)(char *frm, dig_lookup_t *lookup);
|
2017-08-10 22:51:24 -07:00
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
void (*dighost_shutdown)(void);
|
2017-08-10 22:51:24 -07:00
|
|
|
|
|
|
|
/* forward declarations */
|
|
|
|
|
2021-04-27 12:03:20 +02:00
|
|
|
#define cancel_lookup(l) _cancel_lookup(l, __FILE__, __LINE__)
|
2020-02-14 08:14:03 +01:00
|
|
|
static void
|
2021-04-27 12:03:20 +02:00
|
|
|
_cancel_lookup(dig_lookup_t *lookup, const char *file, unsigned int line);
|
2000-05-12 01:02:37 +00:00
|
|
|
|
2020-02-14 08:14:03 +01:00
|
|
|
static void
|
2020-09-05 16:37:24 -07:00
|
|
|
recv_done(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
|
|
|
|
void *arg);
|
2000-07-18 18:51:40 +00:00
|
|
|
|
2020-02-14 08:14:03 +01:00
|
|
|
static void
|
2020-09-05 16:37:24 -07:00
|
|
|
start_udp(dig_query_t *query);
|
2006-08-01 00:49:02 +00:00
|
|
|
|
2022-04-07 09:23:49 +00:00
|
|
|
static void
|
|
|
|
start_tcp(dig_query_t *query);
|
|
|
|
|
2020-02-14 08:14:03 +01:00
|
|
|
static void
|
2020-11-02 21:38:56 -08:00
|
|
|
force_next(dig_query_t *query);
|
2000-07-18 18:51:40 +00:00
|
|
|
|
2020-02-14 08:14:03 +01:00
|
|
|
static void
|
2020-09-05 16:37:24 -07:00
|
|
|
launch_next_query(dig_query_t *query);
|
2001-06-15 01:26:14 +00:00
|
|
|
|
2020-02-14 08:14:03 +01:00
|
|
|
static void
|
2020-11-06 16:12:17 +01:00
|
|
|
clear_current_lookup(void);
|
2014-08-21 18:05:55 +10:00
|
|
|
|
2020-02-14 08:14:03 +01:00
|
|
|
static bool
|
|
|
|
next_origin(dig_lookup_t *oldlookup);
|
2002-08-12 18:25:25 +00:00
|
|
|
|
2000-05-02 23:23:12 +00:00
|
|
|
static int
|
2020-02-13 14:44:37 -08:00
|
|
|
count_dots(char *string) {
|
2000-05-02 23:23:12 +00:00
|
|
|
char *s;
|
2020-02-13 14:44:37 -08:00
|
|
|
int i = 0;
|
2000-05-02 23:23:12 +00:00
|
|
|
|
|
|
|
s = string;
|
2000-07-05 19:31:26 +00:00
|
|
|
while (*s != '\0') {
|
2020-02-13 21:48:23 +01:00
|
|
|
if (*s == '.') {
|
2000-05-02 23:23:12 +00:00
|
|
|
i++;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2000-05-02 23:23:12 +00:00
|
|
|
s++;
|
|
|
|
}
|
|
|
|
return (i);
|
|
|
|
}
|
|
|
|
|
2000-04-26 18:34:17 +00:00
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
hex_dump(isc_buffer_t *b) {
|
2009-02-16 00:01:37 +00:00
|
|
|
unsigned int len, i;
|
2000-04-26 18:34:17 +00:00
|
|
|
isc_region_t r;
|
|
|
|
|
2000-09-13 00:55:13 +00:00
|
|
|
isc_buffer_usedregion(b, &r);
|
2000-04-26 18:34:17 +00:00
|
|
|
|
2018-02-14 17:41:30 +11:00
|
|
|
printf("%u bytes\n", r.length);
|
2000-07-05 19:31:26 +00:00
|
|
|
for (len = 0; len < r.length; len++) {
|
2000-04-26 18:34:17 +00:00
|
|
|
printf("%02x ", r.base[len]);
|
2009-02-16 00:01:37 +00:00
|
|
|
if (len % 16 == 15) {
|
2020-04-02 18:51:06 -07:00
|
|
|
printf(" ");
|
2009-02-16 00:01:37 +00:00
|
|
|
for (i = len - 15; i <= len; i++) {
|
2020-02-13 21:48:23 +01:00
|
|
|
if (r.base[i] >= '!' && r.base[i] <= '}') {
|
2009-02-16 00:01:37 +00:00
|
|
|
putchar(r.base[i]);
|
2020-02-13 21:48:23 +01:00
|
|
|
} else {
|
2009-02-16 00:01:37 +00:00
|
|
|
putchar('.');
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2009-02-16 00:01:37 +00:00
|
|
|
}
|
2000-04-26 18:34:17 +00:00
|
|
|
printf("\n");
|
2009-02-16 00:01:37 +00:00
|
|
|
}
|
2000-04-26 18:34:17 +00:00
|
|
|
}
|
2009-02-16 00:01:37 +00:00
|
|
|
if (len % 16 != 0) {
|
2020-02-13 21:48:23 +01:00
|
|
|
for (i = len; (i % 16) != 0; i++) {
|
2020-04-02 18:51:06 -07:00
|
|
|
printf(" ");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2020-04-02 18:51:06 -07:00
|
|
|
printf(" ");
|
2020-02-12 13:59:18 +01:00
|
|
|
for (i = ((len >> 4) << 4); i < len; i++) {
|
2020-02-13 21:48:23 +01:00
|
|
|
if (r.base[i] >= '!' && r.base[i] <= '}') {
|
2009-02-16 00:01:37 +00:00
|
|
|
putchar(r.base[i]);
|
2020-02-13 21:48:23 +01:00
|
|
|
} else {
|
2009-02-16 00:01:37 +00:00
|
|
|
putchar('.');
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2009-02-16 00:01:37 +00:00
|
|
|
}
|
2000-04-26 18:34:17 +00:00
|
|
|
printf("\n");
|
2009-02-16 00:01:37 +00:00
|
|
|
}
|
2000-04-26 18:34:17 +00:00
|
|
|
}
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
2001-08-29 18:57:28 +00:00
|
|
|
* Append 'len' bytes of 'text' at '*p', failing with
|
|
|
|
* ISC_R_NOSPACE if that would advance p past 'end'.
|
|
|
|
*/
|
|
|
|
static isc_result_t
|
2020-02-13 14:44:37 -08:00
|
|
|
append(const char *text, size_t len, char **p, char *end) {
|
2020-02-13 21:48:23 +01:00
|
|
|
if (*p + len > end) {
|
2001-08-29 18:57:28 +00:00
|
|
|
return (ISC_R_NOSPACE);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2014-01-08 16:27:10 -08:00
|
|
|
memmove(*p, text, len);
|
2001-08-29 18:57:28 +00:00
|
|
|
*p += len;
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
2020-02-13 14:44:37 -08:00
|
|
|
reverse_octets(const char *in, char **p, char *end) {
|
2015-11-20 18:38:24 +11:00
|
|
|
const char *dot = strchr(in, '.');
|
2020-02-13 14:44:37 -08:00
|
|
|
size_t len;
|
2001-08-29 18:57:28 +00:00
|
|
|
if (dot != NULL) {
|
|
|
|
isc_result_t result;
|
|
|
|
result = reverse_octets(dot + 1, p, end);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2001-08-29 18:57:28 +00:00
|
|
|
return (result);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-08-29 18:57:28 +00:00
|
|
|
result = append(".", 1, p, end);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2001-08-29 18:57:28 +00:00
|
|
|
return (result);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2020-02-12 13:59:18 +01:00
|
|
|
len = (int)(dot - in);
|
2001-08-29 18:57:28 +00:00
|
|
|
} else {
|
2020-02-12 13:59:18 +01:00
|
|
|
len = (int)strlen(in);
|
2001-08-29 18:57:28 +00:00
|
|
|
}
|
|
|
|
return (append(in, len, p, end));
|
|
|
|
}
|
2000-10-23 23:13:21 +00:00
|
|
|
|
|
|
|
isc_result_t
|
2020-02-13 14:44:37 -08:00
|
|
|
get_reverse(char *reverse, size_t len, char *value, bool strict) {
|
|
|
|
int r;
|
|
|
|
isc_result_t result;
|
2001-08-29 18:57:28 +00:00
|
|
|
isc_netaddr_t addr;
|
2000-10-23 23:13:21 +00:00
|
|
|
|
2001-08-29 18:57:28 +00:00
|
|
|
addr.family = AF_INET6;
|
2001-10-31 20:39:39 +00:00
|
|
|
r = inet_pton(AF_INET6, value, &addr.type.in6);
|
2001-08-29 18:57:28 +00:00
|
|
|
if (r > 0) {
|
|
|
|
/* This is a valid IPv6 address. */
|
2000-10-23 23:13:21 +00:00
|
|
|
dns_fixedname_t fname;
|
2020-02-13 14:44:37 -08:00
|
|
|
dns_name_t *name;
|
|
|
|
unsigned int options = 0;
|
2002-08-27 04:53:43 +00:00
|
|
|
|
2018-03-28 14:38:09 +02:00
|
|
|
name = dns_fixedname_initname(&fname);
|
2018-04-03 13:10:07 +02:00
|
|
|
result = dns_byaddr_createptrname(&addr, options, name);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2000-10-23 23:13:21 +00:00
|
|
|
return (result);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2013-12-04 12:47:23 +11:00
|
|
|
dns_name_format(name, reverse, (unsigned int)len);
|
2001-08-29 18:57:28 +00:00
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* Not a valid IPv6 address. Assume IPv4.
|
|
|
|
* If 'strict' is not set, construct the
|
|
|
|
* in-addr.arpa name by blindly reversing
|
|
|
|
* octets whether or not they look like integers,
|
|
|
|
* so that this can be used for RFC2317 names
|
|
|
|
* and such.
|
|
|
|
*/
|
|
|
|
char *p = reverse;
|
2003-07-25 04:02:54 +00:00
|
|
|
char *end = reverse + len;
|
2020-02-13 21:48:23 +01:00
|
|
|
if (strict && inet_pton(AF_INET, value, &addr.type.in) != 1) {
|
2002-11-12 23:08:27 +00:00
|
|
|
return (DNS_R_BADDOTTEDQUAD);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-08-29 18:57:28 +00:00
|
|
|
result = reverse_octets(value, &p, end);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2001-08-29 18:57:28 +00:00
|
|
|
return (result);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-08-29 18:57:28 +00:00
|
|
|
/* Append .in-addr.arpa. and a terminating NUL. */
|
|
|
|
result = append(".in-addr.arpa.", 15, &p, end);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2001-08-29 18:57:28 +00:00
|
|
|
return (result);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-08-29 18:57:28 +00:00
|
|
|
return (ISC_R_SUCCESS);
|
2000-10-23 23:13:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-23 16:58:12 +11:00
|
|
|
void (*dighost_pre_exit_hook)(void) = NULL;
|
|
|
|
|
|
|
|
#if TARGET_OS_IPHONE
|
2000-04-26 18:34:17 +00:00
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
warn(const char *format, ...) {
|
2017-11-23 16:58:12 +11:00
|
|
|
va_list args;
|
|
|
|
|
|
|
|
fflush(stdout);
|
|
|
|
fprintf(stderr, ";; Warning: ");
|
|
|
|
va_start(args, format);
|
|
|
|
vfprintf(stderr, format, args);
|
|
|
|
va_end(args);
|
|
|
|
fprintf(stderr, "\n");
|
|
|
|
}
|
2020-02-13 21:48:23 +01:00
|
|
|
#else /* if TARGET_OS_IPHONE */
|
2017-11-23 16:58:12 +11:00
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
warn(const char *format, ...) {
|
2000-04-26 18:34:17 +00:00
|
|
|
va_list args;
|
|
|
|
|
2008-01-17 21:46:33 +00:00
|
|
|
fflush(stdout);
|
2000-07-13 02:14:17 +00:00
|
|
|
fprintf(stderr, "%s: ", progname);
|
2000-08-01 01:33:37 +00:00
|
|
|
va_start(args, format);
|
2000-04-26 18:34:17 +00:00
|
|
|
vfprintf(stderr, format, args);
|
|
|
|
va_end(args);
|
|
|
|
fprintf(stderr, "\n");
|
2017-11-23 16:58:12 +11:00
|
|
|
}
|
2020-02-13 21:48:23 +01:00
|
|
|
#endif /* if TARGET_OS_IPHONE */
|
2017-11-23 16:58:12 +11:00
|
|
|
|
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
digexit(void) {
|
2020-02-13 21:48:23 +01:00
|
|
|
if (exitcode < 10) {
|
2000-08-03 17:43:06 +00:00
|
|
|
exitcode = 10;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if (fatalexit != 0) {
|
2002-09-26 11:17:06 +00:00
|
|
|
exitcode = fatalexit;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2017-11-23 16:58:12 +11:00
|
|
|
if (dighost_pre_exit_hook != NULL) {
|
|
|
|
dighost_pre_exit_hook();
|
|
|
|
}
|
2000-05-08 22:51:08 +00:00
|
|
|
exit(exitcode);
|
2000-04-26 18:34:17 +00:00
|
|
|
}
|
|
|
|
|
2017-11-23 16:58:12 +11:00
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
fatal(const char *format, ...) {
|
2017-11-23 16:58:12 +11:00
|
|
|
va_list args;
|
|
|
|
|
|
|
|
fflush(stdout);
|
|
|
|
fprintf(stderr, "%s: ", progname);
|
|
|
|
va_start(args, format);
|
|
|
|
vfprintf(stderr, format, args);
|
|
|
|
va_end(args);
|
|
|
|
fprintf(stderr, "\n");
|
|
|
|
digexit();
|
|
|
|
}
|
|
|
|
|
2000-04-29 00:12:56 +00:00
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
debug(const char *format, ...) {
|
|
|
|
va_list args;
|
2013-11-18 15:46:24 -08:00
|
|
|
isc_time_t t;
|
2000-04-29 00:12:56 +00:00
|
|
|
|
2000-06-06 22:50:44 +00:00
|
|
|
if (debugging) {
|
2008-01-17 21:46:33 +00:00
|
|
|
fflush(stdout);
|
2013-10-25 10:09:33 +11:00
|
|
|
if (debugtiming) {
|
2013-11-18 15:46:24 -08:00
|
|
|
TIME_NOW(&t);
|
2018-02-14 17:41:30 +11:00
|
|
|
fprintf(stderr, "%u.%06u: ", isc_time_seconds(&t),
|
2013-11-18 15:59:53 -08:00
|
|
|
isc_time_nanoseconds(&t) / 1000);
|
2013-10-25 10:09:33 +11:00
|
|
|
}
|
2000-08-01 01:33:37 +00:00
|
|
|
va_start(args, format);
|
2000-06-06 22:50:44 +00:00
|
|
|
vfprintf(stderr, format, args);
|
|
|
|
va_end(args);
|
|
|
|
fprintf(stderr, "\n");
|
|
|
|
}
|
2000-04-29 00:12:56 +00:00
|
|
|
}
|
|
|
|
|
2000-05-05 18:22:16 +00:00
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
check_result(isc_result_t result, const char *msg) {
|
2000-05-08 22:51:08 +00:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2000-04-26 18:34:17 +00:00
|
|
|
fatal("%s: %s", msg, isc_result_totext(result));
|
2000-05-08 22:51:08 +00:00
|
|
|
}
|
2000-04-26 18:34:17 +00:00
|
|
|
}
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
2000-07-18 18:51:40 +00:00
|
|
|
* Create a server structure, which is part of the lookup structure.
|
|
|
|
* This is little more than a linked list of servers to query in hopes
|
|
|
|
* of finding the answer the user is looking for
|
|
|
|
*/
|
2000-07-14 16:35:30 +00:00
|
|
|
dig_server_t *
|
2020-02-13 14:44:37 -08:00
|
|
|
make_server(const char *servname, const char *userarg) {
|
2000-07-14 16:35:30 +00:00
|
|
|
dig_server_t *srv;
|
|
|
|
|
|
|
|
REQUIRE(servname != NULL);
|
|
|
|
|
2000-10-20 02:21:58 +00:00
|
|
|
debug("make_server(%s)", servname);
|
2000-07-14 16:35:30 +00:00
|
|
|
srv = isc_mem_allocate(mctx, sizeof(struct dig_server));
|
2011-02-21 07:34:57 +00:00
|
|
|
strlcpy(srv->servername, servname, MXNAME);
|
|
|
|
strlcpy(srv->userarg, userarg, MXNAME);
|
2000-10-20 02:21:58 +00:00
|
|
|
ISC_LINK_INIT(srv, link);
|
2000-07-14 16:35:30 +00:00
|
|
|
return (srv);
|
|
|
|
}
|
2004-09-06 01:24:44 +00:00
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
2017-09-08 13:39:09 -07:00
|
|
|
* Create a copy of the server list from the resolver configuration structure.
|
2002-08-12 18:25:25 +00:00
|
|
|
* The dest list must have already had ISC_LIST_INIT applied.
|
|
|
|
*/
|
2002-08-28 07:04:48 +00:00
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
get_server_list(irs_resconf_t *resconf) {
|
2017-09-08 13:39:09 -07:00
|
|
|
isc_sockaddrlist_t *servers;
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_sockaddr_t *sa;
|
|
|
|
dig_server_t *newsrv;
|
2014-07-30 23:26:37 +10:00
|
|
|
char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") +
|
|
|
|
sizeof("%4000000000")];
|
2017-09-08 13:39:09 -07:00
|
|
|
debug("get_server_list()");
|
|
|
|
servers = irs_resconf_getnameservers(resconf);
|
2020-02-12 13:59:18 +01:00
|
|
|
for (sa = ISC_LIST_HEAD(*servers); sa != NULL;
|
|
|
|
sa = ISC_LIST_NEXT(sa, link)) {
|
2020-02-13 14:44:37 -08:00
|
|
|
int pf = isc_sockaddr_pf(sa);
|
2017-09-08 13:39:09 -07:00
|
|
|
isc_netaddr_t na;
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_result_t result;
|
|
|
|
isc_buffer_t b;
|
2002-08-12 18:25:25 +00:00
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (pf == AF_INET && !have_ipv4) {
|
2008-12-13 02:43:25 +00:00
|
|
|
continue;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if (pf == AF_INET6 && !have_ipv6) {
|
2008-12-13 02:43:25 +00:00
|
|
|
continue;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2008-12-13 02:43:25 +00:00
|
|
|
|
2017-09-08 13:39:09 -07:00
|
|
|
isc_buffer_init(&b, tmp, sizeof(tmp));
|
|
|
|
isc_netaddr_fromsockaddr(&na, sa);
|
|
|
|
result = isc_netaddr_totext(&na, &b);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2017-09-08 13:39:09 -07:00
|
|
|
continue;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2017-09-08 13:39:09 -07:00
|
|
|
isc_buffer_putuint8(&b, 0);
|
|
|
|
if (pf == AF_INET6 && na.zone != 0) {
|
2014-07-30 23:26:37 +10:00
|
|
|
char buf[sizeof("%4000000000")];
|
2017-09-08 13:39:09 -07:00
|
|
|
snprintf(buf, sizeof(buf), "%%%u", na.zone);
|
2014-07-30 23:26:37 +10:00
|
|
|
strlcat(tmp, buf, sizeof(tmp));
|
|
|
|
}
|
2004-09-06 01:24:44 +00:00
|
|
|
newsrv = make_server(tmp, tmp);
|
2002-08-12 18:25:25 +00:00
|
|
|
ISC_LINK_INIT(newsrv, link);
|
2017-09-08 13:39:09 -07:00
|
|
|
ISC_LIST_APPEND(server_list, newsrv, link);
|
2002-08-12 18:25:25 +00:00
|
|
|
}
|
|
|
|
}
|
2004-09-06 01:24:44 +00:00
|
|
|
|
2002-08-12 18:25:25 +00:00
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
flush_server_list(void) {
|
2002-08-12 18:25:25 +00:00
|
|
|
dig_server_t *s, *ps;
|
|
|
|
|
|
|
|
debug("flush_server_list()");
|
|
|
|
s = ISC_LIST_HEAD(server_list);
|
|
|
|
while (s != NULL) {
|
|
|
|
ps = s;
|
|
|
|
s = ISC_LIST_NEXT(s, link);
|
|
|
|
ISC_LIST_DEQUEUE(server_list, ps, link);
|
|
|
|
isc_mem_free(mctx, ps);
|
|
|
|
}
|
|
|
|
}
|
2004-09-06 01:24:44 +00:00
|
|
|
|
2002-08-12 18:25:25 +00:00
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
set_nameserver(char *opt) {
|
|
|
|
isc_result_t result;
|
2004-09-06 01:24:44 +00:00
|
|
|
isc_sockaddr_t sockaddrs[DIG_MAX_ADDRESSES];
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_netaddr_t netaddr;
|
|
|
|
int count, i;
|
|
|
|
dig_server_t *srv;
|
|
|
|
char tmp[ISC_NETADDR_FORMATSIZE];
|
2002-08-12 18:25:25 +00:00
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (opt == NULL) {
|
2002-08-12 18:25:25 +00:00
|
|
|
return;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2002-08-12 18:25:25 +00:00
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
result = bind9_getaddresses(opt, 0, sockaddrs, DIG_MAX_ADDRESSES,
|
|
|
|
&count);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2020-02-12 13:59:18 +01:00
|
|
|
fatal("couldn't get address for '%s': %s", opt,
|
|
|
|
isc_result_totext(result));
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2004-09-06 01:24:44 +00:00
|
|
|
|
2002-08-12 18:25:25 +00:00
|
|
|
flush_server_list();
|
2008-01-18 23:46:58 +00:00
|
|
|
|
2004-09-06 01:24:44 +00:00
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
isc_netaddr_fromsockaddr(&netaddr, &sockaddrs[i]);
|
|
|
|
isc_netaddr_format(&netaddr, tmp, sizeof(tmp));
|
|
|
|
srv = make_server(tmp, opt);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (srv == NULL) {
|
2004-09-06 01:24:44 +00:00
|
|
|
fatal("memory allocation failure");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2004-09-06 01:24:44 +00:00
|
|
|
ISC_LIST_APPEND(server_list, srv, link);
|
|
|
|
}
|
2002-08-12 18:25:25 +00:00
|
|
|
}
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
2000-07-18 18:51:40 +00:00
|
|
|
* Produce a cloned server list. The dest list must have already had
|
|
|
|
* ISC_LIST_INIT applied.
|
|
|
|
*/
|
2000-07-14 16:35:30 +00:00
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
clone_server_list(dig_serverlist_t src, dig_serverlist_t *dest) {
|
2000-07-14 16:35:30 +00:00
|
|
|
dig_server_t *srv, *newsrv;
|
|
|
|
|
|
|
|
debug("clone_server_list()");
|
|
|
|
srv = ISC_LIST_HEAD(src);
|
|
|
|
while (srv != NULL) {
|
2004-09-06 01:24:44 +00:00
|
|
|
newsrv = make_server(srv->servername, srv->userarg);
|
2000-10-23 17:49:05 +00:00
|
|
|
ISC_LINK_INIT(newsrv, link);
|
2000-07-14 16:35:30 +00:00
|
|
|
ISC_LIST_ENQUEUE(*dest, newsrv, link);
|
|
|
|
srv = ISC_LIST_NEXT(srv, link);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
2000-07-18 18:51:40 +00:00
|
|
|
* Create an empty lookup structure, which holds all the information needed
|
|
|
|
* to get an answer to a user's question. This structure contains two
|
|
|
|
* linked lists: the server list (servers to query) and the query list
|
|
|
|
* (outstanding queries which have been made to the listed servers).
|
|
|
|
*/
|
2000-07-05 19:31:26 +00:00
|
|
|
dig_lookup_t *
|
2020-02-13 14:44:37 -08:00
|
|
|
make_empty_lookup(void) {
|
2000-05-12 01:02:37 +00:00
|
|
|
dig_lookup_t *looknew;
|
2021-01-27 15:49:27 +01:00
|
|
|
#ifdef HAVE_LIBIDN2
|
|
|
|
bool idn_allowed = isatty(1) ? (getenv("IDN_DISABLE") == NULL) : false;
|
|
|
|
#endif /* HAVE_LIBIDN2 */
|
2000-05-12 01:02:37 +00:00
|
|
|
|
2000-09-21 22:46:39 +00:00
|
|
|
debug("make_empty_lookup()");
|
2000-05-12 01:02:37 +00:00
|
|
|
|
2000-07-13 00:32:20 +00:00
|
|
|
INSIST(!free_now);
|
2000-05-22 22:56:31 +00:00
|
|
|
|
2021-01-27 15:49:27 +01:00
|
|
|
looknew = isc_mem_allocate(mctx, sizeof(*looknew));
|
|
|
|
*looknew = (dig_lookup_t){
|
|
|
|
.pending = true,
|
|
|
|
.rdtype = dns_rdatatype_a,
|
|
|
|
.qrdtype = dns_rdatatype_a,
|
|
|
|
.rdclass = dns_rdataclass_in,
|
|
|
|
.servfail_stops = true,
|
|
|
|
.besteffort = true,
|
|
|
|
.opcode = dns_opcode_query,
|
|
|
|
.badcookie = true,
|
Rework libidn2 detection
Clean up the parts of configure.in responsible for handling libidn2
detection and adjust other pieces of the build system to match these
cleanups:
- use pkg-config when --with-libidn2 is used without an explicit path,
- look for idn2_to_ascii_lz() rather than idn2_to_ascii_8z() as the
former is used in BIND while the latter is not,
- do not look for idn2_to_unicode_8zlz() as it is present in all
libidn2 versions which have idn2_to_ascii_lz(),
- check whether the <idn2.h> header is usable,
- set LDFLAGS in the Makefile for dig so that, if specified, the
requested libidn2 path is used when linking with libidn2,
- override CPPFLAGS when looking for libidn2 components so that the
configure script does not produce warnings when libidn2 is not
installed system-wide,
- merge the AS_CASE() call into the AS_IF() call below it to simplify
code,
- indicate the default value of --with-libidn2 in "./configure --help"
output,
- use $with_libidn2 rather than $use_libidn2 to better match the name
of the configure script argument,
- stop differentiating between IDN "in" and "out" support, i.e. make
dig either support libidn2 or not; remove WITH_* Autoconf macros and
use a new one, HAVE_LIBIDN2, to determine whether libidn2 support
should be enabled.
2018-07-10 14:34:35 +02:00
|
|
|
#ifdef HAVE_LIBIDN2
|
2021-01-27 15:49:27 +01:00
|
|
|
.idnin = idn_allowed,
|
|
|
|
.idnout = idn_allowed,
|
Rework libidn2 detection
Clean up the parts of configure.in responsible for handling libidn2
detection and adjust other pieces of the build system to match these
cleanups:
- use pkg-config when --with-libidn2 is used without an explicit path,
- look for idn2_to_ascii_lz() rather than idn2_to_ascii_8z() as the
former is used in BIND while the latter is not,
- do not look for idn2_to_unicode_8zlz() as it is present in all
libidn2 versions which have idn2_to_ascii_lz(),
- check whether the <idn2.h> header is usable,
- set LDFLAGS in the Makefile for dig so that, if specified, the
requested libidn2 path is used when linking with libidn2,
- override CPPFLAGS when looking for libidn2 components so that the
configure script does not produce warnings when libidn2 is not
installed system-wide,
- merge the AS_CASE() call into the AS_IF() call below it to simplify
code,
- indicate the default value of --with-libidn2 in "./configure --help"
output,
- use $with_libidn2 rather than $use_libidn2 to better match the name
of the configure script argument,
- stop differentiating between IDN "in" and "out" support, i.e. make
dig either support libidn2 or not; remove WITH_* Autoconf macros and
use a new one, HAVE_LIBIDN2, to determine whether libidn2 support
should be enabled.
2018-07-10 14:34:35 +02:00
|
|
|
#endif /* HAVE_LIBIDN2 */
|
2021-01-27 15:49:27 +01:00
|
|
|
.udpsize = -1,
|
|
|
|
.edns = -1,
|
|
|
|
.recurse = true,
|
|
|
|
.retries = tries,
|
|
|
|
.comments = true,
|
|
|
|
.stats = true,
|
|
|
|
.section_question = true,
|
|
|
|
.section_answer = true,
|
|
|
|
.section_authority = true,
|
|
|
|
.section_additional = true,
|
|
|
|
.ednsneg = true,
|
|
|
|
.dscp = -1,
|
|
|
|
};
|
|
|
|
|
2014-03-01 15:32:25 -08:00
|
|
|
dns_fixedname_init(&looknew->fdomain);
|
2000-10-20 02:21:58 +00:00
|
|
|
ISC_LINK_INIT(looknew, link);
|
2000-07-13 18:52:58 +00:00
|
|
|
ISC_LIST_INIT(looknew->q);
|
2000-07-14 16:35:30 +00:00
|
|
|
ISC_LIST_INIT(looknew->my_server_list);
|
2020-11-05 15:22:38 +01:00
|
|
|
|
2022-01-19 13:10:08 +02:00
|
|
|
looknew->tls_ctx_cache = isc_tlsctx_cache_new(mctx);
|
|
|
|
|
2020-11-05 15:22:38 +01:00
|
|
|
isc_refcount_init(&looknew->references, 1);
|
|
|
|
|
|
|
|
looknew->magic = DIG_LOOKUP_MAGIC;
|
|
|
|
|
|
|
|
debug("make_empty_lookup() = %p->references = %" PRIuFAST32, looknew,
|
|
|
|
isc_refcount_current(&looknew->references));
|
|
|
|
|
2000-07-13 18:52:58 +00:00
|
|
|
return (looknew);
|
|
|
|
}
|
|
|
|
|
2017-11-13 16:10:35 +11:00
|
|
|
#define EDNSOPT_OPTIONS 100U
|
|
|
|
|
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
cloneopts(dig_lookup_t *looknew, dig_lookup_t *lookold) {
|
2017-11-13 16:10:35 +11:00
|
|
|
size_t len = sizeof(looknew->ednsopts[0]) * EDNSOPT_OPTIONS;
|
|
|
|
size_t i;
|
|
|
|
looknew->ednsopts = isc_mem_allocate(mctx, len);
|
|
|
|
for (i = 0; i < EDNSOPT_OPTIONS; i++) {
|
|
|
|
looknew->ednsopts[i].code = 0;
|
|
|
|
looknew->ednsopts[i].length = 0;
|
|
|
|
looknew->ednsopts[i].value = NULL;
|
|
|
|
}
|
|
|
|
looknew->ednsoptscnt = 0;
|
2020-02-13 21:48:23 +01:00
|
|
|
if (lookold == NULL || lookold->ednsopts == NULL) {
|
2017-11-13 16:10:35 +11:00
|
|
|
return;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2017-11-13 16:10:35 +11:00
|
|
|
|
|
|
|
for (i = 0; i < lookold->ednsoptscnt; i++) {
|
|
|
|
len = lookold->ednsopts[i].length;
|
|
|
|
if (len != 0) {
|
|
|
|
INSIST(lookold->ednsopts[i].value != NULL);
|
2020-02-13 14:44:37 -08:00
|
|
|
looknew->ednsopts[i].value = isc_mem_allocate(mctx,
|
|
|
|
len);
|
2017-11-13 16:10:35 +11:00
|
|
|
memmove(looknew->ednsopts[i].value,
|
|
|
|
lookold->ednsopts[i].value, len);
|
|
|
|
}
|
|
|
|
looknew->ednsopts[i].code = lookold->ednsopts[i].code;
|
|
|
|
looknew->ednsopts[i].length = len;
|
|
|
|
}
|
|
|
|
looknew->ednsoptscnt = lookold->ednsoptscnt;
|
|
|
|
}
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
2000-07-18 18:51:40 +00:00
|
|
|
* Clone a lookup, perhaps copying the server list. This does not clone
|
|
|
|
* the query list, since it will be regenerated by the setup_lookup()
|
|
|
|
* function, nor does it queue up the new lookup for processing.
|
2000-07-14 16:35:30 +00:00
|
|
|
* Caution: If you don't clone the servers, you MUST clone the server
|
2009-01-17 10:15:38 +00:00
|
|
|
* list separately from somewhere else, or construct it by hand.
|
2000-07-14 16:35:30 +00:00
|
|
|
*/
|
2000-07-13 18:52:58 +00:00
|
|
|
dig_lookup_t *
|
2020-02-13 14:44:37 -08:00
|
|
|
clone_lookup(dig_lookup_t *lookold, bool servers) {
|
2000-07-13 18:52:58 +00:00
|
|
|
dig_lookup_t *looknew;
|
|
|
|
|
|
|
|
debug("clone_lookup()");
|
|
|
|
|
|
|
|
INSIST(!free_now);
|
|
|
|
|
|
|
|
looknew = make_empty_lookup();
|
2012-10-02 23:44:03 -07:00
|
|
|
strlcpy(looknew->textname, lookold->textname, MXNAME);
|
|
|
|
strlcpy(looknew->cmdline, lookold->cmdline, MXNAME);
|
2020-02-12 13:59:18 +01:00
|
|
|
looknew->textname[MXNAME - 1] = 0;
|
2000-07-18 01:28:20 +00:00
|
|
|
looknew->rdtype = lookold->rdtype;
|
2001-07-28 00:11:15 +00:00
|
|
|
looknew->qrdtype = lookold->qrdtype;
|
2000-07-18 01:28:20 +00:00
|
|
|
looknew->rdclass = lookold->rdclass;
|
2000-12-08 17:50:47 +00:00
|
|
|
looknew->rdtypeset = lookold->rdtypeset;
|
|
|
|
looknew->rdclassset = lookold->rdclassset;
|
2000-05-12 01:02:37 +00:00
|
|
|
looknew->doing_xfr = lookold->doing_xfr;
|
2000-06-02 18:45:33 +00:00
|
|
|
looknew->ixfr_serial = lookold->ixfr_serial;
|
2000-05-12 01:02:37 +00:00
|
|
|
looknew->trace = lookold->trace;
|
|
|
|
looknew->trace_root = lookold->trace_root;
|
|
|
|
looknew->identify = lookold->identify;
|
2001-02-13 23:12:17 +00:00
|
|
|
looknew->identify_previous_line = lookold->identify_previous_line;
|
2000-09-13 00:03:28 +00:00
|
|
|
looknew->ignore = lookold->ignore;
|
2000-09-28 23:02:28 +00:00
|
|
|
looknew->servfail_stops = lookold->servfail_stops;
|
2000-10-13 17:54:00 +00:00
|
|
|
looknew->besteffort = lookold->besteffort;
|
2019-07-25 20:26:13 +10:00
|
|
|
looknew->dns64prefix = lookold->dns64prefix;
|
2000-11-13 21:34:03 +00:00
|
|
|
looknew->dnssec = lookold->dnssec;
|
2014-09-13 19:13:59 +10:00
|
|
|
looknew->ednsflags = lookold->ednsflags;
|
2015-05-19 12:46:06 +10:00
|
|
|
looknew->opcode = lookold->opcode;
|
2014-02-20 14:56:20 +11:00
|
|
|
looknew->expire = lookold->expire;
|
2008-04-03 02:01:08 +00:00
|
|
|
looknew->nsid = lookold->nsid;
|
2017-01-04 09:16:30 -08:00
|
|
|
looknew->tcp_keepalive = lookold->tcp_keepalive;
|
2014-10-30 11:42:02 +11:00
|
|
|
looknew->header_only = lookold->header_only;
|
2021-01-27 15:49:27 +01:00
|
|
|
looknew->https_mode = lookold->https_mode;
|
|
|
|
if (lookold->https_path != NULL) {
|
|
|
|
looknew->https_path = isc_mem_strdup(mctx, lookold->https_path);
|
|
|
|
}
|
|
|
|
looknew->https_get = lookold->https_get;
|
|
|
|
looknew->http_plain = lookold->http_plain;
|
2020-12-01 15:10:32 +11:00
|
|
|
|
2022-01-19 13:10:08 +02:00
|
|
|
looknew->tls_ca_set = lookold->tls_ca_set;
|
|
|
|
if (lookold->tls_ca_file != NULL) {
|
|
|
|
looknew->tls_ca_file = isc_mem_strdup(mctx,
|
|
|
|
lookold->tls_ca_file);
|
|
|
|
};
|
|
|
|
|
|
|
|
looknew->tls_hostname_set = lookold->tls_hostname_set;
|
|
|
|
if (lookold->tls_hostname != NULL) {
|
|
|
|
looknew->tls_hostname = isc_mem_strdup(mctx,
|
|
|
|
lookold->tls_hostname);
|
|
|
|
}
|
|
|
|
|
|
|
|
looknew->tls_key_file_set = lookold->tls_key_file_set;
|
|
|
|
if (lookold->tls_key_file != NULL) {
|
|
|
|
looknew->tls_key_file = isc_mem_strdup(mctx,
|
|
|
|
lookold->tls_key_file);
|
|
|
|
}
|
|
|
|
|
|
|
|
looknew->tls_cert_file_set = lookold->tls_cert_file_set;
|
|
|
|
if (lookold->tls_cert_file != NULL) {
|
|
|
|
looknew->tls_cert_file = isc_mem_strdup(mctx,
|
|
|
|
lookold->tls_cert_file);
|
|
|
|
}
|
|
|
|
|
2020-12-01 15:10:32 +11:00
|
|
|
looknew->showbadcookie = lookold->showbadcookie;
|
2015-07-06 09:44:24 +10:00
|
|
|
looknew->sendcookie = lookold->sendcookie;
|
|
|
|
looknew->seenbadcookie = lookold->seenbadcookie;
|
|
|
|
looknew->badcookie = lookold->badcookie;
|
|
|
|
looknew->cookie = lookold->cookie;
|
2017-11-13 16:10:35 +11:00
|
|
|
if (lookold->ednsopts != NULL) {
|
|
|
|
cloneopts(looknew, lookold);
|
|
|
|
} else {
|
|
|
|
looknew->ednsopts = NULL;
|
|
|
|
looknew->ednsoptscnt = 0;
|
|
|
|
}
|
2014-10-30 23:13:12 +11:00
|
|
|
looknew->ednsneg = lookold->ednsneg;
|
2017-01-04 09:16:30 -08:00
|
|
|
looknew->padding = lookold->padding;
|
2016-10-10 11:55:59 +11:00
|
|
|
looknew->multiline = lookold->multiline;
|
|
|
|
looknew->nottl = lookold->nottl;
|
|
|
|
looknew->noclass = lookold->noclass;
|
|
|
|
looknew->onesoa = lookold->onesoa;
|
|
|
|
looknew->use_usec = lookold->use_usec;
|
|
|
|
looknew->nocrypto = lookold->nocrypto;
|
|
|
|
looknew->ttlunits = lookold->ttlunits;
|
2018-12-06 17:36:46 +11:00
|
|
|
looknew->expandaaaa = lookold->expandaaaa;
|
2016-10-10 11:55:59 +11:00
|
|
|
looknew->qr = lookold->qr;
|
2017-08-15 14:36:59 +02:00
|
|
|
looknew->idnin = lookold->idnin;
|
2016-10-28 12:05:19 +11:00
|
|
|
looknew->idnout = lookold->idnout;
|
2000-05-12 01:02:37 +00:00
|
|
|
looknew->udpsize = lookold->udpsize;
|
2005-06-07 00:16:01 +00:00
|
|
|
looknew->edns = lookold->edns;
|
2000-05-12 01:02:37 +00:00
|
|
|
looknew->recurse = lookold->recurse;
|
2000-12-11 19:24:30 +00:00
|
|
|
looknew->aaonly = lookold->aaonly;
|
2000-06-16 18:00:05 +00:00
|
|
|
looknew->adflag = lookold->adflag;
|
|
|
|
looknew->cdflag = lookold->cdflag;
|
2018-04-18 09:18:41 +10:00
|
|
|
looknew->raflag = lookold->raflag;
|
|
|
|
looknew->tcflag = lookold->tcflag;
|
2016-02-09 15:38:34 +05:30
|
|
|
looknew->print_unknown_format = lookold->print_unknown_format;
|
2014-10-31 10:16:00 +11:00
|
|
|
looknew->zflag = lookold->zflag;
|
2020-05-08 12:39:16 -07:00
|
|
|
looknew->setqid = lookold->setqid;
|
|
|
|
looknew->qid = lookold->qid;
|
2000-05-12 01:02:37 +00:00
|
|
|
looknew->ns_search_only = lookold->ns_search_only;
|
|
|
|
looknew->tcp_mode = lookold->tcp_mode;
|
2014-05-14 09:59:02 +10:00
|
|
|
looknew->tcp_mode_set = lookold->tcp_mode_set;
|
2020-07-22 08:59:42 +02:00
|
|
|
looknew->tls_mode = lookold->tls_mode;
|
2000-05-12 01:02:37 +00:00
|
|
|
looknew->comments = lookold->comments;
|
|
|
|
looknew->stats = lookold->stats;
|
|
|
|
looknew->section_question = lookold->section_question;
|
|
|
|
looknew->section_answer = lookold->section_answer;
|
|
|
|
looknew->section_authority = lookold->section_authority;
|
|
|
|
looknew->section_additional = lookold->section_additional;
|
2017-09-11 10:10:16 -07:00
|
|
|
looknew->origin = lookold->origin;
|
2000-09-21 22:46:39 +00:00
|
|
|
looknew->retries = lookold->retries;
|
2001-10-11 00:38:56 +00:00
|
|
|
looknew->tsigctx = NULL;
|
2006-12-07 05:52:16 +00:00
|
|
|
looknew->need_search = lookold->need_search;
|
|
|
|
looknew->done_as_is = lookold->done_as_is;
|
2014-07-15 23:27:14 +10:00
|
|
|
looknew->dscp = lookold->dscp;
|
2016-10-10 11:55:59 +11:00
|
|
|
looknew->rrcomments = lookold->rrcomments;
|
2017-10-05 09:42:31 +02:00
|
|
|
looknew->eoferr = lookold->eoferr;
|
2000-05-12 01:02:37 +00:00
|
|
|
|
2014-02-19 15:51:02 -08:00
|
|
|
if (lookold->ecs_addr != NULL) {
|
|
|
|
size_t len = sizeof(isc_sockaddr_t);
|
|
|
|
looknew->ecs_addr = isc_mem_allocate(mctx, len);
|
|
|
|
memmove(looknew->ecs_addr, lookold->ecs_addr, len);
|
|
|
|
}
|
|
|
|
|
2021-05-21 17:20:44 -07:00
|
|
|
dns_name_copy(dns_fixedname_name(&lookold->fdomain),
|
|
|
|
dns_fixedname_name(&looknew->fdomain));
|
2014-03-01 15:32:25 -08:00
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (servers) {
|
2022-01-19 13:10:08 +02:00
|
|
|
if (lookold->tls_ctx_cache != NULL) {
|
|
|
|
isc_tlsctx_cache_detach(&looknew->tls_ctx_cache);
|
|
|
|
isc_tlsctx_cache_attach(lookold->tls_ctx_cache,
|
|
|
|
&looknew->tls_ctx_cache);
|
|
|
|
}
|
2000-07-14 16:35:30 +00:00
|
|
|
clone_server_list(lookold->my_server_list,
|
|
|
|
&looknew->my_server_list);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2020-11-05 15:22:38 +01:00
|
|
|
|
|
|
|
isc_refcount_init(&looknew->references, 1);
|
|
|
|
|
|
|
|
looknew->magic = DIG_LOOKUP_MAGIC;
|
|
|
|
|
2000-07-13 18:52:58 +00:00
|
|
|
return (looknew);
|
|
|
|
}
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
2000-07-18 18:51:40 +00:00
|
|
|
* Requeue a lookup for further processing, perhaps copying the server
|
|
|
|
* list. The new lookup structure is returned to the caller, and is
|
|
|
|
* queued for processing. If servers are not cloned in the requeue, they
|
|
|
|
* must be added before allowing the current event to complete, since the
|
|
|
|
* completion of the event may result in the next entry on the lookup
|
|
|
|
* queue getting run.
|
|
|
|
*/
|
2000-07-13 18:52:58 +00:00
|
|
|
dig_lookup_t *
|
2020-02-13 14:44:37 -08:00
|
|
|
requeue_lookup(dig_lookup_t *lookold, bool servers) {
|
2020-11-05 15:22:38 +01:00
|
|
|
dig_lookup_t *looknew = NULL;
|
2000-07-13 18:52:58 +00:00
|
|
|
|
|
|
|
debug("requeue_lookup()");
|
|
|
|
|
|
|
|
lookup_counter++;
|
2020-02-13 21:48:23 +01:00
|
|
|
if (lookup_counter > LOOKUP_LIMIT) {
|
2001-09-26 00:38:39 +00:00
|
|
|
fatal("too many lookups");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2000-07-13 18:52:58 +00:00
|
|
|
|
|
|
|
looknew = clone_lookup(lookold, servers);
|
|
|
|
INSIST(looknew != NULL);
|
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
debug("before insertion, init@%p -> %p, new@%p -> %p", lookold,
|
|
|
|
lookold->link.next, looknew, looknew->link.next);
|
2000-07-14 21:33:03 +00:00
|
|
|
ISC_LIST_PREPEND(lookup_list, looknew, link);
|
2020-02-12 13:59:18 +01:00
|
|
|
debug("after insertion, init -> %p, new = %p, new -> %p", lookold,
|
|
|
|
looknew, looknew->link.next);
|
2000-05-12 01:02:37 +00:00
|
|
|
return (looknew);
|
2000-08-01 01:33:37 +00:00
|
|
|
}
|
2000-05-12 01:02:37 +00:00
|
|
|
|
2014-04-18 07:27:50 -07:00
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
setup_text_key(void) {
|
|
|
|
isc_result_t result;
|
|
|
|
dns_name_t keyname;
|
|
|
|
isc_buffer_t secretbuf;
|
|
|
|
unsigned int secretsize;
|
2000-07-19 17:52:27 +00:00
|
|
|
unsigned char *secretstore;
|
|
|
|
|
|
|
|
debug("setup_text_key()");
|
2020-02-02 08:35:46 +01:00
|
|
|
isc_buffer_allocate(mctx, &namebuf, MXNAME);
|
2000-07-19 17:52:27 +00:00
|
|
|
dns_name_init(&keyname, NULL);
|
|
|
|
isc_buffer_putstr(namebuf, keynametext);
|
2020-02-12 13:59:18 +01:00
|
|
|
secretsize = (unsigned int)strlen(keysecret) * 3 / 4;
|
2000-07-20 17:58:59 +00:00
|
|
|
secretstore = isc_mem_allocate(mctx, secretsize);
|
2000-07-19 17:52:27 +00:00
|
|
|
isc_buffer_init(&secretbuf, secretstore, secretsize);
|
2001-03-22 00:07:07 +00:00
|
|
|
result = isc_base64_decodestring(keysecret, &secretbuf);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2000-08-01 00:53:20 +00:00
|
|
|
goto failure;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2008-01-18 23:46:58 +00:00
|
|
|
|
2000-07-19 17:52:27 +00:00
|
|
|
secretsize = isc_buffer_usedlength(&secretbuf);
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2011-11-06 23:18:07 +00:00
|
|
|
if (hmacname == NULL) {
|
|
|
|
result = DST_R_UNSUPPORTEDALG;
|
|
|
|
goto failure;
|
|
|
|
}
|
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
result = dns_name_fromtext(&keyname, namebuf, dns_rootname, 0, namebuf);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2000-08-01 00:53:20 +00:00
|
|
|
goto failure;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-07-27 05:52:45 +00:00
|
|
|
|
2006-01-27 02:35:15 +00:00
|
|
|
result = dns_tsigkey_create(&keyname, hmacname, secretstore,
|
2020-02-12 13:59:18 +01:00
|
|
|
(int)secretsize, false, NULL, 0, 0, mctx,
|
|
|
|
NULL, &tsigkey);
|
|
|
|
failure:
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2020-02-12 13:59:18 +01:00
|
|
|
printf(";; Couldn't create key %s: %s\n", keynametext,
|
|
|
|
isc_result_totext(result));
|
2020-02-13 21:48:23 +01:00
|
|
|
} else {
|
2018-03-19 22:16:10 +00:00
|
|
|
dst_key_setbits(tsigkey->key, digestbits);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-07-27 05:52:45 +00:00
|
|
|
|
2000-07-20 17:58:59 +00:00
|
|
|
isc_mem_free(mctx, secretstore);
|
2000-07-19 17:52:27 +00:00
|
|
|
dns_name_invalidate(&keyname);
|
|
|
|
isc_buffer_free(&namebuf);
|
|
|
|
}
|
|
|
|
|
2014-09-13 19:13:59 +10:00
|
|
|
static isc_result_t
|
2018-03-28 14:19:37 +02:00
|
|
|
parse_uint_helper(uint32_t *uip, const char *value, uint32_t max,
|
2020-02-13 14:44:37 -08:00
|
|
|
const char *desc, int base) {
|
|
|
|
uint32_t n;
|
2014-09-13 19:13:59 +10:00
|
|
|
isc_result_t result = isc_parse_uint32(&n, value, base);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result == ISC_R_SUCCESS && n > max) {
|
2009-09-15 03:13:44 +00:00
|
|
|
result = ISC_R_RANGE;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2009-09-15 03:13:44 +00:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2020-02-12 13:59:18 +01:00
|
|
|
printf("invalid %s '%s': %s\n", desc, value,
|
|
|
|
isc_result_totext(result));
|
2009-09-15 03:13:44 +00:00
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
*uip = n;
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2014-09-13 19:13:59 +10:00
|
|
|
isc_result_t
|
2020-02-13 14:44:37 -08:00
|
|
|
parse_uint(uint32_t *uip, const char *value, uint32_t max, const char *desc) {
|
2014-09-13 19:13:59 +10:00
|
|
|
return (parse_uint_helper(uip, value, max, desc, 10));
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
2020-02-13 14:44:37 -08:00
|
|
|
parse_xint(uint32_t *uip, const char *value, uint32_t max, const char *desc) {
|
2014-09-13 19:13:59 +10:00
|
|
|
return (parse_uint_helper(uip, value, max, desc, 0));
|
|
|
|
}
|
|
|
|
|
2018-03-28 14:19:37 +02:00
|
|
|
static uint32_t
|
2020-02-13 14:44:37 -08:00
|
|
|
parse_bits(char *arg, const char *desc, uint32_t max) {
|
2009-09-15 23:48:09 +00:00
|
|
|
isc_result_t result;
|
2020-02-13 14:44:37 -08:00
|
|
|
uint32_t tmp;
|
2009-09-15 23:48:09 +00:00
|
|
|
|
|
|
|
result = parse_uint(&tmp, arg, max, desc);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2009-09-15 23:48:09 +00:00
|
|
|
fatal("couldn't parse digest bits");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2009-09-15 23:48:09 +00:00
|
|
|
tmp = (tmp + 7) & ~0x7U;
|
|
|
|
return (tmp);
|
2009-09-15 03:13:44 +00:00
|
|
|
}
|
|
|
|
|
2014-02-19 15:51:02 -08:00
|
|
|
isc_result_t
|
2020-02-13 14:44:37 -08:00
|
|
|
parse_netprefix(isc_sockaddr_t **sap, const char *value) {
|
|
|
|
isc_result_t result = ISC_R_SUCCESS;
|
2014-02-19 15:51:02 -08:00
|
|
|
isc_sockaddr_t *sa = NULL;
|
2020-02-13 14:44:37 -08:00
|
|
|
struct in_addr in4;
|
2014-02-19 15:51:02 -08:00
|
|
|
struct in6_addr in6;
|
2020-02-13 14:44:37 -08:00
|
|
|
uint32_t prefix_length = 0xffffffff;
|
|
|
|
char *slash = NULL;
|
|
|
|
bool parsed = false;
|
|
|
|
bool prefix_parsed = false;
|
2015-11-20 18:38:24 +11:00
|
|
|
char buf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:XXX.XXX.XXX.XXX/128")];
|
2014-02-19 15:51:02 -08:00
|
|
|
|
2017-02-14 15:52:40 +11:00
|
|
|
REQUIRE(sap != NULL && *sap == NULL);
|
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (strlcpy(buf, value, sizeof(buf)) >= sizeof(buf)) {
|
2015-11-20 18:38:24 +11:00
|
|
|
fatal("invalid prefix '%s'\n", value);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-11-20 18:38:24 +11:00
|
|
|
|
2016-09-14 08:22:15 +10:00
|
|
|
sa = isc_mem_allocate(mctx, sizeof(*sa));
|
|
|
|
memset(sa, 0, sizeof(*sa));
|
|
|
|
|
|
|
|
if (strcmp(buf, "0") == 0) {
|
|
|
|
sa->type.sa.sa_family = AF_UNSPEC;
|
|
|
|
prefix_length = 0;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2015-11-20 18:38:24 +11:00
|
|
|
slash = strchr(buf, '/');
|
|
|
|
if (slash != NULL) {
|
2014-02-19 15:51:02 -08:00
|
|
|
*slash = '\0';
|
2016-03-23 09:29:57 -07:00
|
|
|
result = isc_parse_uint32(&prefix_length, slash + 1, 10);
|
2014-02-19 15:51:02 -08:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2020-02-12 13:59:18 +01:00
|
|
|
fatal("invalid prefix length in '%s': %s\n", value,
|
|
|
|
isc_result_totext(result));
|
2014-02-19 15:51:02 -08:00
|
|
|
}
|
2018-04-17 08:29:14 -07:00
|
|
|
prefix_parsed = true;
|
2016-03-23 15:00:30 -07:00
|
|
|
}
|
|
|
|
|
2015-11-20 18:38:24 +11:00
|
|
|
if (inet_pton(AF_INET6, buf, &in6) == 1) {
|
2018-04-17 08:29:14 -07:00
|
|
|
parsed = true;
|
2015-11-20 18:38:24 +11:00
|
|
|
isc_sockaddr_fromin6(sa, &in6, 0);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (prefix_length > 128) {
|
2016-03-23 09:29:57 -07:00
|
|
|
prefix_length = 128;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-11-20 18:38:24 +11:00
|
|
|
} else if (inet_pton(AF_INET, buf, &in4) == 1) {
|
2018-04-17 08:29:14 -07:00
|
|
|
parsed = true;
|
2014-02-19 15:51:02 -08:00
|
|
|
isc_sockaddr_fromin(sa, &in4, 0);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (prefix_length > 32) {
|
2016-03-23 09:29:57 -07:00
|
|
|
prefix_length = 32;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2016-09-14 08:22:15 +10:00
|
|
|
} else if (prefix_parsed) {
|
2014-02-19 15:51:02 -08:00
|
|
|
int i;
|
|
|
|
|
2016-01-29 17:41:29 -08:00
|
|
|
for (i = 0; i < 3 && strlen(buf) < sizeof(buf) - 2; i++) {
|
2014-02-19 15:51:02 -08:00
|
|
|
strlcat(buf, ".0", sizeof(buf));
|
|
|
|
if (inet_pton(AF_INET, buf, &in4) == 1) {
|
2018-04-17 08:29:14 -07:00
|
|
|
parsed = true;
|
2014-02-19 15:51:02 -08:00
|
|
|
isc_sockaddr_fromin(sa, &in4, 0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2016-01-27 19:00:36 -08:00
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (prefix_length > 32) {
|
2016-03-23 09:29:57 -07:00
|
|
|
prefix_length = 32;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2014-02-19 15:51:02 -08:00
|
|
|
}
|
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (!parsed) {
|
2014-02-19 15:51:02 -08:00
|
|
|
fatal("invalid address '%s'", value);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2014-02-19 15:51:02 -08:00
|
|
|
|
2016-09-14 08:22:15 +10:00
|
|
|
done:
|
2016-03-23 09:29:57 -07:00
|
|
|
sa->length = prefix_length;
|
2014-02-19 15:51:02 -08:00
|
|
|
*sap = sa;
|
|
|
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2009-09-15 03:13:44 +00:00
|
|
|
/*
|
|
|
|
* Parse HMAC algorithm specification
|
|
|
|
*/
|
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
parse_hmac(const char *hmac) {
|
|
|
|
char buf[20];
|
2016-07-21 15:53:43 -07:00
|
|
|
size_t len;
|
2009-09-15 03:13:44 +00:00
|
|
|
|
|
|
|
REQUIRE(hmac != NULL);
|
|
|
|
|
|
|
|
len = strlen(hmac);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (len >= sizeof(buf)) {
|
2016-07-21 15:53:43 -07:00
|
|
|
fatal("unknown key type '%.*s'", (int)len, hmac);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2012-10-02 23:44:03 -07:00
|
|
|
strlcpy(buf, hmac, sizeof(buf));
|
2009-09-15 03:13:44 +00:00
|
|
|
|
|
|
|
digestbits = 0;
|
|
|
|
|
|
|
|
if (strcasecmp(buf, "hmac-md5") == 0) {
|
|
|
|
hmacname = DNS_TSIG_HMACMD5_NAME;
|
|
|
|
} else if (strncasecmp(buf, "hmac-md5-", 9) == 0) {
|
|
|
|
hmacname = DNS_TSIG_HMACMD5_NAME;
|
|
|
|
digestbits = parse_bits(&buf[9], "digest-bits [0..128]", 128);
|
2020-02-12 13:59:18 +01:00
|
|
|
} else if (strcasecmp(buf, "hmac-sha1") == 0) {
|
2009-09-15 03:13:44 +00:00
|
|
|
hmacname = DNS_TSIG_HMACSHA1_NAME;
|
|
|
|
digestbits = 0;
|
|
|
|
} else if (strncasecmp(buf, "hmac-sha1-", 10) == 0) {
|
|
|
|
hmacname = DNS_TSIG_HMACSHA1_NAME;
|
|
|
|
digestbits = parse_bits(&buf[10], "digest-bits [0..160]", 160);
|
|
|
|
} else if (strcasecmp(buf, "hmac-sha224") == 0) {
|
|
|
|
hmacname = DNS_TSIG_HMACSHA224_NAME;
|
|
|
|
} else if (strncasecmp(buf, "hmac-sha224-", 12) == 0) {
|
|
|
|
hmacname = DNS_TSIG_HMACSHA224_NAME;
|
|
|
|
digestbits = parse_bits(&buf[12], "digest-bits [0..224]", 224);
|
|
|
|
} else if (strcasecmp(buf, "hmac-sha256") == 0) {
|
|
|
|
hmacname = DNS_TSIG_HMACSHA256_NAME;
|
|
|
|
} else if (strncasecmp(buf, "hmac-sha256-", 12) == 0) {
|
|
|
|
hmacname = DNS_TSIG_HMACSHA256_NAME;
|
|
|
|
digestbits = parse_bits(&buf[12], "digest-bits [0..256]", 256);
|
|
|
|
} else if (strcasecmp(buf, "hmac-sha384") == 0) {
|
|
|
|
hmacname = DNS_TSIG_HMACSHA384_NAME;
|
|
|
|
} else if (strncasecmp(buf, "hmac-sha384-", 12) == 0) {
|
|
|
|
hmacname = DNS_TSIG_HMACSHA384_NAME;
|
|
|
|
digestbits = parse_bits(&buf[12], "digest-bits [0..384]", 384);
|
|
|
|
} else if (strcasecmp(buf, "hmac-sha512") == 0) {
|
|
|
|
hmacname = DNS_TSIG_HMACSHA512_NAME;
|
|
|
|
} else if (strncasecmp(buf, "hmac-sha512-", 12) == 0) {
|
|
|
|
hmacname = DNS_TSIG_HMACSHA512_NAME;
|
|
|
|
digestbits = parse_bits(&buf[12], "digest-bits [0..512]", 512);
|
|
|
|
} else {
|
2020-02-12 13:59:18 +01:00
|
|
|
fprintf(stderr,
|
|
|
|
";; Warning, ignoring "
|
|
|
|
"invalid TSIG algorithm %s\n",
|
|
|
|
buf);
|
2009-09-15 03:13:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get a key from a named.conf format keyfile
|
|
|
|
*/
|
|
|
|
static isc_result_t
|
2020-02-13 14:44:37 -08:00
|
|
|
read_confkey(void) {
|
|
|
|
cfg_parser_t *pctx = NULL;
|
|
|
|
cfg_obj_t *file = NULL;
|
2015-01-20 13:29:18 -08:00
|
|
|
const cfg_obj_t *keyobj = NULL;
|
2009-09-15 03:13:44 +00:00
|
|
|
const cfg_obj_t *secretobj = NULL;
|
|
|
|
const cfg_obj_t *algorithmobj = NULL;
|
2020-02-13 14:44:37 -08:00
|
|
|
const char *keyname;
|
|
|
|
const char *secretstr;
|
|
|
|
const char *algorithm;
|
|
|
|
isc_result_t result;
|
2009-09-15 03:13:44 +00:00
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (!isc_file_exists(keyfile)) {
|
2009-09-15 03:13:44 +00:00
|
|
|
return (ISC_R_FILENOTFOUND);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2009-09-15 03:13:44 +00:00
|
|
|
|
2015-01-20 13:29:18 -08:00
|
|
|
result = cfg_parser_create(mctx, NULL, &pctx);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2009-09-15 03:13:44 +00:00
|
|
|
goto cleanup;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2009-09-15 03:13:44 +00:00
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
result = cfg_parse_file(pctx, keyfile, &cfg_type_sessionkey, &file);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2009-09-15 03:13:44 +00:00
|
|
|
goto cleanup;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2009-09-15 03:13:44 +00:00
|
|
|
|
2015-01-20 13:29:18 -08:00
|
|
|
result = cfg_map_get(file, "key", &keyobj);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2009-09-15 03:13:44 +00:00
|
|
|
goto cleanup;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2009-09-15 03:13:44 +00:00
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
(void)cfg_map_get(keyobj, "secret", &secretobj);
|
|
|
|
(void)cfg_map_get(keyobj, "algorithm", &algorithmobj);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (secretobj == NULL || algorithmobj == NULL) {
|
2009-09-15 03:13:44 +00:00
|
|
|
fatal("key must have algorithm and secret");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2009-09-15 03:13:44 +00:00
|
|
|
|
2015-01-20 13:29:18 -08:00
|
|
|
keyname = cfg_obj_asstring(cfg_map_getname(keyobj));
|
2009-09-15 03:13:44 +00:00
|
|
|
secretstr = cfg_obj_asstring(secretobj);
|
|
|
|
algorithm = cfg_obj_asstring(algorithmobj);
|
|
|
|
|
2012-10-02 23:44:03 -07:00
|
|
|
strlcpy(keynametext, keyname, sizeof(keynametext));
|
|
|
|
strlcpy(keysecret, secretstr, sizeof(keysecret));
|
2009-09-15 03:13:44 +00:00
|
|
|
parse_hmac(algorithm);
|
|
|
|
setup_text_key();
|
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
cleanup:
|
2009-09-15 03:13:44 +00:00
|
|
|
if (pctx != NULL) {
|
2020-02-13 21:48:23 +01:00
|
|
|
if (file != NULL) {
|
2009-09-15 03:13:44 +00:00
|
|
|
cfg_obj_destroy(pctx, &file);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2009-09-15 03:13:44 +00:00
|
|
|
cfg_parser_destroy(&pctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2014-04-18 07:27:50 -07:00
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
setup_file_key(void) {
|
2000-07-19 17:52:27 +00:00
|
|
|
isc_result_t result;
|
2020-02-13 14:44:37 -08:00
|
|
|
dst_key_t *dstkey = NULL;
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2000-07-19 17:52:27 +00:00
|
|
|
debug("setup_file_key()");
|
2009-09-15 03:13:44 +00:00
|
|
|
|
|
|
|
/* Try reading the key from a K* pair */
|
2020-02-12 13:59:18 +01:00
|
|
|
result = dst_key_fromnamedfile(
|
|
|
|
keyfile, NULL, DST_TYPE_PRIVATE | DST_TYPE_KEY, mctx, &dstkey);
|
2009-09-15 03:13:44 +00:00
|
|
|
|
|
|
|
/* If that didn't work, try reading it as a session.key keyfile */
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
result = read_confkey();
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
2009-09-15 03:13:44 +00:00
|
|
|
return;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2009-09-15 03:13:44 +00:00
|
|
|
}
|
|
|
|
|
2000-07-19 17:52:27 +00:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2020-02-12 13:59:18 +01:00
|
|
|
fprintf(stderr, "Couldn't read key from %s: %s\n", keyfile,
|
|
|
|
isc_result_totext(result));
|
2000-07-19 17:52:27 +00:00
|
|
|
goto failure;
|
|
|
|
}
|
2001-07-27 05:52:45 +00:00
|
|
|
|
2006-01-27 02:35:15 +00:00
|
|
|
switch (dst_key_alg(dstkey)) {
|
|
|
|
case DST_ALG_HMACMD5:
|
|
|
|
hmacname = DNS_TSIG_HMACMD5_NAME;
|
|
|
|
break;
|
|
|
|
case DST_ALG_HMACSHA1:
|
|
|
|
hmacname = DNS_TSIG_HMACSHA1_NAME;
|
|
|
|
break;
|
|
|
|
case DST_ALG_HMACSHA224:
|
|
|
|
hmacname = DNS_TSIG_HMACSHA224_NAME;
|
|
|
|
break;
|
|
|
|
case DST_ALG_HMACSHA256:
|
|
|
|
hmacname = DNS_TSIG_HMACSHA256_NAME;
|
|
|
|
break;
|
|
|
|
case DST_ALG_HMACSHA384:
|
|
|
|
hmacname = DNS_TSIG_HMACSHA384_NAME;
|
|
|
|
break;
|
|
|
|
case DST_ALG_HMACSHA512:
|
|
|
|
hmacname = DNS_TSIG_HMACSHA512_NAME;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
printf(";; Couldn't create key %s: bad algorithm\n",
|
|
|
|
keynametext);
|
|
|
|
goto failure;
|
|
|
|
}
|
|
|
|
result = dns_tsigkey_createfromkey(dst_key_name(dstkey), hmacname,
|
2020-02-12 13:59:18 +01:00
|
|
|
dstkey, false, NULL, 0, 0, mctx,
|
|
|
|
NULL, &tsigkey);
|
2000-07-19 17:52:27 +00:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2020-02-12 13:59:18 +01:00
|
|
|
printf(";; Couldn't create key %s: %s\n", keynametext,
|
|
|
|
isc_result_totext(result));
|
2001-09-27 17:53:39 +00:00
|
|
|
goto failure;
|
2000-07-19 17:52:27 +00:00
|
|
|
}
|
2020-02-12 13:59:18 +01:00
|
|
|
failure:
|
2020-02-13 21:48:23 +01:00
|
|
|
if (dstkey != NULL) {
|
2000-07-19 17:52:27 +00:00
|
|
|
dst_key_free(&dstkey);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2000-07-19 17:52:27 +00:00
|
|
|
}
|
|
|
|
|
2001-01-18 05:12:44 +00:00
|
|
|
static dig_searchlist_t *
|
2020-02-13 14:44:37 -08:00
|
|
|
make_searchlist_entry(char *domain) {
|
2001-01-18 05:12:44 +00:00
|
|
|
dig_searchlist_t *search;
|
|
|
|
search = isc_mem_allocate(mctx, sizeof(*search));
|
2012-10-02 23:44:03 -07:00
|
|
|
strlcpy(search->origin, domain, MXNAME);
|
2020-02-12 13:59:18 +01:00
|
|
|
search->origin[MXNAME - 1] = 0;
|
2001-01-18 05:12:44 +00:00
|
|
|
ISC_LINK_INIT(search, link);
|
|
|
|
return (search);
|
|
|
|
}
|
|
|
|
|
2010-05-18 01:48:13 +00:00
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
clear_searchlist(void) {
|
2010-05-18 01:48:13 +00:00
|
|
|
dig_searchlist_t *search;
|
|
|
|
while ((search = ISC_LIST_HEAD(search_list)) != NULL) {
|
|
|
|
ISC_LIST_UNLINK(search_list, search, link);
|
|
|
|
isc_mem_free(mctx, search);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-08-28 07:04:48 +00:00
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
create_search_list(irs_resconf_t *resconf) {
|
2017-09-08 13:39:09 -07:00
|
|
|
irs_resconf_searchlist_t *list;
|
2020-02-13 14:44:37 -08:00
|
|
|
irs_resconf_search_t *entry;
|
|
|
|
dig_searchlist_t *search;
|
2002-08-12 18:25:25 +00:00
|
|
|
|
|
|
|
debug("create_search_list()");
|
2010-05-18 01:48:13 +00:00
|
|
|
clear_searchlist();
|
2002-08-12 18:25:25 +00:00
|
|
|
|
2017-09-08 13:39:09 -07:00
|
|
|
list = irs_resconf_getsearchlist(resconf);
|
2020-02-12 13:59:18 +01:00
|
|
|
for (entry = ISC_LIST_HEAD(*list); entry != NULL;
|
2020-02-13 14:44:37 -08:00
|
|
|
entry = ISC_LIST_NEXT(entry, link))
|
|
|
|
{
|
2017-09-08 13:39:09 -07:00
|
|
|
search = make_searchlist_entry(entry->domain);
|
2002-08-12 18:25:25 +00:00
|
|
|
ISC_LIST_APPEND(search_list, search, link);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-13 14:31:18 +01:00
|
|
|
/*%
|
|
|
|
* Append 'addr' to the list of servers to be queried. This function is only
|
|
|
|
* called when no server addresses are explicitly specified and either libirs
|
|
|
|
* returns an empty list of servers to use or none of the addresses returned by
|
|
|
|
* libirs are usable due to the specified address family restrictions.
|
|
|
|
*/
|
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
add_fallback_nameserver(const char *addr) {
|
2018-11-13 14:31:18 +01:00
|
|
|
dig_server_t *server = make_server(addr, addr);
|
|
|
|
ISC_LINK_INIT(server, link);
|
|
|
|
ISC_LIST_APPEND(server_list, server, link);
|
|
|
|
}
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
2000-07-18 18:51:40 +00:00
|
|
|
* Setup the system as a whole, reading key information and resolv.conf
|
|
|
|
* settings.
|
|
|
|
*/
|
2000-05-09 18:05:13 +00:00
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
setup_system(bool ipv4only, bool ipv6only) {
|
2017-09-08 13:39:09 -07:00
|
|
|
irs_resconf_t *resconf = NULL;
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_result_t result;
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2000-07-05 19:31:26 +00:00
|
|
|
debug("setup_system()");
|
2000-06-21 01:40:42 +00:00
|
|
|
|
2015-08-12 12:50:15 +10:00
|
|
|
if (ipv4only) {
|
|
|
|
if (have_ipv4) {
|
|
|
|
isc_net_disableipv6();
|
2018-04-17 08:29:14 -07:00
|
|
|
have_ipv6 = false;
|
2015-08-12 12:50:15 +10:00
|
|
|
} else {
|
|
|
|
fatal("can't find IPv4 networking");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ipv6only) {
|
|
|
|
if (have_ipv6) {
|
|
|
|
isc_net_disableipv4();
|
2018-04-17 08:29:14 -07:00
|
|
|
have_ipv4 = false;
|
2015-08-12 12:50:15 +10:00
|
|
|
} else {
|
|
|
|
fatal("can't find IPv6 networking");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-08 13:39:09 -07:00
|
|
|
result = irs_resconf_load(mctx, RESOLV_CONF, &resconf);
|
|
|
|
if (result != ISC_R_SUCCESS && result != ISC_R_FILENOTFOUND) {
|
2005-06-07 01:00:00 +00:00
|
|
|
fatal("parse of %s failed", RESOLV_CONF);
|
2000-04-26 18:34:17 +00:00
|
|
|
}
|
2008-01-18 23:46:58 +00:00
|
|
|
|
2017-09-08 13:39:09 -07:00
|
|
|
create_search_list(resconf);
|
2005-09-08 23:59:45 +00:00
|
|
|
if (ndots == -1) {
|
2017-09-08 13:39:09 -07:00
|
|
|
ndots = irs_resconf_getndots(resconf);
|
2005-09-08 23:59:45 +00:00
|
|
|
debug("ndots is %d.", ndots);
|
|
|
|
}
|
2021-06-22 16:35:46 +02:00
|
|
|
if (timeout == 0) {
|
|
|
|
timeout = irs_resconf_gettimeout(resconf);
|
|
|
|
debug("timeout is %d.", timeout);
|
|
|
|
}
|
|
|
|
if (tries == -1) {
|
|
|
|
tries = irs_resconf_getattempts(resconf);
|
|
|
|
if (tries == 0) {
|
|
|
|
tries = 3;
|
|
|
|
}
|
|
|
|
debug("retries is %d.", tries);
|
|
|
|
}
|
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
|
|
|
|
2009-06-24 02:51:29 +00:00
|
|
|
/* If user doesn't specify server use nameservers from resolv.conf. */
|
2008-12-13 02:43:25 +00:00
|
|
|
if (ISC_LIST_EMPTY(server_list)) {
|
2017-09-08 13:39:09 -07:00
|
|
|
get_server_list(resconf);
|
2008-12-13 02:43:25 +00:00
|
|
|
}
|
2000-05-02 23:23:12 +00:00
|
|
|
|
2018-11-13 14:31:18 +01:00
|
|
|
/* If we don't find a nameserver fall back to localhost */
|
|
|
|
if (ISC_LIST_EMPTY(server_list)) {
|
|
|
|
if (have_ipv6) {
|
|
|
|
add_fallback_nameserver("::1");
|
|
|
|
}
|
|
|
|
if (have_ipv4) {
|
|
|
|
add_fallback_nameserver("127.0.0.1");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-08 13:39:09 -07:00
|
|
|
irs_resconf_destroy(&resconf);
|
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (keyfile[0] != 0) {
|
2000-07-19 17:52:27 +00:00
|
|
|
setup_file_key();
|
2020-02-13 21:48:23 +01:00
|
|
|
} else if (keysecret[0] != 0) {
|
2000-07-19 17:52:27 +00:00
|
|
|
setup_text_key();
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2018-04-22 14:56:28 +02:00
|
|
|
|
2018-05-28 15:22:23 +02:00
|
|
|
isc_nonce_buf(cookie_secret, sizeof(cookie_secret));
|
2000-04-26 18:34:17 +00:00
|
|
|
}
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
2001-01-18 05:12:44 +00:00
|
|
|
* Override the search list derived from resolv.conf by 'domain'.
|
|
|
|
*/
|
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
set_search_domain(char *domain) {
|
2001-01-18 05:12:44 +00:00
|
|
|
dig_searchlist_t *search;
|
2008-01-18 23:46:58 +00:00
|
|
|
|
2001-01-18 05:12:44 +00:00
|
|
|
clear_searchlist();
|
|
|
|
search = make_searchlist_entry(domain);
|
|
|
|
ISC_LIST_APPEND(search_list, search, link);
|
|
|
|
}
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
2000-07-18 18:51:40 +00:00
|
|
|
* Setup the ISC and DNS libraries for use by the system.
|
|
|
|
*/
|
2000-05-09 18:05:13 +00:00
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
setup_libs(void) {
|
|
|
|
isc_result_t result;
|
2009-09-15 03:13:44 +00:00
|
|
|
isc_logconfig_t *logconfig = NULL;
|
2000-04-26 18:34:17 +00:00
|
|
|
|
2000-07-05 19:31:26 +00:00
|
|
|
debug("setup_libs()");
|
2000-05-12 01:02:37 +00:00
|
|
|
|
2000-04-26 18:34:17 +00:00
|
|
|
result = isc_net_probeipv4();
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
2018-04-17 08:29:14 -07:00
|
|
|
have_ipv4 = true;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2000-04-26 18:34:17 +00:00
|
|
|
|
|
|
|
result = isc_net_probeipv6();
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
2018-04-17 08:29:14 -07:00
|
|
|
have_ipv6 = true;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if (!have_ipv6 && !have_ipv4) {
|
2000-11-21 21:35:32 +00:00
|
|
|
fatal("can't find either v4 or v6 networking");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2000-04-26 18:34:17 +00:00
|
|
|
|
2019-09-05 18:40:57 +02:00
|
|
|
isc_mem_create(&mctx);
|
2020-07-14 14:24:10 +02:00
|
|
|
isc_mem_setname(mctx, "dig");
|
2000-04-26 18:34:17 +00:00
|
|
|
|
2020-03-18 14:17:55 +11:00
|
|
|
isc_log_create(mctx, &lctx, &logconfig);
|
2009-09-15 03:13:44 +00:00
|
|
|
isc_log_setcontext(lctx);
|
|
|
|
dns_log_init(lctx);
|
|
|
|
dns_log_setcontext(lctx);
|
|
|
|
|
|
|
|
result = isc_log_usechannel(logconfig, "default_debug", NULL, NULL);
|
|
|
|
check_result(result, "isc_log_usechannel");
|
|
|
|
|
|
|
|
isc_log_setdebuglevel(lctx, 0);
|
|
|
|
|
2021-10-03 00:27:52 -07:00
|
|
|
isc_managers_create(mctx, 1, 0, &netmgr, &taskmgr, NULL);
|
2000-04-26 18:34:17 +00:00
|
|
|
|
2022-05-19 11:20:21 +02:00
|
|
|
result = isc_task_create(taskmgr, 0, &global_task, 0);
|
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
|
|
|
check_result(result, "isc_task_create");
|
2013-12-02 13:34:23 -08:00
|
|
|
isc_task_setname(global_task, "dig", NULL);
|
2000-04-26 18:34:17 +00:00
|
|
|
|
2018-04-22 14:56:28 +02:00
|
|
|
result = dst_lib_init(mctx, NULL);
|
2000-06-12 19:33:30 +00:00
|
|
|
check_result(result, "dst_lib_init");
|
2018-04-17 08:29:14 -07:00
|
|
|
is_dst_up = true;
|
2000-07-13 01:49:44 +00:00
|
|
|
|
2018-11-16 15:33:22 +01:00
|
|
|
isc_mutex_init(&lookup_lock);
|
2000-04-26 18:34:17 +00:00
|
|
|
}
|
|
|
|
|
2017-01-19 23:46:37 -08:00
|
|
|
typedef struct dig_ednsoptname {
|
2020-02-13 14:44:37 -08:00
|
|
|
uint32_t code;
|
2020-02-12 13:59:18 +01:00
|
|
|
const char *name;
|
2017-01-19 23:46:37 -08:00
|
|
|
} dig_ednsoptname_t;
|
|
|
|
|
|
|
|
dig_ednsoptname_t optnames[] = {
|
2020-02-12 13:59:18 +01:00
|
|
|
{ 1, "LLQ" }, /* draft-sekar-dns-llq */
|
|
|
|
{ 3, "NSID" }, /* RFC 5001 */
|
|
|
|
{ 5, "DAU" }, /* RFC 6975 */
|
|
|
|
{ 6, "DHU" }, /* RFC 6975 */
|
|
|
|
{ 7, "N3U" }, /* RFC 6975 */
|
|
|
|
{ 8, "ECS" }, /* RFC 7871 */
|
|
|
|
{ 9, "EXPIRE" }, /* RFC 7314 */
|
|
|
|
{ 10, "COOKIE" }, /* RFC 7873 */
|
|
|
|
{ 11, "KEEPALIVE" }, /* RFC 7828 */
|
|
|
|
{ 12, "PADDING" }, /* RFC 7830 */
|
|
|
|
{ 12, "PAD" }, /* shorthand */
|
|
|
|
{ 13, "CHAIN" }, /* RFC 7901 */
|
|
|
|
{ 14, "KEY-TAG" }, /* RFC 8145 */
|
2020-05-11 14:44:23 +10:00
|
|
|
{ 15, "EDE" }, /* ietf-dnsop-extended-error-16 */
|
2020-02-12 13:59:18 +01:00
|
|
|
{ 16, "CLIENT-TAG" }, /* draft-bellis-dnsop-edns-tags */
|
|
|
|
{ 17, "SERVER-TAG" }, /* draft-bellis-dnsop-edns-tags */
|
|
|
|
{ 26946, "DEVICEID" }, /* Brian Hartvigsen */
|
2017-01-19 23:46:37 -08:00
|
|
|
};
|
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
#define N_EDNS_OPTNAMES (sizeof(optnames) / sizeof(optnames[0]))
|
2017-01-19 23:46:37 -08:00
|
|
|
|
2014-04-18 09:52:12 +10:00
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
save_opt(dig_lookup_t *lookup, char *code, char *value) {
|
2017-01-19 23:46:37 -08:00
|
|
|
isc_result_t result;
|
2020-02-13 14:44:37 -08:00
|
|
|
uint32_t num = 0;
|
2014-04-22 23:45:19 +00:00
|
|
|
isc_buffer_t b;
|
2020-02-13 14:44:37 -08:00
|
|
|
bool found = false;
|
2017-01-19 23:46:37 -08:00
|
|
|
unsigned int i;
|
2014-04-18 09:52:12 +10:00
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (lookup->ednsoptscnt >= EDNSOPT_OPTIONS) {
|
2014-04-22 23:45:19 +00:00
|
|
|
fatal("too many ednsopts");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2014-04-18 09:52:12 +10:00
|
|
|
|
2017-01-19 23:46:37 -08:00
|
|
|
for (i = 0; i < N_EDNS_OPTNAMES; i++) {
|
|
|
|
if (strcasecmp(code, optnames[i].name) == 0) {
|
|
|
|
num = optnames[i].code;
|
2018-04-17 08:29:14 -07:00
|
|
|
found = true;
|
2017-01-19 23:46:37 -08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found) {
|
|
|
|
result = parse_uint(&num, code, 65535, "ednsopt");
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2017-01-19 23:46:37 -08:00
|
|
|
fatal("bad edns code point: %s", code);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2017-01-19 23:46:37 -08:00
|
|
|
}
|
2014-04-18 09:52:12 +10:00
|
|
|
|
2017-11-13 16:10:35 +11:00
|
|
|
if (lookup->ednsopts == NULL) {
|
|
|
|
cloneopts(lookup, NULL);
|
|
|
|
}
|
2020-06-25 10:45:02 +10:00
|
|
|
INSIST(lookup->ednsopts != NULL);
|
2017-11-13 16:10:35 +11:00
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (lookup->ednsopts[lookup->ednsoptscnt].value != NULL) {
|
2017-11-13 16:10:35 +11:00
|
|
|
isc_mem_free(mctx, lookup->ednsopts[lookup->ednsoptscnt].value);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2017-11-13 16:10:35 +11:00
|
|
|
|
|
|
|
lookup->ednsopts[lookup->ednsoptscnt].code = num;
|
|
|
|
lookup->ednsopts[lookup->ednsoptscnt].length = 0;
|
|
|
|
lookup->ednsopts[lookup->ednsoptscnt].value = NULL;
|
2014-04-22 23:45:19 +00:00
|
|
|
|
|
|
|
if (value != NULL) {
|
|
|
|
char *buf;
|
2019-07-23 10:56:26 -04:00
|
|
|
buf = isc_mem_allocate(mctx, strlen(value) / 2 + 1);
|
2020-02-12 13:59:18 +01:00
|
|
|
isc_buffer_init(&b, buf, (unsigned int)strlen(value) / 2 + 1);
|
2014-04-22 23:45:19 +00:00
|
|
|
result = isc_hex_decodestring(value, &b);
|
|
|
|
check_result(result, "isc_hex_decodestring");
|
2017-11-13 16:10:35 +11:00
|
|
|
lookup->ednsopts[lookup->ednsoptscnt].value =
|
2020-02-12 13:59:18 +01:00
|
|
|
isc_buffer_base(&b);
|
2017-11-13 16:10:35 +11:00
|
|
|
lookup->ednsopts[lookup->ednsoptscnt].length =
|
2020-02-12 13:59:18 +01:00
|
|
|
isc_buffer_usedlength(&b);
|
2014-04-22 23:45:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
lookup->ednsoptscnt++;
|
2014-04-18 09:52:12 +10:00
|
|
|
}
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
2000-07-18 18:51:40 +00:00
|
|
|
* Add EDNS0 option record to a message. Currently, the only supported
|
2014-02-19 15:51:02 -08:00
|
|
|
* options are UDP buffer size, the DO bit, and EDNS options
|
2015-07-06 09:44:24 +10:00
|
|
|
* (e.g., NSID, COOKIE, client-subnet)
|
2000-07-18 18:51:40 +00:00
|
|
|
*/
|
2000-05-08 22:51:08 +00:00
|
|
|
static void
|
2020-02-12 13:59:18 +01:00
|
|
|
add_opt(dns_message_t *msg, uint16_t udpsize, uint16_t edns, unsigned int flags,
|
2020-02-13 14:44:37 -08:00
|
|
|
dns_ednsopt_t *opts, size_t count) {
|
2000-05-08 22:51:08 +00:00
|
|
|
dns_rdataset_t *rdataset = NULL;
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_result_t result;
|
2000-05-08 22:51:08 +00:00
|
|
|
|
2000-07-05 19:31:26 +00:00
|
|
|
debug("add_opt()");
|
2014-02-19 12:53:42 +11:00
|
|
|
result = dns_message_buildopt(msg, &rdataset, edns, udpsize, flags,
|
2015-01-20 13:29:18 -08:00
|
|
|
opts, count);
|
2014-02-19 12:53:42 +11:00
|
|
|
check_result(result, "dns_message_buildopt");
|
2000-05-08 22:51:08 +00:00
|
|
|
result = dns_message_setopt(msg, rdataset);
|
2000-07-05 19:31:26 +00:00
|
|
|
check_result(result, "dns_message_setopt");
|
2000-05-08 22:51:08 +00:00
|
|
|
}
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
2000-08-01 01:33:37 +00:00
|
|
|
* Add a question section to a message, asking for the specified name,
|
2000-07-18 18:51:40 +00:00
|
|
|
* type, and class.
|
|
|
|
*/
|
2000-04-26 18:34:17 +00:00
|
|
|
static void
|
2020-02-12 13:59:18 +01:00
|
|
|
add_question(dns_message_t *message, dns_name_t *name, dns_rdataclass_t rdclass,
|
2020-02-13 14:44:37 -08:00
|
|
|
dns_rdatatype_t rdtype) {
|
2000-04-26 18:34:17 +00:00
|
|
|
dns_rdataset_t *rdataset;
|
|
|
|
|
2000-08-01 01:33:37 +00:00
|
|
|
debug("add_question()");
|
2000-04-26 18:34:17 +00:00
|
|
|
rdataset = NULL;
|
2022-05-16 13:28:13 +02:00
|
|
|
dns_message_gettemprdataset(message, &rdataset);
|
2000-04-26 18:34:17 +00:00
|
|
|
dns_rdataset_makequestion(rdataset, rdclass, rdtype);
|
|
|
|
ISC_LIST_APPEND(name->list, rdataset, link);
|
|
|
|
}
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
2000-07-18 18:51:40 +00:00
|
|
|
* Check if we're done with all the queued lookups, which is true iff
|
|
|
|
* all sockets, sends, and recvs are accounted for (counters == 0),
|
|
|
|
* and the lookup list is empty.
|
|
|
|
* If we are done, pass control back out to dighost_shutdown() (which is
|
|
|
|
* part of dig.c, host.c, or nslookup.c) to either shutdown the system as
|
|
|
|
* a whole or reseed the lookup list.
|
2000-07-05 23:28:32 +00:00
|
|
|
*/
|
2000-07-13 00:32:20 +00:00
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
check_if_done(void) {
|
2020-11-05 15:22:38 +01:00
|
|
|
dig_lookup_t *lookup = NULL;
|
|
|
|
|
2000-07-13 00:32:20 +00:00
|
|
|
debug("check_if_done()");
|
2000-08-02 22:39:01 +00:00
|
|
|
debug("list %s", ISC_LIST_EMPTY(lookup_list) ? "empty" : "full");
|
2020-11-05 15:22:38 +01:00
|
|
|
|
|
|
|
lookup = ISC_LIST_HEAD(lookup_list);
|
|
|
|
while (lookup != NULL) {
|
|
|
|
dig_lookup_t *next = NULL;
|
|
|
|
debug("pending lookup %p", lookup);
|
|
|
|
next = ISC_LIST_NEXT(lookup, link);
|
|
|
|
lookup = next;
|
|
|
|
}
|
|
|
|
|
2000-08-03 18:23:16 +00:00
|
|
|
if (ISC_LIST_EMPTY(lookup_list) && current_lookup == NULL &&
|
2020-09-05 16:37:24 -07:00
|
|
|
isc_refcount_current(&sendcount) == 0)
|
|
|
|
{
|
|
|
|
INSIST(isc_refcount_current(&recvcount) == 0);
|
2000-07-13 00:32:20 +00:00
|
|
|
debug("shutting down");
|
|
|
|
dighost_shutdown();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-20 13:54:39 +00:00
|
|
|
/*%
|
|
|
|
* Check if we're done with all the queries in the lookup, except for
|
|
|
|
* the `except_q` query (can be NULL if no exception is required).
|
|
|
|
* Expects `l` to be a valid and locked lookup.
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
check_if_queries_done(dig_lookup_t *l, dig_query_t *except_q) {
|
|
|
|
dig_query_t *q = ISC_LIST_HEAD(l->q);
|
|
|
|
|
|
|
|
debug("check_if_queries_done(%p)", l);
|
|
|
|
|
|
|
|
while (q != NULL) {
|
|
|
|
if (!q->started || isc_refcount_current(&q->references) > 1) {
|
|
|
|
if (!q->canceled && q != except_q) {
|
|
|
|
debug("there is a pending query %p", q);
|
|
|
|
return (false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
q = ISC_LIST_NEXT(q, link);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (true);
|
|
|
|
}
|
|
|
|
|
2020-11-05 15:22:38 +01:00
|
|
|
static void
|
|
|
|
_destroy_lookup(dig_lookup_t *lookup) {
|
|
|
|
dig_server_t *s;
|
|
|
|
void *ptr;
|
2020-11-04 12:40:13 +01:00
|
|
|
|
2021-04-06 16:49:14 -07:00
|
|
|
REQUIRE(lookup != NULL);
|
|
|
|
REQUIRE(ISC_LIST_EMPTY(lookup->q));
|
|
|
|
|
2020-11-05 15:22:38 +01:00
|
|
|
debug("destroy_lookup");
|
|
|
|
|
|
|
|
isc_refcount_destroy(&lookup->references);
|
|
|
|
|
|
|
|
s = ISC_LIST_HEAD(lookup->my_server_list);
|
|
|
|
while (s != NULL) {
|
|
|
|
debug("freeing server %p belonging to %p", s, lookup);
|
|
|
|
ptr = s;
|
|
|
|
s = ISC_LIST_NEXT(s, link);
|
|
|
|
ISC_LIST_DEQUEUE(lookup->my_server_list, (dig_server_t *)ptr,
|
|
|
|
link);
|
|
|
|
isc_mem_free(mctx, ptr);
|
|
|
|
}
|
|
|
|
if (lookup->sendmsg != NULL) {
|
|
|
|
dns_message_detach(&lookup->sendmsg);
|
|
|
|
}
|
|
|
|
if (lookup->querysig != NULL) {
|
|
|
|
debug("freeing buffer %p", lookup->querysig);
|
|
|
|
isc_buffer_free(&lookup->querysig);
|
|
|
|
}
|
|
|
|
if (lookup->sendspace != NULL) {
|
2021-05-12 21:16:17 +02:00
|
|
|
isc_mem_put(mctx, lookup->sendspace, COMMSIZE);
|
2020-11-05 15:22:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (lookup->tsigctx != NULL) {
|
|
|
|
dst_context_destroy(&lookup->tsigctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lookup->ecs_addr != NULL) {
|
|
|
|
isc_mem_free(mctx, lookup->ecs_addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lookup->ednsopts != NULL) {
|
|
|
|
size_t i;
|
|
|
|
for (i = 0; i < EDNSOPT_OPTIONS; i++) {
|
|
|
|
if (lookup->ednsopts[i].value != NULL) {
|
|
|
|
isc_mem_free(mctx, lookup->ednsopts[i].value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
isc_mem_free(mctx, lookup->ednsopts);
|
|
|
|
}
|
|
|
|
|
2021-01-27 15:49:27 +01:00
|
|
|
if (lookup->https_path) {
|
|
|
|
isc_mem_free(mctx, lookup->https_path);
|
|
|
|
}
|
|
|
|
|
2022-01-19 13:10:08 +02:00
|
|
|
if (lookup->tls_ctx_cache != NULL) {
|
|
|
|
isc_tlsctx_cache_detach(&lookup->tls_ctx_cache);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lookup->tls_ca_file != NULL) {
|
|
|
|
isc_mem_free(mctx, lookup->tls_ca_file);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lookup->tls_hostname != NULL) {
|
|
|
|
isc_mem_free(mctx, lookup->tls_hostname);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lookup->tls_key_file != NULL) {
|
|
|
|
isc_mem_free(mctx, lookup->tls_key_file);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lookup->tls_cert_file != NULL) {
|
|
|
|
isc_mem_free(mctx, lookup->tls_cert_file);
|
|
|
|
}
|
|
|
|
|
2020-11-05 15:22:38 +01:00
|
|
|
isc_mem_free(mctx, lookup);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define lookup_attach(s, t) _lookup_attach(s, t, __FILE__, __LINE__)
|
2000-07-13 00:32:20 +00:00
|
|
|
static void
|
2020-11-05 15:22:38 +01:00
|
|
|
_lookup_attach(dig_lookup_t *lookup, dig_lookup_t **lookupp, const char *file,
|
|
|
|
unsigned int line) {
|
|
|
|
REQUIRE(DIG_VALID_LOOKUP(lookup));
|
|
|
|
REQUIRE(lookupp != NULL && *lookupp == NULL);
|
2000-07-13 00:32:20 +00:00
|
|
|
|
2020-11-05 15:22:38 +01:00
|
|
|
debug("%s:%u:lookup_attach(%p) = %" PRIuFAST32, file, line, lookup,
|
|
|
|
isc_refcount_current(&lookup->references) + 1);
|
2000-07-13 00:32:20 +00:00
|
|
|
|
2020-11-05 15:22:38 +01:00
|
|
|
(void)isc_refcount_increment(&lookup->references);
|
2000-07-13 18:52:58 +00:00
|
|
|
|
2020-11-05 15:22:38 +01:00
|
|
|
*lookupp = lookup;
|
|
|
|
}
|
2020-09-05 16:37:24 -07:00
|
|
|
|
2020-11-05 15:22:38 +01:00
|
|
|
#define lookup_detach(l) _lookup_detach(l, __FILE__, __LINE__)
|
|
|
|
static void
|
|
|
|
_lookup_detach(dig_lookup_t **lookupp, const char *file, unsigned int line) {
|
|
|
|
REQUIRE(DIG_VALID_LOOKUP(*lookupp));
|
|
|
|
|
|
|
|
dig_lookup_t *lookup = *lookupp;
|
|
|
|
*lookupp = NULL;
|
|
|
|
|
|
|
|
debug("%s:%u:lookup_detach(%p) = %" PRIuFAST32, file, line, lookup,
|
|
|
|
isc_refcount_current(&lookup->references) - 1);
|
|
|
|
|
|
|
|
if (isc_refcount_decrement(&lookup->references) == 1) {
|
|
|
|
_destroy_lookup(lookup);
|
|
|
|
if (lookup == current_lookup) {
|
|
|
|
current_lookup = NULL;
|
|
|
|
start_lookup();
|
|
|
|
}
|
|
|
|
}
|
2020-11-04 12:40:13 +01:00
|
|
|
}
|
2020-09-05 16:37:24 -07:00
|
|
|
|
2020-11-05 15:22:38 +01:00
|
|
|
void
|
|
|
|
destroy_lookup(dig_lookup_t *lookup) {
|
|
|
|
REQUIRE(DIG_VALID_LOOKUP(lookup));
|
|
|
|
|
|
|
|
REQUIRE(isc_refcount_decrement(&lookup->references) == 1);
|
|
|
|
_destroy_lookup(lookup);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*%
|
|
|
|
* Destroy a query when we're done with it. WARNING: This routine
|
|
|
|
* WILL invalidate the query pointer.
|
|
|
|
*/
|
2020-11-04 12:40:13 +01:00
|
|
|
static void
|
2020-11-05 15:22:38 +01:00
|
|
|
destroy_query(dig_query_t *query, const char *file, unsigned int line) {
|
2020-11-04 12:40:13 +01:00
|
|
|
debug("%s:%u:destroy_query(%p) = %" PRIuFAST32, file, line, query,
|
|
|
|
isc_refcount_current(&query->references));
|
|
|
|
|
2020-11-05 15:22:38 +01:00
|
|
|
isc_refcount_destroy(&query->references);
|
|
|
|
|
|
|
|
lookup_detach(&query->lookup);
|
|
|
|
|
|
|
|
INSIST(query->recvspace != NULL);
|
|
|
|
|
2021-05-12 21:16:17 +02:00
|
|
|
isc_mem_put(mctx, query->recvspace, COMMSIZE);
|
|
|
|
isc_mem_put(mctx, query->tmpsendspace, COMMSIZE);
|
2000-07-14 17:57:27 +00:00
|
|
|
|
2020-11-04 12:40:13 +01:00
|
|
|
query->magic = 0;
|
|
|
|
isc_mem_free(mctx, query);
|
|
|
|
}
|
2000-09-21 22:46:39 +00:00
|
|
|
|
2020-11-04 12:40:13 +01:00
|
|
|
#define query_attach(s, t) _query_attach(s, t, __FILE__, __LINE__)
|
|
|
|
|
2020-11-04 12:40:13 +01:00
|
|
|
static void
|
2020-11-04 12:40:13 +01:00
|
|
|
_query_attach(dig_query_t *source, dig_query_t **targetp, const char *file,
|
|
|
|
unsigned int line) {
|
2020-11-04 12:40:13 +01:00
|
|
|
REQUIRE(DIG_VALID_QUERY(source));
|
|
|
|
REQUIRE(targetp != NULL && *targetp == NULL);
|
2012-10-18 17:50:07 -05:00
|
|
|
|
2020-11-04 12:40:13 +01:00
|
|
|
debug("%s:%u:query_attach(%p) = %" PRIuFAST32, file, line, source,
|
|
|
|
isc_refcount_current(&source->references) + 1);
|
|
|
|
|
2020-11-04 12:40:13 +01:00
|
|
|
(void)isc_refcount_increment(&source->references);
|
2018-11-07 13:04:13 -05:00
|
|
|
|
2020-11-04 12:40:13 +01:00
|
|
|
*targetp = source;
|
|
|
|
}
|
|
|
|
|
2020-11-04 12:40:13 +01:00
|
|
|
#define query_detach(q) _query_detach(q, __FILE__, __LINE__)
|
|
|
|
|
2020-11-04 12:40:13 +01:00
|
|
|
static void
|
2020-11-04 12:40:13 +01:00
|
|
|
_query_detach(dig_query_t **queryp, const char *file, unsigned int line) {
|
2020-11-04 12:40:13 +01:00
|
|
|
dig_query_t *query = NULL;
|
|
|
|
dig_lookup_t *lookup = NULL;
|
|
|
|
|
|
|
|
REQUIRE(DIG_VALID_QUERY(*queryp));
|
|
|
|
|
|
|
|
query = *queryp;
|
|
|
|
*queryp = NULL;
|
|
|
|
|
2020-11-04 12:40:13 +01:00
|
|
|
lookup = query->lookup;
|
|
|
|
|
|
|
|
if (lookup->current_query == query) {
|
2020-11-05 15:22:38 +01:00
|
|
|
query_detach(&lookup->current_query);
|
2020-11-04 12:40:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
debug("%s:%u:query_detach(%p) = %" PRIuFAST32, file, line, query,
|
|
|
|
isc_refcount_current(&query->references) - 1);
|
2020-11-04 12:40:13 +01:00
|
|
|
|
|
|
|
if (isc_refcount_decrement(&query->references) == 1) {
|
2021-04-27 12:03:20 +02:00
|
|
|
INSIST(query->readhandle == NULL);
|
|
|
|
INSIST(query->sendhandle == NULL);
|
|
|
|
|
2021-03-29 14:04:12 -03:00
|
|
|
if (ISC_LINK_LINKED(query, link)) {
|
|
|
|
ISC_LIST_UNLINK(lookup->q, query, link);
|
|
|
|
}
|
2020-11-05 15:22:38 +01:00
|
|
|
destroy_query(query, file, line);
|
2017-11-13 16:10:35 +11:00
|
|
|
}
|
2000-08-01 01:33:37 +00:00
|
|
|
}
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
2000-07-13 00:32:20 +00:00
|
|
|
* If we can, start the next lookup in the queue running.
|
|
|
|
* This assumes that the lookup on the head of the queue hasn't been
|
2000-08-01 00:53:20 +00:00
|
|
|
* started yet. It also removes the lookup from the head of the queue,
|
|
|
|
* setting the current_lookup pointer pointing to it.
|
2000-07-13 00:32:20 +00:00
|
|
|
*/
|
2000-07-14 20:14:36 +00:00
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
start_lookup(void) {
|
2000-07-14 20:14:36 +00:00
|
|
|
debug("start_lookup()");
|
2020-11-05 15:22:38 +01:00
|
|
|
|
|
|
|
if (atomic_load(&cancel_now)) {
|
2000-07-14 17:57:27 +00:00
|
|
|
return;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2000-07-14 20:14:36 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If there's a current lookup running, we really shouldn't get
|
|
|
|
* here.
|
|
|
|
*/
|
|
|
|
INSIST(current_lookup == NULL);
|
|
|
|
|
2000-08-01 00:53:20 +00:00
|
|
|
current_lookup = ISC_LIST_HEAD(lookup_list);
|
2020-11-05 15:22:38 +01:00
|
|
|
|
2000-07-14 20:14:36 +00:00
|
|
|
/*
|
|
|
|
* Put the current lookup somewhere so cancel_all can find it
|
|
|
|
*/
|
2000-08-01 00:53:20 +00:00
|
|
|
if (current_lookup != NULL) {
|
2020-11-05 15:22:38 +01:00
|
|
|
/*
|
|
|
|
* Formally, we should attach the lookup to the current_lookup
|
|
|
|
* and detach it from the lookup_list, but it would be one
|
|
|
|
* attach and one detach.
|
|
|
|
*/
|
2000-08-01 00:53:20 +00:00
|
|
|
ISC_LIST_DEQUEUE(lookup_list, current_lookup, link);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (setup_lookup(current_lookup)) {
|
2014-08-21 18:05:55 +10:00
|
|
|
do_lookup(current_lookup);
|
2020-02-13 21:48:23 +01:00
|
|
|
} else if (next_origin(current_lookup)) {
|
2020-11-05 15:22:38 +01:00
|
|
|
lookup_detach(¤t_lookup);
|
|
|
|
start_lookup();
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2000-07-13 00:32:20 +00:00
|
|
|
} else {
|
|
|
|
check_if_done();
|
2000-08-01 00:53:20 +00:00
|
|
|
}
|
2000-07-13 00:32:20 +00:00
|
|
|
}
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
2000-07-18 18:51:40 +00:00
|
|
|
* If we can, clear the current lookup and start the next one running.
|
2020-11-06 16:12:17 +01:00
|
|
|
* (Note that while the reference count of current_lookup may be
|
|
|
|
* decremented, current_lookup will not be set to NULL.)
|
2000-07-13 00:32:20 +00:00
|
|
|
*/
|
|
|
|
static void
|
2021-05-04 14:25:55 +02:00
|
|
|
clear_current_lookup(void) {
|
2020-11-06 16:12:17 +01:00
|
|
|
dig_lookup_t *lookup = current_lookup;
|
2000-05-22 22:56:31 +00:00
|
|
|
|
2020-11-06 16:12:17 +01:00
|
|
|
INSIST(!free_now);
|
2020-11-05 15:22:38 +01:00
|
|
|
|
2020-11-06 16:12:17 +01:00
|
|
|
debug("clear_current_lookup()");
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2021-05-04 14:25:55 +02:00
|
|
|
if (lookup == NULL) {
|
|
|
|
debug("current_lookup is already detached");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2000-07-27 19:06:12 +00:00
|
|
|
if (ISC_LIST_HEAD(lookup->q) != NULL) {
|
|
|
|
debug("still have a worker");
|
2000-07-13 00:32:20 +00:00
|
|
|
return;
|
2000-07-27 19:06:12 +00:00
|
|
|
}
|
2020-11-05 15:22:38 +01:00
|
|
|
|
|
|
|
lookup_detach(&lookup);
|
2000-05-12 01:02:37 +00:00
|
|
|
}
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
2000-07-18 18:51:40 +00:00
|
|
|
* Create and queue a new lookup as a followup to the current lookup,
|
|
|
|
* based on the supplied message and section. This is used in trace and
|
|
|
|
* name server search modes to start a new lookup using servers from
|
2001-02-13 23:12:17 +00:00
|
|
|
* NS records in a reply. Returns the number of followup lookups made.
|
2000-07-18 18:51:40 +00:00
|
|
|
*/
|
2001-02-13 23:12:17 +00:00
|
|
|
static int
|
2020-02-13 14:44:37 -08:00
|
|
|
followup_lookup(dns_message_t *msg, dig_query_t *query, dns_section_t section) {
|
|
|
|
dig_lookup_t *lookup = NULL;
|
|
|
|
dig_server_t *srv = NULL;
|
2000-04-28 21:41:19 +00:00
|
|
|
dns_rdataset_t *rdataset = NULL;
|
2020-02-13 14:44:37 -08:00
|
|
|
dns_rdata_t rdata = DNS_RDATA_INIT;
|
|
|
|
dns_name_t *name = NULL;
|
|
|
|
isc_result_t result;
|
|
|
|
bool success = false;
|
|
|
|
int numLookups = 0;
|
|
|
|
int num;
|
|
|
|
isc_result_t lresult, addresses_result;
|
|
|
|
char bad_namestr[DNS_NAME_FORMATSIZE];
|
|
|
|
dns_name_t *domain;
|
|
|
|
bool horizontal = false, bad = false;
|
2000-04-28 21:41:19 +00:00
|
|
|
|
2000-07-13 00:32:20 +00:00
|
|
|
INSIST(!free_now);
|
|
|
|
|
2000-07-05 23:28:32 +00:00
|
|
|
debug("following up %s", query->lookup->textname);
|
2008-01-18 23:46:58 +00:00
|
|
|
|
2011-12-07 17:23:28 +00:00
|
|
|
addresses_result = ISC_R_SUCCESS;
|
|
|
|
bad_namestr[0] = '\0';
|
2001-07-27 22:07:10 +00:00
|
|
|
for (result = dns_message_firstname(msg, section);
|
2001-07-27 05:26:38 +00:00
|
|
|
result == ISC_R_SUCCESS;
|
2020-02-13 14:44:37 -08:00
|
|
|
result = dns_message_nextname(msg, section))
|
|
|
|
{
|
2000-04-28 21:41:19 +00:00
|
|
|
name = NULL;
|
2000-05-06 01:16:07 +00:00
|
|
|
dns_message_currentname(msg, section, &name);
|
2001-07-27 05:26:38 +00:00
|
|
|
|
2004-09-16 02:10:42 +00:00
|
|
|
if (section == DNS_SECTION_AUTHORITY) {
|
|
|
|
rdataset = NULL;
|
|
|
|
result = dns_message_findtype(name, dns_rdatatype_soa,
|
|
|
|
0, &rdataset);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
2004-09-16 02:10:42 +00:00
|
|
|
return (0);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2004-09-16 02:10:42 +00:00
|
|
|
}
|
2001-07-27 22:07:10 +00:00
|
|
|
rdataset = NULL;
|
|
|
|
result = dns_message_findtype(name, dns_rdatatype_ns, 0,
|
|
|
|
&rdataset);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2001-07-27 22:07:10 +00:00
|
|
|
continue;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-07-27 05:26:38 +00:00
|
|
|
|
2001-07-27 22:07:10 +00:00
|
|
|
debug("found NS set");
|
2001-07-27 05:26:38 +00:00
|
|
|
|
2004-10-07 02:21:48 +00:00
|
|
|
if (query->lookup->trace && !query->lookup->trace_root) {
|
|
|
|
dns_namereln_t namereln;
|
2020-02-13 14:44:37 -08:00
|
|
|
unsigned int nlabels;
|
|
|
|
int order;
|
2004-10-07 02:21:48 +00:00
|
|
|
|
|
|
|
domain = dns_fixedname_name(&query->lookup->fdomain);
|
2020-02-12 13:59:18 +01:00
|
|
|
namereln = dns_name_fullcompare(name, domain, &order,
|
|
|
|
&nlabels);
|
2006-12-07 01:21:04 +00:00
|
|
|
if (namereln == dns_namereln_equal) {
|
2019-08-30 14:23:29 +10:00
|
|
|
if (!horizontal) {
|
|
|
|
dighost_warning("BAD (HORIZONTAL) "
|
|
|
|
"REFERRAL");
|
|
|
|
}
|
2018-04-17 08:29:14 -07:00
|
|
|
horizontal = true;
|
2006-12-07 01:21:04 +00:00
|
|
|
} else if (namereln != dns_namereln_subdomain) {
|
2019-08-30 14:23:29 +10:00
|
|
|
if (!bad) {
|
2020-02-12 13:59:18 +01:00
|
|
|
dighost_warning("BAD REFERRAL");
|
2019-08-30 14:23:29 +10:00
|
|
|
}
|
2018-04-17 08:29:14 -07:00
|
|
|
bad = true;
|
2006-12-07 01:21:04 +00:00
|
|
|
continue;
|
|
|
|
}
|
2004-10-07 02:21:48 +00:00
|
|
|
}
|
|
|
|
|
2001-07-27 22:07:10 +00:00
|
|
|
for (result = dns_rdataset_first(rdataset);
|
|
|
|
result == ISC_R_SUCCESS;
|
2020-02-13 14:44:37 -08:00
|
|
|
result = dns_rdataset_next(rdataset))
|
|
|
|
{
|
|
|
|
char namestr[DNS_NAME_FORMATSIZE];
|
2001-07-27 22:07:10 +00:00
|
|
|
dns_rdata_ns_t ns;
|
|
|
|
|
|
|
|
if (query->lookup->trace_root &&
|
2020-02-13 21:48:23 +01:00
|
|
|
query->lookup->nsfound >= MXSERV) {
|
2001-07-27 22:07:10 +00:00
|
|
|
break;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-07-27 22:07:10 +00:00
|
|
|
|
|
|
|
dns_rdataset_current(rdataset, &rdata);
|
|
|
|
|
|
|
|
query->lookup->nsfound++;
|
2008-01-14 23:24:24 +00:00
|
|
|
result = dns_rdata_tostruct(&rdata, &ns, NULL);
|
|
|
|
check_result(result, "dns_rdata_tostruct");
|
2001-07-27 22:07:10 +00:00
|
|
|
dns_name_format(&ns.name, namestr, sizeof(namestr));
|
|
|
|
dns_rdata_freestruct(&ns);
|
|
|
|
|
|
|
|
/* Initialize lookup if we've not yet */
|
2011-02-25 23:11:13 +00:00
|
|
|
debug("found NS %s", namestr);
|
2001-07-27 22:07:10 +00:00
|
|
|
if (!success) {
|
2018-04-17 08:29:14 -07:00
|
|
|
success = true;
|
2001-07-27 22:07:10 +00:00
|
|
|
lookup_counter++;
|
2020-02-12 13:59:18 +01:00
|
|
|
lookup = requeue_lookup(query->lookup, false);
|
2001-10-31 21:55:31 +00:00
|
|
|
cancel_lookup(query->lookup);
|
2018-04-17 08:29:14 -07:00
|
|
|
lookup->doing_xfr = false;
|
2001-07-29 23:23:42 +00:00
|
|
|
if (!lookup->trace_root &&
|
2020-02-13 21:48:23 +01:00
|
|
|
section == DNS_SECTION_ANSWER) {
|
2018-04-17 08:29:14 -07:00
|
|
|
lookup->trace = false;
|
2020-02-13 21:48:23 +01:00
|
|
|
} else {
|
2001-07-29 23:23:42 +00:00
|
|
|
lookup->trace = query->lookup->trace;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-07-28 00:55:15 +00:00
|
|
|
lookup->ns_search_only =
|
|
|
|
query->lookup->ns_search_only;
|
2018-04-17 08:29:14 -07:00
|
|
|
lookup->trace_root = false;
|
2020-02-13 21:48:23 +01:00
|
|
|
if (lookup->ns_search_only) {
|
2018-04-17 08:29:14 -07:00
|
|
|
lookup->recurse = false;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2004-10-07 02:21:48 +00:00
|
|
|
domain = dns_fixedname_name(&lookup->fdomain);
|
2021-05-21 17:20:44 -07:00
|
|
|
dns_name_copy(name, domain);
|
2000-04-28 21:41:19 +00:00
|
|
|
}
|
2011-02-25 23:11:13 +00:00
|
|
|
debug("adding server %s", namestr);
|
2011-12-07 17:23:28 +00:00
|
|
|
num = getaddresses(lookup, namestr, &lresult);
|
|
|
|
if (lresult != ISC_R_SUCCESS) {
|
2013-02-07 14:14:26 -08:00
|
|
|
printf("couldn't get address for '%s': %s\n",
|
|
|
|
namestr, isc_result_totext(lresult));
|
2011-12-07 17:23:28 +00:00
|
|
|
if (addresses_result == ISC_R_SUCCESS) {
|
|
|
|
addresses_result = lresult;
|
2017-09-13 00:14:37 -07:00
|
|
|
strlcpy(bad_namestr, namestr,
|
|
|
|
sizeof(bad_namestr));
|
2011-12-07 17:23:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
numLookups += num;
|
2001-07-27 22:07:10 +00:00
|
|
|
dns_rdata_reset(&rdata);
|
2000-04-28 21:41:19 +00:00
|
|
|
}
|
|
|
|
}
|
2011-12-07 17:23:28 +00:00
|
|
|
if (numLookups == 0 && addresses_result != ISC_R_SUCCESS) {
|
2020-02-12 13:59:18 +01:00
|
|
|
fatal("couldn't get address for '%s': %s", bad_namestr,
|
|
|
|
isc_result_totext(result));
|
2011-12-07 17:23:28 +00:00
|
|
|
}
|
2001-07-27 22:07:10 +00:00
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
if (lookup == NULL && section == DNS_SECTION_ANSWER &&
|
2020-02-13 14:44:37 -08:00
|
|
|
(query->lookup->trace || query->lookup->ns_search_only))
|
|
|
|
{
|
2001-07-27 22:07:10 +00:00
|
|
|
return (followup_lookup(msg, query, DNS_SECTION_AUTHORITY));
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-02-13 23:12:17 +00:00
|
|
|
|
2004-10-07 02:21:48 +00:00
|
|
|
/*
|
|
|
|
* Randomize the order the nameserver will be tried.
|
|
|
|
*/
|
|
|
|
if (numLookups > 1) {
|
2020-02-13 14:44:37 -08:00
|
|
|
uint32_t i, j;
|
2004-10-07 02:21:48 +00:00
|
|
|
dig_serverlist_t my_server_list;
|
2020-02-13 14:44:37 -08:00
|
|
|
dig_server_t *next;
|
2004-10-07 02:21:48 +00:00
|
|
|
|
|
|
|
ISC_LIST_INIT(my_server_list);
|
|
|
|
|
2011-03-11 06:11:27 +00:00
|
|
|
i = numLookups;
|
2020-02-12 13:59:18 +01:00
|
|
|
for (srv = ISC_LIST_HEAD(lookup->my_server_list); srv != NULL;
|
2020-02-13 14:44:37 -08:00
|
|
|
srv = ISC_LIST_HEAD(lookup->my_server_list))
|
|
|
|
{
|
2011-03-11 06:11:27 +00:00
|
|
|
INSIST(i > 0);
|
2018-05-28 15:22:23 +02:00
|
|
|
j = isc_random_uniform(i);
|
2011-03-11 06:11:27 +00:00
|
|
|
next = ISC_LIST_NEXT(srv, link);
|
|
|
|
while (j-- > 0 && next != NULL) {
|
|
|
|
srv = next;
|
|
|
|
next = ISC_LIST_NEXT(srv, link);
|
|
|
|
}
|
2004-10-07 02:21:48 +00:00
|
|
|
ISC_LIST_DEQUEUE(lookup->my_server_list, srv, link);
|
|
|
|
ISC_LIST_APPEND(my_server_list, srv, link);
|
2011-03-11 06:11:27 +00:00
|
|
|
i--;
|
2004-10-07 02:21:48 +00:00
|
|
|
}
|
2020-02-12 13:59:18 +01:00
|
|
|
ISC_LIST_APPENDLIST(lookup->my_server_list, my_server_list,
|
|
|
|
link);
|
2004-10-07 02:21:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return (numLookups);
|
2000-04-28 21:41:19 +00:00
|
|
|
}
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
2001-01-18 05:12:44 +00:00
|
|
|
* Create and queue a new lookup using the next origin from the search
|
2000-07-18 18:51:40 +00:00
|
|
|
* list, read in setup_system().
|
2001-01-18 05:12:44 +00:00
|
|
|
*
|
2018-04-17 08:29:14 -07:00
|
|
|
* Return true iff there was another searchlist entry.
|
2000-07-18 18:51:40 +00:00
|
|
|
*/
|
2018-04-17 08:29:14 -07:00
|
|
|
static bool
|
2020-02-13 14:44:37 -08:00
|
|
|
next_origin(dig_lookup_t *oldlookup) {
|
|
|
|
dig_lookup_t *newlookup;
|
2006-12-07 05:52:16 +00:00
|
|
|
dig_searchlist_t *search;
|
2020-02-13 14:44:37 -08:00
|
|
|
dns_fixedname_t fixed;
|
|
|
|
dns_name_t *name;
|
|
|
|
isc_result_t result;
|
2000-05-02 23:23:12 +00:00
|
|
|
|
2000-07-13 00:32:20 +00:00
|
|
|
INSIST(!free_now);
|
|
|
|
|
2000-08-01 01:33:37 +00:00
|
|
|
debug("next_origin()");
|
2014-08-21 18:05:55 +10:00
|
|
|
debug("following up %s", oldlookup->textname);
|
2000-05-02 23:23:12 +00:00
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (!usesearch) {
|
2000-07-24 18:07:03 +00:00
|
|
|
/*
|
|
|
|
* We're not using a search list, so don't even think
|
|
|
|
* about finding the next entry.
|
|
|
|
*/
|
2018-04-17 08:29:14 -07:00
|
|
|
return (false);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2013-09-04 23:46:16 +00:00
|
|
|
|
2013-09-04 13:24:11 +10:00
|
|
|
/*
|
|
|
|
* Check for a absolute name or ndots being met.
|
|
|
|
*/
|
2018-03-28 14:38:09 +02:00
|
|
|
name = dns_fixedname_initname(&fixed);
|
2020-02-12 13:59:18 +01:00
|
|
|
result = dns_name_fromstring2(name, oldlookup->textname, NULL, 0, NULL);
|
2013-09-04 13:24:11 +10:00
|
|
|
if (result == ISC_R_SUCCESS &&
|
|
|
|
(dns_name_isabsolute(name) ||
|
2020-02-13 14:44:37 -08:00
|
|
|
(int)dns_name_countlabels(name) > ndots))
|
|
|
|
{
|
2018-04-17 08:29:14 -07:00
|
|
|
return (false);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2013-09-04 23:46:16 +00:00
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (oldlookup->origin == NULL && !oldlookup->need_search) {
|
2000-07-05 19:31:26 +00:00
|
|
|
/*
|
|
|
|
* Then we just did rootorg; there's nothing left.
|
|
|
|
*/
|
2018-04-17 08:29:14 -07:00
|
|
|
return (false);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2014-08-21 18:05:55 +10:00
|
|
|
if (oldlookup->origin == NULL && oldlookup->need_search) {
|
2018-04-17 08:29:14 -07:00
|
|
|
newlookup = requeue_lookup(oldlookup, true);
|
2014-08-21 18:05:55 +10:00
|
|
|
newlookup->origin = ISC_LIST_HEAD(search_list);
|
2018-04-17 08:29:14 -07:00
|
|
|
newlookup->need_search = false;
|
2006-12-07 05:52:16 +00:00
|
|
|
} else {
|
2014-08-21 18:05:55 +10:00
|
|
|
search = ISC_LIST_NEXT(oldlookup->origin, link);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (search == NULL && oldlookup->done_as_is) {
|
2018-04-17 08:29:14 -07:00
|
|
|
return (false);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2018-04-17 08:29:14 -07:00
|
|
|
newlookup = requeue_lookup(oldlookup, true);
|
2014-08-21 18:05:55 +10:00
|
|
|
newlookup->origin = search;
|
2006-12-07 05:52:16 +00:00
|
|
|
}
|
2014-08-21 18:05:55 +10:00
|
|
|
cancel_lookup(oldlookup);
|
2018-04-17 08:29:14 -07:00
|
|
|
return (true);
|
2000-05-02 23:23:12 +00:00
|
|
|
}
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
2000-07-18 18:51:40 +00:00
|
|
|
* Insert an SOA record into the sendmessage in a lookup. Used for
|
|
|
|
* creating IXFR queries.
|
|
|
|
*/
|
2000-06-02 18:45:33 +00:00
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
insert_soa(dig_lookup_t *lookup) {
|
|
|
|
isc_result_t result;
|
|
|
|
dns_rdata_soa_t soa;
|
|
|
|
dns_rdata_t *rdata = NULL;
|
2000-06-02 18:45:33 +00:00
|
|
|
dns_rdatalist_t *rdatalist = NULL;
|
2020-02-13 14:44:37 -08:00
|
|
|
dns_rdataset_t *rdataset = NULL;
|
|
|
|
dns_name_t *soaname = NULL;
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2000-07-05 19:31:26 +00:00
|
|
|
debug("insert_soa()");
|
2000-06-02 18:45:33 +00:00
|
|
|
soa.mctx = mctx;
|
|
|
|
soa.serial = lookup->ixfr_serial;
|
2001-07-28 00:55:15 +00:00
|
|
|
soa.refresh = 0;
|
|
|
|
soa.retry = 0;
|
|
|
|
soa.expire = 0;
|
|
|
|
soa.minimum = 0;
|
2000-08-01 00:53:20 +00:00
|
|
|
soa.common.rdclass = lookup->rdclass;
|
2000-06-02 18:45:33 +00:00
|
|
|
soa.common.rdtype = dns_rdatatype_soa;
|
|
|
|
|
|
|
|
dns_name_init(&soa.origin, NULL);
|
2001-07-30 01:09:14 +00:00
|
|
|
dns_name_init(&soa.contact, NULL);
|
2000-06-02 18:45:33 +00:00
|
|
|
|
2001-07-28 00:55:15 +00:00
|
|
|
dns_name_clone(dns_rootname, &soa.origin);
|
2001-07-30 01:09:14 +00:00
|
|
|
dns_name_clone(dns_rootname, &soa.contact);
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2000-06-02 18:45:33 +00:00
|
|
|
isc_buffer_init(&lookup->rdatabuf, lookup->rdatastore,
|
2000-08-01 00:53:20 +00:00
|
|
|
sizeof(lookup->rdatastore));
|
2000-06-02 18:45:33 +00:00
|
|
|
|
2022-05-16 13:28:13 +02:00
|
|
|
dns_message_gettemprdata(lookup->sendmsg, &rdata);
|
2000-08-01 00:53:20 +00:00
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
result = dns_rdata_fromstruct(rdata, lookup->rdclass, dns_rdatatype_soa,
|
|
|
|
&soa, &lookup->rdatabuf);
|
2000-06-02 18:45:33 +00:00
|
|
|
check_result(result, "isc_rdata_fromstruct");
|
|
|
|
|
2022-05-16 13:28:13 +02:00
|
|
|
dns_message_gettemprdatalist(lookup->sendmsg, &rdatalist);
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2022-05-16 13:28:13 +02:00
|
|
|
dns_message_gettemprdataset(lookup->sendmsg, &rdataset);
|
2000-06-02 18:45:33 +00:00
|
|
|
|
|
|
|
dns_rdatalist_init(rdatalist);
|
|
|
|
rdatalist->type = dns_rdatatype_soa;
|
2000-08-01 00:53:20 +00:00
|
|
|
rdatalist->rdclass = lookup->rdclass;
|
2000-06-02 18:45:33 +00:00
|
|
|
ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
|
|
|
|
|
|
|
|
dns_rdatalist_tordataset(rdatalist, rdataset);
|
|
|
|
|
2022-05-16 13:28:13 +02:00
|
|
|
dns_message_gettempname(lookup->sendmsg, &soaname);
|
2000-06-02 18:45:33 +00:00
|
|
|
dns_name_clone(lookup->name, soaname);
|
|
|
|
ISC_LIST_INIT(soaname->list);
|
|
|
|
ISC_LIST_APPEND(soaname->list, rdataset, link);
|
|
|
|
dns_message_addname(lookup->sendmsg, soaname, DNS_SECTION_AUTHORITY);
|
|
|
|
}
|
|
|
|
|
2014-02-19 12:53:42 +11:00
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
compute_cookie(unsigned char *clientcookie, size_t len) {
|
2014-02-19 12:53:42 +11:00
|
|
|
/* XXXMPA need to fix, should be per server. */
|
|
|
|
INSIST(len >= 8U);
|
2015-01-20 13:29:18 -08:00
|
|
|
memmove(clientcookie, cookie_secret, 8);
|
2014-02-19 12:53:42 +11:00
|
|
|
}
|
|
|
|
|
2020-11-04 12:40:13 +01:00
|
|
|
#define new_query(l, s, u) _new_query(l, s, u, __FILE__, __LINE__)
|
|
|
|
|
2020-09-05 16:37:24 -07:00
|
|
|
static dig_query_t *
|
2020-11-04 12:40:13 +01:00
|
|
|
_new_query(dig_lookup_t *lookup, char *servname, char *userarg,
|
|
|
|
const char *file, unsigned int line) {
|
2020-09-05 16:37:24 -07:00
|
|
|
dig_query_t *query = NULL;
|
|
|
|
|
|
|
|
query = isc_mem_allocate(mctx, sizeof(dig_query_t));
|
|
|
|
debug("create query %p linked to lookup %p", query, lookup);
|
2020-11-05 15:22:38 +01:00
|
|
|
*query = (dig_query_t){ .sendbuf = lookup->renderbuf,
|
2020-09-05 16:37:24 -07:00
|
|
|
.servname = servname,
|
|
|
|
.userarg = userarg,
|
|
|
|
.warn_id = true,
|
2021-05-12 21:16:17 +02:00
|
|
|
.recvspace = isc_mem_get(mctx, COMMSIZE),
|
|
|
|
.tmpsendspace = isc_mem_get(mctx, COMMSIZE) };
|
2020-11-04 12:40:13 +01:00
|
|
|
|
2020-11-05 15:22:38 +01:00
|
|
|
lookup_attach(lookup, &query->lookup);
|
|
|
|
|
|
|
|
isc_refcount_init(&query->references, 1);
|
|
|
|
|
2020-11-04 12:40:13 +01:00
|
|
|
debug("%s:%u:new_query(%p) = %" PRIuFAST32, file, line, query,
|
|
|
|
isc_refcount_current(&query->references));
|
|
|
|
|
2020-09-05 16:37:24 -07:00
|
|
|
if (query->recvspace == NULL) {
|
|
|
|
fatal("memory allocation failure");
|
|
|
|
}
|
|
|
|
if (query->tmpsendspace == NULL) {
|
|
|
|
fatal("memory allocation failure");
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_time_settoepoch(&query->time_sent);
|
|
|
|
isc_time_settoepoch(&query->time_recv);
|
|
|
|
|
|
|
|
ISC_LINK_INIT(query, clink);
|
|
|
|
ISC_LINK_INIT(query, link);
|
|
|
|
|
|
|
|
query->magic = DIG_QUERY_MAGIC;
|
|
|
|
return (query);
|
|
|
|
}
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
2000-07-18 18:51:40 +00:00
|
|
|
* Setup the supplied lookup structure, making it ready to start sending
|
|
|
|
* queries to servers. Create and initialize the message to be sent as
|
|
|
|
* well as the query structures and buffer space for the replies. If the
|
|
|
|
* server list is empty, clone it from the system default list.
|
|
|
|
*/
|
2018-04-17 08:29:14 -07:00
|
|
|
bool
|
2020-02-13 14:44:37 -08:00
|
|
|
setup_lookup(dig_lookup_t *lookup) {
|
|
|
|
isc_result_t result;
|
|
|
|
unsigned int len;
|
|
|
|
dig_server_t *serv;
|
|
|
|
dig_query_t *query;
|
|
|
|
isc_buffer_t b;
|
2001-03-05 21:15:47 +00:00
|
|
|
dns_compress_t cctx;
|
2020-02-13 14:44:37 -08:00
|
|
|
char store[MXNAME];
|
|
|
|
char ecsbuf[20];
|
|
|
|
char cookiebuf[256];
|
|
|
|
char *origin = NULL;
|
|
|
|
char *textname = NULL;
|
2019-09-27 08:48:06 +02:00
|
|
|
|
|
|
|
REQUIRE(lookup != NULL);
|
|
|
|
|
Rework libidn2 detection
Clean up the parts of configure.in responsible for handling libidn2
detection and adjust other pieces of the build system to match these
cleanups:
- use pkg-config when --with-libidn2 is used without an explicit path,
- look for idn2_to_ascii_lz() rather than idn2_to_ascii_8z() as the
former is used in BIND while the latter is not,
- do not look for idn2_to_unicode_8zlz() as it is present in all
libidn2 versions which have idn2_to_ascii_lz(),
- check whether the <idn2.h> header is usable,
- set LDFLAGS in the Makefile for dig so that, if specified, the
requested libidn2 path is used when linking with libidn2,
- override CPPFLAGS when looking for libidn2 components so that the
configure script does not produce warnings when libidn2 is not
installed system-wide,
- merge the AS_CASE() call into the AS_IF() call below it to simplify
code,
- indicate the default value of --with-libidn2 in "./configure --help"
output,
- use $with_libidn2 rather than $use_libidn2 to better match the name
of the configure script argument,
- stop differentiating between IDN "in" and "out" support, i.e. make
dig either support libidn2 or not; remove WITH_* Autoconf macros and
use a new one, HAVE_LIBIDN2, to determine whether libidn2 support
should be enabled.
2018-07-10 14:34:35 +02:00
|
|
|
#ifdef HAVE_LIBIDN2
|
2017-08-15 14:36:59 +02:00
|
|
|
char idn_origin[MXNAME], idn_textname[MXNAME];
|
Rework libidn2 detection
Clean up the parts of configure.in responsible for handling libidn2
detection and adjust other pieces of the build system to match these
cleanups:
- use pkg-config when --with-libidn2 is used without an explicit path,
- look for idn2_to_ascii_lz() rather than idn2_to_ascii_8z() as the
former is used in BIND while the latter is not,
- do not look for idn2_to_unicode_8zlz() as it is present in all
libidn2 versions which have idn2_to_ascii_lz(),
- check whether the <idn2.h> header is usable,
- set LDFLAGS in the Makefile for dig so that, if specified, the
requested libidn2 path is used when linking with libidn2,
- override CPPFLAGS when looking for libidn2 components so that the
configure script does not produce warnings when libidn2 is not
installed system-wide,
- merge the AS_CASE() call into the AS_IF() call below it to simplify
code,
- indicate the default value of --with-libidn2 in "./configure --help"
output,
- use $with_libidn2 rather than $use_libidn2 to better match the name
of the configure script argument,
- stop differentiating between IDN "in" and "out" support, i.e. make
dig either support libidn2 or not; remove WITH_* Autoconf macros and
use a new one, HAVE_LIBIDN2, to determine whether libidn2 support
should be enabled.
2018-07-10 14:34:35 +02:00
|
|
|
#endif /* HAVE_LIBIDN2 */
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2000-07-13 00:32:20 +00:00
|
|
|
INSIST(!free_now);
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2000-08-01 00:53:20 +00:00
|
|
|
debug("setup_lookup(%p)", lookup);
|
2000-04-26 18:34:17 +00:00
|
|
|
|
2020-09-25 11:51:36 +02:00
|
|
|
dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &lookup->sendmsg);
|
2000-04-26 18:34:17 +00:00
|
|
|
|
2000-05-24 23:39:30 +00:00
|
|
|
if (lookup->new_search) {
|
2000-07-05 23:28:32 +00:00
|
|
|
debug("resetting lookup counter.");
|
2000-05-24 19:49:51 +00:00
|
|
|
lookup_counter = 0;
|
2000-05-24 23:39:30 +00:00
|
|
|
}
|
2000-04-26 18:34:17 +00:00
|
|
|
|
2000-07-14 16:35:30 +00:00
|
|
|
if (ISC_LIST_EMPTY(lookup->my_server_list)) {
|
|
|
|
debug("cloning server list");
|
|
|
|
clone_server_list(server_list, &lookup->my_server_list);
|
|
|
|
}
|
2022-05-16 13:28:13 +02:00
|
|
|
dns_message_gettempname(lookup->sendmsg, &lookup->name);
|
2000-04-26 18:34:17 +00:00
|
|
|
|
2017-07-21 11:52:24 +10:00
|
|
|
isc_buffer_init(&lookup->namebuf, lookup->name_space,
|
|
|
|
sizeof(lookup->name_space));
|
|
|
|
isc_buffer_init(&lookup->onamebuf, lookup->oname_space,
|
|
|
|
sizeof(lookup->oname_space));
|
2000-05-02 23:23:12 +00:00
|
|
|
|
2005-09-09 06:17:03 +00:00
|
|
|
/*
|
|
|
|
* We cannot convert `textname' and `origin' separately.
|
|
|
|
* `textname' doesn't contain TLD, but local mapping needs
|
|
|
|
* TLD.
|
|
|
|
*/
|
2017-08-15 14:36:59 +02:00
|
|
|
textname = lookup->textname;
|
Rework libidn2 detection
Clean up the parts of configure.in responsible for handling libidn2
detection and adjust other pieces of the build system to match these
cleanups:
- use pkg-config when --with-libidn2 is used without an explicit path,
- look for idn2_to_ascii_lz() rather than idn2_to_ascii_8z() as the
former is used in BIND while the latter is not,
- do not look for idn2_to_unicode_8zlz() as it is present in all
libidn2 versions which have idn2_to_ascii_lz(),
- check whether the <idn2.h> header is usable,
- set LDFLAGS in the Makefile for dig so that, if specified, the
requested libidn2 path is used when linking with libidn2,
- override CPPFLAGS when looking for libidn2 components so that the
configure script does not produce warnings when libidn2 is not
installed system-wide,
- merge the AS_CASE() call into the AS_IF() call below it to simplify
code,
- indicate the default value of --with-libidn2 in "./configure --help"
output,
- use $with_libidn2 rather than $use_libidn2 to better match the name
of the configure script argument,
- stop differentiating between IDN "in" and "out" support, i.e. make
dig either support libidn2 or not; remove WITH_* Autoconf macros and
use a new one, HAVE_LIBIDN2, to determine whether libidn2 support
should be enabled.
2018-07-10 14:34:35 +02:00
|
|
|
#ifdef HAVE_LIBIDN2
|
2017-08-15 14:36:59 +02:00
|
|
|
if (lookup->idnin) {
|
2018-07-10 14:34:35 +02:00
|
|
|
idn_locale_to_ace(textname, idn_textname, sizeof(idn_textname));
|
2017-08-15 14:36:59 +02:00
|
|
|
debug("idn_textname: %s", idn_textname);
|
|
|
|
textname = idn_textname;
|
|
|
|
}
|
Rework libidn2 detection
Clean up the parts of configure.in responsible for handling libidn2
detection and adjust other pieces of the build system to match these
cleanups:
- use pkg-config when --with-libidn2 is used without an explicit path,
- look for idn2_to_ascii_lz() rather than idn2_to_ascii_8z() as the
former is used in BIND while the latter is not,
- do not look for idn2_to_unicode_8zlz() as it is present in all
libidn2 versions which have idn2_to_ascii_lz(),
- check whether the <idn2.h> header is usable,
- set LDFLAGS in the Makefile for dig so that, if specified, the
requested libidn2 path is used when linking with libidn2,
- override CPPFLAGS when looking for libidn2 components so that the
configure script does not produce warnings when libidn2 is not
installed system-wide,
- merge the AS_CASE() call into the AS_IF() call below it to simplify
code,
- indicate the default value of --with-libidn2 in "./configure --help"
output,
- use $with_libidn2 rather than $use_libidn2 to better match the name
of the configure script argument,
- stop differentiating between IDN "in" and "out" support, i.e. make
dig either support libidn2 or not; remove WITH_* Autoconf macros and
use a new one, HAVE_LIBIDN2, to determine whether libidn2 support
should be enabled.
2018-07-10 14:34:35 +02:00
|
|
|
#endif /* HAVE_LIBIDN2 */
|
2005-09-09 06:17:03 +00:00
|
|
|
|
2000-07-24 18:07:03 +00:00
|
|
|
/*
|
2000-08-01 00:53:20 +00:00
|
|
|
* If the name has too many dots, force the origin to be NULL
|
|
|
|
* (which produces an absolute lookup). Otherwise, take the origin
|
2000-07-24 18:07:03 +00:00
|
|
|
* we have if there's one in the struct already. If it's NULL,
|
|
|
|
* take the first entry in the searchlist iff either usesearch
|
|
|
|
* is TRUE or we got a domain line in the resolv.conf file.
|
|
|
|
*/
|
2006-12-07 05:52:16 +00:00
|
|
|
if (lookup->new_search) {
|
2020-02-12 13:59:18 +01:00
|
|
|
if ((count_dots(textname) >= ndots) || !usesearch) {
|
2006-12-07 05:52:16 +00:00
|
|
|
lookup->origin = NULL; /* Force abs lookup */
|
2018-04-17 08:29:14 -07:00
|
|
|
lookup->done_as_is = true;
|
2006-12-07 05:52:16 +00:00
|
|
|
lookup->need_search = usesearch;
|
|
|
|
} else if (lookup->origin == NULL && usesearch) {
|
|
|
|
lookup->origin = ISC_LIST_HEAD(search_list);
|
2018-04-17 08:29:14 -07:00
|
|
|
lookup->need_search = false;
|
2006-12-07 05:52:16 +00:00
|
|
|
}
|
|
|
|
}
|
2005-08-25 00:56:08 +00:00
|
|
|
|
2000-05-02 23:23:12 +00:00
|
|
|
if (lookup->origin != NULL) {
|
2000-07-05 23:28:32 +00:00
|
|
|
debug("trying origin %s", lookup->origin->origin);
|
2022-05-16 13:28:13 +02:00
|
|
|
dns_message_gettempname(lookup->sendmsg, &lookup->oname);
|
2000-08-01 00:53:20 +00:00
|
|
|
/* XXX Helper funct to conv char* to name? */
|
2017-08-15 14:36:59 +02:00
|
|
|
origin = lookup->origin->origin;
|
Rework libidn2 detection
Clean up the parts of configure.in responsible for handling libidn2
detection and adjust other pieces of the build system to match these
cleanups:
- use pkg-config when --with-libidn2 is used without an explicit path,
- look for idn2_to_ascii_lz() rather than idn2_to_ascii_8z() as the
former is used in BIND while the latter is not,
- do not look for idn2_to_unicode_8zlz() as it is present in all
libidn2 versions which have idn2_to_ascii_lz(),
- check whether the <idn2.h> header is usable,
- set LDFLAGS in the Makefile for dig so that, if specified, the
requested libidn2 path is used when linking with libidn2,
- override CPPFLAGS when looking for libidn2 components so that the
configure script does not produce warnings when libidn2 is not
installed system-wide,
- merge the AS_CASE() call into the AS_IF() call below it to simplify
code,
- indicate the default value of --with-libidn2 in "./configure --help"
output,
- use $with_libidn2 rather than $use_libidn2 to better match the name
of the configure script argument,
- stop differentiating between IDN "in" and "out" support, i.e. make
dig either support libidn2 or not; remove WITH_* Autoconf macros and
use a new one, HAVE_LIBIDN2, to determine whether libidn2 support
should be enabled.
2018-07-10 14:34:35 +02:00
|
|
|
#ifdef HAVE_LIBIDN2
|
2017-08-15 14:36:59 +02:00
|
|
|
if (lookup->idnin) {
|
2018-07-10 14:34:35 +02:00
|
|
|
idn_locale_to_ace(origin, idn_origin,
|
|
|
|
sizeof(idn_origin));
|
2017-08-15 14:36:59 +02:00
|
|
|
debug("trying idn origin %s", idn_origin);
|
|
|
|
origin = idn_origin;
|
|
|
|
}
|
Rework libidn2 detection
Clean up the parts of configure.in responsible for handling libidn2
detection and adjust other pieces of the build system to match these
cleanups:
- use pkg-config when --with-libidn2 is used without an explicit path,
- look for idn2_to_ascii_lz() rather than idn2_to_ascii_8z() as the
former is used in BIND while the latter is not,
- do not look for idn2_to_unicode_8zlz() as it is present in all
libidn2 versions which have idn2_to_ascii_lz(),
- check whether the <idn2.h> header is usable,
- set LDFLAGS in the Makefile for dig so that, if specified, the
requested libidn2 path is used when linking with libidn2,
- override CPPFLAGS when looking for libidn2 components so that the
configure script does not produce warnings when libidn2 is not
installed system-wide,
- merge the AS_CASE() call into the AS_IF() call below it to simplify
code,
- indicate the default value of --with-libidn2 in "./configure --help"
output,
- use $with_libidn2 rather than $use_libidn2 to better match the name
of the configure script argument,
- stop differentiating between IDN "in" and "out" support, i.e. make
dig either support libidn2 or not; remove WITH_* Autoconf macros and
use a new one, HAVE_LIBIDN2, to determine whether libidn2 support
should be enabled.
2018-07-10 14:34:35 +02:00
|
|
|
#endif /* HAVE_LIBIDN2 */
|
2020-02-12 13:59:18 +01:00
|
|
|
len = (unsigned int)strlen(origin);
|
2017-08-15 14:36:59 +02:00
|
|
|
isc_buffer_init(&b, origin, len);
|
2000-05-02 23:23:12 +00:00
|
|
|
isc_buffer_add(&b, len);
|
2020-02-12 13:59:18 +01:00
|
|
|
result = dns_name_fromtext(lookup->oname, &b, dns_rootname, 0,
|
|
|
|
&lookup->onamebuf);
|
2000-05-02 23:23:12 +00:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2020-02-12 13:59:18 +01:00
|
|
|
dns_message_puttempname(lookup->sendmsg, &lookup->name);
|
2000-05-02 23:23:12 +00:00
|
|
|
dns_message_puttempname(lookup->sendmsg,
|
|
|
|
&lookup->oname);
|
2020-02-12 13:59:18 +01:00
|
|
|
fatal("'%s' is not in legal name syntax (%s)", origin,
|
2001-07-27 05:41:46 +00:00
|
|
|
isc_result_totext(result));
|
2000-05-02 23:23:12 +00:00
|
|
|
}
|
2001-07-28 00:11:15 +00:00
|
|
|
if (lookup->trace && lookup->trace_root) {
|
2000-08-01 00:53:20 +00:00
|
|
|
dns_name_clone(dns_rootname, lookup->name);
|
|
|
|
} else {
|
2014-08-21 18:05:55 +10:00
|
|
|
dns_fixedname_t fixed;
|
2020-02-13 14:44:37 -08:00
|
|
|
dns_name_t *name;
|
2014-08-21 18:05:55 +10:00
|
|
|
|
2018-03-28 14:38:09 +02:00
|
|
|
name = dns_fixedname_initname(&fixed);
|
2020-02-12 13:59:18 +01:00
|
|
|
len = (unsigned int)strlen(textname);
|
2017-08-15 14:36:59 +02:00
|
|
|
isc_buffer_init(&b, textname, len);
|
2000-05-06 01:16:07 +00:00
|
|
|
isc_buffer_add(&b, len);
|
2014-08-21 18:05:55 +10:00
|
|
|
result = dns_name_fromtext(name, &b, NULL, 0, NULL);
|
2019-09-27 08:37:26 +02:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
if (!dns_name_isabsolute(name)) {
|
2020-02-12 13:59:18 +01:00
|
|
|
result = dns_name_concatenate(
|
|
|
|
name, lookup->oname,
|
|
|
|
lookup->name, &lookup->namebuf);
|
2019-09-27 08:37:26 +02:00
|
|
|
} else {
|
2021-05-21 17:20:44 -07:00
|
|
|
dns_name_copy(name, lookup->name);
|
2019-09-27 08:37:26 +02:00
|
|
|
}
|
|
|
|
}
|
2014-08-21 18:05:55 +10:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
dns_message_puttempname(lookup->sendmsg,
|
|
|
|
&lookup->name);
|
|
|
|
dns_message_puttempname(lookup->sendmsg,
|
|
|
|
&lookup->oname);
|
2019-09-27 08:37:26 +02:00
|
|
|
if (result == DNS_R_NAMETOOLONG) {
|
2018-04-17 08:29:14 -07:00
|
|
|
return (false);
|
2019-09-27 08:37:26 +02:00
|
|
|
}
|
2014-08-21 18:05:55 +10:00
|
|
|
fatal("'%s' is not in legal name syntax (%s)",
|
|
|
|
lookup->textname,
|
|
|
|
isc_result_totext(result));
|
|
|
|
}
|
2000-05-02 23:23:12 +00:00
|
|
|
}
|
|
|
|
dns_message_puttempname(lookup->sendmsg, &lookup->oname);
|
2017-08-15 14:36:59 +02:00
|
|
|
} else {
|
2000-07-05 23:28:32 +00:00
|
|
|
debug("using root origin");
|
2020-02-13 21:48:23 +01:00
|
|
|
if (lookup->trace && lookup->trace_root) {
|
2001-07-28 00:11:15 +00:00
|
|
|
dns_name_clone(dns_rootname, lookup->name);
|
2020-02-13 21:48:23 +01:00
|
|
|
} else {
|
2020-02-12 13:59:18 +01:00
|
|
|
len = (unsigned int)strlen(textname);
|
2017-08-15 14:36:59 +02:00
|
|
|
isc_buffer_init(&b, textname, len);
|
2000-05-06 01:16:07 +00:00
|
|
|
isc_buffer_add(&b, len);
|
|
|
|
result = dns_name_fromtext(lookup->name, &b,
|
2009-09-01 00:22:28 +00:00
|
|
|
dns_rootname, 0,
|
2000-05-06 01:16:07 +00:00
|
|
|
&lookup->namebuf);
|
2022-05-16 13:28:13 +02:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
dns_message_puttempname(lookup->sendmsg,
|
|
|
|
&lookup->name);
|
|
|
|
warn("'%s' is not a legal name (%s)",
|
|
|
|
lookup->textname,
|
|
|
|
isc_result_totext(result));
|
2017-11-23 16:58:12 +11:00
|
|
|
#if TARGET_OS_IPHONE
|
2022-05-16 13:28:13 +02:00
|
|
|
clear_current_lookup();
|
|
|
|
return (false);
|
2020-02-13 21:48:23 +01:00
|
|
|
#else /* if TARGET_OS_IPHONE */
|
2022-05-16 13:28:13 +02:00
|
|
|
digexit();
|
2020-02-13 21:48:23 +01:00
|
|
|
#endif /* if TARGET_OS_IPHONE */
|
2022-05-16 13:28:13 +02:00
|
|
|
}
|
2000-05-02 23:23:12 +00:00
|
|
|
}
|
2000-08-01 01:33:37 +00:00
|
|
|
}
|
2001-07-27 05:26:38 +00:00
|
|
|
dns_name_format(lookup->name, store, sizeof(store));
|
2017-08-10 22:51:24 -07:00
|
|
|
dighost_trying(store, lookup);
|
2000-08-01 00:53:20 +00:00
|
|
|
INSIST(dns_name_isabsolute(lookup->name));
|
2000-04-26 18:34:17 +00:00
|
|
|
|
2018-05-28 15:22:23 +02:00
|
|
|
lookup->sendmsg->id = (dns_messageid_t)isc_random16();
|
2015-05-19 12:46:06 +10:00
|
|
|
lookup->sendmsg->opcode = lookup->opcode;
|
2000-06-07 00:13:57 +00:00
|
|
|
lookup->msgcounter = 0;
|
2019-05-14 11:38:13 +10:00
|
|
|
|
2000-05-24 03:10:24 +00:00
|
|
|
/*
|
2019-05-14 11:38:13 +10:00
|
|
|
* If this is a trace request, completely disallow recursion after
|
|
|
|
* looking up the root name servers, since it's meaningless for traces.
|
2000-05-24 03:10:24 +00:00
|
|
|
*/
|
2019-05-14 11:38:13 +10:00
|
|
|
if ((lookup->trace || lookup->ns_search_only) && !lookup->trace_root) {
|
2018-04-17 08:29:14 -07:00
|
|
|
lookup->recurse = false;
|
2019-05-14 11:38:13 +10:00
|
|
|
}
|
2001-07-28 00:11:15 +00:00
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
if (lookup->recurse && lookup->rdtype != dns_rdatatype_axfr &&
|
2020-02-13 14:44:37 -08:00
|
|
|
lookup->rdtype != dns_rdatatype_ixfr)
|
|
|
|
{
|
2000-07-05 23:28:32 +00:00
|
|
|
debug("recursive query");
|
2000-04-26 18:34:17 +00:00
|
|
|
lookup->sendmsg->flags |= DNS_MESSAGEFLAG_RD;
|
2000-05-03 20:27:13 +00:00
|
|
|
}
|
2000-04-26 18:34:17 +00:00
|
|
|
|
2000-08-01 00:53:20 +00:00
|
|
|
/* XXX aaflag */
|
2000-07-13 21:12:21 +00:00
|
|
|
if (lookup->aaonly) {
|
|
|
|
debug("AA query");
|
|
|
|
lookup->sendmsg->flags |= DNS_MESSAGEFLAG_AA;
|
|
|
|
}
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2000-06-16 18:00:05 +00:00
|
|
|
if (lookup->adflag) {
|
2000-07-05 19:31:26 +00:00
|
|
|
debug("AD query");
|
2000-06-16 18:00:05 +00:00
|
|
|
lookup->sendmsg->flags |= DNS_MESSAGEFLAG_AD;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lookup->cdflag) {
|
2000-07-05 19:31:26 +00:00
|
|
|
debug("CD query");
|
2000-06-16 18:00:05 +00:00
|
|
|
lookup->sendmsg->flags |= DNS_MESSAGEFLAG_CD;
|
|
|
|
}
|
2014-10-31 10:16:00 +11:00
|
|
|
|
2018-04-18 09:18:41 +10:00
|
|
|
if (lookup->raflag) {
|
|
|
|
debug("RA query");
|
|
|
|
lookup->sendmsg->flags |= DNS_MESSAGEFLAG_RA;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lookup->tcflag) {
|
|
|
|
debug("TC query");
|
|
|
|
lookup->sendmsg->flags |= DNS_MESSAGEFLAG_TC;
|
|
|
|
}
|
|
|
|
|
2014-10-31 10:16:00 +11:00
|
|
|
if (lookup->zflag) {
|
|
|
|
debug("Z query");
|
|
|
|
lookup->sendmsg->flags |= 0x0040U;
|
|
|
|
}
|
2000-06-16 18:00:05 +00:00
|
|
|
|
2020-05-08 12:39:16 -07:00
|
|
|
if (lookup->setqid) {
|
|
|
|
debug("set QID");
|
|
|
|
lookup->sendmsg->id = lookup->qid;
|
|
|
|
}
|
|
|
|
|
2000-04-26 18:34:17 +00:00
|
|
|
dns_message_addname(lookup->sendmsg, lookup->name,
|
|
|
|
DNS_SECTION_QUESTION);
|
2000-06-02 18:45:33 +00:00
|
|
|
|
2001-07-28 00:11:15 +00:00
|
|
|
if (lookup->trace && lookup->trace_root) {
|
|
|
|
lookup->qrdtype = lookup->rdtype;
|
|
|
|
lookup->rdtype = dns_rdatatype_ns;
|
|
|
|
}
|
2000-08-01 00:53:20 +00:00
|
|
|
|
2000-07-18 01:28:20 +00:00
|
|
|
if ((lookup->rdtype == dns_rdatatype_axfr) ||
|
2020-02-13 14:44:37 -08:00
|
|
|
(lookup->rdtype == dns_rdatatype_ixfr))
|
|
|
|
{
|
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
|
|
|
/*
|
2007-12-03 00:21:48 +00:00
|
|
|
* Force TCP mode if we're doing an axfr.
|
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
|
|
|
*/
|
2007-12-03 00:21:48 +00:00
|
|
|
if (lookup->rdtype == dns_rdatatype_axfr) {
|
2018-04-17 08:29:14 -07:00
|
|
|
lookup->doing_xfr = true;
|
|
|
|
lookup->tcp_mode = true;
|
2007-12-03 00:21:48 +00:00
|
|
|
} else if (lookup->tcp_mode) {
|
2018-04-17 08:29:14 -07:00
|
|
|
lookup->doing_xfr = true;
|
2007-12-03 00:21:48 +00:00
|
|
|
}
|
2000-04-26 18:34:17 +00:00
|
|
|
}
|
2000-12-08 17:06:52 +00:00
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (!lookup->header_only) {
|
2014-10-30 11:42:02 +11:00
|
|
|
add_question(lookup->sendmsg, lookup->name, lookup->rdclass,
|
|
|
|
lookup->rdtype);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2000-04-26 18:34:17 +00:00
|
|
|
|
2001-07-28 00:11:15 +00:00
|
|
|
/* add_soa */
|
2020-02-13 21:48:23 +01:00
|
|
|
if (lookup->rdtype == dns_rdatatype_ixfr) {
|
2000-06-02 18:45:33 +00:00
|
|
|
insert_soa(lookup);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2000-06-02 18:45:33 +00:00
|
|
|
|
2000-08-01 00:53:20 +00:00
|
|
|
/* XXX Insist this? */
|
|
|
|
lookup->tsigctx = NULL;
|
|
|
|
lookup->querysig = NULL;
|
2018-03-19 22:16:10 +00:00
|
|
|
if (tsigkey != NULL) {
|
2000-07-05 23:28:32 +00:00
|
|
|
debug("initializing keys");
|
2018-03-19 22:16:10 +00:00
|
|
|
result = dns_message_settsigkey(lookup->sendmsg, tsigkey);
|
2000-06-06 00:43:17 +00:00
|
|
|
check_result(result, "dns_message_settsigkey");
|
|
|
|
}
|
|
|
|
|
2021-05-12 21:16:17 +02:00
|
|
|
lookup->sendspace = isc_mem_get(mctx, COMMSIZE);
|
2000-07-13 01:22:38 +00:00
|
|
|
|
2022-05-04 17:35:39 +01:00
|
|
|
result = dns_compress_init(&cctx, mctx);
|
2001-03-05 21:15:47 +00:00
|
|
|
check_result(result, "dns_compress_init");
|
|
|
|
|
2000-07-05 23:28:32 +00:00
|
|
|
debug("starting to render the message");
|
2006-12-07 01:21:04 +00:00
|
|
|
isc_buffer_init(&lookup->renderbuf, lookup->sendspace, COMMSIZE);
|
2001-03-05 21:15:47 +00:00
|
|
|
result = dns_message_renderbegin(lookup->sendmsg, &cctx,
|
2006-12-07 01:21:04 +00:00
|
|
|
&lookup->renderbuf);
|
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
|
|
|
check_result(result, "dns_message_renderbegin");
|
2020-07-29 12:34:54 +10:00
|
|
|
if (lookup->udpsize > -1 || lookup->dnssec || lookup->edns > -1 ||
|
2020-02-13 14:44:37 -08:00
|
|
|
lookup->ecs_addr != NULL)
|
|
|
|
{
|
2017-01-04 09:16:30 -08:00
|
|
|
#define MAXOPTS (EDNSOPT_OPTIONS + DNS_EDNSOPTIONS)
|
|
|
|
dns_ednsopt_t opts[MAXOPTS];
|
2020-02-13 14:44:37 -08:00
|
|
|
unsigned int flags;
|
|
|
|
unsigned int i = 0;
|
2014-02-19 15:51:02 -08:00
|
|
|
|
2017-01-04 09:16:30 -08:00
|
|
|
/*
|
|
|
|
* There can't be more than MAXOPTS options to send:
|
|
|
|
* a maximum of EDNSOPT_OPTIONS set by +ednsopt
|
|
|
|
* and DNS_EDNSOPTIONS set by other arguments
|
|
|
|
* (+nsid, +cookie, etc).
|
|
|
|
*/
|
2020-07-29 12:34:54 +10:00
|
|
|
if (lookup->udpsize < 0) {
|
|
|
|
lookup->udpsize = DEFAULT_EDNS_BUFSIZE;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if (lookup->edns < 0) {
|
2020-07-29 12:34:54 +10:00
|
|
|
lookup->edns = DEFAULT_EDNS_VERSION;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2014-02-19 15:51:02 -08:00
|
|
|
|
2014-02-19 12:53:42 +11:00
|
|
|
if (lookup->nsid) {
|
2017-01-04 09:16:30 -08:00
|
|
|
INSIST(i < MAXOPTS);
|
2014-02-19 12:53:42 +11:00
|
|
|
opts[i].code = DNS_OPT_NSID;
|
|
|
|
opts[i].length = 0;
|
|
|
|
opts[i].value = NULL;
|
|
|
|
i++;
|
|
|
|
}
|
2014-02-19 15:51:02 -08:00
|
|
|
|
|
|
|
if (lookup->ecs_addr != NULL) {
|
2020-02-13 14:44:37 -08:00
|
|
|
uint8_t addr[16];
|
|
|
|
uint16_t family = 0;
|
|
|
|
uint32_t plen;
|
|
|
|
struct sockaddr *sa;
|
|
|
|
struct sockaddr_in *sin;
|
2014-02-19 15:51:02 -08:00
|
|
|
struct sockaddr_in6 *sin6;
|
2020-02-13 14:44:37 -08:00
|
|
|
size_t addrl;
|
2014-02-19 15:51:02 -08:00
|
|
|
|
|
|
|
sa = &lookup->ecs_addr->type.sa;
|
2016-01-29 17:41:29 -08:00
|
|
|
plen = lookup->ecs_addr->length;
|
2014-02-19 15:51:02 -08:00
|
|
|
|
|
|
|
/* Round up prefix len to a multiple of 8 */
|
2016-01-29 17:41:29 -08:00
|
|
|
addrl = (plen + 7) / 8;
|
2014-02-19 15:51:02 -08:00
|
|
|
|
2017-01-04 09:16:30 -08:00
|
|
|
INSIST(i < MAXOPTS);
|
2014-02-19 15:51:02 -08:00
|
|
|
opts[i].code = DNS_OPT_CLIENT_SUBNET;
|
2020-02-12 13:59:18 +01:00
|
|
|
opts[i].length = (uint16_t)addrl + 4;
|
2014-02-19 15:51:02 -08:00
|
|
|
check_result(result, "isc_buffer_allocate");
|
2016-03-23 15:00:30 -07:00
|
|
|
|
2016-09-14 08:22:15 +10:00
|
|
|
/*
|
|
|
|
* XXXMUKS: According to RFC7871, "If there is
|
|
|
|
* no ADDRESS set, i.e., SOURCE PREFIX-LENGTH is
|
|
|
|
* set to 0, then FAMILY SHOULD be set to the
|
|
|
|
* transport over which the query is sent."
|
|
|
|
*
|
|
|
|
* However, at this point we don't know what
|
|
|
|
* transport(s) we'll be using, so we can't
|
|
|
|
* set the value now. For now, we're using
|
|
|
|
* IPv4 as the default the +subnet option
|
|
|
|
* used an IPv4 prefix, or for +subnet=0,
|
|
|
|
* and IPv6 if the +subnet option used an
|
|
|
|
* IPv6 prefix.
|
|
|
|
*
|
|
|
|
* (For future work: preserve the offset into
|
|
|
|
* the buffer where the family field is;
|
2020-09-05 16:37:24 -07:00
|
|
|
* that way we can update it in start_udp()
|
|
|
|
* or start_tcp() once we know
|
2016-09-14 08:22:15 +10:00
|
|
|
* what it outght to be.)
|
|
|
|
*/
|
|
|
|
switch (sa->sa_family) {
|
2016-03-23 09:29:57 -07:00
|
|
|
case AF_UNSPEC:
|
|
|
|
INSIST(plen == 0);
|
2016-09-14 08:22:15 +10:00
|
|
|
family = 1;
|
2016-03-23 09:29:57 -07:00
|
|
|
break;
|
|
|
|
case AF_INET:
|
2016-09-14 08:22:15 +10:00
|
|
|
INSIST(plen <= 32);
|
2016-01-29 17:41:29 -08:00
|
|
|
family = 1;
|
2020-02-12 13:59:18 +01:00
|
|
|
sin = (struct sockaddr_in *)sa;
|
2016-09-14 08:22:15 +10:00
|
|
|
memmove(addr, &sin->sin_addr, addrl);
|
2016-03-23 09:29:57 -07:00
|
|
|
break;
|
|
|
|
case AF_INET6:
|
2016-09-14 08:22:15 +10:00
|
|
|
INSIST(plen <= 128);
|
2016-01-29 17:41:29 -08:00
|
|
|
family = 2;
|
2020-02-12 13:59:18 +01:00
|
|
|
sin6 = (struct sockaddr_in6 *)sa;
|
2016-09-14 08:22:15 +10:00
|
|
|
memmove(addr, &sin6->sin6_addr, addrl);
|
2016-03-23 09:29:57 -07:00
|
|
|
break;
|
|
|
|
default:
|
2021-10-11 12:50:17 +02:00
|
|
|
UNREACHABLE();
|
2014-02-19 15:51:02 -08:00
|
|
|
}
|
|
|
|
|
2016-09-14 08:22:15 +10:00
|
|
|
isc_buffer_init(&b, ecsbuf, sizeof(ecsbuf));
|
2016-01-29 17:41:29 -08:00
|
|
|
/* family */
|
|
|
|
isc_buffer_putuint16(&b, family);
|
|
|
|
/* source prefix-length */
|
|
|
|
isc_buffer_putuint8(&b, plen);
|
|
|
|
/* scope prefix-length */
|
|
|
|
isc_buffer_putuint8(&b, 0);
|
2016-09-14 08:22:15 +10:00
|
|
|
|
2016-01-29 17:41:29 -08:00
|
|
|
/* address */
|
2016-09-14 08:22:15 +10:00
|
|
|
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(&b, addr, (unsigned)addrl);
|
2016-09-14 08:22:15 +10:00
|
|
|
}
|
2016-01-29 17:41:29 -08:00
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
opts[i].value = (uint8_t *)ecsbuf;
|
2014-02-19 15:51:02 -08:00
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
2015-07-06 09:44:24 +10:00
|
|
|
if (lookup->sendcookie) {
|
2017-01-04 09:16:30 -08:00
|
|
|
INSIST(i < MAXOPTS);
|
2015-07-06 09:44:24 +10:00
|
|
|
opts[i].code = DNS_OPT_COOKIE;
|
|
|
|
if (lookup->cookie != NULL) {
|
|
|
|
isc_buffer_init(&b, cookiebuf,
|
|
|
|
sizeof(cookiebuf));
|
|
|
|
result = isc_hex_decodestring(lookup->cookie,
|
2014-02-19 12:53:42 +11:00
|
|
|
&b);
|
|
|
|
check_result(result, "isc_hex_decodestring");
|
|
|
|
opts[i].value = isc_buffer_base(&b);
|
|
|
|
opts[i].length = isc_buffer_usedlength(&b);
|
|
|
|
} else {
|
|
|
|
compute_cookie(cookie, sizeof(cookie));
|
|
|
|
opts[i].length = 8;
|
|
|
|
opts[i].value = cookie;
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
2014-02-19 15:51:02 -08:00
|
|
|
|
2014-02-20 14:56:20 +11:00
|
|
|
if (lookup->expire) {
|
2017-01-04 09:16:30 -08:00
|
|
|
INSIST(i < MAXOPTS);
|
2014-02-20 14:56:20 +11:00
|
|
|
opts[i].code = DNS_OPT_EXPIRE;
|
|
|
|
opts[i].length = 0;
|
|
|
|
opts[i].value = NULL;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
2017-01-04 09:16:30 -08:00
|
|
|
if (lookup->tcp_keepalive) {
|
|
|
|
INSIST(i < MAXOPTS);
|
|
|
|
opts[i].code = DNS_OPT_TCP_KEEPALIVE;
|
|
|
|
opts[i].length = 0;
|
|
|
|
opts[i].value = NULL;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
2014-04-18 09:52:12 +10:00
|
|
|
if (lookup->ednsoptscnt != 0) {
|
2017-01-04 09:16:30 -08:00
|
|
|
INSIST(i + lookup->ednsoptscnt <= MAXOPTS);
|
2014-04-18 09:52:12 +10:00
|
|
|
memmove(&opts[i], lookup->ednsopts,
|
2014-04-22 23:45:19 +00:00
|
|
|
sizeof(dns_ednsopt_t) * lookup->ednsoptscnt);
|
2014-04-18 09:52:12 +10:00
|
|
|
i += lookup->ednsoptscnt;
|
|
|
|
}
|
|
|
|
|
2017-01-19 23:52:41 -08:00
|
|
|
if (lookup->padding != 0 && (i >= MAXOPTS)) {
|
2017-01-04 09:16:30 -08:00
|
|
|
debug("turned off padding because of EDNS overflow");
|
|
|
|
lookup->padding = 0;
|
|
|
|
}
|
|
|
|
|
2017-01-19 23:52:41 -08:00
|
|
|
if (lookup->padding != 0) {
|
2017-01-04 09:16:30 -08:00
|
|
|
INSIST(i < MAXOPTS);
|
|
|
|
opts[i].code = DNS_OPT_PAD;
|
|
|
|
opts[i].length = 0;
|
|
|
|
opts[i].value = NULL;
|
|
|
|
i++;
|
|
|
|
dns_message_setpadding(lookup->sendmsg,
|
|
|
|
lookup->padding);
|
|
|
|
}
|
|
|
|
|
2014-09-13 19:13:59 +10:00
|
|
|
flags = lookup->ednsflags;
|
|
|
|
flags &= ~DNS_MESSAGEEXTFLAG_DO;
|
2020-02-13 21:48:23 +01:00
|
|
|
if (lookup->dnssec) {
|
2014-09-13 19:13:59 +10:00
|
|
|
flags |= DNS_MESSAGEEXTFLAG_DO;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2020-02-12 13:59:18 +01:00
|
|
|
add_opt(lookup->sendmsg, lookup->udpsize, lookup->edns, flags,
|
|
|
|
opts, i);
|
2000-10-11 17:44:18 +00:00
|
|
|
}
|
2000-08-01 00:53:20 +00:00
|
|
|
|
2000-04-26 18:34:17 +00:00
|
|
|
result = dns_message_rendersection(lookup->sendmsg,
|
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
|
|
|
DNS_SECTION_QUESTION, 0);
|
|
|
|
check_result(result, "dns_message_rendersection");
|
2000-06-02 18:45:33 +00:00
|
|
|
result = dns_message_rendersection(lookup->sendmsg,
|
|
|
|
DNS_SECTION_AUTHORITY, 0);
|
|
|
|
check_result(result, "dns_message_rendersection");
|
2000-04-26 18:34:17 +00:00
|
|
|
result = dns_message_renderend(lookup->sendmsg);
|
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
|
|
|
check_result(result, "dns_message_renderend");
|
2000-07-05 23:28:32 +00:00
|
|
|
debug("done rendering");
|
2000-04-26 18:34:17 +00:00
|
|
|
|
2001-03-05 21:15:47 +00:00
|
|
|
dns_compress_invalidate(&cctx);
|
|
|
|
|
2001-01-08 20:50:04 +00:00
|
|
|
/*
|
|
|
|
* Force TCP mode if the request is larger than 512 bytes.
|
|
|
|
*/
|
2020-02-13 21:48:23 +01:00
|
|
|
if (isc_buffer_usedlength(&lookup->renderbuf) > 512) {
|
2018-04-17 08:29:14 -07:00
|
|
|
lookup->tcp_mode = true;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-01-08 20:50:04 +00:00
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
lookup->pending = false;
|
2000-04-26 18:34:17 +00:00
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
for (serv = ISC_LIST_HEAD(lookup->my_server_list); serv != NULL;
|
2020-02-13 14:44:37 -08:00
|
|
|
serv = ISC_LIST_NEXT(serv, link))
|
|
|
|
{
|
2020-09-05 16:37:24 -07:00
|
|
|
query = new_query(lookup, serv->servername, serv->userarg);
|
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_LIST_ENQUEUE(lookup->q, query, link);
|
2000-04-26 18:34:17 +00:00
|
|
|
}
|
2014-02-19 15:51:02 -08:00
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
return (true);
|
2000-08-01 00:53:20 +00:00
|
|
|
}
|
2000-04-26 18:34:17 +00:00
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
2000-07-18 18:51:40 +00:00
|
|
|
* Event handler for send completion. Track send counter, and clear out
|
|
|
|
* the query if the send was canceled.
|
|
|
|
*/
|
2000-04-26 18:34:17 +00:00
|
|
|
static void
|
2020-09-05 16:37:24 -07:00
|
|
|
send_done(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) {
|
|
|
|
dig_query_t *query = (dig_query_t *)arg;
|
|
|
|
dig_query_t *next = NULL;
|
|
|
|
dig_lookup_t *l = NULL;
|
2006-06-06 00:53:36 +00:00
|
|
|
|
2020-09-05 16:37:24 -07:00
|
|
|
REQUIRE(DIG_VALID_QUERY(query));
|
2020-11-04 12:40:13 +01:00
|
|
|
INSIST(query->sendhandle != NULL);
|
|
|
|
INSIST(handle == query->sendhandle);
|
2000-07-13 22:53:51 +00:00
|
|
|
|
2020-11-06 16:12:17 +01:00
|
|
|
debug("send_done(%p, %s, %p)", handle, isc_result_totext(eresult), arg);
|
2020-11-04 12:40:13 +01:00
|
|
|
|
2020-09-05 16:37:24 -07:00
|
|
|
isc_refcount_decrement0(&sendcount);
|
|
|
|
debug("sendcount=%" PRIuFAST32, isc_refcount_current(&sendcount));
|
2000-05-26 00:48:18 +00:00
|
|
|
|
2020-09-05 16:37:24 -07:00
|
|
|
INSIST(!free_now);
|
|
|
|
|
2020-11-05 15:22:38 +01:00
|
|
|
LOCK_LOOKUP;
|
|
|
|
|
|
|
|
isc_nmhandle_detach(&query->sendhandle);
|
|
|
|
|
Fix query context management issues in dighost.c
For the reference, the _cancel_lookup() function iterates through
the lookup's queries list and detaches them. In the ideal scenario,
that should be the last reference and the query will be destroyed
after that, but it is also possible that we are still expecting a
callback, which also holds a reference (for example, _cancel_lookup()
could have been called from recv_done(), when send_done() was still
not executed).
The start_udp() and start_tcp() functions are currently designed in
slightly different ways: start_udp() creates a new query attachment
`connectquery`, to be called in the callback function, while
start_tcp() does not, which is a bug, but is hidden by the fact
that when the query is being erroneously destroyed prematurely (before
_cancel_lookup() is called) in the result of that, it also gets
de-listed from the lookup's queries' list, so _cancel_lookup() doesn't
even try to detach it.
For better understanding, here's an illustration of the query's
references count changes, and from where it was changed:
UDP
---
1. _new_query() -> refcount = 1 (initial)
2. start_udp() -> refcount = 2 (lookup->current_query)
3. start_udp() -> refcount = 3 (connectquery)
4. udp_ready() -> refcount = 4 (readquery)
5. udp_ready() -> refcount = 5 (sendquery)
6. udp_ready() -> refcount = 4 (lookup->current_query)
7. udp_ready() -> refcount = 3 (connectquery)
8. send_done() -> refcount = 2 (sendquery)
9. recv_done() -> refcount = 1 (readquery)
10. _cancel_lookup() -> refcount = 0 (initial)
11. the query gets destroyed and removed from `lookup->q`
TCP, fortunate scenario
-----------------------
1. _new_query() -> refcount = 1 (initial)
2. start_tcp() -> refcount = 2 (lookup->current_query)
3. launch_next_query() -> refcount = 3 (readquery)
4. launch_next_query() -> refcount = 4 (sendquery)
5. tcp_connected() -> refcount = 3 (lookup->current_query)
6. tcp_connected() -> refcount = 2 (bug, there was no connectquery)
7. send_done() -> refcount = 1 (sendquery)
8. recv_done() -> refcount = 0 (readquery)
9. the query gets prematurely destroyed and removed from `lookup->q`
10. _cancel_lookup() -> the query is not in `lookup->q`
TCP, unfortunate scenario, revealing the bug
--------------------------------------------
1. _new_query() -> refcount = 1 (initial)
2. start_tcp() -> refcount = 2 (lookup->current_query)
3. launch_next_query() -> refcount = 3 (readquery)
4. launch_next_query() -> refcount = 4 (sendquery)
5. tcp_connected() -> refcount = 3 (lookup->current_query)
6. tcp_connected() -> refcount = 2 (bug, there was no connectquery)
7. recv_done() -> refcount = 1 (readquery)
8. _cancel_lookup() -> refcount = 0 (the query was in `lookup->q`)
9. we hit an assertion here when trying to destroy the query, because
sendhandle is not detached (which is done by send_done()).
10. send_done() -> this never happens
This commit does the following:
1. Add a `connectquery` attachment in start_tcp(), like done in
start_udp().
2. Add missing _cancel_lookup() calls for error scenarios, which
were possibly missing because before fixing the bug, calling
_cancel_lookup() and then calling query_detach() would cause
an assertion.
3. Log a debug message and call isc_nm_cancelread(query->readhandle)
for every query in the lookup from inside the _cancel_lookup()
function, like it is done in _cancel_all().
4. Add a `canceled` property for the query which becomes `true` when
the lookup (and subsequently, its queries) are canceled.
5. Use the `canceled` property in the network manager callbacks to
know that the query was canceled, and act like `eresult` was equal
to `ISC_R_CANCELED`.
2022-03-02 00:06:34 +00:00
|
|
|
lookup_attach(query->lookup, &l);
|
|
|
|
|
|
|
|
if (eresult == ISC_R_CANCELED || query->canceled) {
|
|
|
|
debug("send_done: cancel");
|
|
|
|
if (!query->canceled) {
|
|
|
|
cancel_lookup(l);
|
2020-09-05 16:37:24 -07:00
|
|
|
}
|
2020-11-05 15:22:38 +01:00
|
|
|
query_detach(&query);
|
Fix query context management issues in dighost.c
For the reference, the _cancel_lookup() function iterates through
the lookup's queries list and detaches them. In the ideal scenario,
that should be the last reference and the query will be destroyed
after that, but it is also possible that we are still expecting a
callback, which also holds a reference (for example, _cancel_lookup()
could have been called from recv_done(), when send_done() was still
not executed).
The start_udp() and start_tcp() functions are currently designed in
slightly different ways: start_udp() creates a new query attachment
`connectquery`, to be called in the callback function, while
start_tcp() does not, which is a bug, but is hidden by the fact
that when the query is being erroneously destroyed prematurely (before
_cancel_lookup() is called) in the result of that, it also gets
de-listed from the lookup's queries' list, so _cancel_lookup() doesn't
even try to detach it.
For better understanding, here's an illustration of the query's
references count changes, and from where it was changed:
UDP
---
1. _new_query() -> refcount = 1 (initial)
2. start_udp() -> refcount = 2 (lookup->current_query)
3. start_udp() -> refcount = 3 (connectquery)
4. udp_ready() -> refcount = 4 (readquery)
5. udp_ready() -> refcount = 5 (sendquery)
6. udp_ready() -> refcount = 4 (lookup->current_query)
7. udp_ready() -> refcount = 3 (connectquery)
8. send_done() -> refcount = 2 (sendquery)
9. recv_done() -> refcount = 1 (readquery)
10. _cancel_lookup() -> refcount = 0 (initial)
11. the query gets destroyed and removed from `lookup->q`
TCP, fortunate scenario
-----------------------
1. _new_query() -> refcount = 1 (initial)
2. start_tcp() -> refcount = 2 (lookup->current_query)
3. launch_next_query() -> refcount = 3 (readquery)
4. launch_next_query() -> refcount = 4 (sendquery)
5. tcp_connected() -> refcount = 3 (lookup->current_query)
6. tcp_connected() -> refcount = 2 (bug, there was no connectquery)
7. send_done() -> refcount = 1 (sendquery)
8. recv_done() -> refcount = 0 (readquery)
9. the query gets prematurely destroyed and removed from `lookup->q`
10. _cancel_lookup() -> the query is not in `lookup->q`
TCP, unfortunate scenario, revealing the bug
--------------------------------------------
1. _new_query() -> refcount = 1 (initial)
2. start_tcp() -> refcount = 2 (lookup->current_query)
3. launch_next_query() -> refcount = 3 (readquery)
4. launch_next_query() -> refcount = 4 (sendquery)
5. tcp_connected() -> refcount = 3 (lookup->current_query)
6. tcp_connected() -> refcount = 2 (bug, there was no connectquery)
7. recv_done() -> refcount = 1 (readquery)
8. _cancel_lookup() -> refcount = 0 (the query was in `lookup->q`)
9. we hit an assertion here when trying to destroy the query, because
sendhandle is not detached (which is done by send_done()).
10. send_done() -> this never happens
This commit does the following:
1. Add a `connectquery` attachment in start_tcp(), like done in
start_udp().
2. Add missing _cancel_lookup() calls for error scenarios, which
were possibly missing because before fixing the bug, calling
_cancel_lookup() and then calling query_detach() would cause
an assertion.
3. Log a debug message and call isc_nm_cancelread(query->readhandle)
for every query in the lookup from inside the _cancel_lookup()
function, like it is done in _cancel_all().
4. Add a `canceled` property for the query which becomes `true` when
the lookup (and subsequently, its queries) are canceled.
5. Use the `canceled` property in the network manager callbacks to
know that the query was canceled, and act like `eresult` was equal
to `ISC_R_CANCELED`.
2022-03-02 00:06:34 +00:00
|
|
|
lookup_detach(&l);
|
|
|
|
UNLOCK_LOOKUP;
|
|
|
|
return;
|
|
|
|
} else if (eresult != ISC_R_SUCCESS) {
|
|
|
|
debug("send failed: %s", isc_result_totext(eresult));
|
|
|
|
cancel_lookup(l);
|
|
|
|
query_detach(&query);
|
|
|
|
lookup_detach(&l);
|
2020-11-05 15:22:38 +01:00
|
|
|
UNLOCK_LOOKUP;
|
|
|
|
return;
|
|
|
|
}
|
2006-08-01 00:49:02 +00:00
|
|
|
|
2022-04-07 09:23:49 +00:00
|
|
|
if (l->ns_search_only && !l->trace_root) {
|
|
|
|
bool tcp_mode = l->tcp_mode;
|
|
|
|
|
2006-08-01 00:49:02 +00:00
|
|
|
debug("sending next, since searching");
|
|
|
|
next = ISC_LIST_NEXT(query, link);
|
2020-11-05 15:22:38 +01:00
|
|
|
|
|
|
|
query_detach(&query);
|
|
|
|
lookup_detach(&l);
|
|
|
|
|
|
|
|
if (next == NULL) {
|
2020-11-06 16:12:17 +01:00
|
|
|
clear_current_lookup();
|
2020-11-05 15:22:38 +01:00
|
|
|
} else {
|
2022-04-07 09:23:49 +00:00
|
|
|
if (tcp_mode) {
|
|
|
|
start_tcp(next);
|
|
|
|
} else {
|
|
|
|
start_udp(next);
|
|
|
|
}
|
2018-11-07 13:04:13 -05:00
|
|
|
}
|
2006-08-01 00:49:02 +00:00
|
|
|
|
2020-11-05 15:22:38 +01:00
|
|
|
check_if_done();
|
|
|
|
UNLOCK_LOOKUP;
|
|
|
|
return;
|
|
|
|
}
|
2020-11-04 12:40:13 +01:00
|
|
|
|
|
|
|
query_detach(&query);
|
2020-11-05 15:22:38 +01:00
|
|
|
lookup_detach(&l);
|
2006-10-02 03:08:34 +00:00
|
|
|
|
2020-11-04 12:40:13 +01:00
|
|
|
check_if_done();
|
2000-07-14 17:57:27 +00:00
|
|
|
UNLOCK_LOOKUP;
|
2000-04-26 18:34:17 +00:00
|
|
|
}
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
2020-09-05 16:37:24 -07:00
|
|
|
* Cancel a lookup, sending canceling reads on all existing sockets.
|
2000-07-18 18:51:40 +00:00
|
|
|
*/
|
2021-04-27 12:03:20 +02:00
|
|
|
|
2000-09-26 17:21:25 +00:00
|
|
|
static void
|
2021-04-27 12:03:20 +02:00
|
|
|
_cancel_lookup(dig_lookup_t *lookup, const char *file, unsigned int line) {
|
2000-09-21 22:46:39 +00:00
|
|
|
dig_query_t *query, *next;
|
2000-04-26 18:34:17 +00:00
|
|
|
|
2021-04-27 12:03:20 +02:00
|
|
|
debug("%s:%u:%s()", file, line, __func__);
|
2000-09-21 22:46:39 +00:00
|
|
|
query = ISC_LIST_HEAD(lookup->q);
|
|
|
|
while (query != NULL) {
|
2018-11-07 13:04:13 -05:00
|
|
|
REQUIRE(DIG_VALID_QUERY(query));
|
2000-09-21 22:46:39 +00:00
|
|
|
next = ISC_LIST_NEXT(query, link);
|
2020-11-04 12:40:13 +01:00
|
|
|
ISC_LIST_DEQUEUE(lookup->q, query, link);
|
Fix query context management issues in dighost.c
For the reference, the _cancel_lookup() function iterates through
the lookup's queries list and detaches them. In the ideal scenario,
that should be the last reference and the query will be destroyed
after that, but it is also possible that we are still expecting a
callback, which also holds a reference (for example, _cancel_lookup()
could have been called from recv_done(), when send_done() was still
not executed).
The start_udp() and start_tcp() functions are currently designed in
slightly different ways: start_udp() creates a new query attachment
`connectquery`, to be called in the callback function, while
start_tcp() does not, which is a bug, but is hidden by the fact
that when the query is being erroneously destroyed prematurely (before
_cancel_lookup() is called) in the result of that, it also gets
de-listed from the lookup's queries' list, so _cancel_lookup() doesn't
even try to detach it.
For better understanding, here's an illustration of the query's
references count changes, and from where it was changed:
UDP
---
1. _new_query() -> refcount = 1 (initial)
2. start_udp() -> refcount = 2 (lookup->current_query)
3. start_udp() -> refcount = 3 (connectquery)
4. udp_ready() -> refcount = 4 (readquery)
5. udp_ready() -> refcount = 5 (sendquery)
6. udp_ready() -> refcount = 4 (lookup->current_query)
7. udp_ready() -> refcount = 3 (connectquery)
8. send_done() -> refcount = 2 (sendquery)
9. recv_done() -> refcount = 1 (readquery)
10. _cancel_lookup() -> refcount = 0 (initial)
11. the query gets destroyed and removed from `lookup->q`
TCP, fortunate scenario
-----------------------
1. _new_query() -> refcount = 1 (initial)
2. start_tcp() -> refcount = 2 (lookup->current_query)
3. launch_next_query() -> refcount = 3 (readquery)
4. launch_next_query() -> refcount = 4 (sendquery)
5. tcp_connected() -> refcount = 3 (lookup->current_query)
6. tcp_connected() -> refcount = 2 (bug, there was no connectquery)
7. send_done() -> refcount = 1 (sendquery)
8. recv_done() -> refcount = 0 (readquery)
9. the query gets prematurely destroyed and removed from `lookup->q`
10. _cancel_lookup() -> the query is not in `lookup->q`
TCP, unfortunate scenario, revealing the bug
--------------------------------------------
1. _new_query() -> refcount = 1 (initial)
2. start_tcp() -> refcount = 2 (lookup->current_query)
3. launch_next_query() -> refcount = 3 (readquery)
4. launch_next_query() -> refcount = 4 (sendquery)
5. tcp_connected() -> refcount = 3 (lookup->current_query)
6. tcp_connected() -> refcount = 2 (bug, there was no connectquery)
7. recv_done() -> refcount = 1 (readquery)
8. _cancel_lookup() -> refcount = 0 (the query was in `lookup->q`)
9. we hit an assertion here when trying to destroy the query, because
sendhandle is not detached (which is done by send_done()).
10. send_done() -> this never happens
This commit does the following:
1. Add a `connectquery` attachment in start_tcp(), like done in
start_udp().
2. Add missing _cancel_lookup() calls for error scenarios, which
were possibly missing because before fixing the bug, calling
_cancel_lookup() and then calling query_detach() would cause
an assertion.
3. Log a debug message and call isc_nm_cancelread(query->readhandle)
for every query in the lookup from inside the _cancel_lookup()
function, like it is done in _cancel_all().
4. Add a `canceled` property for the query which becomes `true` when
the lookup (and subsequently, its queries) are canceled.
5. Use the `canceled` property in the network manager callbacks to
know that the query was canceled, and act like `eresult` was equal
to `ISC_R_CANCELED`.
2022-03-02 00:06:34 +00:00
|
|
|
debug("canceling pending query %p, belonging to %p", query,
|
|
|
|
query->lookup);
|
|
|
|
query->canceled = true;
|
2022-05-10 23:09:59 +03:00
|
|
|
if (query->readhandle != NULL &&
|
|
|
|
!isc_nm_is_http_handle(query->readhandle)) {
|
Fix query context management issues in dighost.c
For the reference, the _cancel_lookup() function iterates through
the lookup's queries list and detaches them. In the ideal scenario,
that should be the last reference and the query will be destroyed
after that, but it is also possible that we are still expecting a
callback, which also holds a reference (for example, _cancel_lookup()
could have been called from recv_done(), when send_done() was still
not executed).
The start_udp() and start_tcp() functions are currently designed in
slightly different ways: start_udp() creates a new query attachment
`connectquery`, to be called in the callback function, while
start_tcp() does not, which is a bug, but is hidden by the fact
that when the query is being erroneously destroyed prematurely (before
_cancel_lookup() is called) in the result of that, it also gets
de-listed from the lookup's queries' list, so _cancel_lookup() doesn't
even try to detach it.
For better understanding, here's an illustration of the query's
references count changes, and from where it was changed:
UDP
---
1. _new_query() -> refcount = 1 (initial)
2. start_udp() -> refcount = 2 (lookup->current_query)
3. start_udp() -> refcount = 3 (connectquery)
4. udp_ready() -> refcount = 4 (readquery)
5. udp_ready() -> refcount = 5 (sendquery)
6. udp_ready() -> refcount = 4 (lookup->current_query)
7. udp_ready() -> refcount = 3 (connectquery)
8. send_done() -> refcount = 2 (sendquery)
9. recv_done() -> refcount = 1 (readquery)
10. _cancel_lookup() -> refcount = 0 (initial)
11. the query gets destroyed and removed from `lookup->q`
TCP, fortunate scenario
-----------------------
1. _new_query() -> refcount = 1 (initial)
2. start_tcp() -> refcount = 2 (lookup->current_query)
3. launch_next_query() -> refcount = 3 (readquery)
4. launch_next_query() -> refcount = 4 (sendquery)
5. tcp_connected() -> refcount = 3 (lookup->current_query)
6. tcp_connected() -> refcount = 2 (bug, there was no connectquery)
7. send_done() -> refcount = 1 (sendquery)
8. recv_done() -> refcount = 0 (readquery)
9. the query gets prematurely destroyed and removed from `lookup->q`
10. _cancel_lookup() -> the query is not in `lookup->q`
TCP, unfortunate scenario, revealing the bug
--------------------------------------------
1. _new_query() -> refcount = 1 (initial)
2. start_tcp() -> refcount = 2 (lookup->current_query)
3. launch_next_query() -> refcount = 3 (readquery)
4. launch_next_query() -> refcount = 4 (sendquery)
5. tcp_connected() -> refcount = 3 (lookup->current_query)
6. tcp_connected() -> refcount = 2 (bug, there was no connectquery)
7. recv_done() -> refcount = 1 (readquery)
8. _cancel_lookup() -> refcount = 0 (the query was in `lookup->q`)
9. we hit an assertion here when trying to destroy the query, because
sendhandle is not detached (which is done by send_done()).
10. send_done() -> this never happens
This commit does the following:
1. Add a `connectquery` attachment in start_tcp(), like done in
start_udp().
2. Add missing _cancel_lookup() calls for error scenarios, which
were possibly missing because before fixing the bug, calling
_cancel_lookup() and then calling query_detach() would cause
an assertion.
3. Log a debug message and call isc_nm_cancelread(query->readhandle)
for every query in the lookup from inside the _cancel_lookup()
function, like it is done in _cancel_all().
4. Add a `canceled` property for the query which becomes `true` when
the lookup (and subsequently, its queries) are canceled.
5. Use the `canceled` property in the network manager callbacks to
know that the query was canceled, and act like `eresult` was equal
to `ISC_R_CANCELED`.
2022-03-02 00:06:34 +00:00
|
|
|
isc_nm_cancelread(query->readhandle);
|
|
|
|
}
|
2020-11-04 12:40:13 +01:00
|
|
|
query_detach(&query);
|
2000-09-21 22:46:39 +00:00
|
|
|
query = next;
|
2000-04-26 18:34:17 +00:00
|
|
|
}
|
2018-04-17 08:29:14 -07:00
|
|
|
lookup->pending = false;
|
2000-05-12 01:02:37 +00:00
|
|
|
lookup->retries = 0;
|
2020-11-04 12:40:13 +01:00
|
|
|
check_if_done();
|
2000-04-26 18:34:17 +00:00
|
|
|
}
|
|
|
|
|
2022-01-19 13:10:08 +02:00
|
|
|
static isc_tlsctx_t *
|
2022-04-22 11:41:14 +03:00
|
|
|
get_create_tls_context(dig_query_t *query, const bool is_https,
|
|
|
|
isc_tlsctx_client_session_cache_t **psess_cache) {
|
2022-01-19 13:10:08 +02:00
|
|
|
isc_result_t result;
|
|
|
|
isc_tlsctx_t *ctx = NULL, *found_ctx = NULL;
|
|
|
|
isc_tls_cert_store_t *store = NULL, *found_store = NULL;
|
|
|
|
char tlsctxname[ISC_SOCKADDR_FORMATSIZE];
|
|
|
|
const uint16_t family = isc_sockaddr_pf(&query->sockaddr) == PF_INET6
|
|
|
|
? AF_INET6
|
|
|
|
: AF_INET;
|
|
|
|
isc_tlsctx_cache_transport_t transport =
|
|
|
|
is_https ? isc_tlsctx_cache_https : isc_tlsctx_cache_tls;
|
|
|
|
const bool hostname_ignore_subject = !is_https;
|
2022-04-22 11:41:14 +03:00
|
|
|
isc_tlsctx_client_session_cache_t *sess_cache = NULL,
|
|
|
|
*found_sess_cache = NULL;
|
2022-01-19 13:10:08 +02:00
|
|
|
|
|
|
|
if (query->lookup->tls_key_file_set != query->lookup->tls_cert_file_set)
|
|
|
|
{
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_sockaddr_format(&query->sockaddr, tlsctxname, sizeof(tlsctxname));
|
|
|
|
|
|
|
|
result = isc_tlsctx_cache_find(query->lookup->tls_ctx_cache, tlsctxname,
|
|
|
|
transport, family, &found_ctx,
|
2022-04-22 11:41:14 +03:00
|
|
|
&found_store, &found_sess_cache);
|
2022-01-19 13:10:08 +02:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
if (query->lookup->tls_ca_set) {
|
|
|
|
if (found_store == NULL) {
|
|
|
|
result = isc_tls_cert_store_create(
|
|
|
|
query->lookup->tls_ca_file, &store);
|
|
|
|
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
goto failure;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
store = found_store;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
result = isc_tlsctx_createclient(&ctx);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
goto failure;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (store != NULL) {
|
|
|
|
const char *hostname =
|
|
|
|
query->lookup->tls_hostname_set
|
|
|
|
? query->lookup->tls_hostname
|
|
|
|
: query->userarg;
|
|
|
|
/*
|
|
|
|
* According to RFC 8310, Subject field MUST NOT be
|
|
|
|
* inspected when verifying hostname for DoT. Only
|
|
|
|
* SubjectAltName must be checked. That is NOT the case
|
|
|
|
* for HTTPS.
|
|
|
|
*/
|
|
|
|
result = isc_tlsctx_enable_peer_verification(
|
|
|
|
ctx, false, store, hostname,
|
|
|
|
hostname_ignore_subject);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
goto failure;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (query->lookup->tls_key_file_set &&
|
|
|
|
query->lookup->tls_cert_file_set) {
|
|
|
|
result = isc_tlsctx_load_certificate(
|
|
|
|
ctx, query->lookup->tls_key_file,
|
|
|
|
query->lookup->tls_cert_file);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
goto failure;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!is_https) {
|
|
|
|
isc_tlsctx_enable_dot_client_alpn(ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if HAVE_LIBNGHTTP2
|
|
|
|
if (is_https) {
|
|
|
|
isc_tlsctx_enable_http2client_alpn(ctx);
|
|
|
|
}
|
|
|
|
#endif /* HAVE_LIBNGHTTP2 */
|
|
|
|
|
2022-04-22 11:41:14 +03:00
|
|
|
sess_cache = isc_tlsctx_client_session_cache_new(
|
|
|
|
mctx, ctx,
|
|
|
|
ISC_TLSCTX_CLIENT_SESSION_CACHE_DEFAULT_SIZE);
|
|
|
|
|
|
|
|
result = isc_tlsctx_cache_add(
|
|
|
|
query->lookup->tls_ctx_cache, tlsctxname, transport,
|
|
|
|
family, ctx, store, sess_cache, NULL, NULL, NULL);
|
2022-01-19 13:10:08 +02:00
|
|
|
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
2022-04-22 11:41:14 +03:00
|
|
|
if (psess_cache != NULL) {
|
|
|
|
INSIST(*psess_cache == NULL);
|
|
|
|
*psess_cache = sess_cache;
|
|
|
|
}
|
2022-01-19 13:10:08 +02:00
|
|
|
return (ctx);
|
|
|
|
}
|
|
|
|
|
2022-04-22 11:41:14 +03:00
|
|
|
if (psess_cache != NULL) {
|
|
|
|
INSIST(*psess_cache == NULL);
|
|
|
|
*psess_cache = found_sess_cache;
|
|
|
|
}
|
|
|
|
|
2022-01-19 13:10:08 +02:00
|
|
|
INSIST(!query->lookup->tls_ca_set || found_store != NULL);
|
|
|
|
return (found_ctx);
|
|
|
|
failure:
|
2022-05-24 11:25:30 +03:00
|
|
|
if (ctx != NULL) {
|
2022-01-19 13:10:08 +02:00
|
|
|
isc_tlsctx_free(&ctx);
|
|
|
|
}
|
2022-05-24 11:25:30 +03:00
|
|
|
/*
|
|
|
|
* The 'found_store' is being managed by the TLS context
|
|
|
|
* cache. Thus, we should keep it as it is, as it will get
|
|
|
|
* destroyed alongside the cache. As there is one store per
|
|
|
|
* multiple TLS contexts, we need to handle store deletion in a
|
|
|
|
* special way.
|
|
|
|
*/
|
2022-01-19 13:10:08 +02:00
|
|
|
if (store != NULL && store != found_store) {
|
|
|
|
isc_tls_cert_store_free(&store);
|
|
|
|
}
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
2020-02-14 08:14:03 +01:00
|
|
|
static void
|
2020-09-05 16:37:24 -07:00
|
|
|
tcp_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg);
|
2000-09-21 22:46:39 +00:00
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
2020-09-05 16:37:24 -07:00
|
|
|
* Unlike start_udp, this can't be called multiple times with the same
|
2000-09-21 22:46:39 +00:00
|
|
|
* query. When we retry TCP, we requeue the whole lookup, which should
|
|
|
|
* start anew.
|
|
|
|
*/
|
|
|
|
static void
|
2020-09-05 16:37:24 -07:00
|
|
|
start_tcp(dig_query_t *query) {
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_result_t result;
|
Fix query context management issues in dighost.c
For the reference, the _cancel_lookup() function iterates through
the lookup's queries list and detaches them. In the ideal scenario,
that should be the last reference and the query will be destroyed
after that, but it is also possible that we are still expecting a
callback, which also holds a reference (for example, _cancel_lookup()
could have been called from recv_done(), when send_done() was still
not executed).
The start_udp() and start_tcp() functions are currently designed in
slightly different ways: start_udp() creates a new query attachment
`connectquery`, to be called in the callback function, while
start_tcp() does not, which is a bug, but is hidden by the fact
that when the query is being erroneously destroyed prematurely (before
_cancel_lookup() is called) in the result of that, it also gets
de-listed from the lookup's queries' list, so _cancel_lookup() doesn't
even try to detach it.
For better understanding, here's an illustration of the query's
references count changes, and from where it was changed:
UDP
---
1. _new_query() -> refcount = 1 (initial)
2. start_udp() -> refcount = 2 (lookup->current_query)
3. start_udp() -> refcount = 3 (connectquery)
4. udp_ready() -> refcount = 4 (readquery)
5. udp_ready() -> refcount = 5 (sendquery)
6. udp_ready() -> refcount = 4 (lookup->current_query)
7. udp_ready() -> refcount = 3 (connectquery)
8. send_done() -> refcount = 2 (sendquery)
9. recv_done() -> refcount = 1 (readquery)
10. _cancel_lookup() -> refcount = 0 (initial)
11. the query gets destroyed and removed from `lookup->q`
TCP, fortunate scenario
-----------------------
1. _new_query() -> refcount = 1 (initial)
2. start_tcp() -> refcount = 2 (lookup->current_query)
3. launch_next_query() -> refcount = 3 (readquery)
4. launch_next_query() -> refcount = 4 (sendquery)
5. tcp_connected() -> refcount = 3 (lookup->current_query)
6. tcp_connected() -> refcount = 2 (bug, there was no connectquery)
7. send_done() -> refcount = 1 (sendquery)
8. recv_done() -> refcount = 0 (readquery)
9. the query gets prematurely destroyed and removed from `lookup->q`
10. _cancel_lookup() -> the query is not in `lookup->q`
TCP, unfortunate scenario, revealing the bug
--------------------------------------------
1. _new_query() -> refcount = 1 (initial)
2. start_tcp() -> refcount = 2 (lookup->current_query)
3. launch_next_query() -> refcount = 3 (readquery)
4. launch_next_query() -> refcount = 4 (sendquery)
5. tcp_connected() -> refcount = 3 (lookup->current_query)
6. tcp_connected() -> refcount = 2 (bug, there was no connectquery)
7. recv_done() -> refcount = 1 (readquery)
8. _cancel_lookup() -> refcount = 0 (the query was in `lookup->q`)
9. we hit an assertion here when trying to destroy the query, because
sendhandle is not detached (which is done by send_done()).
10. send_done() -> this never happens
This commit does the following:
1. Add a `connectquery` attachment in start_tcp(), like done in
start_udp().
2. Add missing _cancel_lookup() calls for error scenarios, which
were possibly missing because before fixing the bug, calling
_cancel_lookup() and then calling query_detach() would cause
an assertion.
3. Log a debug message and call isc_nm_cancelread(query->readhandle)
for every query in the lookup from inside the _cancel_lookup()
function, like it is done in _cancel_all().
4. Add a `canceled` property for the query which becomes `true` when
the lookup (and subsequently, its queries) are canceled.
5. Use the `canceled` property in the network manager callbacks to
know that the query was canceled, and act like `eresult` was equal
to `ISC_R_CANCELED`.
2022-03-02 00:06:34 +00:00
|
|
|
dig_query_t *next = NULL;
|
|
|
|
dig_query_t *connectquery = NULL;
|
2022-01-19 13:10:08 +02:00
|
|
|
isc_tlsctx_t *tlsctx = NULL;
|
|
|
|
bool tls_mode = false;
|
2022-04-22 11:41:14 +03:00
|
|
|
isc_tlsctx_client_session_cache_t *sess_cache = NULL;
|
2018-11-07 13:04:13 -05:00
|
|
|
REQUIRE(DIG_VALID_QUERY(query));
|
2000-09-21 22:46:39 +00:00
|
|
|
|
2020-09-05 16:37:24 -07:00
|
|
|
debug("start_tcp(%p)", query);
|
2000-09-21 22:46:39 +00:00
|
|
|
|
2020-11-05 15:22:38 +01:00
|
|
|
query_attach(query, &query->lookup->current_query);
|
2020-07-22 08:59:42 +02:00
|
|
|
|
2022-01-19 13:10:08 +02:00
|
|
|
tls_mode = dig_lookup_is_tls(query->lookup);
|
|
|
|
|
2020-07-22 08:59:42 +02:00
|
|
|
/*
|
|
|
|
* For TLS connections, we want to override the default
|
|
|
|
* port number.
|
|
|
|
*/
|
2021-01-27 15:49:27 +01:00
|
|
|
if (!port_set) {
|
2022-01-19 13:10:08 +02:00
|
|
|
if (tls_mode) {
|
2021-01-27 15:49:27 +01:00
|
|
|
port = 853;
|
|
|
|
} else if (query->lookup->https_mode &&
|
|
|
|
!query->lookup->http_plain) {
|
|
|
|
port = 443;
|
|
|
|
} else if (query->lookup->https_mode) {
|
|
|
|
port = 80;
|
|
|
|
} else {
|
|
|
|
port = 53;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
debug("query->servname = %s\n", query->servname);
|
2020-07-22 08:59:42 +02:00
|
|
|
|
2008-12-16 02:57:24 +00:00
|
|
|
result = get_address(query->servname, port, &query->sockaddr);
|
2010-06-24 07:22:18 +00:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2008-12-16 02:57:24 +00:00
|
|
|
/*
|
|
|
|
* This servname doesn't have an address. Try the next server
|
|
|
|
* by triggering an immediate 'timeout' (we lie, but the effect
|
|
|
|
* is the same).
|
|
|
|
*/
|
2020-11-02 21:38:56 -08:00
|
|
|
force_next(query);
|
2008-12-16 02:57:24 +00:00
|
|
|
return;
|
|
|
|
}
|
2008-01-18 23:46:58 +00:00
|
|
|
|
2022-01-13 13:29:09 +01:00
|
|
|
if (isc_sockaddr_pf(&query->sockaddr) == AF_INET6 &&
|
2020-02-13 14:44:37 -08:00
|
|
|
IN6_IS_ADDR_V4MAPPED(&query->sockaddr.type.sin6.sin6_addr))
|
|
|
|
{
|
2015-12-19 09:47:11 +11:00
|
|
|
isc_netaddr_t netaddr;
|
2020-02-13 14:44:37 -08:00
|
|
|
char buf[ISC_NETADDR_FORMATSIZE];
|
2015-12-19 09:47:11 +11:00
|
|
|
|
|
|
|
isc_netaddr_fromsockaddr(&netaddr, &query->sockaddr);
|
|
|
|
isc_netaddr_format(&netaddr, buf, sizeof(buf));
|
2019-08-30 14:23:29 +10:00
|
|
|
dighost_warning("Skipping mapped address '%s'", buf);
|
2015-12-19 09:47:11 +11:00
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (ISC_LINK_LINKED(query, link)) {
|
2016-12-14 15:42:43 +11:00
|
|
|
next = ISC_LIST_NEXT(query, link);
|
2020-02-13 21:48:23 +01:00
|
|
|
} else {
|
2016-12-14 15:42:43 +11:00
|
|
|
next = NULL;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2020-11-04 12:40:13 +01:00
|
|
|
query_detach(&query);
|
2015-12-19 09:47:11 +11:00
|
|
|
if (next == NULL) {
|
2019-08-30 14:23:29 +10:00
|
|
|
dighost_warning("No acceptable nameservers");
|
2020-11-06 16:12:17 +01:00
|
|
|
clear_current_lookup();
|
2020-11-05 15:22:38 +01:00
|
|
|
} else {
|
|
|
|
start_tcp(next);
|
2015-12-19 09:47:11 +11:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-09-05 16:37:24 -07:00
|
|
|
INSIST(query->handle == NULL);
|
2013-11-07 10:50:01 +11:00
|
|
|
|
|
|
|
if (keep != NULL && isc_sockaddr_equal(&keepaddr, &query->sockaddr)) {
|
2020-09-05 16:37:24 -07:00
|
|
|
query->handle = keep;
|
|
|
|
launch_next_query(query);
|
2020-11-04 12:40:13 +01:00
|
|
|
query_detach(&query);
|
|
|
|
return;
|
2020-02-13 21:48:23 +01:00
|
|
|
} else {
|
2020-09-05 16:37:24 -07:00
|
|
|
int local_timeout = timeout * 1000;
|
|
|
|
if (local_timeout == 0) {
|
|
|
|
local_timeout = TCP_TIMEOUT * 1000;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (keep != NULL) {
|
|
|
|
isc_nmhandle_detach(&keep);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2020-09-05 16:37:24 -07:00
|
|
|
|
|
|
|
if (!specified_source) {
|
|
|
|
if ((isc_sockaddr_pf(&query->sockaddr) == AF_INET) &&
|
|
|
|
have_ipv4) {
|
|
|
|
isc_sockaddr_any(&localaddr);
|
|
|
|
} else {
|
|
|
|
isc_sockaddr_any6(&localaddr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-04 12:40:13 +01:00
|
|
|
REQUIRE(query != NULL);
|
|
|
|
|
Fix query context management issues in dighost.c
For the reference, the _cancel_lookup() function iterates through
the lookup's queries list and detaches them. In the ideal scenario,
that should be the last reference and the query will be destroyed
after that, but it is also possible that we are still expecting a
callback, which also holds a reference (for example, _cancel_lookup()
could have been called from recv_done(), when send_done() was still
not executed).
The start_udp() and start_tcp() functions are currently designed in
slightly different ways: start_udp() creates a new query attachment
`connectquery`, to be called in the callback function, while
start_tcp() does not, which is a bug, but is hidden by the fact
that when the query is being erroneously destroyed prematurely (before
_cancel_lookup() is called) in the result of that, it also gets
de-listed from the lookup's queries' list, so _cancel_lookup() doesn't
even try to detach it.
For better understanding, here's an illustration of the query's
references count changes, and from where it was changed:
UDP
---
1. _new_query() -> refcount = 1 (initial)
2. start_udp() -> refcount = 2 (lookup->current_query)
3. start_udp() -> refcount = 3 (connectquery)
4. udp_ready() -> refcount = 4 (readquery)
5. udp_ready() -> refcount = 5 (sendquery)
6. udp_ready() -> refcount = 4 (lookup->current_query)
7. udp_ready() -> refcount = 3 (connectquery)
8. send_done() -> refcount = 2 (sendquery)
9. recv_done() -> refcount = 1 (readquery)
10. _cancel_lookup() -> refcount = 0 (initial)
11. the query gets destroyed and removed from `lookup->q`
TCP, fortunate scenario
-----------------------
1. _new_query() -> refcount = 1 (initial)
2. start_tcp() -> refcount = 2 (lookup->current_query)
3. launch_next_query() -> refcount = 3 (readquery)
4. launch_next_query() -> refcount = 4 (sendquery)
5. tcp_connected() -> refcount = 3 (lookup->current_query)
6. tcp_connected() -> refcount = 2 (bug, there was no connectquery)
7. send_done() -> refcount = 1 (sendquery)
8. recv_done() -> refcount = 0 (readquery)
9. the query gets prematurely destroyed and removed from `lookup->q`
10. _cancel_lookup() -> the query is not in `lookup->q`
TCP, unfortunate scenario, revealing the bug
--------------------------------------------
1. _new_query() -> refcount = 1 (initial)
2. start_tcp() -> refcount = 2 (lookup->current_query)
3. launch_next_query() -> refcount = 3 (readquery)
4. launch_next_query() -> refcount = 4 (sendquery)
5. tcp_connected() -> refcount = 3 (lookup->current_query)
6. tcp_connected() -> refcount = 2 (bug, there was no connectquery)
7. recv_done() -> refcount = 1 (readquery)
8. _cancel_lookup() -> refcount = 0 (the query was in `lookup->q`)
9. we hit an assertion here when trying to destroy the query, because
sendhandle is not detached (which is done by send_done()).
10. send_done() -> this never happens
This commit does the following:
1. Add a `connectquery` attachment in start_tcp(), like done in
start_udp().
2. Add missing _cancel_lookup() calls for error scenarios, which
were possibly missing because before fixing the bug, calling
_cancel_lookup() and then calling query_detach() would cause
an assertion.
3. Log a debug message and call isc_nm_cancelread(query->readhandle)
for every query in the lookup from inside the _cancel_lookup()
function, like it is done in _cancel_all().
4. Add a `canceled` property for the query which becomes `true` when
the lookup (and subsequently, its queries) are canceled.
5. Use the `canceled` property in the network manager callbacks to
know that the query was canceled, and act like `eresult` was equal
to `ISC_R_CANCELED`.
2022-03-02 00:06:34 +00:00
|
|
|
query_attach(query, &connectquery);
|
|
|
|
|
2022-01-19 13:10:08 +02:00
|
|
|
if (tls_mode) {
|
2022-04-22 11:41:14 +03:00
|
|
|
tlsctx = get_create_tls_context(connectquery, false,
|
|
|
|
&sess_cache);
|
2022-01-19 13:10:08 +02:00
|
|
|
if (tlsctx == NULL) {
|
|
|
|
goto failure_tls;
|
|
|
|
}
|
2021-05-26 08:15:34 +02:00
|
|
|
isc_nm_tlsdnsconnect(netmgr, &localaddr,
|
|
|
|
&query->sockaddr, tcp_connected,
|
2022-03-23 13:57:15 +01:00
|
|
|
connectquery, local_timeout,
|
2022-04-25 16:47:06 +03:00
|
|
|
tlsctx, sess_cache);
|
2021-04-21 13:52:15 +02:00
|
|
|
#if HAVE_LIBNGHTTP2
|
2021-01-27 15:49:27 +01:00
|
|
|
} else if (query->lookup->https_mode) {
|
|
|
|
char uri[4096] = { 0 };
|
2021-08-12 10:18:26 +03:00
|
|
|
isc_nm_http_makeuri(!query->lookup->http_plain,
|
|
|
|
&query->sockaddr, query->userarg,
|
|
|
|
port, query->lookup->https_path,
|
|
|
|
uri, sizeof(uri));
|
2021-01-27 15:49:27 +01:00
|
|
|
|
|
|
|
if (!query->lookup->http_plain) {
|
2022-04-22 11:41:14 +03:00
|
|
|
tlsctx = get_create_tls_context(
|
|
|
|
connectquery, true, &sess_cache);
|
2022-01-19 13:10:08 +02:00
|
|
|
if (tlsctx == NULL) {
|
|
|
|
goto failure_tls;
|
|
|
|
}
|
2021-01-27 15:49:27 +01:00
|
|
|
}
|
|
|
|
|
2021-05-26 08:15:34 +02:00
|
|
|
isc_nm_httpconnect(netmgr, &localaddr, &query->sockaddr,
|
2021-04-01 14:02:03 -07:00
|
|
|
uri, !query->lookup->https_get,
|
2022-01-19 13:10:08 +02:00
|
|
|
tcp_connected, connectquery, tlsctx,
|
2022-04-22 15:59:11 +03:00
|
|
|
sess_cache, local_timeout);
|
2021-04-21 13:52:15 +02:00
|
|
|
#endif
|
2020-07-22 08:59:42 +02:00
|
|
|
} else {
|
2021-05-26 08:15:34 +02:00
|
|
|
isc_nm_tcpdnsconnect(netmgr, &localaddr,
|
|
|
|
&query->sockaddr, tcp_connected,
|
2022-03-23 13:57:15 +01:00
|
|
|
connectquery, local_timeout);
|
2020-07-22 08:59:42 +02:00
|
|
|
}
|
|
|
|
|
2020-09-05 16:37:24 -07:00
|
|
|
/* XXX: set DSCP */
|
|
|
|
}
|
|
|
|
|
2022-01-19 13:10:08 +02:00
|
|
|
return;
|
2022-04-07 09:23:49 +00:00
|
|
|
|
2022-01-19 13:10:08 +02:00
|
|
|
failure_tls:
|
|
|
|
if (query->lookup->tls_key_file_set != query->lookup->tls_cert_file_set)
|
|
|
|
{
|
|
|
|
dighost_warning(
|
|
|
|
"both TLS client certificate and key file must be "
|
|
|
|
"specified a the same time");
|
|
|
|
} else {
|
|
|
|
dighost_warning("TLS context cannot be created");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ISC_LINK_LINKED(query, link)) {
|
|
|
|
next = ISC_LIST_NEXT(query, link);
|
|
|
|
} else {
|
|
|
|
next = NULL;
|
|
|
|
}
|
2022-06-06 15:12:46 +00:00
|
|
|
query_detach(&connectquery);
|
2022-01-19 13:10:08 +02:00
|
|
|
query_detach(&query);
|
|
|
|
if (next == NULL) {
|
|
|
|
clear_current_lookup();
|
|
|
|
} else {
|
|
|
|
start_tcp(next);
|
|
|
|
}
|
2000-09-21 22:46:39 +00:00
|
|
|
}
|
|
|
|
|
2019-08-30 14:23:29 +10:00
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
print_query_size(dig_query_t *query) {
|
2019-08-30 14:23:29 +10:00
|
|
|
if (!yaml) {
|
|
|
|
printf(";; QUERY SIZE: %u\n\n",
|
|
|
|
isc_buffer_usedlength(&query->lookup->renderbuf));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-05 16:37:24 -07:00
|
|
|
static void
|
|
|
|
send_udp(dig_query_t *query) {
|
2020-11-04 12:40:13 +01:00
|
|
|
dig_query_t *sendquery = NULL;
|
2020-09-05 16:37:24 -07:00
|
|
|
isc_region_t r;
|
|
|
|
|
2020-11-04 12:40:13 +01:00
|
|
|
query_attach(query, &sendquery);
|
|
|
|
|
2020-09-05 16:37:24 -07:00
|
|
|
isc_buffer_usedregion(&query->sendbuf, &r);
|
|
|
|
debug("sending a request");
|
2021-03-19 22:50:51 -07:00
|
|
|
if (query->lookup->use_usec) {
|
|
|
|
TIME_NOW_HIRES(&query->time_sent);
|
|
|
|
} else {
|
|
|
|
TIME_NOW(&query->time_sent);
|
|
|
|
}
|
2020-09-05 16:37:24 -07:00
|
|
|
|
2020-11-04 12:40:13 +01:00
|
|
|
isc_nmhandle_attach(query->handle, &query->sendhandle);
|
2020-09-05 16:37:24 -07:00
|
|
|
|
2020-11-04 12:40:13 +01:00
|
|
|
isc_nm_send(query->handle, &r, send_done, sendquery);
|
2020-09-05 16:37:24 -07:00
|
|
|
isc_refcount_increment0(&sendcount);
|
2020-07-22 08:59:42 +02:00
|
|
|
debug("sendcount=%" PRIuFAST32, isc_refcount_current(&sendcount));
|
2020-09-05 16:37:24 -07:00
|
|
|
|
|
|
|
/* XXX qrflag, print_query, etc... */
|
2022-03-31 14:33:49 +00:00
|
|
|
if (query->lookup->qr) {
|
2020-09-05 16:37:24 -07:00
|
|
|
extrabytes = 0;
|
2022-03-31 14:33:49 +00:00
|
|
|
dighost_printmessage(query, &query->lookup->renderbuf,
|
2020-09-05 16:37:24 -07:00
|
|
|
query->lookup->sendmsg, true);
|
|
|
|
if (query->lookup->stats) {
|
|
|
|
print_query_size(query);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
udp_ready(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) {
|
|
|
|
dig_query_t *query = (dig_query_t *)arg;
|
2020-11-04 12:40:13 +01:00
|
|
|
dig_query_t *readquery = NULL;
|
2020-11-02 21:38:56 -08:00
|
|
|
int local_timeout = timeout * 1000;
|
2020-09-05 16:37:24 -07:00
|
|
|
|
2022-03-29 20:58:15 +00:00
|
|
|
REQUIRE(DIG_VALID_QUERY(query));
|
|
|
|
REQUIRE(query->handle == NULL);
|
|
|
|
|
|
|
|
debug("udp_ready()");
|
|
|
|
|
2022-03-20 13:54:39 +00:00
|
|
|
query->started = true;
|
|
|
|
|
2022-03-29 20:58:15 +00:00
|
|
|
if (atomic_load(&cancel_now)) {
|
2022-04-10 17:42:49 -07:00
|
|
|
query_detach(&query);
|
2022-03-29 20:58:15 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
INSIST(!free_now);
|
|
|
|
|
|
|
|
debug("udp_ready(%p, %s, %p)", handle, isc_result_totext(eresult),
|
|
|
|
query);
|
|
|
|
|
Fix query context management issues in dighost.c
For the reference, the _cancel_lookup() function iterates through
the lookup's queries list and detaches them. In the ideal scenario,
that should be the last reference and the query will be destroyed
after that, but it is also possible that we are still expecting a
callback, which also holds a reference (for example, _cancel_lookup()
could have been called from recv_done(), when send_done() was still
not executed).
The start_udp() and start_tcp() functions are currently designed in
slightly different ways: start_udp() creates a new query attachment
`connectquery`, to be called in the callback function, while
start_tcp() does not, which is a bug, but is hidden by the fact
that when the query is being erroneously destroyed prematurely (before
_cancel_lookup() is called) in the result of that, it also gets
de-listed from the lookup's queries' list, so _cancel_lookup() doesn't
even try to detach it.
For better understanding, here's an illustration of the query's
references count changes, and from where it was changed:
UDP
---
1. _new_query() -> refcount = 1 (initial)
2. start_udp() -> refcount = 2 (lookup->current_query)
3. start_udp() -> refcount = 3 (connectquery)
4. udp_ready() -> refcount = 4 (readquery)
5. udp_ready() -> refcount = 5 (sendquery)
6. udp_ready() -> refcount = 4 (lookup->current_query)
7. udp_ready() -> refcount = 3 (connectquery)
8. send_done() -> refcount = 2 (sendquery)
9. recv_done() -> refcount = 1 (readquery)
10. _cancel_lookup() -> refcount = 0 (initial)
11. the query gets destroyed and removed from `lookup->q`
TCP, fortunate scenario
-----------------------
1. _new_query() -> refcount = 1 (initial)
2. start_tcp() -> refcount = 2 (lookup->current_query)
3. launch_next_query() -> refcount = 3 (readquery)
4. launch_next_query() -> refcount = 4 (sendquery)
5. tcp_connected() -> refcount = 3 (lookup->current_query)
6. tcp_connected() -> refcount = 2 (bug, there was no connectquery)
7. send_done() -> refcount = 1 (sendquery)
8. recv_done() -> refcount = 0 (readquery)
9. the query gets prematurely destroyed and removed from `lookup->q`
10. _cancel_lookup() -> the query is not in `lookup->q`
TCP, unfortunate scenario, revealing the bug
--------------------------------------------
1. _new_query() -> refcount = 1 (initial)
2. start_tcp() -> refcount = 2 (lookup->current_query)
3. launch_next_query() -> refcount = 3 (readquery)
4. launch_next_query() -> refcount = 4 (sendquery)
5. tcp_connected() -> refcount = 3 (lookup->current_query)
6. tcp_connected() -> refcount = 2 (bug, there was no connectquery)
7. recv_done() -> refcount = 1 (readquery)
8. _cancel_lookup() -> refcount = 0 (the query was in `lookup->q`)
9. we hit an assertion here when trying to destroy the query, because
sendhandle is not detached (which is done by send_done()).
10. send_done() -> this never happens
This commit does the following:
1. Add a `connectquery` attachment in start_tcp(), like done in
start_udp().
2. Add missing _cancel_lookup() calls for error scenarios, which
were possibly missing because before fixing the bug, calling
_cancel_lookup() and then calling query_detach() would cause
an assertion.
3. Log a debug message and call isc_nm_cancelread(query->readhandle)
for every query in the lookup from inside the _cancel_lookup()
function, like it is done in _cancel_all().
4. Add a `canceled` property for the query which becomes `true` when
the lookup (and subsequently, its queries) are canceled.
5. Use the `canceled` property in the network manager callbacks to
know that the query was canceled, and act like `eresult` was equal
to `ISC_R_CANCELED`.
2022-03-02 00:06:34 +00:00
|
|
|
if (eresult == ISC_R_CANCELED || query->canceled) {
|
|
|
|
dig_lookup_t *l = query->lookup;
|
|
|
|
|
|
|
|
debug("in cancel handler");
|
|
|
|
if (!query->canceled) {
|
|
|
|
cancel_lookup(l);
|
|
|
|
}
|
2022-03-06 10:16:29 +01:00
|
|
|
query_detach(&query);
|
Fix query context management issues in dighost.c
For the reference, the _cancel_lookup() function iterates through
the lookup's queries list and detaches them. In the ideal scenario,
that should be the last reference and the query will be destroyed
after that, but it is also possible that we are still expecting a
callback, which also holds a reference (for example, _cancel_lookup()
could have been called from recv_done(), when send_done() was still
not executed).
The start_udp() and start_tcp() functions are currently designed in
slightly different ways: start_udp() creates a new query attachment
`connectquery`, to be called in the callback function, while
start_tcp() does not, which is a bug, but is hidden by the fact
that when the query is being erroneously destroyed prematurely (before
_cancel_lookup() is called) in the result of that, it also gets
de-listed from the lookup's queries' list, so _cancel_lookup() doesn't
even try to detach it.
For better understanding, here's an illustration of the query's
references count changes, and from where it was changed:
UDP
---
1. _new_query() -> refcount = 1 (initial)
2. start_udp() -> refcount = 2 (lookup->current_query)
3. start_udp() -> refcount = 3 (connectquery)
4. udp_ready() -> refcount = 4 (readquery)
5. udp_ready() -> refcount = 5 (sendquery)
6. udp_ready() -> refcount = 4 (lookup->current_query)
7. udp_ready() -> refcount = 3 (connectquery)
8. send_done() -> refcount = 2 (sendquery)
9. recv_done() -> refcount = 1 (readquery)
10. _cancel_lookup() -> refcount = 0 (initial)
11. the query gets destroyed and removed from `lookup->q`
TCP, fortunate scenario
-----------------------
1. _new_query() -> refcount = 1 (initial)
2. start_tcp() -> refcount = 2 (lookup->current_query)
3. launch_next_query() -> refcount = 3 (readquery)
4. launch_next_query() -> refcount = 4 (sendquery)
5. tcp_connected() -> refcount = 3 (lookup->current_query)
6. tcp_connected() -> refcount = 2 (bug, there was no connectquery)
7. send_done() -> refcount = 1 (sendquery)
8. recv_done() -> refcount = 0 (readquery)
9. the query gets prematurely destroyed and removed from `lookup->q`
10. _cancel_lookup() -> the query is not in `lookup->q`
TCP, unfortunate scenario, revealing the bug
--------------------------------------------
1. _new_query() -> refcount = 1 (initial)
2. start_tcp() -> refcount = 2 (lookup->current_query)
3. launch_next_query() -> refcount = 3 (readquery)
4. launch_next_query() -> refcount = 4 (sendquery)
5. tcp_connected() -> refcount = 3 (lookup->current_query)
6. tcp_connected() -> refcount = 2 (bug, there was no connectquery)
7. recv_done() -> refcount = 1 (readquery)
8. _cancel_lookup() -> refcount = 0 (the query was in `lookup->q`)
9. we hit an assertion here when trying to destroy the query, because
sendhandle is not detached (which is done by send_done()).
10. send_done() -> this never happens
This commit does the following:
1. Add a `connectquery` attachment in start_tcp(), like done in
start_udp().
2. Add missing _cancel_lookup() calls for error scenarios, which
were possibly missing because before fixing the bug, calling
_cancel_lookup() and then calling query_detach() would cause
an assertion.
3. Log a debug message and call isc_nm_cancelread(query->readhandle)
for every query in the lookup from inside the _cancel_lookup()
function, like it is done in _cancel_all().
4. Add a `canceled` property for the query which becomes `true` when
the lookup (and subsequently, its queries) are canceled.
5. Use the `canceled` property in the network manager callbacks to
know that the query was canceled, and act like `eresult` was equal
to `ISC_R_CANCELED`.
2022-03-02 00:06:34 +00:00
|
|
|
lookup_detach(&l);
|
2020-09-05 16:37:24 -07:00
|
|
|
return;
|
|
|
|
} else if (eresult != ISC_R_SUCCESS) {
|
2021-04-06 16:49:14 -07:00
|
|
|
dig_lookup_t *l = query->lookup;
|
|
|
|
|
Fix query context management issues in dighost.c
For the reference, the _cancel_lookup() function iterates through
the lookup's queries list and detaches them. In the ideal scenario,
that should be the last reference and the query will be destroyed
after that, but it is also possible that we are still expecting a
callback, which also holds a reference (for example, _cancel_lookup()
could have been called from recv_done(), when send_done() was still
not executed).
The start_udp() and start_tcp() functions are currently designed in
slightly different ways: start_udp() creates a new query attachment
`connectquery`, to be called in the callback function, while
start_tcp() does not, which is a bug, but is hidden by the fact
that when the query is being erroneously destroyed prematurely (before
_cancel_lookup() is called) in the result of that, it also gets
de-listed from the lookup's queries' list, so _cancel_lookup() doesn't
even try to detach it.
For better understanding, here's an illustration of the query's
references count changes, and from where it was changed:
UDP
---
1. _new_query() -> refcount = 1 (initial)
2. start_udp() -> refcount = 2 (lookup->current_query)
3. start_udp() -> refcount = 3 (connectquery)
4. udp_ready() -> refcount = 4 (readquery)
5. udp_ready() -> refcount = 5 (sendquery)
6. udp_ready() -> refcount = 4 (lookup->current_query)
7. udp_ready() -> refcount = 3 (connectquery)
8. send_done() -> refcount = 2 (sendquery)
9. recv_done() -> refcount = 1 (readquery)
10. _cancel_lookup() -> refcount = 0 (initial)
11. the query gets destroyed and removed from `lookup->q`
TCP, fortunate scenario
-----------------------
1. _new_query() -> refcount = 1 (initial)
2. start_tcp() -> refcount = 2 (lookup->current_query)
3. launch_next_query() -> refcount = 3 (readquery)
4. launch_next_query() -> refcount = 4 (sendquery)
5. tcp_connected() -> refcount = 3 (lookup->current_query)
6. tcp_connected() -> refcount = 2 (bug, there was no connectquery)
7. send_done() -> refcount = 1 (sendquery)
8. recv_done() -> refcount = 0 (readquery)
9. the query gets prematurely destroyed and removed from `lookup->q`
10. _cancel_lookup() -> the query is not in `lookup->q`
TCP, unfortunate scenario, revealing the bug
--------------------------------------------
1. _new_query() -> refcount = 1 (initial)
2. start_tcp() -> refcount = 2 (lookup->current_query)
3. launch_next_query() -> refcount = 3 (readquery)
4. launch_next_query() -> refcount = 4 (sendquery)
5. tcp_connected() -> refcount = 3 (lookup->current_query)
6. tcp_connected() -> refcount = 2 (bug, there was no connectquery)
7. recv_done() -> refcount = 1 (readquery)
8. _cancel_lookup() -> refcount = 0 (the query was in `lookup->q`)
9. we hit an assertion here when trying to destroy the query, because
sendhandle is not detached (which is done by send_done()).
10. send_done() -> this never happens
This commit does the following:
1. Add a `connectquery` attachment in start_tcp(), like done in
start_udp().
2. Add missing _cancel_lookup() calls for error scenarios, which
were possibly missing because before fixing the bug, calling
_cancel_lookup() and then calling query_detach() would cause
an assertion.
3. Log a debug message and call isc_nm_cancelread(query->readhandle)
for every query in the lookup from inside the _cancel_lookup()
function, like it is done in _cancel_all().
4. Add a `canceled` property for the query which becomes `true` when
the lookup (and subsequently, its queries) are canceled.
5. Use the `canceled` property in the network manager callbacks to
know that the query was canceled, and act like `eresult` was equal
to `ISC_R_CANCELED`.
2022-03-02 00:06:34 +00:00
|
|
|
debug("udp setup failed: %s", isc_result_totext(eresult));
|
2022-04-08 00:33:24 -07:00
|
|
|
|
|
|
|
if (exitcode < 9) {
|
|
|
|
exitcode = 9;
|
|
|
|
}
|
Fix query context management issues in dighost.c
For the reference, the _cancel_lookup() function iterates through
the lookup's queries list and detaches them. In the ideal scenario,
that should be the last reference and the query will be destroyed
after that, but it is also possible that we are still expecting a
callback, which also holds a reference (for example, _cancel_lookup()
could have been called from recv_done(), when send_done() was still
not executed).
The start_udp() and start_tcp() functions are currently designed in
slightly different ways: start_udp() creates a new query attachment
`connectquery`, to be called in the callback function, while
start_tcp() does not, which is a bug, but is hidden by the fact
that when the query is being erroneously destroyed prematurely (before
_cancel_lookup() is called) in the result of that, it also gets
de-listed from the lookup's queries' list, so _cancel_lookup() doesn't
even try to detach it.
For better understanding, here's an illustration of the query's
references count changes, and from where it was changed:
UDP
---
1. _new_query() -> refcount = 1 (initial)
2. start_udp() -> refcount = 2 (lookup->current_query)
3. start_udp() -> refcount = 3 (connectquery)
4. udp_ready() -> refcount = 4 (readquery)
5. udp_ready() -> refcount = 5 (sendquery)
6. udp_ready() -> refcount = 4 (lookup->current_query)
7. udp_ready() -> refcount = 3 (connectquery)
8. send_done() -> refcount = 2 (sendquery)
9. recv_done() -> refcount = 1 (readquery)
10. _cancel_lookup() -> refcount = 0 (initial)
11. the query gets destroyed and removed from `lookup->q`
TCP, fortunate scenario
-----------------------
1. _new_query() -> refcount = 1 (initial)
2. start_tcp() -> refcount = 2 (lookup->current_query)
3. launch_next_query() -> refcount = 3 (readquery)
4. launch_next_query() -> refcount = 4 (sendquery)
5. tcp_connected() -> refcount = 3 (lookup->current_query)
6. tcp_connected() -> refcount = 2 (bug, there was no connectquery)
7. send_done() -> refcount = 1 (sendquery)
8. recv_done() -> refcount = 0 (readquery)
9. the query gets prematurely destroyed and removed from `lookup->q`
10. _cancel_lookup() -> the query is not in `lookup->q`
TCP, unfortunate scenario, revealing the bug
--------------------------------------------
1. _new_query() -> refcount = 1 (initial)
2. start_tcp() -> refcount = 2 (lookup->current_query)
3. launch_next_query() -> refcount = 3 (readquery)
4. launch_next_query() -> refcount = 4 (sendquery)
5. tcp_connected() -> refcount = 3 (lookup->current_query)
6. tcp_connected() -> refcount = 2 (bug, there was no connectquery)
7. recv_done() -> refcount = 1 (readquery)
8. _cancel_lookup() -> refcount = 0 (the query was in `lookup->q`)
9. we hit an assertion here when trying to destroy the query, because
sendhandle is not detached (which is done by send_done()).
10. send_done() -> this never happens
This commit does the following:
1. Add a `connectquery` attachment in start_tcp(), like done in
start_udp().
2. Add missing _cancel_lookup() calls for error scenarios, which
were possibly missing because before fixing the bug, calling
_cancel_lookup() and then calling query_detach() would cause
an assertion.
3. Log a debug message and call isc_nm_cancelread(query->readhandle)
for every query in the lookup from inside the _cancel_lookup()
function, like it is done in _cancel_all().
4. Add a `canceled` property for the query which becomes `true` when
the lookup (and subsequently, its queries) are canceled.
5. Use the `canceled` property in the network manager callbacks to
know that the query was canceled, and act like `eresult` was equal
to `ISC_R_CANCELED`.
2022-03-02 00:06:34 +00:00
|
|
|
query_detach(&query);
|
2021-05-04 14:25:55 +02:00
|
|
|
cancel_lookup(l);
|
2021-04-06 16:49:14 -07:00
|
|
|
lookup_detach(&l);
|
2020-09-05 16:37:24 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-11-04 12:40:13 +01:00
|
|
|
query_attach(query, &readquery);
|
|
|
|
|
2020-09-05 16:37:24 -07:00
|
|
|
debug("recving with lookup=%p, query=%p, handle=%p", query->lookup,
|
2022-03-31 22:00:21 +00:00
|
|
|
query, handle);
|
2020-09-05 16:37:24 -07:00
|
|
|
|
|
|
|
query->handle = handle;
|
|
|
|
isc_nmhandle_attach(handle, &query->readhandle);
|
|
|
|
isc_refcount_increment0(&recvcount);
|
|
|
|
debug("recvcount=%" PRIuFAST32, isc_refcount_current(&recvcount));
|
2020-11-02 21:38:56 -08:00
|
|
|
|
|
|
|
if (local_timeout == 0) {
|
|
|
|
local_timeout = UDP_TIMEOUT * 1000;
|
|
|
|
}
|
|
|
|
|
|
|
|
debug("have local timeout of %d", local_timeout);
|
|
|
|
isc_nmhandle_settimeout(handle, local_timeout);
|
|
|
|
|
2020-11-04 12:40:13 +01:00
|
|
|
isc_nm_read(handle, recv_done, readquery);
|
|
|
|
send_udp(readquery);
|
|
|
|
|
|
|
|
query_detach(&query);
|
2020-09-05 16:37:24 -07:00
|
|
|
}
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
2000-09-21 22:46:39 +00:00
|
|
|
* Send a UDP packet to the remote nameserver, possible starting the
|
|
|
|
* recv action as well. Also make sure that the timer is running and
|
|
|
|
* is properly reset.
|
|
|
|
*/
|
|
|
|
static void
|
2020-09-05 16:37:24 -07:00
|
|
|
start_udp(dig_query_t *query) {
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_result_t result;
|
2020-09-05 16:37:24 -07:00
|
|
|
dig_query_t *next = NULL;
|
2021-04-27 12:03:20 +02:00
|
|
|
dig_query_t *connectquery = NULL;
|
2020-09-05 16:37:24 -07:00
|
|
|
|
2018-11-07 13:04:13 -05:00
|
|
|
REQUIRE(DIG_VALID_QUERY(query));
|
2000-09-21 22:46:39 +00:00
|
|
|
|
2020-09-05 16:37:24 -07:00
|
|
|
debug("start_udp(%p)", query);
|
2000-09-21 22:46:39 +00:00
|
|
|
|
2020-11-05 15:22:38 +01:00
|
|
|
query_attach(query, &query->lookup->current_query);
|
2005-08-25 00:56:08 +00:00
|
|
|
debug("working on lookup %p, query %p", query->lookup, query);
|
2020-11-05 15:22:38 +01:00
|
|
|
|
2020-09-05 16:37:24 -07:00
|
|
|
if (query->handle != NULL) {
|
2020-11-05 15:22:38 +01:00
|
|
|
launch_next_query(query);
|
|
|
|
query_detach(&query);
|
2020-09-05 16:37:24 -07:00
|
|
|
return;
|
|
|
|
}
|
2000-09-21 22:46:39 +00:00
|
|
|
|
2020-09-05 16:37:24 -07:00
|
|
|
result = get_address(query->servname, port, &query->sockaddr);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
/* This servname doesn't have an address. */
|
2020-11-02 21:38:56 -08:00
|
|
|
force_next(query);
|
2020-09-05 16:37:24 -07:00
|
|
|
return;
|
|
|
|
}
|
2015-12-19 09:47:11 +11:00
|
|
|
|
2022-01-13 13:29:09 +01:00
|
|
|
if (isc_sockaddr_pf(&query->sockaddr) == AF_INET6 &&
|
2020-09-05 16:37:24 -07:00
|
|
|
IN6_IS_ADDR_V4MAPPED(&query->sockaddr.type.sin6.sin6_addr))
|
|
|
|
{
|
|
|
|
isc_netaddr_t netaddr;
|
|
|
|
char buf[ISC_NETADDR_FORMATSIZE];
|
2015-12-19 09:47:11 +11:00
|
|
|
|
2020-09-05 16:37:24 -07:00
|
|
|
isc_netaddr_fromsockaddr(&netaddr, &query->sockaddr);
|
|
|
|
isc_netaddr_format(&netaddr, buf, sizeof(buf));
|
|
|
|
dighost_warning("Skipping mapped address '%s'", buf);
|
|
|
|
next = ISC_LIST_NEXT(query, link);
|
2020-11-04 12:40:13 +01:00
|
|
|
query_detach(&query);
|
2020-09-05 16:37:24 -07:00
|
|
|
if (next == NULL) {
|
|
|
|
dighost_warning("No acceptable nameservers");
|
2020-11-06 16:12:17 +01:00
|
|
|
clear_current_lookup();
|
2000-09-21 22:46:39 +00:00
|
|
|
} else {
|
2020-09-05 16:37:24 -07:00
|
|
|
start_udp(next);
|
2000-07-18 01:28:20 +00:00
|
|
|
}
|
2020-09-05 16:37:24 -07:00
|
|
|
return;
|
2000-09-21 22:46:39 +00:00
|
|
|
}
|
2019-07-16 23:44:20 -07:00
|
|
|
|
2020-09-05 16:37:24 -07:00
|
|
|
if (!specified_source) {
|
|
|
|
if ((isc_sockaddr_pf(&query->sockaddr) == AF_INET) && have_ipv4)
|
|
|
|
{
|
|
|
|
isc_sockaddr_any(&localaddr);
|
|
|
|
} else {
|
|
|
|
isc_sockaddr_any6(&localaddr);
|
2019-07-16 23:44:20 -07:00
|
|
|
}
|
|
|
|
}
|
2020-09-05 16:37:24 -07:00
|
|
|
|
2021-04-27 12:03:20 +02:00
|
|
|
query_attach(query, &connectquery);
|
2021-05-26 08:15:34 +02:00
|
|
|
isc_nm_udpconnect(netmgr, &localaddr, &query->sockaddr, udp_ready,
|
2021-04-27 12:03:20 +02:00
|
|
|
connectquery,
|
2022-03-23 13:57:15 +01:00
|
|
|
(timeout ? timeout : UDP_TIMEOUT) * 1000);
|
2000-05-02 23:23:12 +00:00
|
|
|
}
|
|
|
|
|
2019-01-08 11:17:39 +01:00
|
|
|
/*%
|
|
|
|
* If there are more servers available for querying within 'lookup', initiate a
|
|
|
|
* TCP or UDP query to the next available server and return true; otherwise,
|
|
|
|
* return false.
|
|
|
|
*/
|
|
|
|
static bool
|
2020-02-13 14:44:37 -08:00
|
|
|
try_next_server(dig_lookup_t *lookup) {
|
2019-01-08 11:17:39 +01:00
|
|
|
dig_query_t *current_query, *next_query;
|
|
|
|
|
|
|
|
current_query = lookup->current_query;
|
|
|
|
if (current_query == NULL || !ISC_LINK_LINKED(current_query, link)) {
|
|
|
|
return (false);
|
|
|
|
}
|
|
|
|
|
|
|
|
next_query = ISC_LIST_NEXT(current_query, link);
|
|
|
|
if (next_query == NULL) {
|
|
|
|
return (false);
|
|
|
|
}
|
|
|
|
|
|
|
|
debug("trying next server...");
|
|
|
|
|
|
|
|
if (lookup->tcp_mode) {
|
2020-09-05 16:37:24 -07:00
|
|
|
start_tcp(next_query);
|
2019-01-08 11:17:39 +01:00
|
|
|
} else {
|
2020-09-05 16:37:24 -07:00
|
|
|
start_udp(next_query);
|
2019-01-08 11:17:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return (true);
|
|
|
|
}
|
|
|
|
|
2000-04-26 18:34:17 +00:00
|
|
|
static void
|
2020-11-02 21:38:56 -08:00
|
|
|
force_next(dig_query_t *query) {
|
2005-10-14 01:14:08 +00:00
|
|
|
dig_lookup_t *l = NULL;
|
2000-04-26 18:34:17 +00:00
|
|
|
|
2020-11-02 21:38:56 -08:00
|
|
|
REQUIRE(DIG_VALID_QUERY(query));
|
2000-04-26 18:34:17 +00:00
|
|
|
|
2020-11-02 21:38:56 -08:00
|
|
|
debug("force_next()");
|
2000-04-29 00:12:56 +00:00
|
|
|
|
2000-07-14 17:57:27 +00:00
|
|
|
LOCK_LOOKUP;
|
2000-07-18 01:28:20 +00:00
|
|
|
INSIST(!free_now);
|
2000-09-21 22:46:39 +00:00
|
|
|
|
2020-11-05 15:22:38 +01:00
|
|
|
if (atomic_load(&cancel_now)) {
|
2018-11-13 13:50:47 +01:00
|
|
|
UNLOCK_LOOKUP;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-11-05 15:22:38 +01:00
|
|
|
lookup_attach(query->lookup, &l);
|
|
|
|
|
2019-01-08 11:17:39 +01:00
|
|
|
if (try_next_server(l)) {
|
2020-11-05 15:22:38 +01:00
|
|
|
lookup_detach(&l);
|
2000-09-21 22:46:39 +00:00
|
|
|
UNLOCK_LOOKUP;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-09-05 16:37:24 -07:00
|
|
|
if (l->retries > 1) {
|
|
|
|
l->retries--;
|
When resending a UDP request, insert the query to the lookup's list
When a query times out, and `dig` (or `host`) creates a new query
to resend the request, it is being prepended to the lookup's queries
list, which can cause a confusion later, making `dig` (or `host`)
believe that there is another new query in the list, but that is
actually the old one, which was timed out. That mistake will result
in an assertion failure.
That can happen, in particular, when after a timed out request,
the retried request returns a SERVFAIL result, and the recursion
is enabled, and `+nofail` option was used with `dig` (that is the
default behavior in `host`, unless the `-s` option is provided).
Fix the problem by inserting the query just after the current,
timed-out query, instead of prepending to the list.
Before calling start_udp() detach `l->current_query`, like it is
done in another place in the function.
Slightly update a couple of debug messages to make them more
consistent.
2022-03-09 19:45:54 +00:00
|
|
|
debug("making new %s request, %d tries left",
|
|
|
|
l->tcp_mode ? "TCP" : "UDP", l->retries);
|
2020-09-05 16:37:24 -07:00
|
|
|
requeue_lookup(l, true);
|
2020-11-05 15:22:38 +01:00
|
|
|
lookup_detach(&l);
|
2020-09-05 16:37:24 -07:00
|
|
|
isc_refcount_decrement0(&recvcount);
|
2020-11-06 16:12:17 +01:00
|
|
|
debug("recvcount=%" PRIuFAST32,
|
|
|
|
isc_refcount_current(&recvcount));
|
2020-11-04 12:40:13 +01:00
|
|
|
query_detach(&query);
|
2020-11-06 16:12:17 +01:00
|
|
|
clear_current_lookup();
|
2020-09-05 16:37:24 -07:00
|
|
|
UNLOCK_LOOKUP;
|
|
|
|
return;
|
2016-12-14 15:42:43 +11:00
|
|
|
}
|
|
|
|
|
2020-09-05 16:37:24 -07:00
|
|
|
if (query->readhandle != NULL) {
|
|
|
|
isc_refcount_decrement0(&recvcount);
|
2020-11-06 16:12:17 +01:00
|
|
|
debug("recvcount=%" PRIuFAST32,
|
|
|
|
isc_refcount_current(&recvcount));
|
2020-09-05 16:37:24 -07:00
|
|
|
}
|
2018-02-15 16:11:52 -08:00
|
|
|
|
2020-09-05 16:37:24 -07:00
|
|
|
if (l->ns_search_only) {
|
|
|
|
isc_netaddr_t netaddr;
|
|
|
|
char buf[ISC_NETADDR_FORMATSIZE];
|
2018-02-15 16:11:52 -08:00
|
|
|
|
2020-09-05 16:37:24 -07:00
|
|
|
isc_netaddr_fromsockaddr(&netaddr, &query->sockaddr);
|
|
|
|
isc_netaddr_format(&netaddr, buf, sizeof(buf));
|
|
|
|
|
|
|
|
dighost_error("no response from %s\n", buf);
|
|
|
|
} else {
|
|
|
|
printf("%s", l->cmdline);
|
|
|
|
dighost_error("connection timed out; "
|
|
|
|
"no servers could be reached\n");
|
2000-07-18 01:28:20 +00:00
|
|
|
}
|
2020-09-05 16:37:24 -07:00
|
|
|
|
|
|
|
if (exitcode < 9) {
|
|
|
|
exitcode = 9;
|
|
|
|
}
|
|
|
|
|
2020-11-04 12:40:13 +01:00
|
|
|
query_detach(&query);
|
2020-09-05 16:37:24 -07:00
|
|
|
cancel_lookup(l);
|
2020-11-05 15:22:38 +01:00
|
|
|
lookup_detach(&l);
|
2020-11-06 16:12:17 +01:00
|
|
|
clear_current_lookup();
|
2000-07-14 17:57:27 +00:00
|
|
|
UNLOCK_LOOKUP;
|
2000-04-26 18:34:17 +00:00
|
|
|
}
|
|
|
|
|
2019-01-18 11:15:19 +01:00
|
|
|
/*%
|
|
|
|
* Called when a peer closes a TCP socket prematurely.
|
|
|
|
*/
|
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
requeue_or_update_exitcode(dig_lookup_t *lookup) {
|
2021-02-15 19:28:50 -03:00
|
|
|
if (lookup->eoferr == 0U && lookup->retries > 1) {
|
|
|
|
--lookup->retries;
|
2019-01-18 11:15:19 +01:00
|
|
|
/*
|
|
|
|
* Peer closed the connection prematurely for the first time
|
|
|
|
* for this lookup. Try again, keeping track of this failure.
|
|
|
|
*/
|
|
|
|
dig_lookup_t *requeued_lookup = requeue_lookup(lookup, true);
|
|
|
|
requeued_lookup->eoferr++;
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* Peer closed the connection prematurely and it happened
|
|
|
|
* previously for this lookup. Indicate an error.
|
|
|
|
*/
|
|
|
|
exitcode = 9;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
2000-07-18 18:51:40 +00:00
|
|
|
* For transfers that involve multiple recvs (XFR's in particular),
|
|
|
|
* launch the next recv.
|
|
|
|
*/
|
2000-04-26 18:34:17 +00:00
|
|
|
static void
|
2020-09-05 16:37:24 -07:00
|
|
|
launch_next_query(dig_query_t *query) {
|
2020-11-04 12:40:13 +01:00
|
|
|
dig_query_t *readquery = NULL;
|
2020-11-02 21:38:56 -08:00
|
|
|
int local_timeout = timeout * 1000;
|
|
|
|
dig_lookup_t *l = NULL;
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_region_t r;
|
2021-09-02 15:39:50 +03:00
|
|
|
bool xfr;
|
2000-04-26 18:34:17 +00:00
|
|
|
|
2020-09-05 16:37:24 -07:00
|
|
|
REQUIRE(DIG_VALID_QUERY(query));
|
2000-07-13 00:32:20 +00:00
|
|
|
INSIST(!free_now);
|
2000-04-29 00:12:56 +00:00
|
|
|
|
2000-07-13 00:32:20 +00:00
|
|
|
debug("launch_next_query()");
|
2000-05-22 22:56:31 +00:00
|
|
|
|
2020-11-05 15:22:38 +01:00
|
|
|
lookup_attach(query->lookup, &l);
|
|
|
|
|
|
|
|
if (!l->pending) {
|
2000-07-05 23:28:32 +00:00
|
|
|
debug("ignoring launch_next_query because !pending");
|
2020-11-04 12:40:13 +01:00
|
|
|
query_detach(&query);
|
2020-11-05 15:22:38 +01:00
|
|
|
lookup_detach(&l);
|
2020-11-06 16:12:17 +01:00
|
|
|
clear_current_lookup();
|
2000-04-26 18:34:17 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-11-04 12:40:13 +01:00
|
|
|
isc_nmhandle_attach(query->handle, &query->readhandle);
|
2020-09-05 16:37:24 -07:00
|
|
|
isc_refcount_increment0(&recvcount);
|
|
|
|
debug("recvcount=%" PRIuFAST32, isc_refcount_current(&recvcount));
|
|
|
|
|
2020-11-02 21:38:56 -08:00
|
|
|
if (local_timeout == 0) {
|
|
|
|
local_timeout = TCP_TIMEOUT * 1000;
|
2020-09-05 16:37:24 -07:00
|
|
|
}
|
|
|
|
|
2020-11-02 21:38:56 -08:00
|
|
|
debug("have local timeout of %d", local_timeout);
|
|
|
|
isc_nmhandle_settimeout(query->handle, local_timeout);
|
|
|
|
|
2021-09-02 15:39:50 +03:00
|
|
|
xfr = query->lookup->rdtype == dns_rdatatype_ixfr ||
|
|
|
|
query->lookup->rdtype == dns_rdatatype_axfr;
|
2021-11-15 17:42:15 +02:00
|
|
|
if (xfr && isc_nm_socket_type(query->handle) == isc_nm_tlsdnssocket &&
|
2021-09-02 15:39:50 +03:00
|
|
|
!isc_nm_xfr_allowed(query->handle))
|
|
|
|
{
|
|
|
|
dighost_error("zone transfers over the "
|
|
|
|
"established TLS connection are not allowed");
|
|
|
|
dighost_error("as the "
|
|
|
|
"connection does not meet the requirements "
|
|
|
|
"enforced by the RFC 9103");
|
|
|
|
isc_refcount_decrement0(&recvcount);
|
|
|
|
isc_nmhandle_detach(&query->readhandle);
|
|
|
|
cancel_lookup(l);
|
|
|
|
lookup_detach(&l);
|
|
|
|
clear_current_lookup();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
Fix query context management issues in dighost.c
For the reference, the _cancel_lookup() function iterates through
the lookup's queries list and detaches them. In the ideal scenario,
that should be the last reference and the query will be destroyed
after that, but it is also possible that we are still expecting a
callback, which also holds a reference (for example, _cancel_lookup()
could have been called from recv_done(), when send_done() was still
not executed).
The start_udp() and start_tcp() functions are currently designed in
slightly different ways: start_udp() creates a new query attachment
`connectquery`, to be called in the callback function, while
start_tcp() does not, which is a bug, but is hidden by the fact
that when the query is being erroneously destroyed prematurely (before
_cancel_lookup() is called) in the result of that, it also gets
de-listed from the lookup's queries' list, so _cancel_lookup() doesn't
even try to detach it.
For better understanding, here's an illustration of the query's
references count changes, and from where it was changed:
UDP
---
1. _new_query() -> refcount = 1 (initial)
2. start_udp() -> refcount = 2 (lookup->current_query)
3. start_udp() -> refcount = 3 (connectquery)
4. udp_ready() -> refcount = 4 (readquery)
5. udp_ready() -> refcount = 5 (sendquery)
6. udp_ready() -> refcount = 4 (lookup->current_query)
7. udp_ready() -> refcount = 3 (connectquery)
8. send_done() -> refcount = 2 (sendquery)
9. recv_done() -> refcount = 1 (readquery)
10. _cancel_lookup() -> refcount = 0 (initial)
11. the query gets destroyed and removed from `lookup->q`
TCP, fortunate scenario
-----------------------
1. _new_query() -> refcount = 1 (initial)
2. start_tcp() -> refcount = 2 (lookup->current_query)
3. launch_next_query() -> refcount = 3 (readquery)
4. launch_next_query() -> refcount = 4 (sendquery)
5. tcp_connected() -> refcount = 3 (lookup->current_query)
6. tcp_connected() -> refcount = 2 (bug, there was no connectquery)
7. send_done() -> refcount = 1 (sendquery)
8. recv_done() -> refcount = 0 (readquery)
9. the query gets prematurely destroyed and removed from `lookup->q`
10. _cancel_lookup() -> the query is not in `lookup->q`
TCP, unfortunate scenario, revealing the bug
--------------------------------------------
1. _new_query() -> refcount = 1 (initial)
2. start_tcp() -> refcount = 2 (lookup->current_query)
3. launch_next_query() -> refcount = 3 (readquery)
4. launch_next_query() -> refcount = 4 (sendquery)
5. tcp_connected() -> refcount = 3 (lookup->current_query)
6. tcp_connected() -> refcount = 2 (bug, there was no connectquery)
7. recv_done() -> refcount = 1 (readquery)
8. _cancel_lookup() -> refcount = 0 (the query was in `lookup->q`)
9. we hit an assertion here when trying to destroy the query, because
sendhandle is not detached (which is done by send_done()).
10. send_done() -> this never happens
This commit does the following:
1. Add a `connectquery` attachment in start_tcp(), like done in
start_udp().
2. Add missing _cancel_lookup() calls for error scenarios, which
were possibly missing because before fixing the bug, calling
_cancel_lookup() and then calling query_detach() would cause
an assertion.
3. Log a debug message and call isc_nm_cancelread(query->readhandle)
for every query in the lookup from inside the _cancel_lookup()
function, like it is done in _cancel_all().
4. Add a `canceled` property for the query which becomes `true` when
the lookup (and subsequently, its queries) are canceled.
5. Use the `canceled` property in the network manager callbacks to
know that the query was canceled, and act like `eresult` was equal
to `ISC_R_CANCELED`.
2022-03-02 00:06:34 +00:00
|
|
|
query_attach(query, &readquery);
|
|
|
|
|
2020-11-04 12:40:13 +01:00
|
|
|
isc_nm_read(query->handle, recv_done, readquery);
|
2020-09-05 16:37:24 -07:00
|
|
|
|
2000-04-29 00:12:56 +00:00
|
|
|
if (!query->first_soa_rcvd) {
|
2020-11-04 12:40:13 +01:00
|
|
|
dig_query_t *sendquery = NULL;
|
2000-07-18 18:51:40 +00:00
|
|
|
debug("sending a request in launch_next_query");
|
2021-03-19 22:50:51 -07:00
|
|
|
if (query->lookup->use_usec) {
|
|
|
|
TIME_NOW_HIRES(&query->time_sent);
|
|
|
|
} else {
|
|
|
|
TIME_NOW(&query->time_sent);
|
|
|
|
}
|
|
|
|
|
2020-11-04 12:40:13 +01:00
|
|
|
query_attach(query, &sendquery);
|
2020-09-05 16:37:24 -07:00
|
|
|
isc_buffer_usedregion(&query->sendbuf, &r);
|
|
|
|
if (keep != NULL) {
|
|
|
|
query->handle = keep;
|
2018-10-29 09:15:42 +00:00
|
|
|
}
|
2020-07-22 08:59:42 +02:00
|
|
|
|
2020-09-05 16:37:24 -07:00
|
|
|
isc_nmhandle_attach(query->handle, &query->sendhandle);
|
2020-11-04 12:40:13 +01:00
|
|
|
isc_nm_send(query->handle, &r, send_done, sendquery);
|
2020-09-05 16:37:24 -07:00
|
|
|
isc_refcount_increment0(&sendcount);
|
|
|
|
debug("sendcount=%" PRIuFAST32,
|
|
|
|
isc_refcount_current(&sendcount));
|
2019-07-16 23:44:20 -07:00
|
|
|
|
|
|
|
/* XXX qrflag, print_query, etc... */
|
2022-03-31 14:33:49 +00:00
|
|
|
if (l->qr) {
|
2019-07-16 23:44:20 -07:00
|
|
|
extrabytes = 0;
|
2022-03-31 14:33:49 +00:00
|
|
|
dighost_printmessage(query, &l->renderbuf, l->sendmsg,
|
|
|
|
true);
|
2020-11-05 15:22:38 +01:00
|
|
|
if (l->stats) {
|
2019-08-30 14:23:29 +10:00
|
|
|
print_query_size(query);
|
2019-07-16 23:44:20 -07:00
|
|
|
}
|
|
|
|
}
|
2000-04-29 00:12:56 +00:00
|
|
|
}
|
2021-01-27 15:49:27 +01:00
|
|
|
|
2020-11-05 15:22:38 +01:00
|
|
|
lookup_detach(&l);
|
2000-04-26 18:34:17 +00:00
|
|
|
return;
|
|
|
|
}
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
2000-07-18 18:51:40 +00:00
|
|
|
* Event handler for TCP connect complete. Make sure the connection was
|
|
|
|
* successful, then pass into launch_next_query to actually send the
|
|
|
|
* question.
|
|
|
|
*/
|
2000-04-26 18:34:17 +00:00
|
|
|
static void
|
2020-09-05 16:37:24 -07:00
|
|
|
tcp_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) {
|
|
|
|
dig_query_t *query = (dig_query_t *)arg;
|
|
|
|
dig_query_t *next = NULL;
|
2020-02-13 14:44:37 -08:00
|
|
|
char sockstr[ISC_SOCKADDR_FORMATSIZE];
|
2020-09-05 16:37:24 -07:00
|
|
|
dig_lookup_t *l = NULL;
|
2000-04-26 18:34:17 +00:00
|
|
|
|
2022-03-20 13:54:39 +00:00
|
|
|
REQUIRE(DIG_VALID_QUERY(query));
|
|
|
|
REQUIRE(query->handle == NULL);
|
|
|
|
|
2020-11-18 13:08:03 -08:00
|
|
|
debug("tcp_connected()");
|
|
|
|
|
2022-03-20 13:54:39 +00:00
|
|
|
query->started = true;
|
|
|
|
|
2020-11-18 13:08:03 -08:00
|
|
|
if (atomic_load(&cancel_now)) {
|
2022-04-10 17:42:49 -07:00
|
|
|
query_detach(&query);
|
2020-11-18 13:08:03 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
INSIST(!free_now);
|
|
|
|
|
|
|
|
debug("tcp_connected(%p, %s, %p)", handle, isc_result_totext(eresult),
|
|
|
|
query);
|
2000-05-25 19:32:11 +00:00
|
|
|
|
2000-07-14 17:57:27 +00:00
|
|
|
LOCK_LOOKUP;
|
2020-11-05 15:22:38 +01:00
|
|
|
lookup_attach(query->lookup, &l);
|
2000-04-26 18:34:17 +00:00
|
|
|
|
2022-01-19 13:10:08 +02:00
|
|
|
if (eresult == ISC_R_CANCELED || eresult == ISC_R_TLSBADPEERCERT ||
|
|
|
|
query->canceled)
|
|
|
|
{
|
2000-09-14 20:11:48 +00:00
|
|
|
debug("in cancel handler");
|
2016-12-14 15:42:43 +11:00
|
|
|
isc_sockaddr_format(&query->sockaddr, sockstr, sizeof(sockstr));
|
2022-01-19 13:10:08 +02:00
|
|
|
if (eresult == ISC_R_TLSBADPEERCERT) {
|
|
|
|
dighost_warning(
|
|
|
|
"TLS peer certificate verification for "
|
|
|
|
"%s failed: %s",
|
|
|
|
sockstr,
|
|
|
|
isc_nm_verify_tls_peer_result_string(handle));
|
|
|
|
} else if (query->lookup->rdtype == dns_rdatatype_ixfr ||
|
|
|
|
query->lookup->rdtype == dns_rdatatype_axfr)
|
|
|
|
{
|
|
|
|
puts("; Transfer failed.");
|
|
|
|
}
|
|
|
|
|
Fix query context management issues in dighost.c
For the reference, the _cancel_lookup() function iterates through
the lookup's queries list and detaches them. In the ideal scenario,
that should be the last reference and the query will be destroyed
after that, but it is also possible that we are still expecting a
callback, which also holds a reference (for example, _cancel_lookup()
could have been called from recv_done(), when send_done() was still
not executed).
The start_udp() and start_tcp() functions are currently designed in
slightly different ways: start_udp() creates a new query attachment
`connectquery`, to be called in the callback function, while
start_tcp() does not, which is a bug, but is hidden by the fact
that when the query is being erroneously destroyed prematurely (before
_cancel_lookup() is called) in the result of that, it also gets
de-listed from the lookup's queries' list, so _cancel_lookup() doesn't
even try to detach it.
For better understanding, here's an illustration of the query's
references count changes, and from where it was changed:
UDP
---
1. _new_query() -> refcount = 1 (initial)
2. start_udp() -> refcount = 2 (lookup->current_query)
3. start_udp() -> refcount = 3 (connectquery)
4. udp_ready() -> refcount = 4 (readquery)
5. udp_ready() -> refcount = 5 (sendquery)
6. udp_ready() -> refcount = 4 (lookup->current_query)
7. udp_ready() -> refcount = 3 (connectquery)
8. send_done() -> refcount = 2 (sendquery)
9. recv_done() -> refcount = 1 (readquery)
10. _cancel_lookup() -> refcount = 0 (initial)
11. the query gets destroyed and removed from `lookup->q`
TCP, fortunate scenario
-----------------------
1. _new_query() -> refcount = 1 (initial)
2. start_tcp() -> refcount = 2 (lookup->current_query)
3. launch_next_query() -> refcount = 3 (readquery)
4. launch_next_query() -> refcount = 4 (sendquery)
5. tcp_connected() -> refcount = 3 (lookup->current_query)
6. tcp_connected() -> refcount = 2 (bug, there was no connectquery)
7. send_done() -> refcount = 1 (sendquery)
8. recv_done() -> refcount = 0 (readquery)
9. the query gets prematurely destroyed and removed from `lookup->q`
10. _cancel_lookup() -> the query is not in `lookup->q`
TCP, unfortunate scenario, revealing the bug
--------------------------------------------
1. _new_query() -> refcount = 1 (initial)
2. start_tcp() -> refcount = 2 (lookup->current_query)
3. launch_next_query() -> refcount = 3 (readquery)
4. launch_next_query() -> refcount = 4 (sendquery)
5. tcp_connected() -> refcount = 3 (lookup->current_query)
6. tcp_connected() -> refcount = 2 (bug, there was no connectquery)
7. recv_done() -> refcount = 1 (readquery)
8. _cancel_lookup() -> refcount = 0 (the query was in `lookup->q`)
9. we hit an assertion here when trying to destroy the query, because
sendhandle is not detached (which is done by send_done()).
10. send_done() -> this never happens
This commit does the following:
1. Add a `connectquery` attachment in start_tcp(), like done in
start_udp().
2. Add missing _cancel_lookup() calls for error scenarios, which
were possibly missing because before fixing the bug, calling
_cancel_lookup() and then calling query_detach() would cause
an assertion.
3. Log a debug message and call isc_nm_cancelread(query->readhandle)
for every query in the lookup from inside the _cancel_lookup()
function, like it is done in _cancel_all().
4. Add a `canceled` property for the query which becomes `true` when
the lookup (and subsequently, its queries) are canceled.
5. Use the `canceled` property in the network manager callbacks to
know that the query was canceled, and act like `eresult` was equal
to `ISC_R_CANCELED`.
2022-03-02 00:06:34 +00:00
|
|
|
if (!query->canceled) {
|
|
|
|
cancel_lookup(l);
|
|
|
|
}
|
2022-01-19 13:10:08 +02:00
|
|
|
|
2020-11-04 12:40:13 +01:00
|
|
|
query_detach(&query);
|
2020-11-05 15:22:38 +01:00
|
|
|
lookup_detach(&l);
|
2020-11-06 16:12:17 +01:00
|
|
|
clear_current_lookup();
|
2000-09-14 20:11:48 +00:00
|
|
|
UNLOCK_LOOKUP;
|
|
|
|
return;
|
2020-09-05 16:37:24 -07:00
|
|
|
} else if (eresult != ISC_R_SUCCESS) {
|
2000-07-13 22:53:51 +00:00
|
|
|
debug("unsuccessful connection: %s",
|
2020-09-05 16:37:24 -07:00
|
|
|
isc_result_totext(eresult));
|
2005-08-25 00:56:08 +00:00
|
|
|
isc_sockaddr_format(&query->sockaddr, sockstr, sizeof(sockstr));
|
Fix query context management issues in dighost.c
For the reference, the _cancel_lookup() function iterates through
the lookup's queries list and detaches them. In the ideal scenario,
that should be the last reference and the query will be destroyed
after that, but it is also possible that we are still expecting a
callback, which also holds a reference (for example, _cancel_lookup()
could have been called from recv_done(), when send_done() was still
not executed).
The start_udp() and start_tcp() functions are currently designed in
slightly different ways: start_udp() creates a new query attachment
`connectquery`, to be called in the callback function, while
start_tcp() does not, which is a bug, but is hidden by the fact
that when the query is being erroneously destroyed prematurely (before
_cancel_lookup() is called) in the result of that, it also gets
de-listed from the lookup's queries' list, so _cancel_lookup() doesn't
even try to detach it.
For better understanding, here's an illustration of the query's
references count changes, and from where it was changed:
UDP
---
1. _new_query() -> refcount = 1 (initial)
2. start_udp() -> refcount = 2 (lookup->current_query)
3. start_udp() -> refcount = 3 (connectquery)
4. udp_ready() -> refcount = 4 (readquery)
5. udp_ready() -> refcount = 5 (sendquery)
6. udp_ready() -> refcount = 4 (lookup->current_query)
7. udp_ready() -> refcount = 3 (connectquery)
8. send_done() -> refcount = 2 (sendquery)
9. recv_done() -> refcount = 1 (readquery)
10. _cancel_lookup() -> refcount = 0 (initial)
11. the query gets destroyed and removed from `lookup->q`
TCP, fortunate scenario
-----------------------
1. _new_query() -> refcount = 1 (initial)
2. start_tcp() -> refcount = 2 (lookup->current_query)
3. launch_next_query() -> refcount = 3 (readquery)
4. launch_next_query() -> refcount = 4 (sendquery)
5. tcp_connected() -> refcount = 3 (lookup->current_query)
6. tcp_connected() -> refcount = 2 (bug, there was no connectquery)
7. send_done() -> refcount = 1 (sendquery)
8. recv_done() -> refcount = 0 (readquery)
9. the query gets prematurely destroyed and removed from `lookup->q`
10. _cancel_lookup() -> the query is not in `lookup->q`
TCP, unfortunate scenario, revealing the bug
--------------------------------------------
1. _new_query() -> refcount = 1 (initial)
2. start_tcp() -> refcount = 2 (lookup->current_query)
3. launch_next_query() -> refcount = 3 (readquery)
4. launch_next_query() -> refcount = 4 (sendquery)
5. tcp_connected() -> refcount = 3 (lookup->current_query)
6. tcp_connected() -> refcount = 2 (bug, there was no connectquery)
7. recv_done() -> refcount = 1 (readquery)
8. _cancel_lookup() -> refcount = 0 (the query was in `lookup->q`)
9. we hit an assertion here when trying to destroy the query, because
sendhandle is not detached (which is done by send_done()).
10. send_done() -> this never happens
This commit does the following:
1. Add a `connectquery` attachment in start_tcp(), like done in
start_udp().
2. Add missing _cancel_lookup() calls for error scenarios, which
were possibly missing because before fixing the bug, calling
_cancel_lookup() and then calling query_detach() would cause
an assertion.
3. Log a debug message and call isc_nm_cancelread(query->readhandle)
for every query in the lookup from inside the _cancel_lookup()
function, like it is done in _cancel_all().
4. Add a `canceled` property for the query which becomes `true` when
the lookup (and subsequently, its queries) are canceled.
5. Use the `canceled` property in the network manager callbacks to
know that the query was canceled, and act like `eresult` was equal
to `ISC_R_CANCELED`.
2022-03-02 00:06:34 +00:00
|
|
|
dighost_warning("Connection to %s(%s) for %s failed: %s.",
|
|
|
|
sockstr, query->servname, l->textname,
|
|
|
|
isc_result_totext(eresult));
|
2020-09-05 16:37:24 -07:00
|
|
|
|
2000-08-01 00:53:20 +00:00
|
|
|
/* XXX Clean up exitcodes */
|
2020-02-13 21:48:23 +01:00
|
|
|
if (exitcode < 9) {
|
2000-05-08 22:51:08 +00:00
|
|
|
exitcode = 9;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2020-09-05 16:37:24 -07:00
|
|
|
|
|
|
|
if (l->retries > 1) {
|
2022-03-11 19:37:27 +00:00
|
|
|
l->retries--;
|
2020-09-05 16:37:24 -07:00
|
|
|
debug("making new TCP request, %d tries left",
|
|
|
|
l->retries);
|
|
|
|
requeue_lookup(l, true);
|
|
|
|
next = NULL;
|
|
|
|
} else if ((l->current_query != NULL) &&
|
|
|
|
(ISC_LINK_LINKED(l->current_query, link)))
|
|
|
|
{
|
2000-09-21 22:46:39 +00:00
|
|
|
next = ISC_LIST_NEXT(l->current_query, link);
|
2020-02-13 21:48:23 +01:00
|
|
|
} else {
|
2000-09-21 22:46:39 +00:00
|
|
|
next = NULL;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2020-09-05 16:37:24 -07:00
|
|
|
|
2020-11-04 12:40:13 +01:00
|
|
|
query_detach(&query);
|
2022-03-13 13:47:16 +00:00
|
|
|
if (next == NULL) {
|
|
|
|
cancel_lookup(l);
|
|
|
|
}
|
2020-11-05 15:22:38 +01:00
|
|
|
lookup_detach(&l);
|
2020-09-05 16:37:24 -07:00
|
|
|
|
2000-09-21 22:46:39 +00:00
|
|
|
if (next != NULL) {
|
2020-09-05 16:37:24 -07:00
|
|
|
start_tcp(next);
|
2020-02-13 21:48:23 +01:00
|
|
|
} else {
|
2020-11-06 16:12:17 +01:00
|
|
|
clear_current_lookup();
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2020-09-05 16:37:24 -07:00
|
|
|
|
2020-11-04 12:40:13 +01:00
|
|
|
check_if_done();
|
2000-07-14 17:57:27 +00:00
|
|
|
UNLOCK_LOOKUP;
|
2000-04-26 18:34:17 +00:00
|
|
|
return;
|
|
|
|
}
|
2020-09-05 16:37:24 -07:00
|
|
|
|
2018-08-24 13:49:45 +02:00
|
|
|
exitcode = 0;
|
2020-09-05 16:37:24 -07:00
|
|
|
|
|
|
|
query->handle = handle;
|
2013-11-07 10:50:01 +11:00
|
|
|
if (keep_open) {
|
2020-09-05 16:37:24 -07:00
|
|
|
keepaddr = query->sockaddr;
|
2020-02-13 21:48:23 +01:00
|
|
|
if (keep != NULL) {
|
2020-09-05 16:37:24 -07:00
|
|
|
isc_nmhandle_detach(&keep);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2020-09-05 16:37:24 -07:00
|
|
|
|
|
|
|
isc_nmhandle_attach(handle, &keep);
|
2013-11-07 10:50:01 +11:00
|
|
|
}
|
2020-09-05 16:37:24 -07:00
|
|
|
|
|
|
|
launch_next_query(query);
|
2020-11-04 12:40:13 +01:00
|
|
|
query_detach(&query);
|
2020-11-05 15:22:38 +01:00
|
|
|
lookup_detach(&l);
|
2000-07-14 17:57:27 +00:00
|
|
|
UNLOCK_LOOKUP;
|
2000-04-26 18:34:17 +00:00
|
|
|
}
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
2000-07-18 18:51:40 +00:00
|
|
|
* Check if the ongoing XFR needs more data before it's complete, using
|
|
|
|
* the semantics of IXFR and AXFR protocols. Much of the complexity of
|
|
|
|
* this routine comes from determining when an IXFR is complete.
|
2018-04-17 08:29:14 -07:00
|
|
|
* false means more data is on the way, and the recv has been issued.
|
2000-06-30 22:53:07 +00:00
|
|
|
*/
|
2018-04-17 08:29:14 -07:00
|
|
|
static bool
|
2020-11-05 15:22:38 +01:00
|
|
|
check_for_more_data(dig_lookup_t *lookup, dig_query_t *query,
|
|
|
|
dns_message_t *msg, isc_sockaddr_t *peer, int len) {
|
2000-06-02 18:45:33 +00:00
|
|
|
dns_rdataset_t *rdataset = NULL;
|
2020-02-13 14:44:37 -08:00
|
|
|
dns_rdata_t rdata = DNS_RDATA_INIT;
|
2000-06-02 18:45:33 +00:00
|
|
|
dns_rdata_soa_t soa;
|
2020-11-05 15:22:38 +01:00
|
|
|
uint32_t ixfr_serial = lookup->ixfr_serial, serial;
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_result_t result;
|
2020-11-05 15:22:38 +01:00
|
|
|
bool ixfr = lookup->rdtype == dns_rdatatype_ixfr;
|
|
|
|
bool axfr = lookup->rdtype == dns_rdatatype_axfr;
|
2000-06-02 18:45:33 +00:00
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (ixfr) {
|
2014-01-06 06:22:30 +11:00
|
|
|
axfr = query->ixfr_axfr;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2014-01-06 06:22:30 +11:00
|
|
|
|
2000-07-05 19:31:26 +00:00
|
|
|
debug("check_for_more_data()");
|
2000-06-02 18:45:33 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* By the time we're in this routine, we know we're doing
|
|
|
|
* either an AXFR or IXFR. If there's no second_rr_type,
|
|
|
|
* then we don't yet know which kind of answer we got back
|
|
|
|
* from the server. Here, we're going to walk through the
|
|
|
|
* rr's in the message, acting as necessary whenever we hit
|
|
|
|
* an SOA rr.
|
|
|
|
*/
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2002-05-29 05:31:05 +00:00
|
|
|
query->msg_count++;
|
2020-09-05 16:37:24 -07:00
|
|
|
query->byte_count += len;
|
2000-06-02 18:45:33 +00:00
|
|
|
result = dns_message_firstname(msg, DNS_SECTION_ANSWER);
|
2000-06-06 22:50:44 +00:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
puts("; Transfer failed.");
|
2018-04-17 08:29:14 -07:00
|
|
|
return (true);
|
2000-06-06 22:50:44 +00:00
|
|
|
}
|
2000-06-02 18:45:33 +00:00
|
|
|
do {
|
2000-08-03 17:43:06 +00:00
|
|
|
dns_name_t *name;
|
|
|
|
name = NULL;
|
2020-02-12 13:59:18 +01:00
|
|
|
dns_message_currentname(msg, DNS_SECTION_ANSWER, &name);
|
|
|
|
for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL;
|
2020-02-13 14:44:37 -08:00
|
|
|
rdataset = ISC_LIST_NEXT(rdataset, link))
|
|
|
|
{
|
2000-06-02 18:45:33 +00:00
|
|
|
result = dns_rdataset_first(rdataset);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2000-06-02 18:45:33 +00:00
|
|
|
continue;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2000-06-02 18:45:33 +00:00
|
|
|
do {
|
2000-07-20 19:41:44 +00:00
|
|
|
query->rr_count++;
|
2000-10-31 03:22:05 +00:00
|
|
|
dns_rdata_reset(&rdata);
|
2000-06-02 18:45:33 +00:00
|
|
|
dns_rdataset_current(rdataset, &rdata);
|
|
|
|
/*
|
|
|
|
* If this is the first rr, make sure
|
|
|
|
* it's an SOA
|
|
|
|
*/
|
|
|
|
if ((!query->first_soa_rcvd) &&
|
|
|
|
(rdata.type != dns_rdatatype_soa)) {
|
|
|
|
puts("; Transfer failed. "
|
2005-08-25 00:56:08 +00:00
|
|
|
"Didn't start with SOA answer.");
|
2018-04-17 08:29:14 -07:00
|
|
|
return (true);
|
2000-06-02 18:45:33 +00:00
|
|
|
}
|
|
|
|
if ((!query->second_rr_rcvd) &&
|
|
|
|
(rdata.type != dns_rdatatype_soa)) {
|
2018-04-17 08:29:14 -07:00
|
|
|
query->second_rr_rcvd = true;
|
2000-06-02 18:45:33 +00:00
|
|
|
query->second_rr_serial = 0;
|
2000-07-05 23:28:32 +00:00
|
|
|
debug("got the second rr as nonsoa");
|
2018-04-17 08:29:14 -07:00
|
|
|
axfr = query->ixfr_axfr = true;
|
2003-07-17 07:42:00 +00:00
|
|
|
goto next_rdata;
|
2000-06-02 18:45:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the record is anything except an SOA
|
|
|
|
* now, just continue on...
|
|
|
|
*/
|
2020-02-13 21:48:23 +01:00
|
|
|
if (rdata.type != dns_rdatatype_soa) {
|
2000-07-05 19:31:26 +00:00
|
|
|
goto next_rdata;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2011-12-01 00:53:58 +00:00
|
|
|
|
2000-06-02 18:45:33 +00:00
|
|
|
/* Now we have an SOA. Work with it. */
|
2000-07-05 23:28:32 +00:00
|
|
|
debug("got an SOA");
|
2008-01-14 23:24:24 +00:00
|
|
|
result = dns_rdata_tostruct(&rdata, &soa, NULL);
|
|
|
|
check_result(result, "dns_rdata_tostruct");
|
2001-07-27 05:26:38 +00:00
|
|
|
serial = soa.serial;
|
|
|
|
dns_rdata_freestruct(&soa);
|
2000-06-02 18:45:33 +00:00
|
|
|
if (!query->first_soa_rcvd) {
|
2018-04-17 08:29:14 -07:00
|
|
|
query->first_soa_rcvd = true;
|
2001-07-27 05:26:38 +00:00
|
|
|
query->first_rr_serial = serial;
|
2011-12-01 00:53:58 +00:00
|
|
|
debug("this is the first serial %u",
|
|
|
|
serial);
|
2020-02-13 14:44:37 -08:00
|
|
|
if (ixfr &&
|
|
|
|
isc_serial_ge(ixfr_serial, serial))
|
|
|
|
{
|
2011-12-01 00:53:58 +00:00
|
|
|
debug("got up to date "
|
|
|
|
"response");
|
2000-08-03 17:43:06 +00:00
|
|
|
goto doexit;
|
2011-12-01 00:53:58 +00:00
|
|
|
}
|
2000-07-05 19:31:26 +00:00
|
|
|
goto next_rdata;
|
2000-06-02 18:45:33 +00:00
|
|
|
}
|
2011-12-01 00:53:58 +00:00
|
|
|
if (axfr) {
|
2000-07-28 21:56:53 +00:00
|
|
|
debug("doing axfr, got second SOA");
|
2000-08-03 17:43:06 +00:00
|
|
|
goto doexit;
|
2000-07-28 21:56:53 +00:00
|
|
|
}
|
2000-06-02 18:45:33 +00:00
|
|
|
if (!query->second_rr_rcvd) {
|
2001-07-27 05:26:38 +00:00
|
|
|
if (query->first_rr_serial == serial) {
|
2000-07-28 21:56:53 +00:00
|
|
|
debug("doing ixfr, got "
|
|
|
|
"empty zone");
|
2000-08-03 17:43:06 +00:00
|
|
|
goto doexit;
|
2000-07-28 21:56:53 +00:00
|
|
|
}
|
2011-12-01 00:53:58 +00:00
|
|
|
debug("this is the second serial %u",
|
|
|
|
serial);
|
2018-04-17 08:29:14 -07:00
|
|
|
query->second_rr_rcvd = true;
|
2001-07-27 05:26:38 +00:00
|
|
|
query->second_rr_serial = serial;
|
2000-07-05 19:31:26 +00:00
|
|
|
goto next_rdata;
|
2000-06-02 18:45:33 +00:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
* If we get to this point, we're doing an
|
|
|
|
* IXFR and have to start really looking
|
|
|
|
* at serial numbers.
|
|
|
|
*/
|
2001-07-27 05:26:38 +00:00
|
|
|
if (query->first_rr_serial == serial) {
|
2000-07-05 23:28:32 +00:00
|
|
|
debug("got a match for ixfr");
|
2000-06-02 18:45:33 +00:00
|
|
|
if (!query->first_repeat_rcvd) {
|
2020-02-12 13:59:18 +01:00
|
|
|
query->first_repeat_rcvd = true;
|
2000-07-05 19:31:26 +00:00
|
|
|
goto next_rdata;
|
2000-06-02 18:45:33 +00:00
|
|
|
}
|
2000-07-05 23:28:32 +00:00
|
|
|
debug("done with ixfr");
|
2000-08-03 17:43:06 +00:00
|
|
|
goto doexit;
|
2000-06-02 18:45:33 +00:00
|
|
|
}
|
2011-12-01 00:53:58 +00:00
|
|
|
debug("meaningless soa %u", serial);
|
2000-07-05 19:31:26 +00:00
|
|
|
next_rdata:
|
2000-06-02 18:45:33 +00:00
|
|
|
result = dns_rdataset_next(rdataset);
|
|
|
|
} while (result == ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
result = dns_message_nextname(msg, DNS_SECTION_ANSWER);
|
|
|
|
} while (result == ISC_R_SUCCESS);
|
2020-11-06 16:12:17 +01:00
|
|
|
isc_nmhandle_detach(&query->readhandle);
|
2020-09-05 16:37:24 -07:00
|
|
|
launch_next_query(query);
|
2020-11-04 12:40:13 +01:00
|
|
|
query_detach(&query);
|
2018-04-17 08:29:14 -07:00
|
|
|
return (false);
|
2020-02-12 13:59:18 +01:00
|
|
|
doexit:
|
2020-09-05 16:37:24 -07:00
|
|
|
dighost_received(len, peer, query);
|
2018-04-17 08:29:14 -07:00
|
|
|
return (true);
|
2000-06-02 18:45:33 +00:00
|
|
|
}
|
2000-04-26 18:34:17 +00:00
|
|
|
|
2014-02-19 12:53:42 +11:00
|
|
|
static void
|
2020-02-12 13:59:18 +01:00
|
|
|
process_cookie(dig_lookup_t *l, dns_message_t *msg, isc_buffer_t *optbuf,
|
2020-02-13 14:44:37 -08:00
|
|
|
size_t optlen) {
|
|
|
|
char bb[256];
|
|
|
|
isc_buffer_t hexbuf;
|
|
|
|
size_t len;
|
2015-07-06 09:44:24 +10:00
|
|
|
const unsigned char *sent;
|
2020-02-13 14:44:37 -08:00
|
|
|
bool copy = true;
|
|
|
|
isc_result_t result;
|
2014-02-19 12:53:42 +11:00
|
|
|
|
2015-07-06 09:44:24 +10:00
|
|
|
if (l->cookie != NULL) {
|
2014-02-19 12:53:42 +11:00
|
|
|
isc_buffer_init(&hexbuf, bb, sizeof(bb));
|
2015-07-06 09:44:24 +10:00
|
|
|
result = isc_hex_decodestring(l->cookie, &hexbuf);
|
2014-02-19 12:53:42 +11:00
|
|
|
check_result(result, "isc_hex_decodestring");
|
2015-07-06 09:44:24 +10:00
|
|
|
sent = isc_buffer_base(&hexbuf);
|
2014-02-19 12:53:42 +11:00
|
|
|
len = isc_buffer_usedlength(&hexbuf);
|
|
|
|
} else {
|
2015-07-06 09:44:24 +10:00
|
|
|
sent = cookie;
|
2014-02-19 12:53:42 +11:00
|
|
|
len = sizeof(cookie);
|
|
|
|
}
|
|
|
|
|
2015-07-06 09:44:24 +10:00
|
|
|
INSIST(msg->cc_ok == 0 && msg->cc_bad == 0);
|
2019-02-06 10:08:47 +11:00
|
|
|
if (len >= 8 && optlen >= 8U) {
|
2015-08-17 18:26:44 -07:00
|
|
|
if (isc_safe_memequal(isc_buffer_current(optbuf), sent, 8)) {
|
2015-07-06 09:44:24 +10:00
|
|
|
msg->cc_ok = 1;
|
2014-02-20 15:55:09 +11:00
|
|
|
} else {
|
2019-08-30 14:23:29 +10:00
|
|
|
dighost_warning("Warning: Client COOKIE mismatch");
|
2015-07-06 09:44:24 +10:00
|
|
|
msg->cc_bad = 1;
|
2018-04-17 08:29:14 -07:00
|
|
|
copy = false;
|
2014-02-20 15:55:09 +11:00
|
|
|
}
|
|
|
|
} else {
|
2019-08-30 14:23:29 +10:00
|
|
|
dighost_warning("Warning: COOKIE bad token (too short)");
|
2015-07-06 09:44:24 +10:00
|
|
|
msg->cc_bad = 1;
|
2018-04-17 08:29:14 -07:00
|
|
|
copy = false;
|
2015-04-06 23:13:35 -07:00
|
|
|
}
|
2015-07-06 09:44:24 +10:00
|
|
|
if (copy) {
|
2015-04-06 23:13:35 -07:00
|
|
|
isc_region_t r;
|
|
|
|
|
|
|
|
r.base = isc_buffer_current(optbuf);
|
|
|
|
r.length = (unsigned int)optlen;
|
2015-07-06 09:44:24 +10:00
|
|
|
isc_buffer_init(&hexbuf, servercookie, sizeof(servercookie));
|
2015-04-06 23:13:35 -07:00
|
|
|
result = isc_hex_totext(&r, 2, "", &hexbuf);
|
|
|
|
check_result(result, "isc_hex_totext");
|
|
|
|
if (isc_buffer_availablelength(&hexbuf) > 0) {
|
|
|
|
isc_buffer_putuint8(&hexbuf, 0);
|
2015-07-06 09:44:24 +10:00
|
|
|
l->cookie = servercookie;
|
2015-04-06 23:13:35 -07:00
|
|
|
}
|
2014-02-20 15:55:09 +11:00
|
|
|
}
|
2014-02-19 23:17:52 +01:00
|
|
|
isc_buffer_forward(optbuf, (unsigned int)optlen);
|
2014-02-19 12:53:42 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
process_opt(dig_lookup_t *l, dns_message_t *msg) {
|
|
|
|
dns_rdata_t rdata;
|
|
|
|
isc_result_t result;
|
|
|
|
isc_buffer_t optbuf;
|
|
|
|
uint16_t optcode, optlen;
|
2014-02-20 15:55:09 +11:00
|
|
|
dns_rdataset_t *opt = msg->opt;
|
2020-02-13 14:44:37 -08:00
|
|
|
bool seen_cookie = false;
|
2014-02-19 12:53:42 +11:00
|
|
|
|
2014-02-19 23:46:31 +00:00
|
|
|
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) {
|
2015-07-06 09:44:24 +10:00
|
|
|
case DNS_OPT_COOKIE:
|
2016-02-27 11:23:50 +11:00
|
|
|
/*
|
|
|
|
* Only process the first cookie option.
|
|
|
|
*/
|
|
|
|
if (seen_cookie) {
|
|
|
|
isc_buffer_forward(&optbuf, optlen);
|
|
|
|
break;
|
|
|
|
}
|
2015-07-06 09:44:24 +10:00
|
|
|
process_cookie(l, msg, &optbuf, optlen);
|
2018-04-17 08:29:14 -07:00
|
|
|
seen_cookie = true;
|
2014-02-19 23:46:31 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
isc_buffer_forward(&optbuf, optlen);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-02-19 12:53:42 +11:00
|
|
|
}
|
|
|
|
|
2014-10-30 23:13:12 +11:00
|
|
|
static int
|
2020-02-13 14:44:37 -08:00
|
|
|
ednsvers(dns_rdataset_t *opt) {
|
2014-10-30 23:13:12 +11:00
|
|
|
return ((opt->ttl >> 16) & 0xff);
|
|
|
|
}
|
2014-02-19 12:53:42 +11:00
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
2000-07-18 18:51:40 +00:00
|
|
|
* Event handler for recv complete. Perform whatever actions are necessary,
|
|
|
|
* based on the specifics of the user's request.
|
|
|
|
*/
|
2000-04-26 18:34:17 +00:00
|
|
|
static void
|
2020-09-05 16:37:24 -07:00
|
|
|
recv_done(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
|
|
|
|
void *arg) {
|
|
|
|
dig_query_t *query = (dig_query_t *)arg;
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_buffer_t b;
|
|
|
|
dns_message_t *msg = NULL;
|
|
|
|
isc_result_t result;
|
2020-11-05 15:22:38 +01:00
|
|
|
dig_lookup_t *n = NULL;
|
|
|
|
dig_lookup_t *l = NULL;
|
2020-02-13 14:44:37 -08:00
|
|
|
bool docancel = false;
|
2020-11-06 16:12:17 +01:00
|
|
|
bool donext = false;
|
2020-02-13 14:44:37 -08:00
|
|
|
bool match = true;
|
|
|
|
bool done_process_opt = false;
|
|
|
|
unsigned int parseflags;
|
|
|
|
dns_messageid_t id;
|
|
|
|
unsigned int msgflags;
|
|
|
|
int newedns;
|
2020-09-05 16:37:24 -07:00
|
|
|
isc_sockaddr_t peer;
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2020-09-05 16:37:24 -07:00
|
|
|
REQUIRE(DIG_VALID_QUERY(query));
|
2021-01-27 15:49:27 +01:00
|
|
|
REQUIRE(query->readhandle != NULL);
|
2000-07-13 00:32:20 +00:00
|
|
|
INSIST(!free_now);
|
2000-04-26 18:34:17 +00:00
|
|
|
|
2020-11-04 12:40:13 +01:00
|
|
|
debug("recv_done(%p, %s, %p, %p)", handle, isc_result_totext(eresult),
|
|
|
|
region, arg);
|
2000-05-25 19:32:11 +00:00
|
|
|
|
2020-11-06 16:12:17 +01:00
|
|
|
LOCK_LOOKUP;
|
|
|
|
|
2020-11-18 13:08:03 -08:00
|
|
|
isc_refcount_decrement0(&recvcount);
|
|
|
|
debug("recvcount=%" PRIuFAST32, isc_refcount_current(&recvcount));
|
|
|
|
|
Fix query context management issues in dighost.c
For the reference, the _cancel_lookup() function iterates through
the lookup's queries list and detaches them. In the ideal scenario,
that should be the last reference and the query will be destroyed
after that, but it is also possible that we are still expecting a
callback, which also holds a reference (for example, _cancel_lookup()
could have been called from recv_done(), when send_done() was still
not executed).
The start_udp() and start_tcp() functions are currently designed in
slightly different ways: start_udp() creates a new query attachment
`connectquery`, to be called in the callback function, while
start_tcp() does not, which is a bug, but is hidden by the fact
that when the query is being erroneously destroyed prematurely (before
_cancel_lookup() is called) in the result of that, it also gets
de-listed from the lookup's queries' list, so _cancel_lookup() doesn't
even try to detach it.
For better understanding, here's an illustration of the query's
references count changes, and from where it was changed:
UDP
---
1. _new_query() -> refcount = 1 (initial)
2. start_udp() -> refcount = 2 (lookup->current_query)
3. start_udp() -> refcount = 3 (connectquery)
4. udp_ready() -> refcount = 4 (readquery)
5. udp_ready() -> refcount = 5 (sendquery)
6. udp_ready() -> refcount = 4 (lookup->current_query)
7. udp_ready() -> refcount = 3 (connectquery)
8. send_done() -> refcount = 2 (sendquery)
9. recv_done() -> refcount = 1 (readquery)
10. _cancel_lookup() -> refcount = 0 (initial)
11. the query gets destroyed and removed from `lookup->q`
TCP, fortunate scenario
-----------------------
1. _new_query() -> refcount = 1 (initial)
2. start_tcp() -> refcount = 2 (lookup->current_query)
3. launch_next_query() -> refcount = 3 (readquery)
4. launch_next_query() -> refcount = 4 (sendquery)
5. tcp_connected() -> refcount = 3 (lookup->current_query)
6. tcp_connected() -> refcount = 2 (bug, there was no connectquery)
7. send_done() -> refcount = 1 (sendquery)
8. recv_done() -> refcount = 0 (readquery)
9. the query gets prematurely destroyed and removed from `lookup->q`
10. _cancel_lookup() -> the query is not in `lookup->q`
TCP, unfortunate scenario, revealing the bug
--------------------------------------------
1. _new_query() -> refcount = 1 (initial)
2. start_tcp() -> refcount = 2 (lookup->current_query)
3. launch_next_query() -> refcount = 3 (readquery)
4. launch_next_query() -> refcount = 4 (sendquery)
5. tcp_connected() -> refcount = 3 (lookup->current_query)
6. tcp_connected() -> refcount = 2 (bug, there was no connectquery)
7. recv_done() -> refcount = 1 (readquery)
8. _cancel_lookup() -> refcount = 0 (the query was in `lookup->q`)
9. we hit an assertion here when trying to destroy the query, because
sendhandle is not detached (which is done by send_done()).
10. send_done() -> this never happens
This commit does the following:
1. Add a `connectquery` attachment in start_tcp(), like done in
start_udp().
2. Add missing _cancel_lookup() calls for error scenarios, which
were possibly missing because before fixing the bug, calling
_cancel_lookup() and then calling query_detach() would cause
an assertion.
3. Log a debug message and call isc_nm_cancelread(query->readhandle)
for every query in the lookup from inside the _cancel_lookup()
function, like it is done in _cancel_all().
4. Add a `canceled` property for the query which becomes `true` when
the lookup (and subsequently, its queries) are canceled.
5. Use the `canceled` property in the network manager callbacks to
know that the query was canceled, and act like `eresult` was equal
to `ISC_R_CANCELED`.
2022-03-02 00:06:34 +00:00
|
|
|
lookup_attach(query->lookup, &l);
|
|
|
|
|
|
|
|
if (eresult == ISC_R_CANCELED || query->canceled) {
|
2020-09-05 16:37:24 -07:00
|
|
|
debug("recv_done: cancel");
|
2021-05-04 14:25:55 +02:00
|
|
|
isc_nmhandle_detach(&query->readhandle);
|
Fix query context management issues in dighost.c
For the reference, the _cancel_lookup() function iterates through
the lookup's queries list and detaches them. In the ideal scenario,
that should be the last reference and the query will be destroyed
after that, but it is also possible that we are still expecting a
callback, which also holds a reference (for example, _cancel_lookup()
could have been called from recv_done(), when send_done() was still
not executed).
The start_udp() and start_tcp() functions are currently designed in
slightly different ways: start_udp() creates a new query attachment
`connectquery`, to be called in the callback function, while
start_tcp() does not, which is a bug, but is hidden by the fact
that when the query is being erroneously destroyed prematurely (before
_cancel_lookup() is called) in the result of that, it also gets
de-listed from the lookup's queries' list, so _cancel_lookup() doesn't
even try to detach it.
For better understanding, here's an illustration of the query's
references count changes, and from where it was changed:
UDP
---
1. _new_query() -> refcount = 1 (initial)
2. start_udp() -> refcount = 2 (lookup->current_query)
3. start_udp() -> refcount = 3 (connectquery)
4. udp_ready() -> refcount = 4 (readquery)
5. udp_ready() -> refcount = 5 (sendquery)
6. udp_ready() -> refcount = 4 (lookup->current_query)
7. udp_ready() -> refcount = 3 (connectquery)
8. send_done() -> refcount = 2 (sendquery)
9. recv_done() -> refcount = 1 (readquery)
10. _cancel_lookup() -> refcount = 0 (initial)
11. the query gets destroyed and removed from `lookup->q`
TCP, fortunate scenario
-----------------------
1. _new_query() -> refcount = 1 (initial)
2. start_tcp() -> refcount = 2 (lookup->current_query)
3. launch_next_query() -> refcount = 3 (readquery)
4. launch_next_query() -> refcount = 4 (sendquery)
5. tcp_connected() -> refcount = 3 (lookup->current_query)
6. tcp_connected() -> refcount = 2 (bug, there was no connectquery)
7. send_done() -> refcount = 1 (sendquery)
8. recv_done() -> refcount = 0 (readquery)
9. the query gets prematurely destroyed and removed from `lookup->q`
10. _cancel_lookup() -> the query is not in `lookup->q`
TCP, unfortunate scenario, revealing the bug
--------------------------------------------
1. _new_query() -> refcount = 1 (initial)
2. start_tcp() -> refcount = 2 (lookup->current_query)
3. launch_next_query() -> refcount = 3 (readquery)
4. launch_next_query() -> refcount = 4 (sendquery)
5. tcp_connected() -> refcount = 3 (lookup->current_query)
6. tcp_connected() -> refcount = 2 (bug, there was no connectquery)
7. recv_done() -> refcount = 1 (readquery)
8. _cancel_lookup() -> refcount = 0 (the query was in `lookup->q`)
9. we hit an assertion here when trying to destroy the query, because
sendhandle is not detached (which is done by send_done()).
10. send_done() -> this never happens
This commit does the following:
1. Add a `connectquery` attachment in start_tcp(), like done in
start_udp().
2. Add missing _cancel_lookup() calls for error scenarios, which
were possibly missing because before fixing the bug, calling
_cancel_lookup() and then calling query_detach() would cause
an assertion.
3. Log a debug message and call isc_nm_cancelread(query->readhandle)
for every query in the lookup from inside the _cancel_lookup()
function, like it is done in _cancel_all().
4. Add a `canceled` property for the query which becomes `true` when
the lookup (and subsequently, its queries) are canceled.
5. Use the `canceled` property in the network manager callbacks to
know that the query was canceled, and act like `eresult` was equal
to `ISC_R_CANCELED`.
2022-03-02 00:06:34 +00:00
|
|
|
if (!query->canceled) {
|
|
|
|
cancel_lookup(l);
|
|
|
|
}
|
2021-05-04 14:25:55 +02:00
|
|
|
query_detach(&query);
|
Fix query context management issues in dighost.c
For the reference, the _cancel_lookup() function iterates through
the lookup's queries list and detaches them. In the ideal scenario,
that should be the last reference and the query will be destroyed
after that, but it is also possible that we are still expecting a
callback, which also holds a reference (for example, _cancel_lookup()
could have been called from recv_done(), when send_done() was still
not executed).
The start_udp() and start_tcp() functions are currently designed in
slightly different ways: start_udp() creates a new query attachment
`connectquery`, to be called in the callback function, while
start_tcp() does not, which is a bug, but is hidden by the fact
that when the query is being erroneously destroyed prematurely (before
_cancel_lookup() is called) in the result of that, it also gets
de-listed from the lookup's queries' list, so _cancel_lookup() doesn't
even try to detach it.
For better understanding, here's an illustration of the query's
references count changes, and from where it was changed:
UDP
---
1. _new_query() -> refcount = 1 (initial)
2. start_udp() -> refcount = 2 (lookup->current_query)
3. start_udp() -> refcount = 3 (connectquery)
4. udp_ready() -> refcount = 4 (readquery)
5. udp_ready() -> refcount = 5 (sendquery)
6. udp_ready() -> refcount = 4 (lookup->current_query)
7. udp_ready() -> refcount = 3 (connectquery)
8. send_done() -> refcount = 2 (sendquery)
9. recv_done() -> refcount = 1 (readquery)
10. _cancel_lookup() -> refcount = 0 (initial)
11. the query gets destroyed and removed from `lookup->q`
TCP, fortunate scenario
-----------------------
1. _new_query() -> refcount = 1 (initial)
2. start_tcp() -> refcount = 2 (lookup->current_query)
3. launch_next_query() -> refcount = 3 (readquery)
4. launch_next_query() -> refcount = 4 (sendquery)
5. tcp_connected() -> refcount = 3 (lookup->current_query)
6. tcp_connected() -> refcount = 2 (bug, there was no connectquery)
7. send_done() -> refcount = 1 (sendquery)
8. recv_done() -> refcount = 0 (readquery)
9. the query gets prematurely destroyed and removed from `lookup->q`
10. _cancel_lookup() -> the query is not in `lookup->q`
TCP, unfortunate scenario, revealing the bug
--------------------------------------------
1. _new_query() -> refcount = 1 (initial)
2. start_tcp() -> refcount = 2 (lookup->current_query)
3. launch_next_query() -> refcount = 3 (readquery)
4. launch_next_query() -> refcount = 4 (sendquery)
5. tcp_connected() -> refcount = 3 (lookup->current_query)
6. tcp_connected() -> refcount = 2 (bug, there was no connectquery)
7. recv_done() -> refcount = 1 (readquery)
8. _cancel_lookup() -> refcount = 0 (the query was in `lookup->q`)
9. we hit an assertion here when trying to destroy the query, because
sendhandle is not detached (which is done by send_done()).
10. send_done() -> this never happens
This commit does the following:
1. Add a `connectquery` attachment in start_tcp(), like done in
start_udp().
2. Add missing _cancel_lookup() calls for error scenarios, which
were possibly missing because before fixing the bug, calling
_cancel_lookup() and then calling query_detach() would cause
an assertion.
3. Log a debug message and call isc_nm_cancelread(query->readhandle)
for every query in the lookup from inside the _cancel_lookup()
function, like it is done in _cancel_all().
4. Add a `canceled` property for the query which becomes `true` when
the lookup (and subsequently, its queries) are canceled.
5. Use the `canceled` property in the network manager callbacks to
know that the query was canceled, and act like `eresult` was equal
to `ISC_R_CANCELED`.
2022-03-02 00:06:34 +00:00
|
|
|
lookup_detach(&l);
|
2022-03-29 13:01:24 +00:00
|
|
|
clear_current_lookup();
|
2022-03-01 12:47:24 +00:00
|
|
|
UNLOCK_LOOKUP;
|
2021-05-04 14:25:55 +02:00
|
|
|
return;
|
2020-09-05 16:37:24 -07:00
|
|
|
}
|
|
|
|
|
2021-03-19 22:50:51 -07:00
|
|
|
if (query->lookup->use_usec) {
|
|
|
|
TIME_NOW_HIRES(&query->time_recv);
|
|
|
|
} else {
|
|
|
|
TIME_NOW(&query->time_recv);
|
|
|
|
}
|
2000-04-29 00:12:56 +00:00
|
|
|
|
2020-11-05 15:22:38 +01:00
|
|
|
if ((!l->pending && !l->ns_search_only) || atomic_load(&cancel_now)) {
|
2020-09-05 16:37:24 -07:00
|
|
|
debug("no longer pending. Got %s", isc_result_totext(eresult));
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2020-11-06 16:12:17 +01:00
|
|
|
goto next_lookup;
|
2000-04-26 18:34:17 +00:00
|
|
|
}
|
2012-10-18 23:46:07 +00:00
|
|
|
|
Fix a crash in dig NS search mode
In special NS search mode, after the initial lookup, dig starts the
followup lookup with discovered NS servers in the queries list. If one
of those queries then fail, dig, as usual, tries to start the next query
in the list, which results in a crash, because the NS search mode is
special in a way that the queries are running in parallel, so the next
query is usually already started.
Apply some special logic in `recv_done()` function to deal with the
described situation when handling the query result for the NS search
mode. Particularly, print a warning message for the failed query,
and do not try to start the next query in the list. Also, set a non-zero
exit code if all the queries in the followup lookup fail.
2022-05-19 20:44:32 +00:00
|
|
|
/*
|
|
|
|
* NSSEARCH mode is special, because the queries in the followup lookup
|
|
|
|
* are independent and they are being started in parallel, so if one of
|
|
|
|
* them fails there is no need to start the next query in the lookup,
|
|
|
|
* and this failure can be treated as a soft error (with a warning
|
|
|
|
* message), because there are usually more than one NS servers in the
|
|
|
|
* lookup's queries list. However, if there was not a single successful
|
|
|
|
* query in the followup lookup, then print an error message and exit
|
|
|
|
* with a non-zero exit code.
|
|
|
|
*/
|
|
|
|
if (l->ns_search_only && !l->trace_root) {
|
|
|
|
if (eresult == ISC_R_SUCCESS) {
|
|
|
|
l->ns_search_success = true;
|
|
|
|
} else {
|
|
|
|
char sockstr[ISC_SOCKADDR_FORMATSIZE];
|
|
|
|
isc_sockaddr_format(&query->sockaddr, sockstr,
|
|
|
|
sizeof(sockstr));
|
|
|
|
|
|
|
|
dighost_warning("communications error to %s: %s",
|
|
|
|
sockstr, isc_result_totext(eresult));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If this is not the last query, then we detach the
|
|
|
|
* query, but keep the lookup running.
|
|
|
|
*/
|
|
|
|
if (!check_if_queries_done(l, query)) {
|
|
|
|
goto detach_query;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is the last query, and if there was not a
|
|
|
|
* single successful query in the whole lookup, then
|
|
|
|
* treat the situation as an error.
|
|
|
|
*/
|
|
|
|
if (!l->ns_search_success) {
|
|
|
|
dighost_error("no NS servers could be reached");
|
|
|
|
if (exitcode < 9) {
|
|
|
|
exitcode = 9;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
goto cancel_lookup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-11 19:37:27 +00:00
|
|
|
if (eresult == ISC_R_TIMEDOUT) {
|
|
|
|
if (l->retries > 1 && !l->tcp_mode) {
|
|
|
|
dig_query_t *newq = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For UDP, insert a copy of the current query just
|
|
|
|
* after itself in the list, and start it to retry the
|
|
|
|
* request.
|
|
|
|
*/
|
|
|
|
newq = new_query(l, query->servname, query->userarg);
|
|
|
|
ISC_LIST_INSERTAFTER(l->q, query, newq, link);
|
|
|
|
if (l->current_query == query) {
|
|
|
|
query_detach(&l->current_query);
|
|
|
|
}
|
|
|
|
if (l->current_query == NULL) {
|
|
|
|
l->retries--;
|
|
|
|
debug("making new UDP request, %d tries left",
|
|
|
|
l->retries);
|
|
|
|
start_udp(newq);
|
|
|
|
}
|
Fix dig hanging issue in cases when the lookup's next query can't start
In recv_done(), when dig decides to start the lookup's next query in
the line using `start_udp()` or `start_tcp()`, and for some reason,
no queries get started, dig doesn't cancel the lookup.
This can occur, for example, when there are two queries in the lookup,
one with a regular IP address, and another with a IPv4 mapped IPv6
address. When the regular IP address fails to serve the query, its
`recv_done()` callback starts the next query in the line (in this
case the one with a mapped IP address), but because `dig` doesn't
connect to such IP addresses, and there are no other queries in the
list, no new queries are being started, and the lookup keeps hanging.
After calling `start_udp()` or `start_tcp()` in `recv_done()`, check
if there are no pending/working queries then cancel the lookup instead
of only detaching from the current query.
2022-04-01 13:12:40 +00:00
|
|
|
if (check_if_queries_done(l, query)) {
|
|
|
|
goto cancel_lookup;
|
|
|
|
}
|
2022-03-11 19:37:27 +00:00
|
|
|
|
|
|
|
goto detach_query;
|
|
|
|
} else if (l->retries > 1 && l->tcp_mode) {
|
|
|
|
/*
|
|
|
|
* For TCP, we have to requeue the whole lookup, see
|
|
|
|
* the comments above the start_tcp() function.
|
|
|
|
*/
|
|
|
|
l->retries--;
|
|
|
|
debug("making new TCP request, %d tries left",
|
|
|
|
l->retries);
|
|
|
|
requeue_lookup(l, true);
|
|
|
|
|
|
|
|
if (keep != NULL) {
|
|
|
|
isc_nmhandle_detach(&keep);
|
|
|
|
}
|
|
|
|
|
|
|
|
goto cancel_lookup;
|
|
|
|
} else {
|
|
|
|
dig_query_t *next = ISC_LIST_NEXT(query, link);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* No retries left, go to the next query, if there is
|
|
|
|
* one.
|
|
|
|
*/
|
|
|
|
if (next != NULL) {
|
|
|
|
if (l->current_query == query) {
|
|
|
|
query_detach(&l->current_query);
|
|
|
|
}
|
|
|
|
if (l->current_query == NULL) {
|
|
|
|
debug("starting next query %p", next);
|
|
|
|
if (l->tcp_mode) {
|
|
|
|
start_tcp(next);
|
|
|
|
} else {
|
|
|
|
start_udp(next);
|
|
|
|
}
|
|
|
|
}
|
Fix dig hanging issue in cases when the lookup's next query can't start
In recv_done(), when dig decides to start the lookup's next query in
the line using `start_udp()` or `start_tcp()`, and for some reason,
no queries get started, dig doesn't cancel the lookup.
This can occur, for example, when there are two queries in the lookup,
one with a regular IP address, and another with a IPv4 mapped IPv6
address. When the regular IP address fails to serve the query, its
`recv_done()` callback starts the next query in the line (in this
case the one with a mapped IP address), but because `dig` doesn't
connect to such IP addresses, and there are no other queries in the
list, no new queries are being started, and the lookup keeps hanging.
After calling `start_udp()` or `start_tcp()` in `recv_done()`, check
if there are no pending/working queries then cancel the lookup instead
of only detaching from the current query.
2022-04-01 13:12:40 +00:00
|
|
|
if (check_if_queries_done(l, query)) {
|
|
|
|
goto cancel_lookup;
|
|
|
|
}
|
|
|
|
|
2022-03-11 19:37:27 +00:00
|
|
|
goto detach_query;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Otherwise, print the cmdline and an error message,
|
|
|
|
* and cancel the lookup.
|
|
|
|
*/
|
|
|
|
printf("%s", l->cmdline);
|
|
|
|
dighost_error("connection timed out; "
|
|
|
|
"no servers could be reached\n");
|
|
|
|
if (exitcode < 9) {
|
|
|
|
exitcode = 9;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (keep != NULL) {
|
|
|
|
isc_nmhandle_detach(&keep);
|
|
|
|
}
|
|
|
|
|
|
|
|
goto cancel_lookup;
|
|
|
|
}
|
|
|
|
} else if (eresult != ISC_R_SUCCESS) {
|
|
|
|
dig_query_t *next = ISC_LIST_NEXT(query, link);
|
2020-09-05 16:37:24 -07:00
|
|
|
char sockstr[ISC_SOCKADDR_FORMATSIZE];
|
|
|
|
isc_sockaddr_format(&query->sockaddr, sockstr, sizeof(sockstr));
|
|
|
|
|
2022-03-11 19:37:27 +00:00
|
|
|
/*
|
|
|
|
* There was a communication error with the current query,
|
|
|
|
* go to the next query, if there is one.
|
|
|
|
*/
|
|
|
|
if (next != NULL) {
|
|
|
|
if (l->current_query == query) {
|
|
|
|
query_detach(&l->current_query);
|
|
|
|
}
|
|
|
|
if (l->current_query == NULL) {
|
|
|
|
debug("starting next query %p", next);
|
|
|
|
if (l->tcp_mode) {
|
|
|
|
start_tcp(next);
|
|
|
|
} else {
|
|
|
|
start_udp(next);
|
2020-11-02 21:38:56 -08:00
|
|
|
}
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
Fix dig hanging issue in cases when the lookup's next query can't start
In recv_done(), when dig decides to start the lookup's next query in
the line using `start_udp()` or `start_tcp()`, and for some reason,
no queries get started, dig doesn't cancel the lookup.
This can occur, for example, when there are two queries in the lookup,
one with a regular IP address, and another with a IPv4 mapped IPv6
address. When the regular IP address fails to serve the query, its
`recv_done()` callback starts the next query in the line (in this
case the one with a mapped IP address), but because `dig` doesn't
connect to such IP addresses, and there are no other queries in the
list, no new queries are being started, and the lookup keeps hanging.
After calling `start_udp()` or `start_tcp()` in `recv_done()`, check
if there are no pending/working queries then cancel the lookup instead
of only detaching from the current query.
2022-04-01 13:12:40 +00:00
|
|
|
if (check_if_queries_done(l, query)) {
|
|
|
|
goto cancel_lookup;
|
|
|
|
}
|
|
|
|
|
2022-03-11 19:37:27 +00:00
|
|
|
goto detach_query;
|
2020-09-05 16:37:24 -07:00
|
|
|
}
|
|
|
|
|
2022-03-11 19:37:27 +00:00
|
|
|
/*
|
|
|
|
* Otherwise, print an error message and cancel the
|
|
|
|
* lookup.
|
|
|
|
*/
|
|
|
|
dighost_error("communications error to %s: %s\n", sockstr,
|
|
|
|
isc_result_totext(eresult));
|
|
|
|
|
2020-09-05 16:37:24 -07:00
|
|
|
if (keep != NULL) {
|
|
|
|
isc_nmhandle_detach(&keep);
|
2001-07-27 22:07:10 +00:00
|
|
|
}
|
2020-09-05 16:37:24 -07:00
|
|
|
|
|
|
|
if (eresult == ISC_R_EOF) {
|
2019-01-18 11:15:19 +01:00
|
|
|
requeue_or_update_exitcode(l);
|
2022-04-08 00:33:24 -07:00
|
|
|
} else if (exitcode < 9) {
|
|
|
|
exitcode = 9;
|
2017-10-05 09:42:31 +02:00
|
|
|
}
|
2020-09-05 16:37:24 -07:00
|
|
|
|
2020-11-06 16:12:17 +01:00
|
|
|
goto cancel_lookup;
|
2001-07-27 22:07:10 +00:00
|
|
|
}
|
|
|
|
|
2020-09-05 16:37:24 -07:00
|
|
|
isc_buffer_init(&b, region->base, region->length);
|
|
|
|
isc_buffer_add(&b, region->length);
|
|
|
|
|
|
|
|
peer = isc_nmhandle_peeraddr(handle);
|
2002-04-19 04:06:53 +00:00
|
|
|
|
2018-10-29 09:15:42 +00:00
|
|
|
result = dns_message_peekheader(&b, &id, &msgflags);
|
2002-02-21 04:48:00 +00:00
|
|
|
if (result != ISC_R_SUCCESS || l->sendmsg->id != id) {
|
2018-04-17 08:29:14 -07:00
|
|
|
match = false;
|
2002-02-21 04:48:00 +00:00
|
|
|
if (l->tcp_mode) {
|
2018-04-17 08:29:14 -07:00
|
|
|
bool fail = true;
|
2003-07-17 07:42:00 +00:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
2020-02-13 14:44:37 -08:00
|
|
|
if ((!query->first_soa_rcvd || query->warn_id))
|
|
|
|
{
|
2019-08-30 14:23:29 +10:00
|
|
|
dighost_warning("%s: ID mismatch: "
|
|
|
|
"expected ID %u, got "
|
|
|
|
"%u",
|
2020-02-12 13:59:18 +01:00
|
|
|
query->first_soa_rcvd
|
|
|
|
? "WARNING"
|
|
|
|
: "ERROR",
|
2019-08-30 14:23:29 +10:00
|
|
|
l->sendmsg->id, id);
|
|
|
|
}
|
2020-02-13 21:48:23 +01:00
|
|
|
if (query->first_soa_rcvd) {
|
2018-04-17 08:29:14 -07:00
|
|
|
fail = false;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2018-04-17 08:29:14 -07:00
|
|
|
query->warn_id = false;
|
2019-08-30 14:23:29 +10:00
|
|
|
} else {
|
|
|
|
dighost_warning("ERROR: short (< header size) "
|
|
|
|
"message");
|
|
|
|
}
|
2003-07-17 07:42:00 +00:00
|
|
|
if (fail) {
|
2020-11-06 16:12:17 +01:00
|
|
|
goto cancel_lookup;
|
2003-07-17 07:42:00 +00:00
|
|
|
}
|
2018-04-17 08:29:14 -07:00
|
|
|
match = true;
|
2019-08-30 14:23:29 +10:00
|
|
|
} else if (result == ISC_R_SUCCESS) {
|
|
|
|
dighost_warning("Warning: ID mismatch: expected ID %u,"
|
2020-02-12 13:59:18 +01:00
|
|
|
" got %u",
|
|
|
|
l->sendmsg->id, id);
|
2019-08-30 14:23:29 +10:00
|
|
|
} else {
|
|
|
|
dighost_warning("Warning: short (< header size) "
|
|
|
|
"message received");
|
|
|
|
}
|
2002-04-19 04:06:53 +00:00
|
|
|
}
|
|
|
|
|
2019-08-30 14:23:29 +10:00
|
|
|
if (result == ISC_R_SUCCESS && (msgflags & DNS_MESSAGEFLAG_QR) == 0) {
|
|
|
|
dighost_warning("Warning: query response not set");
|
|
|
|
}
|
2006-01-06 00:54:21 +00:00
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (!match) {
|
2020-11-04 12:40:13 +01:00
|
|
|
/*
|
|
|
|
* We are still attached to query and the query->readhandle is
|
|
|
|
* also attached
|
|
|
|
*/
|
2020-09-05 16:37:24 -07:00
|
|
|
isc_refcount_increment0(&recvcount);
|
2020-11-06 16:12:17 +01:00
|
|
|
debug("recvcount=%" PRIuFAST32,
|
|
|
|
isc_refcount_current(&recvcount));
|
2020-09-05 16:37:24 -07:00
|
|
|
isc_nm_read(handle, recv_done, query);
|
2020-11-06 16:12:17 +01:00
|
|
|
goto keep_query;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2002-02-21 04:48:00 +00:00
|
|
|
|
2020-09-25 11:51:36 +02:00
|
|
|
dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &msg);
|
2001-07-27 22:07:10 +00:00
|
|
|
|
2018-03-19 22:16:10 +00:00
|
|
|
if (tsigkey != NULL) {
|
2001-07-27 22:07:10 +00:00
|
|
|
if (l->querysig == NULL) {
|
|
|
|
debug("getting initial querysig");
|
|
|
|
result = dns_message_getquerytsig(l->sendmsg, mctx,
|
|
|
|
&l->querysig);
|
|
|
|
check_result(result, "dns_message_getquerytsig");
|
|
|
|
}
|
|
|
|
result = dns_message_setquerytsig(msg, l->querysig);
|
|
|
|
check_result(result, "dns_message_setquerytsig");
|
2018-03-19 22:16:10 +00:00
|
|
|
result = dns_message_settsigkey(msg, tsigkey);
|
2001-07-27 22:07:10 +00:00
|
|
|
check_result(result, "dns_message_settsigkey");
|
|
|
|
msg->tsigctx = l->tsigctx;
|
2001-09-11 22:34:21 +00:00
|
|
|
l->tsigctx = NULL;
|
2020-02-13 21:48:23 +01:00
|
|
|
if (l->msgcounter != 0) {
|
2001-07-27 22:07:10 +00:00
|
|
|
msg->tcp_continuation = 1;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-07-27 22:07:10 +00:00
|
|
|
l->msgcounter++;
|
|
|
|
}
|
2001-07-28 00:11:15 +00:00
|
|
|
|
2001-07-27 22:07:10 +00:00
|
|
|
debug("before parse starts");
|
2019-07-25 20:26:13 +10:00
|
|
|
parseflags = l->dns64prefix ? 0 : DNS_MESSAGEPARSE_PRESERVEORDER;
|
2002-02-12 02:10:33 +00:00
|
|
|
if (l->besteffort) {
|
2001-07-27 22:07:10 +00:00
|
|
|
parseflags |= DNS_MESSAGEPARSE_BESTEFFORT;
|
2002-02-12 02:10:33 +00:00
|
|
|
parseflags |= DNS_MESSAGEPARSE_IGNORETRUNCATION;
|
|
|
|
}
|
2020-09-05 16:37:24 -07:00
|
|
|
|
2018-10-29 09:15:42 +00:00
|
|
|
result = dns_message_parse(msg, &b, parseflags);
|
2001-07-27 22:07:10 +00:00
|
|
|
if (result == DNS_R_RECOVERABLE) {
|
2019-08-30 14:23:29 +10:00
|
|
|
dighost_warning("Warning: Message parser reports malformed "
|
|
|
|
"message packet.");
|
2020-09-05 16:37:24 -07:00
|
|
|
} else if (result != ISC_R_SUCCESS) {
|
2019-08-30 14:23:29 +10:00
|
|
|
if (!yaml) {
|
|
|
|
printf(";; Got bad packet: %s\n",
|
|
|
|
isc_result_totext(result));
|
|
|
|
hex_dump(&b);
|
|
|
|
}
|
2020-11-06 16:12:17 +01:00
|
|
|
goto cancel_lookup;
|
2001-07-27 22:07:10 +00:00
|
|
|
}
|
2020-09-05 16:37:24 -07:00
|
|
|
|
2020-03-11 13:55:14 +11:00
|
|
|
if (msg->opcode != l->opcode) {
|
|
|
|
char expect[20] = { 0 }, got[20] = { 0 };
|
|
|
|
|
|
|
|
isc_buffer_init(&b, &expect, sizeof(expect));
|
|
|
|
result = dns_opcode_totext(l->opcode, &b);
|
|
|
|
check_result(result, "dns_opcode_totext");
|
|
|
|
|
|
|
|
isc_buffer_init(&b, &got, sizeof(got));
|
|
|
|
result = dns_opcode_totext(msg->opcode, &b);
|
|
|
|
check_result(result, "dns_opcode_totext");
|
|
|
|
|
|
|
|
dighost_warning("Warning: Opcode mismatch: expected %s, got %s",
|
|
|
|
expect, got);
|
2020-11-05 15:22:38 +01:00
|
|
|
|
|
|
|
isc_refcount_increment0(&recvcount);
|
2020-11-06 16:12:17 +01:00
|
|
|
debug("recvcount=%" PRIuFAST32,
|
|
|
|
isc_refcount_current(&recvcount));
|
2020-11-05 15:22:38 +01:00
|
|
|
isc_nm_read(handle, recv_done, query);
|
2020-11-06 16:12:17 +01:00
|
|
|
goto keep_query;
|
2020-03-11 13:55:14 +11:00
|
|
|
}
|
2020-09-05 16:37:24 -07:00
|
|
|
|
2009-01-20 04:39:29 +00:00
|
|
|
if (msg->counts[DNS_SECTION_QUESTION] != 0) {
|
2018-04-17 08:29:14 -07:00
|
|
|
match = true;
|
2009-01-20 04:39:29 +00:00
|
|
|
for (result = dns_message_firstname(msg, DNS_SECTION_QUESTION);
|
|
|
|
result == ISC_R_SUCCESS && match;
|
2020-02-13 14:44:37 -08:00
|
|
|
result = dns_message_nextname(msg, DNS_SECTION_QUESTION))
|
|
|
|
{
|
|
|
|
dns_name_t *name = NULL;
|
2009-01-20 04:39:29 +00:00
|
|
|
dns_rdataset_t *rdataset;
|
|
|
|
|
|
|
|
dns_message_currentname(msg, DNS_SECTION_QUESTION,
|
|
|
|
&name);
|
|
|
|
for (rdataset = ISC_LIST_HEAD(name->list);
|
|
|
|
rdataset != NULL;
|
2020-02-13 14:44:37 -08:00
|
|
|
rdataset = ISC_LIST_NEXT(rdataset, link))
|
|
|
|
{
|
2009-01-20 04:39:29 +00:00
|
|
|
if (l->rdtype != rdataset->type ||
|
|
|
|
l->rdclass != rdataset->rdclass ||
|
2020-02-13 14:44:37 -08:00
|
|
|
!dns_name_equal(l->name, name))
|
|
|
|
{
|
2009-01-20 04:39:29 +00:00
|
|
|
char namestr[DNS_NAME_FORMATSIZE];
|
|
|
|
char typebuf[DNS_RDATATYPE_FORMATSIZE];
|
|
|
|
char classbuf[DNS_RDATACLASS_FORMATSIZE];
|
|
|
|
dns_name_format(name, namestr,
|
|
|
|
sizeof(namestr));
|
|
|
|
dns_rdatatype_format(rdataset->type,
|
|
|
|
typebuf,
|
|
|
|
sizeof(typebuf));
|
|
|
|
dns_rdataclass_format(rdataset->rdclass,
|
|
|
|
classbuf,
|
|
|
|
sizeof(classbuf));
|
2019-08-30 14:23:29 +10:00
|
|
|
dighost_warning(";; Question section "
|
|
|
|
"mismatch: got "
|
2020-02-12 13:59:18 +01:00
|
|
|
"%s/%s/%s",
|
|
|
|
namestr, typebuf,
|
|
|
|
classbuf);
|
2018-04-17 08:29:14 -07:00
|
|
|
match = false;
|
2009-01-20 04:39:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-09-05 16:37:24 -07:00
|
|
|
|
2009-01-20 04:39:29 +00:00
|
|
|
if (!match) {
|
|
|
|
if (l->tcp_mode) {
|
2020-11-06 16:12:17 +01:00
|
|
|
goto cancel_lookup;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2020-11-05 15:22:38 +01:00
|
|
|
|
2020-11-06 16:12:17 +01:00
|
|
|
/*
|
|
|
|
* We are still attached to query and the
|
|
|
|
* query->readhandle is also attached
|
|
|
|
*/
|
2020-11-05 15:22:38 +01:00
|
|
|
isc_refcount_increment0(&recvcount);
|
2020-11-06 16:12:17 +01:00
|
|
|
debug("recvcount=%" PRIuFAST32,
|
|
|
|
isc_refcount_current(&recvcount));
|
2020-11-05 15:22:38 +01:00
|
|
|
isc_nm_read(handle, recv_done, query);
|
2020-11-06 16:12:17 +01:00
|
|
|
goto keep_query;
|
2009-01-20 04:39:29 +00:00
|
|
|
}
|
|
|
|
}
|
2020-09-05 16:37:24 -07:00
|
|
|
|
2014-10-30 23:13:12 +11:00
|
|
|
if (msg->rcode == dns_rcode_badvers && msg->opt != NULL &&
|
2020-02-13 14:44:37 -08:00
|
|
|
(newedns = ednsvers(msg->opt)) < l->edns && l->ednsneg)
|
|
|
|
{
|
2014-10-30 23:13:12 +11:00
|
|
|
/*
|
|
|
|
* Add minimum EDNS version required checks here if needed.
|
|
|
|
*/
|
2019-08-30 14:23:29 +10:00
|
|
|
dighost_comments(l, "BADVERS, retrying with EDNS version %u.",
|
|
|
|
(unsigned int)newedns);
|
2014-10-30 23:13:12 +11:00
|
|
|
l->edns = newedns;
|
2018-04-17 08:29:14 -07:00
|
|
|
n = requeue_lookup(l, true);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (l->trace && l->trace_root) {
|
2015-09-12 09:04:37 +10:00
|
|
|
n->rdtype = l->qrdtype;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2020-11-06 16:12:17 +01:00
|
|
|
goto cancel_lookup;
|
2014-10-30 23:13:12 +11:00
|
|
|
}
|
2020-09-05 16:37:24 -07:00
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0 && !l->ignore &&
|
|
|
|
!l->tcp_mode) {
|
2020-02-13 21:48:23 +01:00
|
|
|
if (l->cookie == NULL && l->sendcookie && msg->opt != NULL) {
|
2015-04-06 23:13:35 -07:00
|
|
|
process_opt(l, msg);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2019-08-30 14:23:29 +10:00
|
|
|
dighost_comments(l, "Truncated, retrying in TCP mode.");
|
2018-04-17 08:29:14 -07:00
|
|
|
n = requeue_lookup(l, true);
|
|
|
|
n->tcp_mode = true;
|
2020-02-13 21:48:23 +01:00
|
|
|
if (l->trace && l->trace_root) {
|
2015-09-12 09:04:37 +10:00
|
|
|
n->rdtype = l->qrdtype;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2020-11-06 16:12:17 +01:00
|
|
|
goto cancel_lookup;
|
2008-01-18 23:46:58 +00:00
|
|
|
}
|
2020-09-05 16:37:24 -07:00
|
|
|
|
2015-07-06 09:44:24 +10:00
|
|
|
if (msg->rcode == dns_rcode_badcookie && !l->tcp_mode &&
|
2020-02-13 14:44:37 -08:00
|
|
|
l->sendcookie && l->badcookie)
|
|
|
|
{
|
2015-07-06 09:44:24 +10:00
|
|
|
process_opt(l, msg);
|
|
|
|
if (msg->cc_ok) {
|
2020-12-01 15:10:32 +11:00
|
|
|
if (l->showbadcookie) {
|
|
|
|
dighost_printmessage(query, &b, msg, true);
|
|
|
|
dighost_received(isc_buffer_usedlength(&b),
|
|
|
|
&peer, query);
|
|
|
|
}
|
2019-08-30 14:23:29 +10:00
|
|
|
dighost_comments(l, "BADCOOKIE, retrying%s.",
|
2020-02-12 13:59:18 +01:00
|
|
|
l->seenbadcookie ? " in TCP mode"
|
|
|
|
: "");
|
2018-04-17 08:29:14 -07:00
|
|
|
n = requeue_lookup(l, true);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (l->seenbadcookie) {
|
2018-04-17 08:29:14 -07:00
|
|
|
n->tcp_mode = true;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2018-04-17 08:29:14 -07:00
|
|
|
n->seenbadcookie = true;
|
2020-02-13 21:48:23 +01:00
|
|
|
if (l->trace && l->trace_root) {
|
2015-09-12 09:04:37 +10:00
|
|
|
n->rdtype = l->qrdtype;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2020-11-06 16:12:17 +01:00
|
|
|
goto cancel_lookup;
|
2015-07-06 09:44:24 +10:00
|
|
|
}
|
2019-02-06 10:08:47 +11:00
|
|
|
done_process_opt = true;
|
2015-07-06 09:44:24 +10:00
|
|
|
}
|
2020-09-05 16:37:24 -07:00
|
|
|
|
2005-08-25 00:40:50 +00:00
|
|
|
if ((msg->rcode == dns_rcode_servfail && !l->servfail_stops) ||
|
2020-02-13 14:44:37 -08:00
|
|
|
(check_ra && (msg->flags & DNS_MESSAGEFLAG_RA) == 0 && l->recurse))
|
|
|
|
{
|
2001-07-27 22:07:10 +00:00
|
|
|
dig_query_t *next = ISC_LIST_NEXT(query, link);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (l->current_query == query) {
|
2020-11-05 15:22:38 +01:00
|
|
|
query_detach(&l->current_query);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-07-27 22:07:10 +00:00
|
|
|
if (next != NULL) {
|
2020-11-04 12:40:13 +01:00
|
|
|
debug("sending query %p", next);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (l->tcp_mode) {
|
2020-09-05 16:37:24 -07:00
|
|
|
start_tcp(next);
|
2020-02-13 21:48:23 +01:00
|
|
|
} else {
|
2020-09-05 16:37:24 -07:00
|
|
|
start_udp(next);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2020-02-12 13:59:18 +01:00
|
|
|
dighost_comments(l,
|
|
|
|
"Got %s from %s, trying next "
|
2019-08-30 14:23:29 +10:00
|
|
|
"server",
|
2020-02-12 13:59:18 +01:00
|
|
|
msg->rcode == dns_rcode_servfail
|
|
|
|
? "SERVFAIL reply"
|
|
|
|
: "recursion not available",
|
2019-08-30 14:23:29 +10:00
|
|
|
query->servname);
|
Fix dig hanging issue in cases when the lookup's next query can't start
In recv_done(), when dig decides to start the lookup's next query in
the line using `start_udp()` or `start_tcp()`, and for some reason,
no queries get started, dig doesn't cancel the lookup.
This can occur, for example, when there are two queries in the lookup,
one with a regular IP address, and another with a IPv4 mapped IPv6
address. When the regular IP address fails to serve the query, its
`recv_done()` callback starts the next query in the line (in this
case the one with a mapped IP address), but because `dig` doesn't
connect to such IP addresses, and there are no other queries in the
list, no new queries are being started, and the lookup keeps hanging.
After calling `start_udp()` or `start_tcp()` in `recv_done()`, check
if there are no pending/working queries then cancel the lookup instead
of only detaching from the current query.
2022-04-01 13:12:40 +00:00
|
|
|
if (check_if_queries_done(l, query)) {
|
|
|
|
goto cancel_lookup;
|
|
|
|
}
|
|
|
|
|
2022-03-10 17:30:34 +00:00
|
|
|
goto detach_query;
|
2000-09-25 23:10:00 +00:00
|
|
|
}
|
2001-07-27 22:07:10 +00:00
|
|
|
}
|
2000-09-11 19:38:22 +00:00
|
|
|
|
2018-03-19 22:16:10 +00:00
|
|
|
if (tsigkey != NULL) {
|
2018-10-29 09:15:42 +00:00
|
|
|
result = dns_tsig_verify(&b, msg, NULL, NULL);
|
2001-07-27 22:07:10 +00:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2019-08-30 14:23:29 +10:00
|
|
|
dighost_warning("Couldn't verify signature: %s",
|
|
|
|
isc_result_totext(result));
|
2018-04-17 08:29:14 -07:00
|
|
|
validated = false;
|
2000-06-06 18:49:06 +00:00
|
|
|
}
|
2001-07-27 22:07:10 +00:00
|
|
|
l->tsigctx = msg->tsigctx;
|
2001-09-11 22:34:21 +00:00
|
|
|
msg->tsigctx = NULL;
|
2001-07-27 22:07:10 +00:00
|
|
|
if (l->querysig != NULL) {
|
|
|
|
debug("freeing querysig buffer %p", l->querysig);
|
|
|
|
isc_buffer_free(&l->querysig);
|
|
|
|
}
|
|
|
|
result = dns_message_getquerytsig(msg, mctx, &l->querysig);
|
2020-02-12 13:59:18 +01:00
|
|
|
check_result(result, "dns_message_getquerytsig");
|
2001-07-27 22:07:10 +00:00
|
|
|
}
|
|
|
|
|
2018-10-29 09:15:42 +00:00
|
|
|
extrabytes = isc_buffer_remaininglength(&b);
|
2005-07-04 03:03:21 +00:00
|
|
|
|
2001-07-27 22:07:10 +00:00
|
|
|
debug("after parse");
|
2001-07-28 00:11:15 +00:00
|
|
|
if (l->doing_xfr && l->xfr_q == NULL) {
|
2001-07-27 22:07:10 +00:00
|
|
|
l->xfr_q = query;
|
|
|
|
/*
|
|
|
|
* Once we are in the XFR message, increase
|
|
|
|
* the timeout to much longer, so brief network
|
|
|
|
* outages won't cause the XFR to abort
|
|
|
|
*/
|
2016-12-14 15:42:43 +11:00
|
|
|
if (timeout != INT_MAX && query->timer != NULL) {
|
2001-07-28 00:11:15 +00:00
|
|
|
unsigned int local_timeout;
|
|
|
|
|
2001-07-27 22:07:10 +00:00
|
|
|
if (timeout == 0) {
|
2020-02-13 21:48:23 +01:00
|
|
|
if (l->tcp_mode) {
|
2020-11-02 21:38:56 -08:00
|
|
|
local_timeout = TCP_TIMEOUT * 4000;
|
2020-02-13 21:48:23 +01:00
|
|
|
} else {
|
2020-11-02 21:38:56 -08:00
|
|
|
local_timeout = UDP_TIMEOUT * 4000;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-07-27 22:07:10 +00:00
|
|
|
} else {
|
2020-02-13 21:48:23 +01:00
|
|
|
if (timeout < (INT_MAX / 4)) {
|
2020-11-02 21:38:56 -08:00
|
|
|
local_timeout = timeout * 4000;
|
2020-02-13 21:48:23 +01:00
|
|
|
} else {
|
2001-07-27 22:07:10 +00:00
|
|
|
local_timeout = INT_MAX;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2000-07-10 17:25:59 +00:00
|
|
|
}
|
2020-11-02 21:38:56 -08:00
|
|
|
|
2001-07-27 22:07:10 +00:00
|
|
|
debug("have local timeout of %d", local_timeout);
|
2020-11-02 21:38:56 -08:00
|
|
|
isc_nmhandle_settimeout(query->handle, local_timeout);
|
2000-07-10 17:25:59 +00:00
|
|
|
}
|
2001-07-27 22:07:10 +00:00
|
|
|
}
|
2001-07-28 00:11:15 +00:00
|
|
|
|
2019-02-06 10:08:47 +11:00
|
|
|
if (!done_process_opt) {
|
|
|
|
if (l->cookie != NULL) {
|
|
|
|
if (msg->opt == NULL) {
|
2019-08-30 14:23:29 +10:00
|
|
|
dighost_warning("expected opt record in "
|
|
|
|
"response");
|
2019-02-06 10:08:47 +11:00
|
|
|
} else {
|
|
|
|
process_opt(l, msg);
|
|
|
|
}
|
|
|
|
} else if (l->sendcookie && msg->opt != NULL) {
|
2014-02-20 15:55:09 +11:00
|
|
|
process_opt(l, msg);
|
2019-02-06 10:08:47 +11:00
|
|
|
}
|
|
|
|
}
|
2020-09-05 16:37:24 -07:00
|
|
|
|
2001-07-28 00:11:15 +00:00
|
|
|
if (!l->doing_xfr || l->xfr_q == query) {
|
2013-09-04 13:24:11 +10:00
|
|
|
if (msg->rcode == dns_rcode_nxdomain &&
|
2006-12-07 05:52:16 +00:00
|
|
|
(l->origin != NULL || l->need_search)) {
|
2020-11-05 15:22:38 +01:00
|
|
|
if (!next_origin(l) || showsearch) {
|
2019-07-16 23:44:20 -07:00
|
|
|
dighost_printmessage(query, &b, msg, true);
|
2018-10-29 09:15:42 +00:00
|
|
|
dighost_received(isc_buffer_usedlength(&b),
|
2020-09-05 16:37:24 -07:00
|
|
|
&peer, query);
|
2000-04-28 21:41:19 +00:00
|
|
|
}
|
2001-07-29 23:23:42 +00:00
|
|
|
} else if (!l->trace && !l->ns_search_only) {
|
2019-07-16 23:44:20 -07:00
|
|
|
dighost_printmessage(query, &b, msg, true);
|
2001-07-29 23:23:42 +00:00
|
|
|
} else if (l->trace) {
|
2015-01-20 13:29:18 -08:00
|
|
|
int nl = 0;
|
2001-07-29 23:23:42 +00:00
|
|
|
int count = msg->counts[DNS_SECTION_ANSWER];
|
|
|
|
|
|
|
|
debug("in TRACE code");
|
2020-02-13 21:48:23 +01:00
|
|
|
if (!l->ns_search_only) {
|
2019-07-16 23:44:20 -07:00
|
|
|
dighost_printmessage(query, &b, msg, true);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-07-29 23:23:42 +00:00
|
|
|
|
|
|
|
l->rdtype = l->qrdtype;
|
2004-04-13 02:39:35 +00:00
|
|
|
if (l->trace_root || (l->ns_search_only && count > 0)) {
|
2020-02-13 21:48:23 +01:00
|
|
|
if (!l->trace_root) {
|
2001-07-29 23:23:42 +00:00
|
|
|
l->rdtype = dns_rdatatype_soa;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-01-20 13:29:18 -08:00
|
|
|
nl = followup_lookup(msg, query,
|
|
|
|
DNS_SECTION_ANSWER);
|
2018-04-17 08:29:14 -07:00
|
|
|
l->trace_root = false;
|
2020-02-13 21:48:23 +01:00
|
|
|
} else if (count == 0) {
|
2015-01-20 13:29:18 -08:00
|
|
|
nl = followup_lookup(msg, query,
|
|
|
|
DNS_SECTION_AUTHORITY);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if (nl == 0) {
|
2018-04-17 08:29:14 -07:00
|
|
|
docancel = true;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-07-29 23:23:42 +00:00
|
|
|
} else {
|
2001-07-28 00:11:15 +00:00
|
|
|
debug("in NSSEARCH code");
|
|
|
|
|
|
|
|
if (l->trace_root) {
|
|
|
|
/*
|
2008-01-18 23:46:58 +00:00
|
|
|
* This is the initial NS query.
|
2001-07-28 00:11:15 +00:00
|
|
|
*/
|
2015-01-20 13:29:18 -08:00
|
|
|
int nl;
|
2001-07-28 00:11:15 +00:00
|
|
|
|
|
|
|
l->rdtype = dns_rdatatype_soa;
|
2015-01-20 13:29:18 -08:00
|
|
|
nl = followup_lookup(msg, query,
|
|
|
|
DNS_SECTION_ANSWER);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (nl == 0) {
|
2018-04-17 08:29:14 -07:00
|
|
|
docancel = true;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2018-04-17 08:29:14 -07:00
|
|
|
l->trace_root = false;
|
|
|
|
usesearch = false;
|
2017-08-09 11:03:27 -07:00
|
|
|
} else {
|
2022-03-20 13:54:39 +00:00
|
|
|
/*
|
|
|
|
* This is a query in the followup lookup
|
|
|
|
*/
|
2019-07-16 23:44:20 -07:00
|
|
|
dighost_printmessage(query, &b, msg, true);
|
2022-03-20 13:54:39 +00:00
|
|
|
|
|
|
|
docancel = check_if_queries_done(l, query);
|
2004-04-13 02:39:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (l->pending) {
|
2001-07-27 22:07:10 +00:00
|
|
|
debug("still pending.");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2020-09-05 16:37:24 -07:00
|
|
|
|
2001-07-27 22:07:10 +00:00
|
|
|
if (l->doing_xfr) {
|
|
|
|
if (query != l->xfr_q) {
|
2020-11-06 16:12:17 +01:00
|
|
|
goto detach_query;
|
2001-07-27 22:07:10 +00:00
|
|
|
}
|
2020-02-13 21:48:23 +01:00
|
|
|
if (!docancel) {
|
2020-11-05 15:22:38 +01:00
|
|
|
docancel = check_for_more_data(l, query, msg, &peer,
|
2020-09-05 16:37:24 -07:00
|
|
|
region->length);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-07-27 22:07:10 +00:00
|
|
|
if (docancel) {
|
2020-11-06 16:12:17 +01:00
|
|
|
goto cancel_lookup;
|
2000-04-26 18:34:17 +00:00
|
|
|
}
|
2020-11-06 16:12:17 +01:00
|
|
|
/*
|
|
|
|
* check_for_more_data() will detach from query->readhandle
|
|
|
|
* and query on its own, as it needs to reuse the query and
|
|
|
|
* reattach to the readhandle in launch_next_query().
|
|
|
|
*/
|
|
|
|
goto keep_query;
|
2001-07-27 22:07:10 +00:00
|
|
|
} else {
|
2004-04-13 02:39:35 +00:00
|
|
|
if (msg->rcode == dns_rcode_noerror || l->origin == NULL) {
|
2020-09-05 16:37:24 -07:00
|
|
|
dighost_received(isc_buffer_usedlength(&b), &peer,
|
|
|
|
query);
|
2004-04-13 02:39:35 +00:00
|
|
|
}
|
|
|
|
|
2020-11-05 15:22:38 +01:00
|
|
|
if (!l->ns_search_only) {
|
|
|
|
l->pending = false;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2020-11-05 15:22:38 +01:00
|
|
|
if (!l->ns_search_only || l->trace_root || docancel) {
|
2020-11-06 16:12:17 +01:00
|
|
|
goto cancel_lookup;
|
2001-07-27 22:07:10 +00:00
|
|
|
}
|
2020-11-06 16:12:17 +01:00
|
|
|
goto next_lookup;
|
|
|
|
}
|
|
|
|
cancel_lookup:
|
|
|
|
docancel = true;
|
|
|
|
next_lookup:
|
|
|
|
donext = true;
|
|
|
|
detach_query:
|
|
|
|
isc_nmhandle_detach(&query->readhandle);
|
|
|
|
query_detach(&query);
|
|
|
|
if (docancel) {
|
|
|
|
cancel_lookup(l);
|
|
|
|
}
|
|
|
|
keep_query:
|
|
|
|
if (msg != NULL) {
|
2020-09-21 16:16:15 -03:00
|
|
|
dns_message_detach(&msg);
|
2004-04-13 02:39:35 +00:00
|
|
|
}
|
2020-11-05 15:22:38 +01:00
|
|
|
lookup_detach(&l);
|
2020-11-06 16:12:17 +01:00
|
|
|
if (donext) {
|
|
|
|
clear_current_lookup();
|
|
|
|
}
|
2009-01-20 04:39:29 +00:00
|
|
|
UNLOCK_LOOKUP;
|
2000-04-26 18:34:17 +00:00
|
|
|
}
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
2000-07-18 18:51:40 +00:00
|
|
|
* Turn a name into an address, using system-supplied routines. This is
|
|
|
|
* used in looking up server names, etc... and needs to use system-supplied
|
|
|
|
* routines, since they may be using a non-DNS system for these lookups.
|
|
|
|
*/
|
2008-12-16 02:57:24 +00:00
|
|
|
isc_result_t
|
2020-02-13 14:44:37 -08:00
|
|
|
get_address(char *host, in_port_t myport, isc_sockaddr_t *sockaddr) {
|
|
|
|
int count;
|
2001-11-14 22:08:38 +00:00
|
|
|
isc_result_t result;
|
2020-02-13 14:44:37 -08:00
|
|
|
bool is_running;
|
2000-04-29 00:12:56 +00:00
|
|
|
|
2015-02-26 14:00:57 +05:30
|
|
|
is_running = isc_app_isrunning();
|
2020-02-13 21:48:23 +01:00
|
|
|
if (is_running) {
|
2015-02-26 14:00:57 +05:30
|
|
|
isc_app_block();
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-01-20 13:29:18 -08:00
|
|
|
result = bind9_getaddresses(host, myport, sockaddr, 1, &count);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (is_running) {
|
2015-02-26 14:00:57 +05:30
|
|
|
isc_app_unblock();
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
2008-12-16 02:57:24 +00:00
|
|
|
return (result);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2008-12-16 02:57:24 +00:00
|
|
|
|
2001-11-14 22:08:38 +00:00
|
|
|
INSIST(count == 1);
|
2008-12-16 02:57:24 +00:00
|
|
|
|
|
|
|
return (ISC_R_SUCCESS);
|
2000-04-26 18:34:17 +00:00
|
|
|
}
|
|
|
|
|
2011-02-25 23:11:13 +00:00
|
|
|
int
|
2020-02-13 14:44:37 -08:00
|
|
|
getaddresses(dig_lookup_t *lookup, const char *host, isc_result_t *resultp) {
|
|
|
|
isc_result_t result;
|
2011-02-25 23:11:13 +00:00
|
|
|
isc_sockaddr_t sockaddrs[DIG_MAX_ADDRESSES];
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_netaddr_t netaddr;
|
|
|
|
int count, i;
|
|
|
|
dig_server_t *srv;
|
|
|
|
char tmp[ISC_NETADDR_FORMATSIZE];
|
2011-02-25 23:11:13 +00:00
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
result = bind9_getaddresses(host, 0, sockaddrs, DIG_MAX_ADDRESSES,
|
|
|
|
&count);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (resultp != NULL) {
|
2011-12-07 17:23:28 +00:00
|
|
|
*resultp = result;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2011-12-07 17:23:28 +00:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2020-02-13 21:48:23 +01:00
|
|
|
if (resultp == NULL) {
|
2020-02-12 13:59:18 +01:00
|
|
|
fatal("couldn't get address for '%s': %s", host,
|
|
|
|
isc_result_totext(result));
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2017-09-13 00:14:37 -07:00
|
|
|
return (0);
|
2011-12-07 17:23:28 +00:00
|
|
|
}
|
2011-02-25 23:11:13 +00:00
|
|
|
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
isc_netaddr_fromsockaddr(&netaddr, &sockaddrs[i]);
|
|
|
|
isc_netaddr_format(&netaddr, tmp, sizeof(tmp));
|
|
|
|
srv = make_server(tmp, host);
|
|
|
|
ISC_LIST_APPEND(lookup->my_server_list, srv, link);
|
|
|
|
}
|
|
|
|
|
2017-09-13 00:14:37 -07:00
|
|
|
return (count);
|
2011-02-25 23:11:13 +00:00
|
|
|
}
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
2000-07-18 18:51:40 +00:00
|
|
|
* Initiate either a TCP or UDP lookup
|
|
|
|
*/
|
2000-05-12 01:02:37 +00:00
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
do_lookup(dig_lookup_t *lookup) {
|
2012-10-06 14:20:45 +10:00
|
|
|
dig_query_t *query;
|
2000-05-12 01:02:37 +00:00
|
|
|
|
2000-07-05 19:31:26 +00:00
|
|
|
REQUIRE(lookup != NULL);
|
2000-05-12 01:02:37 +00:00
|
|
|
|
2000-07-05 19:31:26 +00:00
|
|
|
debug("do_lookup()");
|
2018-04-17 08:29:14 -07:00
|
|
|
lookup->pending = true;
|
2012-10-06 14:20:45 +10:00
|
|
|
query = ISC_LIST_HEAD(lookup->q);
|
|
|
|
if (query != NULL) {
|
2018-11-07 13:04:13 -05:00
|
|
|
REQUIRE(DIG_VALID_QUERY(query));
|
2020-02-13 21:48:23 +01:00
|
|
|
if (lookup->tcp_mode) {
|
2020-09-05 16:37:24 -07:00
|
|
|
start_tcp(query);
|
2020-02-13 21:48:23 +01:00
|
|
|
} else {
|
2020-09-05 16:37:24 -07:00
|
|
|
start_udp(query);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2012-10-06 14:20:45 +10:00
|
|
|
}
|
2000-05-12 01:02:37 +00:00
|
|
|
}
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
2000-07-18 18:51:40 +00:00
|
|
|
* Start everything in action upon task startup.
|
|
|
|
*/
|
2000-07-10 18:02:31 +00:00
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
onrun_callback(isc_task_t *task, isc_event_t *event) {
|
2000-07-10 18:02:31 +00:00
|
|
|
UNUSED(task);
|
2000-08-01 00:53:20 +00:00
|
|
|
|
2000-07-10 18:02:31 +00:00
|
|
|
isc_event_free(&event);
|
2000-07-14 17:57:27 +00:00
|
|
|
LOCK_LOOKUP;
|
2000-07-10 18:02:31 +00:00
|
|
|
start_lookup();
|
2000-07-14 17:57:27 +00:00
|
|
|
UNLOCK_LOOKUP;
|
2000-07-10 18:02:31 +00:00
|
|
|
}
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
2000-07-18 18:51:40 +00:00
|
|
|
* Make everything on the lookup queue go away. Mainly used by the
|
|
|
|
* SIGINT handler.
|
2000-07-13 00:32:20 +00:00
|
|
|
*/
|
2000-07-14 17:57:27 +00:00
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
cancel_all(void) {
|
2000-07-14 20:14:36 +00:00
|
|
|
dig_lookup_t *l, *n;
|
2020-02-13 14:44:37 -08:00
|
|
|
dig_query_t *q, *nq;
|
2000-04-26 18:34:17 +00:00
|
|
|
|
2000-07-13 02:14:17 +00:00
|
|
|
debug("cancel_all()");
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2000-07-14 17:57:27 +00:00
|
|
|
LOCK_LOOKUP;
|
|
|
|
if (free_now) {
|
|
|
|
UNLOCK_LOOKUP;
|
|
|
|
return;
|
|
|
|
}
|
2020-11-05 15:22:38 +01:00
|
|
|
atomic_store(&cancel_now, true);
|
2021-04-27 12:03:20 +02:00
|
|
|
while (current_lookup != NULL) {
|
2020-02-12 13:59:18 +01:00
|
|
|
for (q = ISC_LIST_HEAD(current_lookup->q); q != NULL; q = nq) {
|
2000-09-22 23:21:32 +00:00
|
|
|
nq = ISC_LIST_NEXT(q, link);
|
2020-02-12 13:59:18 +01:00
|
|
|
debug("canceling pending query %p, belonging to %p", q,
|
|
|
|
current_lookup);
|
Fix query context management issues in dighost.c
For the reference, the _cancel_lookup() function iterates through
the lookup's queries list and detaches them. In the ideal scenario,
that should be the last reference and the query will be destroyed
after that, but it is also possible that we are still expecting a
callback, which also holds a reference (for example, _cancel_lookup()
could have been called from recv_done(), when send_done() was still
not executed).
The start_udp() and start_tcp() functions are currently designed in
slightly different ways: start_udp() creates a new query attachment
`connectquery`, to be called in the callback function, while
start_tcp() does not, which is a bug, but is hidden by the fact
that when the query is being erroneously destroyed prematurely (before
_cancel_lookup() is called) in the result of that, it also gets
de-listed from the lookup's queries' list, so _cancel_lookup() doesn't
even try to detach it.
For better understanding, here's an illustration of the query's
references count changes, and from where it was changed:
UDP
---
1. _new_query() -> refcount = 1 (initial)
2. start_udp() -> refcount = 2 (lookup->current_query)
3. start_udp() -> refcount = 3 (connectquery)
4. udp_ready() -> refcount = 4 (readquery)
5. udp_ready() -> refcount = 5 (sendquery)
6. udp_ready() -> refcount = 4 (lookup->current_query)
7. udp_ready() -> refcount = 3 (connectquery)
8. send_done() -> refcount = 2 (sendquery)
9. recv_done() -> refcount = 1 (readquery)
10. _cancel_lookup() -> refcount = 0 (initial)
11. the query gets destroyed and removed from `lookup->q`
TCP, fortunate scenario
-----------------------
1. _new_query() -> refcount = 1 (initial)
2. start_tcp() -> refcount = 2 (lookup->current_query)
3. launch_next_query() -> refcount = 3 (readquery)
4. launch_next_query() -> refcount = 4 (sendquery)
5. tcp_connected() -> refcount = 3 (lookup->current_query)
6. tcp_connected() -> refcount = 2 (bug, there was no connectquery)
7. send_done() -> refcount = 1 (sendquery)
8. recv_done() -> refcount = 0 (readquery)
9. the query gets prematurely destroyed and removed from `lookup->q`
10. _cancel_lookup() -> the query is not in `lookup->q`
TCP, unfortunate scenario, revealing the bug
--------------------------------------------
1. _new_query() -> refcount = 1 (initial)
2. start_tcp() -> refcount = 2 (lookup->current_query)
3. launch_next_query() -> refcount = 3 (readquery)
4. launch_next_query() -> refcount = 4 (sendquery)
5. tcp_connected() -> refcount = 3 (lookup->current_query)
6. tcp_connected() -> refcount = 2 (bug, there was no connectquery)
7. recv_done() -> refcount = 1 (readquery)
8. _cancel_lookup() -> refcount = 0 (the query was in `lookup->q`)
9. we hit an assertion here when trying to destroy the query, because
sendhandle is not detached (which is done by send_done()).
10. send_done() -> this never happens
This commit does the following:
1. Add a `connectquery` attachment in start_tcp(), like done in
start_udp().
2. Add missing _cancel_lookup() calls for error scenarios, which
were possibly missing because before fixing the bug, calling
_cancel_lookup() and then calling query_detach() would cause
an assertion.
3. Log a debug message and call isc_nm_cancelread(query->readhandle)
for every query in the lookup from inside the _cancel_lookup()
function, like it is done in _cancel_all().
4. Add a `canceled` property for the query which becomes `true` when
the lookup (and subsequently, its queries) are canceled.
5. Use the `canceled` property in the network manager callbacks to
know that the query was canceled, and act like `eresult` was equal
to `ISC_R_CANCELED`.
2022-03-02 00:06:34 +00:00
|
|
|
q->canceled = true;
|
2022-05-10 23:09:59 +03:00
|
|
|
if (q->readhandle != NULL &&
|
|
|
|
!isc_nm_is_http_handle(q->readhandle)) {
|
2021-04-27 12:03:20 +02:00
|
|
|
isc_nm_cancelread(q->readhandle);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2020-11-04 12:40:13 +01:00
|
|
|
query_detach(&q);
|
2013-12-02 13:34:23 -08:00
|
|
|
}
|
2021-05-04 14:25:55 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* current_lookup could have been detached via query_detach().
|
|
|
|
*/
|
|
|
|
if (current_lookup != NULL) {
|
|
|
|
lookup_detach(¤t_lookup);
|
|
|
|
}
|
2000-07-14 20:14:36 +00:00
|
|
|
}
|
|
|
|
l = ISC_LIST_HEAD(lookup_list);
|
|
|
|
while (l != NULL) {
|
|
|
|
n = ISC_LIST_NEXT(l, link);
|
|
|
|
ISC_LIST_DEQUEUE(lookup_list, l, link);
|
2020-11-05 15:22:38 +01:00
|
|
|
lookup_detach(&l);
|
2000-07-14 20:14:36 +00:00
|
|
|
l = n;
|
2000-04-26 18:34:17 +00:00
|
|
|
}
|
2000-07-14 17:57:27 +00:00
|
|
|
UNLOCK_LOOKUP;
|
2000-07-13 00:32:20 +00:00
|
|
|
}
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
2000-08-01 01:33:37 +00:00
|
|
|
* Destroy all of the libs we are using, and get everything ready for a
|
2000-07-18 18:51:40 +00:00
|
|
|
* clean shutdown.
|
|
|
|
*/
|
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
destroy_libs(void) {
|
2020-02-13 21:48:23 +01:00
|
|
|
if (keep != NULL) {
|
2020-09-05 16:37:24 -07:00
|
|
|
isc_nmhandle_detach(&keep);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2000-07-18 18:51:40 +00:00
|
|
|
debug("destroy_libs()");
|
|
|
|
if (global_task != NULL) {
|
|
|
|
debug("freeing task");
|
|
|
|
isc_task_detach(&global_task);
|
|
|
|
}
|
2020-09-05 16:37:24 -07:00
|
|
|
|
2021-10-03 00:27:52 -07:00
|
|
|
isc_managers_destroy(&netmgr, &taskmgr, NULL);
|
2020-09-05 16:37:24 -07:00
|
|
|
|
2000-07-18 18:51:40 +00:00
|
|
|
LOCK_LOOKUP;
|
2020-09-05 16:37:24 -07:00
|
|
|
isc_refcount_destroy(&recvcount);
|
|
|
|
isc_refcount_destroy(&sendcount);
|
2000-07-13 00:32:20 +00:00
|
|
|
|
|
|
|
INSIST(ISC_LIST_HEAD(lookup_list) == NULL);
|
2000-07-14 20:14:36 +00:00
|
|
|
INSIST(current_lookup == NULL);
|
2000-07-13 00:32:20 +00:00
|
|
|
INSIST(!free_now);
|
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
free_now = true;
|
2000-07-13 00:32:20 +00:00
|
|
|
|
2002-08-12 18:25:25 +00:00
|
|
|
flush_server_list();
|
|
|
|
|
2001-01-18 05:12:44 +00:00
|
|
|
clear_searchlist();
|
2005-09-18 07:16:24 +00:00
|
|
|
|
2018-03-19 22:16:10 +00:00
|
|
|
if (tsigkey != NULL) {
|
|
|
|
debug("freeing key %p", tsigkey);
|
|
|
|
dns_tsigkey_detach(&tsigkey);
|
2000-06-06 18:49:06 +00:00
|
|
|
}
|
2020-02-13 21:48:23 +01:00
|
|
|
if (namebuf != NULL) {
|
2000-06-06 00:43:17 +00:00
|
|
|
isc_buffer_free(&namebuf);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2000-06-12 19:33:30 +00:00
|
|
|
|
2000-06-30 22:53:07 +00:00
|
|
|
if (is_dst_up) {
|
2000-07-05 23:28:32 +00:00
|
|
|
debug("destroy DST lib");
|
2000-06-30 22:53:07 +00:00
|
|
|
dst_lib_destroy();
|
2018-04-17 08:29:14 -07:00
|
|
|
is_dst_up = false;
|
2000-06-30 22:53:07 +00:00
|
|
|
}
|
2000-07-14 17:57:27 +00:00
|
|
|
|
2000-08-28 05:06:18 +00:00
|
|
|
UNLOCK_LOOKUP;
|
2018-11-19 10:31:09 +00:00
|
|
|
isc_mutex_destroy(&lookup_lock);
|
2009-09-15 03:13:44 +00:00
|
|
|
debug("Removing log context");
|
|
|
|
isc_log_destroy(&lctx);
|
|
|
|
|
|
|
|
debug("Destroy memory");
|
2020-02-13 21:48:23 +01:00
|
|
|
if (memdebugging != 0) {
|
2000-07-14 17:57:27 +00:00
|
|
|
isc_mem_stats(mctx, stderr);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if (mctx != NULL) {
|
2000-08-01 01:33:37 +00:00
|
|
|
isc_mem_destroy(&mctx);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2000-07-14 17:57:27 +00:00
|
|
|
}
|
2004-04-13 02:39:35 +00:00
|
|
|
|
Rework libidn2 detection
Clean up the parts of configure.in responsible for handling libidn2
detection and adjust other pieces of the build system to match these
cleanups:
- use pkg-config when --with-libidn2 is used without an explicit path,
- look for idn2_to_ascii_lz() rather than idn2_to_ascii_8z() as the
former is used in BIND while the latter is not,
- do not look for idn2_to_unicode_8zlz() as it is present in all
libidn2 versions which have idn2_to_ascii_lz(),
- check whether the <idn2.h> header is usable,
- set LDFLAGS in the Makefile for dig so that, if specified, the
requested libidn2 path is used when linking with libidn2,
- override CPPFLAGS when looking for libidn2 components so that the
configure script does not produce warnings when libidn2 is not
installed system-wide,
- merge the AS_CASE() call into the AS_IF() call below it to simplify
code,
- indicate the default value of --with-libidn2 in "./configure --help"
output,
- use $with_libidn2 rather than $use_libidn2 to better match the name
of the configure script argument,
- stop differentiating between IDN "in" and "out" support, i.e. make
dig either support libidn2 or not; remove WITH_* Autoconf macros and
use a new one, HAVE_LIBIDN2, to determine whether libidn2 support
should be enabled.
2018-07-10 14:34:35 +02:00
|
|
|
#ifdef HAVE_LIBIDN2
|
2005-09-09 06:17:03 +00:00
|
|
|
static isc_result_t
|
2020-02-13 14:44:37 -08:00
|
|
|
idn_output_filter(isc_buffer_t *buffer, unsigned int used_org) {
|
2021-06-22 13:05:15 +02:00
|
|
|
char src[MXNAME], *dst = NULL;
|
2018-07-10 14:34:35 +02:00
|
|
|
size_t srclen, dstlen;
|
2021-06-22 13:05:15 +02:00
|
|
|
isc_result_t result = ISC_R_SUCCESS;
|
2018-07-10 14:34:35 +02:00
|
|
|
|
2005-09-09 06:17:03 +00:00
|
|
|
/*
|
2018-07-10 14:34:35 +02:00
|
|
|
* Copy name from 'buffer' to 'src' and terminate it with NULL.
|
2005-09-09 06:17:03 +00:00
|
|
|
*/
|
2018-07-10 14:34:35 +02:00
|
|
|
srclen = isc_buffer_usedlength(buffer) - used_org;
|
2020-03-17 13:56:30 +11:00
|
|
|
if (srclen >= sizeof(src)) {
|
2018-07-10 14:34:35 +02:00
|
|
|
warn("Input name too long to perform IDN conversion");
|
2021-06-22 13:05:15 +02:00
|
|
|
goto cleanup;
|
2005-09-09 06:17:03 +00:00
|
|
|
}
|
2018-07-10 14:34:35 +02:00
|
|
|
memmove(src, (char *)isc_buffer_base(buffer) + used_org, srclen);
|
|
|
|
src[srclen] = '\0';
|
2005-09-09 06:17:03 +00:00
|
|
|
|
2021-06-22 13:05:15 +02:00
|
|
|
systemlocale(LC_ALL);
|
|
|
|
|
2005-09-09 06:17:03 +00:00
|
|
|
/*
|
2018-07-10 14:34:35 +02:00
|
|
|
* Convert 'src' to the current locale's character encoding.
|
2005-09-09 06:17:03 +00:00
|
|
|
*/
|
2018-07-10 14:34:35 +02:00
|
|
|
idn_ace_to_locale(src, &dst);
|
2018-07-10 14:34:35 +02:00
|
|
|
|
2021-06-22 13:05:15 +02:00
|
|
|
resetlocale(LC_ALL);
|
|
|
|
|
2005-09-09 06:17:03 +00:00
|
|
|
/*
|
2018-07-10 14:34:35 +02:00
|
|
|
* Check whether the converted name will fit back into 'buffer'.
|
2005-09-09 06:17:03 +00:00
|
|
|
*/
|
2018-07-10 14:34:35 +02:00
|
|
|
dstlen = strlen(dst);
|
|
|
|
if (isc_buffer_length(buffer) < used_org + dstlen) {
|
2021-06-22 13:05:15 +02:00
|
|
|
result = ISC_R_NOSPACE;
|
|
|
|
goto cleanup;
|
2018-07-10 14:34:35 +02:00
|
|
|
}
|
2005-09-09 06:17:03 +00:00
|
|
|
|
2018-07-10 14:34:35 +02:00
|
|
|
/*
|
|
|
|
* Put the converted name back into 'buffer'.
|
|
|
|
*/
|
|
|
|
isc_buffer_subtract(buffer, srclen);
|
|
|
|
memmove(isc_buffer_used(buffer), dst, dstlen);
|
|
|
|
isc_buffer_add(buffer, dstlen);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Clean up.
|
|
|
|
*/
|
2021-06-22 13:05:15 +02:00
|
|
|
cleanup:
|
|
|
|
if (dst != NULL) {
|
|
|
|
idn2_free(dst);
|
|
|
|
}
|
2005-09-09 06:17:03 +00:00
|
|
|
|
2021-06-22 13:05:15 +02:00
|
|
|
return (result);
|
2005-09-09 06:17:03 +00:00
|
|
|
}
|
|
|
|
|
2018-07-10 14:34:35 +02:00
|
|
|
/*%
|
|
|
|
* Convert 'src', which is a string using the current locale's character
|
|
|
|
* encoding, into an ACE string suitable for use in the DNS, storing the
|
|
|
|
* conversion result in 'dst', which is 'dstlen' bytes large.
|
|
|
|
*
|
|
|
|
* 'dst' MUST be large enough to hold any valid domain name.
|
|
|
|
*/
|
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
idn_locale_to_ace(const char *src, char *dst, size_t dstlen) {
|
2018-07-10 14:34:35 +02:00
|
|
|
const char *final_src;
|
2020-02-13 14:44:37 -08:00
|
|
|
char *ascii_src;
|
|
|
|
int res;
|
2015-09-23 16:47:37 +02:00
|
|
|
|
2021-06-22 13:05:15 +02:00
|
|
|
systemlocale(LC_ALL);
|
|
|
|
|
2018-07-10 14:34:35 +02:00
|
|
|
/*
|
|
|
|
* We trust libidn2 to return an error if 'src' is too large to be a
|
|
|
|
* valid domain name.
|
|
|
|
*/
|
2021-11-30 15:18:40 +01:00
|
|
|
res = idn2_to_ascii_lz(src, &ascii_src, IDN2_NONTRANSITIONAL);
|
2018-07-10 14:34:35 +02:00
|
|
|
if (res != IDN2_OK) {
|
|
|
|
fatal("'%s' is not a legal IDNA2008 name (%s), use +noidnin",
|
|
|
|
src, idn2_strerror(res));
|
2015-09-23 16:47:37 +02:00
|
|
|
}
|
|
|
|
|
2018-07-10 14:34:35 +02:00
|
|
|
/*
|
|
|
|
* idn2_to_ascii_lz() normalizes all strings to lower case, but we
|
|
|
|
* generally don't want to lowercase all input strings; make sure to
|
|
|
|
* return the original case if the two strings differ only in case.
|
|
|
|
*/
|
|
|
|
final_src = (strcasecmp(src, ascii_src) == 0 ? src : ascii_src);
|
|
|
|
|
|
|
|
(void)strlcpy(dst, final_src, dstlen);
|
|
|
|
|
|
|
|
idn2_free(ascii_src);
|
2021-06-22 13:05:15 +02:00
|
|
|
|
|
|
|
resetlocale(LC_ALL);
|
2015-09-23 16:47:37 +02:00
|
|
|
}
|
|
|
|
|
2018-07-10 14:34:35 +02:00
|
|
|
/*%
|
|
|
|
* Convert 'src', which is an ACE string suitable for use in the DNS, into a
|
|
|
|
* string using the current locale's character encoding, storing the conversion
|
|
|
|
* result in 'dst'.
|
|
|
|
*
|
|
|
|
* The caller MUST subsequently release 'dst' using idn2_free().
|
|
|
|
*/
|
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
idn_ace_to_locale(const char *src, char **dst) {
|
2018-07-10 14:34:35 +02:00
|
|
|
char *local_src, *utf8_src;
|
2020-02-13 14:44:37 -08:00
|
|
|
int res;
|
2015-09-23 16:47:37 +02:00
|
|
|
|
2021-06-22 13:05:15 +02:00
|
|
|
systemlocale(LC_ALL);
|
|
|
|
|
2018-07-10 14:34:35 +02:00
|
|
|
/*
|
|
|
|
* We need to:
|
|
|
|
*
|
|
|
|
* 1) check whether 'src' is a valid IDNA2008 name,
|
|
|
|
* 2) if it is, output it in the current locale's character encoding.
|
|
|
|
*
|
|
|
|
* Unlike idn2_to_ascii_*(), idn2_to_unicode_*() functions are unable
|
|
|
|
* to perform IDNA2008 validity checks. Thus, we need to decode any
|
|
|
|
* Punycode in 'src', check if the resulting name is a valid IDNA2008
|
|
|
|
* name, and only once we ensure it is, output that name in the current
|
|
|
|
* locale's character encoding.
|
|
|
|
*
|
|
|
|
* We could just use idn2_to_unicode_8zlz() + idn2_to_ascii_lz(), but
|
|
|
|
* then we would not be able to universally tell invalid names and
|
|
|
|
* character encoding errors apart (if the current locale uses ASCII
|
|
|
|
* for character encoding, the former function would fail even for a
|
|
|
|
* valid IDNA2008 name, as long as it contained any non-ASCII
|
|
|
|
* character). Thus, we need to take a longer route.
|
|
|
|
*
|
|
|
|
* First, convert 'src' to UTF-8, ignoring the current locale.
|
|
|
|
*/
|
2021-11-30 15:18:40 +01:00
|
|
|
res = idn2_to_unicode_8z8z(src, &utf8_src, 0);
|
2018-07-10 14:34:35 +02:00
|
|
|
if (res != IDN2_OK) {
|
2020-02-12 13:59:18 +01:00
|
|
|
fatal("Bad ACE string '%s' (%s), use +noidnout", src,
|
|
|
|
idn2_strerror(res));
|
2018-07-10 14:34:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Then, check whether decoded 'src' is a valid IDNA2008 name.
|
|
|
|
*/
|
2021-11-30 15:18:40 +01:00
|
|
|
res = idn2_to_ascii_8z(utf8_src, NULL, IDN2_NONTRANSITIONAL);
|
2018-07-10 14:34:35 +02:00
|
|
|
if (res != IDN2_OK) {
|
|
|
|
fatal("'%s' is not a legal IDNA2008 name (%s), use +noidnout",
|
|
|
|
src, idn2_strerror(res));
|
2015-09-23 16:47:37 +02:00
|
|
|
}
|
|
|
|
|
2018-07-10 14:34:35 +02:00
|
|
|
/*
|
|
|
|
* Finally, try converting the decoded 'src' into the current locale's
|
|
|
|
* character encoding.
|
|
|
|
*/
|
2021-11-30 15:18:40 +01:00
|
|
|
res = idn2_to_unicode_8zlz(utf8_src, &local_src, 0);
|
2018-07-10 14:34:35 +02:00
|
|
|
if (res != IDN2_OK) {
|
2019-01-30 15:38:54 +01:00
|
|
|
static bool warned = false;
|
|
|
|
|
2021-11-30 15:18:40 +01:00
|
|
|
res = idn2_to_ascii_8z(utf8_src, &local_src, 0);
|
2019-01-29 18:07:44 +01:00
|
|
|
if (res != IDN2_OK) {
|
|
|
|
fatal("Cannot represent '%s' "
|
|
|
|
"in the current locale nor ascii (%s), "
|
|
|
|
"use +noidnout or a different locale",
|
|
|
|
src, idn2_strerror(res));
|
2019-01-30 15:38:54 +01:00
|
|
|
} else if (!warned) {
|
2020-02-12 13:59:18 +01:00
|
|
|
fprintf(stderr,
|
|
|
|
";; Warning: cannot represent '%s' "
|
|
|
|
"in the current locale",
|
|
|
|
local_src);
|
2019-01-30 15:38:54 +01:00
|
|
|
warned = true;
|
2019-01-29 18:07:44 +01:00
|
|
|
}
|
2018-07-10 14:34:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Free the interim conversion result.
|
|
|
|
*/
|
|
|
|
idn2_free(utf8_src);
|
|
|
|
|
2018-07-10 14:34:35 +02:00
|
|
|
*dst = local_src;
|
2021-06-22 13:05:15 +02:00
|
|
|
|
|
|
|
resetlocale(LC_ALL);
|
2015-09-23 16:47:37 +02:00
|
|
|
}
|
Rework libidn2 detection
Clean up the parts of configure.in responsible for handling libidn2
detection and adjust other pieces of the build system to match these
cleanups:
- use pkg-config when --with-libidn2 is used without an explicit path,
- look for idn2_to_ascii_lz() rather than idn2_to_ascii_8z() as the
former is used in BIND while the latter is not,
- do not look for idn2_to_unicode_8zlz() as it is present in all
libidn2 versions which have idn2_to_ascii_lz(),
- check whether the <idn2.h> header is usable,
- set LDFLAGS in the Makefile for dig so that, if specified, the
requested libidn2 path is used when linking with libidn2,
- override CPPFLAGS when looking for libidn2 components so that the
configure script does not produce warnings when libidn2 is not
installed system-wide,
- merge the AS_CASE() call into the AS_IF() call below it to simplify
code,
- indicate the default value of --with-libidn2 in "./configure --help"
output,
- use $with_libidn2 rather than $use_libidn2 to better match the name
of the configure script argument,
- stop differentiating between IDN "in" and "out" support, i.e. make
dig either support libidn2 or not; remove WITH_* Autoconf macros and
use a new one, HAVE_LIBIDN2, to determine whether libidn2 support
should be enabled.
2018-07-10 14:34:35 +02:00
|
|
|
#endif /* HAVE_LIBIDN2 */
|
2020-09-12 13:23:52 -07:00
|
|
|
|
|
|
|
void
|
|
|
|
dig_idnsetup(dig_lookup_t *lookup, bool active) {
|
|
|
|
#ifdef HAVE_LIBIDN2
|
|
|
|
isc_result_t result;
|
|
|
|
result = dns_name_settotextfilter(
|
|
|
|
(active && lookup->idnout) ? idn_output_filter : NULL);
|
|
|
|
check_result(result, "dns_name_settotextfilter");
|
|
|
|
#else
|
|
|
|
UNUSED(lookup);
|
|
|
|
UNUSED(active);
|
|
|
|
return;
|
|
|
|
#endif /* HAVE_LIBIDN2 */
|
|
|
|
}
|
2022-01-19 13:10:08 +02:00
|
|
|
|
|
|
|
bool
|
|
|
|
dig_lookup_is_tls(const dig_lookup_t *lookup) {
|
|
|
|
if (lookup->tls_mode || (lookup->tls_ca_set && !lookup->https_mode)) {
|
|
|
|
return (true);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (false);
|
|
|
|
}
|