2000-04-26 14:34:17 -04:00
|
|
|
/*
|
2011-02-21 18:47:45 -05:00
|
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
2000-04-26 14:34:17 -04:00
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: MPL-2.0
|
2021-06-03 02:37:05 -04:00
|
|
|
*
|
2000-04-26 14:34:17 -04: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
|
|
|
|
|
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
2018-02-23 03:53:12 -05:00
|
|
|
*
|
2000-04-26 14:34:17 -04:00
|
|
|
* See the COPYRIGHT file distributed with this work for additional
|
2000-07-18 14:51:40 -04:00
|
|
|
* information regarding copyright ownership.
|
2000-04-26 14:34:17 -04:00
|
|
|
*/
|
|
|
|
|
|
2005-04-27 00:57:32 -04:00
|
|
|
/*! \file
|
|
|
|
|
* \note
|
2000-05-08 18:51:08 -04: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.
|
|
|
|
|
*/
|
|
|
|
|
|
2015-09-23 08:37:16 -04:00
|
|
|
#include <errno.h>
|
2018-03-28 08:19:37 -04:00
|
|
|
#include <inttypes.h>
|
2000-07-05 21:02:42 -04:00
|
|
|
#include <limits.h>
|
2021-06-22 07:05:15 -04:00
|
|
|
#include <locale.h>
|
2022-12-16 06:04:39 -05:00
|
|
|
#include <netdb.h>
|
2018-04-17 11:29:14 -04:00
|
|
|
#include <stdbool.h>
|
2000-04-26 14:34:17 -04:00
|
|
|
#include <stdlib.h>
|
2000-06-15 15:05:30 -04:00
|
|
|
#include <string.h>
|
2015-09-23 08:37:16 -04:00
|
|
|
#include <unistd.h>
|
2000-04-26 14:34:17 -04: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 08:34:35 -04:00
|
|
|
#ifdef HAVE_LIBIDN2
|
2015-09-23 10:47:37 -04: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 08:34:35 -04:00
|
|
|
#endif /* HAVE_LIBIDN2 */
|
2015-09-23 08:37:16 -04:00
|
|
|
|
2000-06-21 13:48:32 -04:00
|
|
|
#include <isc/base64.h>
|
2024-08-08 06:16:50 -04:00
|
|
|
#include <isc/crypto.h>
|
2005-08-31 22:25:06 -04:00
|
|
|
#include <isc/file.h>
|
2022-12-16 05:19:16 -05:00
|
|
|
#include <isc/getaddresses.h>
|
2014-02-18 20:53:42 -05:00
|
|
|
#include <isc/hex.h>
|
2009-09-14 23:13:44 -04:00
|
|
|
#include <isc/log.h>
|
2022-07-26 07:03:40 -04:00
|
|
|
#include <isc/loop.h>
|
2021-04-26 18:07:43 -04:00
|
|
|
#include <isc/managers.h>
|
2000-10-23 19:13:21 -04:00
|
|
|
#include <isc/netaddr.h>
|
2018-05-28 09:22:23 -04:00
|
|
|
#include <isc/nonce.h>
|
2009-09-14 23:13:44 -04:00
|
|
|
#include <isc/parseint.h>
|
2004-04-07 21:21:16 -04:00
|
|
|
#include <isc/random.h>
|
2000-06-23 16:57:19 -04:00
|
|
|
#include <isc/result.h>
|
2015-08-17 21:26:44 -04:00
|
|
|
#include <isc/safe.h>
|
2011-11-30 19:53:58 -05:00
|
|
|
#include <isc/serial.h>
|
2014-02-19 18:51:02 -05:00
|
|
|
#include <isc/sockaddr.h>
|
2000-06-21 13:48:32 -04:00
|
|
|
#include <isc/string.h>
|
2022-07-26 07:03:45 -04:00
|
|
|
#include <isc/timer.h>
|
2022-09-23 10:06:42 -04:00
|
|
|
#include <isc/tls.h>
|
2000-06-21 13:48:32 -04:00
|
|
|
#include <isc/types.h>
|
|
|
|
|
#include <isc/util.h>
|
2022-09-23 10:06:42 -04:00
|
|
|
#include <isc/uv.h>
|
|
|
|
|
#include <isc/xml.h>
|
2000-06-12 15:33:30 -04:00
|
|
|
|
2000-10-23 19:13:21 -04:00
|
|
|
#include <dns/byaddr.h>
|
2025-01-29 05:11:32 -05:00
|
|
|
#include <dns/ede.h>
|
2016-08-18 18:02:51 -04:00
|
|
|
#include <dns/fixedname.h>
|
2000-04-26 14:34:17 -04:00
|
|
|
#include <dns/message.h>
|
2000-05-30 18:27:27 -04:00
|
|
|
#include <dns/name.h>
|
2020-03-10 22:55:14 -04:00
|
|
|
#include <dns/opcode.h>
|
2014-09-30 20:01:54 -04:00
|
|
|
#include <dns/rcode.h>
|
2000-04-26 14:34:17 -04:00
|
|
|
#include <dns/rdata.h>
|
|
|
|
|
#include <dns/rdataclass.h>
|
2000-06-21 13:48:32 -04:00
|
|
|
#include <dns/rdatalist.h>
|
2000-05-08 10:38:29 -04:00
|
|
|
#include <dns/rdataset.h>
|
2000-06-21 13:48:32 -04:00
|
|
|
#include <dns/rdatastruct.h>
|
2000-04-26 14:34:17 -04:00
|
|
|
#include <dns/rdatatype.h>
|
2016-08-18 18:02:51 -04:00
|
|
|
#include <dns/tsig.h>
|
|
|
|
|
|
2020-03-09 11:17:26 -04:00
|
|
|
#include <dst/dst.h>
|
|
|
|
|
|
2009-09-14 23:13:44 -04:00
|
|
|
#include <isccfg/namedconf.h>
|
|
|
|
|
|
2020-03-09 11:17:26 -04:00
|
|
|
#include <irs/resconf.h>
|
|
|
|
|
|
2018-08-07 10:46:53 -04:00
|
|
|
#include "dighost.h"
|
2001-01-18 17:21:31 -05:00
|
|
|
|
2021-06-22 07:05:15 -04:00
|
|
|
#define systemlocale(l) (void)setlocale(l, "")
|
|
|
|
|
#define resetlocale(l) (void)setlocale(l, "C")
|
|
|
|
|
|
2005-07-03 23:03:21 -04:00
|
|
|
dig_lookuplist_t lookup_list;
|
2000-07-14 12:35:30 -04:00
|
|
|
dig_serverlist_t server_list;
|
2005-07-03 23:03:21 -04:00
|
|
|
dig_searchlistlist_t search_list;
|
2000-04-26 14:34:17 -04:00
|
|
|
|
2022-07-26 07:03:40 -04:00
|
|
|
static bool cancel_now = false;
|
2020-11-05 09:22:38 -05:00
|
|
|
|
2018-04-17 11:29:14 -04:00
|
|
|
bool check_ra = false, have_ipv4 = false, have_ipv6 = false,
|
2020-11-05 09:22:38 -05:00
|
|
|
specified_source = false, free_now = false, usesearch = false,
|
2024-08-05 06:14:26 -04:00
|
|
|
showsearch = false, keep_open = false, verbose = false, yaml = false;
|
2000-05-03 16:27:13 -04:00
|
|
|
in_port_t port = 53;
|
2020-07-22 02:59:42 -04:00
|
|
|
bool port_set = false;
|
2000-07-10 13:25:59 -04:00
|
|
|
unsigned int timeout = 0;
|
2005-07-03 23:03:21 -04:00
|
|
|
unsigned int extrabytes;
|
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-26 20:03:12 -04:00
|
|
|
isc_mem_t *mctx = NULL;
|
2021-04-26 18:07:43 -04:00
|
|
|
isc_nm_t *netmgr = NULL;
|
2022-07-26 07:03:40 -04:00
|
|
|
isc_loopmgr_t *loopmgr = NULL;
|
|
|
|
|
isc_loop_t *mainloop = NULL;
|
2020-09-05 19:37:24 -04:00
|
|
|
isc_sockaddr_t localaddr;
|
2022-03-08 17:55:10 -05:00
|
|
|
isc_refcount_t sendcount = 0;
|
|
|
|
|
isc_refcount_t recvcount = 0;
|
2000-05-02 19:23:12 -04:00
|
|
|
int ndots = -1;
|
2021-06-22 10:35:46 -04:00
|
|
|
int tries = -1;
|
2000-05-05 21:16:07 -04:00
|
|
|
int lookup_counter = 0;
|
2001-01-18 00:12:44 -05:00
|
|
|
|
2015-07-05 19:44:24 -04:00
|
|
|
static char servercookie[256];
|
2015-04-07 02:13:35 -04: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 08:34:35 -04:00
|
|
|
#ifdef HAVE_LIBIDN2
|
2018-07-10 08:34:35 -04:00
|
|
|
static void
|
2022-09-05 10:49:49 -04:00
|
|
|
idn_input(const char *src, char *dst, size_t dstlen);
|
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 08:34:35 -04:00
|
|
|
#endif /* HAVE_LIBIDN2 */
|
2005-09-09 02:17:03 -04:00
|
|
|
|
2020-09-05 19:37:24 -04:00
|
|
|
isc_nmhandle_t *keep = NULL;
|
2013-11-06 18:50:01 -05:00
|
|
|
isc_sockaddr_t keepaddr;
|
|
|
|
|
|
2005-04-27 00:57:32 -04:00
|
|
|
/*%
|
2000-08-03 13:43:06 -04:00
|
|
|
* Exit Codes:
|
2005-04-27 00:57:32 -04:00
|
|
|
*
|
2005-08-24 20:56:08 -04: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 13:43:06 -04:00
|
|
|
*/
|
|
|
|
|
int exitcode = 0;
|
2002-09-26 07:17:06 -04:00
|
|
|
int fatalexit = 0;
|
2000-06-05 20:43:17 -04:00
|
|
|
char keynametext[MXNAME];
|
2000-07-19 13:52:27 -04:00
|
|
|
char keyfile[MXNAME] = "";
|
2000-07-05 15:31:26 -04:00
|
|
|
char keysecret[MXNAME] = "";
|
2014-02-18 20:53:42 -05:00
|
|
|
unsigned char cookie_secret[33];
|
|
|
|
|
unsigned char cookie[8];
|
2023-12-07 02:07:55 -05:00
|
|
|
dst_algorithm_t hmac_alg = DST_ALG_UNKNOWN;
|
2006-01-26 21:35:15 -05:00
|
|
|
unsigned int digestbits = 0;
|
2000-06-05 20:43:17 -04:00
|
|
|
isc_buffer_t *namebuf = NULL;
|
2018-03-19 18:16:10 -04:00
|
|
|
dns_tsigkey_t *tsigkey = NULL;
|
2022-03-13 22:43:07 -04:00
|
|
|
dst_key_t *sig0key = NULL;
|
2018-04-17 11:29:14 -04:00
|
|
|
bool validated = true;
|
|
|
|
|
bool debugging = false;
|
|
|
|
|
bool debugtiming = false;
|
|
|
|
|
bool memdebugging = false;
|
2000-07-05 19:28:32 -04:00
|
|
|
char *progname = NULL;
|
2000-07-14 16:14:36 -04:00
|
|
|
dig_lookup_t *current_lookup = NULL;
|
2000-07-14 13:57:27 -04:00
|
|
|
|
2004-09-05 21:24:44 -04:00
|
|
|
#define DIG_MAX_ADDRESSES 20
|
|
|
|
|
|
2019-08-30 00:23:29 -04:00
|
|
|
static void
|
|
|
|
|
default_warnerr(const char *format, ...) {
|
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
|
|
printf(";; ");
|
|
|
|
|
va_start(args, format);
|
|
|
|
|
vprintf(format, args);
|
|
|
|
|
va_end(args);
|
|
|
|
|
printf("\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
default_comments(dig_lookup_t *lookup, const char *format, ...) {
|
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
|
|
if (lookup->comments) {
|
|
|
|
|
printf(";; ");
|
|
|
|
|
va_start(args, format);
|
|
|
|
|
vprintf(format, args);
|
|
|
|
|
va_end(args);
|
|
|
|
|
printf("\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-11 01:51:24 -04:00
|
|
|
/* dynamic callbacks */
|
|
|
|
|
|
2019-07-17 02:44:20 -04:00
|
|
|
isc_result_t (*dighost_printmessage)(dig_query_t *query,
|
|
|
|
|
const isc_buffer_t *msgbuf,
|
|
|
|
|
dns_message_t *msg, bool headers);
|
2017-08-11 01:51:24 -04:00
|
|
|
|
2019-08-30 00:23:29 -04:00
|
|
|
void (*dighost_error)(const char *format, ...) = default_warnerr;
|
|
|
|
|
|
|
|
|
|
void (*dighost_warning)(const char *format, ...) = default_warnerr;
|
|
|
|
|
|
|
|
|
|
void (*dighost_comments)(dig_lookup_t *lookup, const char *format,
|
|
|
|
|
...) = default_comments;
|
2019-07-17 02:44:20 -04:00
|
|
|
|
|
|
|
|
void (*dighost_received)(unsigned int bytes, isc_sockaddr_t *from,
|
|
|
|
|
dig_query_t *query);
|
2017-08-11 01:51:24 -04:00
|
|
|
|
|
|
|
|
void (*dighost_trying)(char *frm, dig_lookup_t *lookup);
|
|
|
|
|
|
|
|
|
|
void (*dighost_shutdown)(void);
|
|
|
|
|
|
|
|
|
|
/* forward declarations */
|
|
|
|
|
|
2021-04-27 06:03:20 -04:00
|
|
|
#define cancel_lookup(l) _cancel_lookup(l, __FILE__, __LINE__)
|
2000-05-11 21:02:37 -04:00
|
|
|
static void
|
2021-04-27 06:03:20 -04:00
|
|
|
_cancel_lookup(dig_lookup_t *lookup, const char *file, unsigned int line);
|
2000-05-11 21:02:37 -04:00
|
|
|
|
2000-07-18 14:51:40 -04:00
|
|
|
static void
|
2020-09-05 19:37:24 -04:00
|
|
|
recv_done(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
|
|
|
|
|
void *arg);
|
2000-07-18 14:51:40 -04:00
|
|
|
|
2006-07-31 20:49:02 -04:00
|
|
|
static void
|
2020-09-05 19:37:24 -04:00
|
|
|
start_udp(dig_query_t *query);
|
2006-07-31 20:49:02 -04:00
|
|
|
|
2022-04-07 05:23:49 -04:00
|
|
|
static void
|
|
|
|
|
start_tcp(dig_query_t *query);
|
|
|
|
|
|
2000-07-18 14:51:40 -04:00
|
|
|
static void
|
2020-11-03 00:38:56 -05:00
|
|
|
force_next(dig_query_t *query);
|
2000-07-18 14:51:40 -04:00
|
|
|
|
2018-04-17 11:29:14 -04:00
|
|
|
static void
|
2020-09-05 19:37:24 -04:00
|
|
|
launch_next_query(dig_query_t *query);
|
2001-06-14 21:26:14 -04:00
|
|
|
|
2014-08-21 04:05:55 -04:00
|
|
|
static void
|
2020-11-06 10:12:17 -05:00
|
|
|
clear_current_lookup(void);
|
2014-08-21 04:05:55 -04:00
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
next_origin(dig_lookup_t *oldlookup);
|
2002-08-12 14:25:25 -04:00
|
|
|
|
2000-05-02 19:23:12 -04:00
|
|
|
static int
|
|
|
|
|
count_dots(char *string) {
|
|
|
|
|
char *s;
|
2000-07-05 15:31:26 -04:00
|
|
|
int i = 0;
|
2000-05-02 19:23:12 -04:00
|
|
|
|
|
|
|
|
s = string;
|
2000-07-05 15:31:26 -04:00
|
|
|
while (*s != '\0') {
|
2000-05-02 19:23:12 -04:00
|
|
|
if (*s == '.') {
|
|
|
|
|
i++;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2000-05-02 19:23:12 -04:00
|
|
|
s++;
|
|
|
|
|
}
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
|
2000-04-26 14:34:17 -04:00
|
|
|
static void
|
2000-04-26 15:36:40 -04:00
|
|
|
hex_dump(isc_buffer_t *b) {
|
2009-02-15 19:01:37 -05:00
|
|
|
unsigned int len, i;
|
2000-04-26 14:34:17 -04:00
|
|
|
isc_region_t r;
|
|
|
|
|
|
2000-09-12 20:55:13 -04:00
|
|
|
isc_buffer_usedregion(b, &r);
|
2000-04-26 14:34:17 -04:00
|
|
|
|
2018-02-14 01:41:30 -05:00
|
|
|
printf("%u bytes\n", r.length);
|
2000-07-05 15:31:26 -04:00
|
|
|
for (len = 0; len < r.length; len++) {
|
2000-04-26 14:34:17 -04:00
|
|
|
printf("%02x ", r.base[len]);
|
2009-02-15 19:01:37 -05:00
|
|
|
if (len % 16 == 15) {
|
2020-04-02 21:51:06 -04:00
|
|
|
printf(" ");
|
2009-02-15 19:01:37 -05:00
|
|
|
for (i = len - 15; i <= len; i++) {
|
|
|
|
|
if (r.base[i] >= '!' && r.base[i] <= '}') {
|
|
|
|
|
putchar(r.base[i]);
|
2009-02-16 18:48:04 -05:00
|
|
|
} else {
|
2009-02-15 19:01:37 -05:00
|
|
|
putchar('.');
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2009-02-15 19:01:37 -05:00
|
|
|
}
|
2000-04-26 14:34:17 -04:00
|
|
|
printf("\n");
|
2009-02-15 19:01:37 -05:00
|
|
|
}
|
2000-04-26 14:34:17 -04:00
|
|
|
}
|
2009-02-15 19:01:37 -05:00
|
|
|
if (len % 16 != 0) {
|
|
|
|
|
for (i = len; (i % 16) != 0; i++) {
|
2020-04-02 21:51:06 -04:00
|
|
|
printf(" ");
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2020-04-02 21:51:06 -04:00
|
|
|
printf(" ");
|
2009-02-15 19:01:37 -05:00
|
|
|
for (i = ((len >> 4) << 4); i < len; i++) {
|
|
|
|
|
if (r.base[i] >= '!' && r.base[i] <= '}') {
|
|
|
|
|
putchar(r.base[i]);
|
2009-02-16 18:48:04 -05:00
|
|
|
} else {
|
2009-02-15 19:01:37 -05:00
|
|
|
putchar('.');
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2009-02-15 19:01:37 -05:00
|
|
|
}
|
2000-04-26 14:34:17 -04:00
|
|
|
printf("\n");
|
2009-02-15 19:01:37 -05:00
|
|
|
}
|
2000-04-26 14:34:17 -04:00
|
|
|
}
|
|
|
|
|
|
2005-04-27 00:57:32 -04:00
|
|
|
/*%
|
2001-08-29 14:57:28 -04:00
|
|
|
* Append 'len' bytes of 'text' at '*p', failing with
|
|
|
|
|
* ISC_R_NOSPACE if that would advance p past 'end'.
|
|
|
|
|
*/
|
|
|
|
|
static isc_result_t
|
2017-07-04 06:51:36 -04:00
|
|
|
append(const char *text, size_t len, char **p, char *end) {
|
2017-07-04 07:12:11 -04:00
|
|
|
if (*p + len > end) {
|
2001-08-29 14:57:28 -04:00
|
|
|
return ISC_R_NOSPACE;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2014-01-08 19:27:10 -05:00
|
|
|
memmove(*p, text, len);
|
2001-08-29 14:57:28 -04:00
|
|
|
*p += len;
|
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
|
reverse_octets(const char *in, char **p, char *end) {
|
2015-11-20 02:38:24 -05:00
|
|
|
const char *dot = strchr(in, '.');
|
2017-07-04 06:51:36 -04:00
|
|
|
size_t len;
|
2001-08-29 14:57:28 -04:00
|
|
|
if (dot != NULL) {
|
|
|
|
|
isc_result_t result;
|
|
|
|
|
result = reverse_octets(dot + 1, p, end);
|
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
|
return result;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2001-08-29 14:57:28 -04:00
|
|
|
result = append(".", 1, p, end);
|
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
|
return result;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2016-07-21 18:53:43 -04:00
|
|
|
len = (int)(dot - in);
|
2001-08-29 14:57:28 -04:00
|
|
|
} else {
|
2016-07-21 18:53:43 -04:00
|
|
|
len = (int)strlen(in);
|
2001-08-29 14:57:28 -04:00
|
|
|
}
|
|
|
|
|
return append(in, len, p, end);
|
|
|
|
|
}
|
2000-10-23 19:13:21 -04:00
|
|
|
|
|
|
|
|
isc_result_t
|
2018-11-02 10:23:01 -04:00
|
|
|
get_reverse(char *reverse, size_t len, char *value, bool strict) {
|
2001-08-29 14:57:28 -04:00
|
|
|
int r;
|
2000-10-23 19:13:21 -04:00
|
|
|
isc_result_t result;
|
2001-08-29 14:57:28 -04:00
|
|
|
isc_netaddr_t addr;
|
2000-10-23 19:13:21 -04:00
|
|
|
|
2001-08-29 14:57:28 -04:00
|
|
|
addr.family = AF_INET6;
|
2001-10-31 15:39:39 -05:00
|
|
|
r = inet_pton(AF_INET6, value, &addr.type.in6);
|
2001-08-29 14:57:28 -04:00
|
|
|
if (r > 0) {
|
|
|
|
|
/* This is a valid IPv6 address. */
|
2000-10-23 19:13:21 -04:00
|
|
|
dns_fixedname_t fname;
|
|
|
|
|
dns_name_t *name;
|
2002-08-27 00:53:43 -04:00
|
|
|
|
2018-03-28 08:38:09 -04:00
|
|
|
name = dns_fixedname_initname(&fname);
|
2022-12-07 14:58:40 -05:00
|
|
|
result = dns_byaddr_createptrname(&addr, name);
|
2000-10-23 19:13:21 -04:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
|
return result;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2013-12-03 20:47:23 -05:00
|
|
|
dns_name_format(name, reverse, (unsigned int)len);
|
2001-08-29 14:57:28 -04: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 00:02:54 -04:00
|
|
|
char *end = reverse + len;
|
2002-11-12 18:08:27 -05:00
|
|
|
if (strict && inet_pton(AF_INET, value, &addr.type.in) != 1) {
|
|
|
|
|
return DNS_R_BADDOTTEDQUAD;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2001-08-29 14:57:28 -04:00
|
|
|
result = reverse_octets(value, &p, end);
|
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
|
return result;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2001-08-29 14:57:28 -04:00
|
|
|
/* Append .in-addr.arpa. and a terminating NUL. */
|
|
|
|
|
result = append(".in-addr.arpa.", 15, &p, end);
|
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
|
return result;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2001-08-29 14:57:28 -04:00
|
|
|
return ISC_R_SUCCESS;
|
2000-10-23 19:13:21 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-23 00:58:12 -05:00
|
|
|
#if TARGET_OS_IPHONE
|
2000-04-26 14:34:17 -04:00
|
|
|
void
|
2017-11-23 00:58:12 -05:00
|
|
|
warn(const char *format, ...) {
|
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
|
|
fflush(stdout);
|
|
|
|
|
fprintf(stderr, ";; Warning: ");
|
|
|
|
|
va_start(args, format);
|
|
|
|
|
vfprintf(stderr, format, args);
|
|
|
|
|
va_end(args);
|
|
|
|
|
fprintf(stderr, "\n");
|
|
|
|
|
}
|
|
|
|
|
#else /* if TARGET_OS_IPHONE */
|
|
|
|
|
void
|
|
|
|
|
warn(const char *format, ...) {
|
2000-04-26 14:34:17 -04:00
|
|
|
va_list args;
|
|
|
|
|
|
2008-01-17 16:46:33 -05:00
|
|
|
fflush(stdout);
|
2000-07-12 22:14:17 -04:00
|
|
|
fprintf(stderr, "%s: ", progname);
|
2000-04-26 14:34:17 -04:00
|
|
|
va_start(args, format);
|
|
|
|
|
vfprintf(stderr, format, args);
|
|
|
|
|
va_end(args);
|
|
|
|
|
fprintf(stderr, "\n");
|
2017-11-23 00:58:12 -05:00
|
|
|
}
|
|
|
|
|
#endif /* if TARGET_OS_IPHONE */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
digexit(void) {
|
2000-08-03 13:43:06 -04:00
|
|
|
if (exitcode < 10) {
|
|
|
|
|
exitcode = 10;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2002-09-26 07:17:06 -04:00
|
|
|
if (fatalexit != 0) {
|
2024-02-07 08:44:39 -05:00
|
|
|
_exit(fatalexit);
|
2017-11-23 00:58:12 -05:00
|
|
|
}
|
2000-05-08 18:51:08 -04:00
|
|
|
exit(exitcode);
|
2000-04-26 14:34:17 -04:00
|
|
|
}
|
|
|
|
|
|
2017-11-23 00:58:12 -05:00
|
|
|
void
|
|
|
|
|
fatal(const char *format, ...) {
|
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
|
|
fflush(stdout);
|
|
|
|
|
fprintf(stderr, "%s: ", progname);
|
|
|
|
|
va_start(args, format);
|
|
|
|
|
vfprintf(stderr, format, args);
|
|
|
|
|
va_end(args);
|
|
|
|
|
fprintf(stderr, "\n");
|
2024-02-07 08:44:39 -05:00
|
|
|
if (fatalexit == 0 && exitcode != 0) {
|
|
|
|
|
fatalexit = exitcode;
|
|
|
|
|
} else if (fatalexit == 0) {
|
|
|
|
|
fatalexit = EXIT_FAILURE;
|
|
|
|
|
}
|
2017-11-23 00:58:12 -05:00
|
|
|
digexit();
|
|
|
|
|
}
|
|
|
|
|
|
2000-04-28 20:12:56 -04:00
|
|
|
void
|
2000-06-01 14:49:22 -04:00
|
|
|
debug(const char *format, ...) {
|
2000-04-28 20:12:56 -04:00
|
|
|
va_list args;
|
2013-11-18 18:46:24 -05:00
|
|
|
isc_time_t t;
|
2000-04-28 20:12:56 -04:00
|
|
|
|
2000-06-06 18:50:44 -04:00
|
|
|
if (debugging) {
|
2008-01-17 16:46:33 -05:00
|
|
|
fflush(stdout);
|
2013-10-24 19:09:33 -04:00
|
|
|
if (debugtiming) {
|
2023-03-30 18:12:33 -04:00
|
|
|
t = isc_time_now();
|
2018-02-14 01:41:30 -05:00
|
|
|
fprintf(stderr, "%u.%06u: ", isc_time_seconds(&t),
|
2013-11-18 18:59:53 -05:00
|
|
|
isc_time_nanoseconds(&t) / 1000);
|
2013-10-24 19:09:33 -04:00
|
|
|
}
|
2000-06-06 18:50:44 -04:00
|
|
|
va_start(args, format);
|
|
|
|
|
vfprintf(stderr, format, args);
|
|
|
|
|
va_end(args);
|
|
|
|
|
fprintf(stderr, "\n");
|
|
|
|
|
}
|
2000-04-28 20:12:56 -04:00
|
|
|
}
|
|
|
|
|
|
2000-05-05 14:22:16 -04:00
|
|
|
void
|
2000-06-01 14:49:22 -04:00
|
|
|
check_result(isc_result_t result, const char *msg) {
|
2000-05-08 18:51:08 -04:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2000-04-26 14:34:17 -04:00
|
|
|
fatal("%s: %s", msg, isc_result_totext(result));
|
2000-05-08 18:51:08 -04:00
|
|
|
}
|
2000-04-26 14:34:17 -04:00
|
|
|
}
|
|
|
|
|
|
2005-04-27 00:57:32 -04:00
|
|
|
/*%
|
2000-07-18 14:51:40 -04: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 12:35:30 -04:00
|
|
|
dig_server_t *
|
2004-09-05 21:24:44 -04:00
|
|
|
make_server(const char *servname, const char *userarg) {
|
2000-07-14 12:35:30 -04:00
|
|
|
dig_server_t *srv;
|
|
|
|
|
|
|
|
|
|
REQUIRE(servname != NULL);
|
|
|
|
|
|
2000-10-19 22:21:58 -04:00
|
|
|
debug("make_server(%s)", servname);
|
2000-07-14 12:35:30 -04:00
|
|
|
srv = isc_mem_allocate(mctx, sizeof(struct dig_server));
|
2011-02-21 02:34:57 -05:00
|
|
|
strlcpy(srv->servername, servname, MXNAME);
|
|
|
|
|
strlcpy(srv->userarg, userarg, MXNAME);
|
2000-10-19 22:21:58 -04:00
|
|
|
ISC_LINK_INIT(srv, link);
|
2000-07-14 12:35:30 -04:00
|
|
|
return srv;
|
|
|
|
|
}
|
2004-09-05 21:24:44 -04:00
|
|
|
|
2005-04-27 00:57:32 -04:00
|
|
|
/*%
|
2017-09-08 16:39:09 -04:00
|
|
|
* Create a copy of the server list from the resolver configuration structure.
|
2002-08-12 14:25:25 -04:00
|
|
|
* The dest list must have already had ISC_LIST_INIT applied.
|
|
|
|
|
*/
|
2002-08-28 03:04:48 -04:00
|
|
|
static void
|
2017-09-08 16:39:09 -04:00
|
|
|
get_server_list(irs_resconf_t *resconf) {
|
|
|
|
|
isc_sockaddrlist_t *servers;
|
|
|
|
|
isc_sockaddr_t *sa;
|
2002-08-12 14:25:25 -04:00
|
|
|
dig_server_t *newsrv;
|
2014-07-30 09:26:37 -04:00
|
|
|
char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") +
|
|
|
|
|
sizeof("%4000000000")];
|
2017-09-08 16:39:09 -04:00
|
|
|
debug("get_server_list()");
|
|
|
|
|
servers = irs_resconf_getnameservers(resconf);
|
|
|
|
|
for (sa = ISC_LIST_HEAD(*servers); sa != NULL;
|
2022-11-02 14:33:14 -04:00
|
|
|
sa = ISC_LIST_NEXT(sa, link))
|
|
|
|
|
{
|
2017-09-08 16:39:09 -04:00
|
|
|
int pf = isc_sockaddr_pf(sa);
|
|
|
|
|
isc_netaddr_t na;
|
|
|
|
|
isc_result_t result;
|
|
|
|
|
isc_buffer_t b;
|
2002-08-12 14:25:25 -04:00
|
|
|
|
2017-09-08 16:39:09 -04:00
|
|
|
if (pf == AF_INET && !have_ipv4) {
|
2008-12-12 21:43:25 -05:00
|
|
|
continue;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2017-09-08 16:39:09 -04:00
|
|
|
if (pf == AF_INET6 && !have_ipv6) {
|
2008-12-12 21:43:25 -05:00
|
|
|
continue;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2008-12-12 21:43:25 -05:00
|
|
|
|
2017-09-08 16:39:09 -04:00
|
|
|
isc_buffer_init(&b, tmp, sizeof(tmp));
|
|
|
|
|
isc_netaddr_fromsockaddr(&na, sa);
|
|
|
|
|
result = isc_netaddr_totext(&na, &b);
|
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
|
continue;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2017-09-08 16:39:09 -04:00
|
|
|
isc_buffer_putuint8(&b, 0);
|
|
|
|
|
if (pf == AF_INET6 && na.zone != 0) {
|
2014-07-30 09:26:37 -04:00
|
|
|
char buf[sizeof("%4000000000")];
|
2017-09-08 16:39:09 -04:00
|
|
|
snprintf(buf, sizeof(buf), "%%%u", na.zone);
|
2014-07-30 09:26:37 -04:00
|
|
|
strlcat(tmp, buf, sizeof(tmp));
|
|
|
|
|
}
|
2004-09-05 21:24:44 -04:00
|
|
|
newsrv = make_server(tmp, tmp);
|
2002-08-12 14:25:25 -04:00
|
|
|
ISC_LINK_INIT(newsrv, link);
|
2017-09-08 16:39:09 -04:00
|
|
|
ISC_LIST_APPEND(server_list, newsrv, link);
|
2002-08-12 14:25:25 -04:00
|
|
|
}
|
|
|
|
|
}
|
2004-09-05 21:24:44 -04:00
|
|
|
|
2002-08-12 14:25:25 -04:00
|
|
|
void
|
|
|
|
|
flush_server_list(void) {
|
|
|
|
|
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-05 21:24:44 -04:00
|
|
|
|
2002-08-12 14:25:25 -04:00
|
|
|
void
|
|
|
|
|
set_nameserver(char *opt) {
|
2004-09-05 21:24:44 -04:00
|
|
|
isc_result_t result;
|
|
|
|
|
isc_sockaddr_t sockaddrs[DIG_MAX_ADDRESSES];
|
|
|
|
|
isc_netaddr_t netaddr;
|
2004-09-15 21:01:27 -04:00
|
|
|
int count, i;
|
2002-08-12 14:25:25 -04:00
|
|
|
dig_server_t *srv;
|
2004-09-05 21:24:44 -04:00
|
|
|
char tmp[ISC_NETADDR_FORMATSIZE];
|
2002-08-12 14:25:25 -04:00
|
|
|
|
|
|
|
|
if (opt == NULL) {
|
|
|
|
|
return;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2002-08-12 14:25:25 -04:00
|
|
|
|
2022-07-26 07:03:40 -04:00
|
|
|
isc_loopmgr_blocking(loopmgr);
|
2022-12-16 05:19:16 -05:00
|
|
|
result = isc_getaddresses(opt, 0, sockaddrs, DIG_MAX_ADDRESSES, &count);
|
2022-07-26 07:03:40 -04:00
|
|
|
isc_loopmgr_nonblocking(loopmgr);
|
2004-09-05 21:24:44 -04:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
|
fatal("couldn't get address for '%s': %s", opt,
|
|
|
|
|
isc_result_totext(result));
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2004-09-05 21:24:44 -04:00
|
|
|
|
2002-08-12 14:25:25 -04:00
|
|
|
flush_server_list();
|
2008-01-18 18:46:58 -05:00
|
|
|
|
2004-09-05 21:24:44 -04: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);
|
|
|
|
|
if (srv == NULL) {
|
|
|
|
|
fatal("memory allocation failure");
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2004-09-05 21:24:44 -04:00
|
|
|
ISC_LIST_APPEND(server_list, srv, link);
|
|
|
|
|
}
|
2002-08-12 14:25:25 -04:00
|
|
|
}
|
|
|
|
|
|
2005-04-27 00:57:32 -04:00
|
|
|
/*%
|
2000-07-18 14:51:40 -04:00
|
|
|
* Produce a cloned server list. The dest list must have already had
|
|
|
|
|
* ISC_LIST_INIT applied.
|
|
|
|
|
*/
|
2000-07-14 12:35:30 -04:00
|
|
|
void
|
2001-07-27 20:55:15 -04:00
|
|
|
clone_server_list(dig_serverlist_t src, dig_serverlist_t *dest) {
|
2000-07-14 12:35:30 -04:00
|
|
|
dig_server_t *srv, *newsrv;
|
|
|
|
|
|
|
|
|
|
debug("clone_server_list()");
|
|
|
|
|
srv = ISC_LIST_HEAD(src);
|
|
|
|
|
while (srv != NULL) {
|
2004-09-05 21:24:44 -04:00
|
|
|
newsrv = make_server(srv->servername, srv->userarg);
|
2000-10-23 13:49:05 -04:00
|
|
|
ISC_LINK_INIT(newsrv, link);
|
2000-07-14 12:35:30 -04:00
|
|
|
ISC_LIST_ENQUEUE(*dest, newsrv, link);
|
|
|
|
|
srv = ISC_LIST_NEXT(srv, link);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-27 00:57:32 -04:00
|
|
|
/*%
|
2000-07-18 14:51:40 -04: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 15:31:26 -04:00
|
|
|
dig_lookup_t *
|
2000-07-13 14:52:58 -04:00
|
|
|
make_empty_lookup(void) {
|
2000-05-11 21:02:37 -04:00
|
|
|
dig_lookup_t *looknew;
|
2022-09-05 10:49:49 -04:00
|
|
|
int idnin = false, idnout = false;
|
|
|
|
|
|
2021-01-27 09:49:27 -05:00
|
|
|
#ifdef HAVE_LIBIDN2
|
2022-09-05 10:49:49 -04:00
|
|
|
if (getenv("IDN_DISABLE") == NULL) {
|
|
|
|
|
idnin = true;
|
|
|
|
|
idnout = isatty(1);
|
|
|
|
|
}
|
2021-01-27 09:49:27 -05:00
|
|
|
#endif /* HAVE_LIBIDN2 */
|
2000-05-11 21:02:37 -04:00
|
|
|
|
2000-09-21 18:46:39 -04:00
|
|
|
debug("make_empty_lookup()");
|
2000-05-11 21:02:37 -04:00
|
|
|
|
2000-07-12 20:32:20 -04:00
|
|
|
INSIST(!free_now);
|
2000-05-22 18:56:31 -04:00
|
|
|
|
2021-01-27 09:49:27 -05: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,
|
2022-09-05 10:49:49 -04:00
|
|
|
.idnin = idnin,
|
|
|
|
|
.idnout = idnout,
|
2021-01-27 09:49:27 -05:00
|
|
|
.udpsize = -1,
|
|
|
|
|
.edns = -1,
|
2025-03-11 19:02:05 -04:00
|
|
|
.original_edns = -1,
|
2021-01-27 09:49:27 -05:00
|
|
|
.recurse = true,
|
|
|
|
|
.retries = tries,
|
|
|
|
|
.comments = true,
|
|
|
|
|
.stats = true,
|
|
|
|
|
.section_question = true,
|
|
|
|
|
.section_answer = true,
|
|
|
|
|
.section_authority = true,
|
|
|
|
|
.section_additional = true,
|
|
|
|
|
.ednsneg = true,
|
|
|
|
|
};
|
|
|
|
|
|
2014-03-01 18:32:25 -05:00
|
|
|
dns_fixedname_init(&looknew->fdomain);
|
2000-10-19 22:21:58 -04:00
|
|
|
ISC_LINK_INIT(looknew, link);
|
2000-07-13 14:52:58 -04:00
|
|
|
ISC_LIST_INIT(looknew->q);
|
2000-07-14 12:35:30 -04:00
|
|
|
ISC_LIST_INIT(looknew->my_server_list);
|
2020-11-05 09:22:38 -05:00
|
|
|
|
2022-12-22 12:54:16 -05:00
|
|
|
isc_tlsctx_cache_create(mctx, &looknew->tls_ctx_cache);
|
2022-01-19 06:10:08 -05:00
|
|
|
|
2020-11-05 09:22:38 -05: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 14:52:58 -04:00
|
|
|
return looknew;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-13 00:10:35 -05:00
|
|
|
#define EDNSOPT_OPTIONS 100U
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
cloneopts(dig_lookup_t *looknew, dig_lookup_t *lookold) {
|
|
|
|
|
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;
|
|
|
|
|
if (lookold == NULL || lookold->ednsopts == NULL) {
|
|
|
|
|
return;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2017-11-13 00:10:35 -05:00
|
|
|
|
|
|
|
|
for (i = 0; i < lookold->ednsoptscnt; i++) {
|
|
|
|
|
len = lookold->ednsopts[i].length;
|
|
|
|
|
if (len != 0) {
|
|
|
|
|
INSIST(lookold->ednsopts[i].value != NULL);
|
2019-07-23 10:56:26 -04:00
|
|
|
looknew->ednsopts[i].value = isc_mem_allocate(mctx,
|
|
|
|
|
len);
|
2017-11-13 00:10:35 -05: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 00:57:32 -04:00
|
|
|
/*%
|
2000-07-18 14:51:40 -04: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 12:35:30 -04:00
|
|
|
* Caution: If you don't clone the servers, you MUST clone the server
|
2009-01-17 05:15:38 -05:00
|
|
|
* list separately from somewhere else, or construct it by hand.
|
2000-07-14 12:35:30 -04:00
|
|
|
*/
|
2000-07-13 14:52:58 -04:00
|
|
|
dig_lookup_t *
|
2018-04-17 11:29:14 -04:00
|
|
|
clone_lookup(dig_lookup_t *lookold, bool servers) {
|
2000-07-13 14:52:58 -04:00
|
|
|
dig_lookup_t *looknew;
|
|
|
|
|
|
|
|
|
|
debug("clone_lookup()");
|
|
|
|
|
|
|
|
|
|
INSIST(!free_now);
|
|
|
|
|
|
|
|
|
|
looknew = make_empty_lookup();
|
2012-10-03 02:44:03 -04:00
|
|
|
strlcpy(looknew->textname, lookold->textname, MXNAME);
|
|
|
|
|
strlcpy(looknew->cmdline, lookold->cmdline, MXNAME);
|
2001-01-08 18:50:34 -05:00
|
|
|
looknew->textname[MXNAME - 1] = 0;
|
2000-07-17 21:28:20 -04:00
|
|
|
looknew->rdtype = lookold->rdtype;
|
2001-07-27 20:11:15 -04:00
|
|
|
looknew->qrdtype = lookold->qrdtype;
|
2000-07-17 21:28:20 -04:00
|
|
|
looknew->rdclass = lookold->rdclass;
|
2000-12-08 12:50:47 -05:00
|
|
|
looknew->rdtypeset = lookold->rdtypeset;
|
|
|
|
|
looknew->rdclassset = lookold->rdclassset;
|
2000-05-11 21:02:37 -04:00
|
|
|
looknew->doing_xfr = lookold->doing_xfr;
|
2000-06-02 14:45:33 -04:00
|
|
|
looknew->ixfr_serial = lookold->ixfr_serial;
|
2000-05-11 21:02:37 -04:00
|
|
|
looknew->trace = lookold->trace;
|
|
|
|
|
looknew->trace_root = lookold->trace_root;
|
|
|
|
|
looknew->identify = lookold->identify;
|
2001-02-13 18:12:17 -05:00
|
|
|
looknew->identify_previous_line = lookold->identify_previous_line;
|
2000-09-12 20:03:28 -04:00
|
|
|
looknew->ignore = lookold->ignore;
|
2000-09-28 19:02:28 -04:00
|
|
|
looknew->servfail_stops = lookold->servfail_stops;
|
2000-10-13 13:54:00 -04:00
|
|
|
looknew->besteffort = lookold->besteffort;
|
2019-07-25 06:26:13 -04:00
|
|
|
looknew->dns64prefix = lookold->dns64prefix;
|
2000-11-13 16:34:03 -05:00
|
|
|
looknew->dnssec = lookold->dnssec;
|
2014-09-13 05:13:59 -04:00
|
|
|
looknew->ednsflags = lookold->ednsflags;
|
2015-05-18 22:46:06 -04:00
|
|
|
looknew->opcode = lookold->opcode;
|
2014-02-19 22:56:20 -05:00
|
|
|
looknew->expire = lookold->expire;
|
2008-04-02 22:01:08 -04:00
|
|
|
looknew->nsid = lookold->nsid;
|
2024-06-12 17:53:59 -04:00
|
|
|
looknew->zoneversion = lookold->zoneversion;
|
2017-01-04 12:16:30 -05:00
|
|
|
looknew->tcp_keepalive = lookold->tcp_keepalive;
|
2014-10-29 20:42:02 -04:00
|
|
|
looknew->header_only = lookold->header_only;
|
2021-01-27 09:49:27 -05: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-11-30 23:10:32 -05:00
|
|
|
|
2022-01-19 06:10:08 -05: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-11-30 23:10:32 -05:00
|
|
|
looknew->showbadcookie = lookold->showbadcookie;
|
2025-03-11 19:02:05 -04:00
|
|
|
looknew->showbadvers = lookold->showbadvers;
|
2015-07-05 19:44:24 -04:00
|
|
|
looknew->sendcookie = lookold->sendcookie;
|
|
|
|
|
looknew->seenbadcookie = lookold->seenbadcookie;
|
|
|
|
|
looknew->badcookie = lookold->badcookie;
|
|
|
|
|
looknew->cookie = lookold->cookie;
|
2017-11-13 00:10:35 -05:00
|
|
|
if (lookold->ednsopts != NULL) {
|
|
|
|
|
cloneopts(looknew, lookold);
|
|
|
|
|
} else {
|
|
|
|
|
looknew->ednsopts = NULL;
|
|
|
|
|
looknew->ednsoptscnt = 0;
|
|
|
|
|
}
|
2014-10-30 08:13:12 -04:00
|
|
|
looknew->ednsneg = lookold->ednsneg;
|
2017-01-04 12:16:30 -05:00
|
|
|
looknew->padding = lookold->padding;
|
2016-10-09 20:55:59 -04: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 01:36:46 -05:00
|
|
|
looknew->expandaaaa = lookold->expandaaaa;
|
2025-02-10 08:22:58 -05:00
|
|
|
looknew->svcparamkeycompat = lookold->svcparamkeycompat;
|
2016-10-09 20:55:59 -04:00
|
|
|
looknew->qr = lookold->qr;
|
2017-08-15 08:36:59 -04:00
|
|
|
looknew->idnin = lookold->idnin;
|
2016-10-27 21:05:19 -04:00
|
|
|
looknew->idnout = lookold->idnout;
|
2000-05-11 21:02:37 -04:00
|
|
|
looknew->udpsize = lookold->udpsize;
|
2005-06-06 20:16:01 -04:00
|
|
|
looknew->edns = lookold->edns;
|
2025-03-11 19:02:05 -04:00
|
|
|
looknew->original_edns = lookold->original_edns;
|
2000-05-11 21:02:37 -04:00
|
|
|
looknew->recurse = lookold->recurse;
|
2000-12-11 14:24:30 -05:00
|
|
|
looknew->aaonly = lookold->aaonly;
|
2000-06-16 14:00:05 -04:00
|
|
|
looknew->adflag = lookold->adflag;
|
|
|
|
|
looknew->cdflag = lookold->cdflag;
|
2018-04-17 19:18:41 -04:00
|
|
|
looknew->raflag = lookold->raflag;
|
|
|
|
|
looknew->tcflag = lookold->tcflag;
|
2016-02-09 05:08:34 -05:00
|
|
|
looknew->print_unknown_format = lookold->print_unknown_format;
|
2014-10-30 19:16:00 -04:00
|
|
|
looknew->zflag = lookold->zflag;
|
2020-05-08 15:39:16 -04:00
|
|
|
looknew->setqid = lookold->setqid;
|
|
|
|
|
looknew->qid = lookold->qid;
|
2000-05-11 21:02:37 -04:00
|
|
|
looknew->ns_search_only = lookold->ns_search_only;
|
|
|
|
|
looknew->tcp_mode = lookold->tcp_mode;
|
2014-05-13 19:59:02 -04:00
|
|
|
looknew->tcp_mode_set = lookold->tcp_mode_set;
|
2020-07-22 02:59:42 -04:00
|
|
|
looknew->tls_mode = lookold->tls_mode;
|
2000-05-11 21:02:37 -04: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 13:10:16 -04:00
|
|
|
looknew->origin = lookold->origin;
|
2000-09-21 18:46:39 -04:00
|
|
|
looknew->retries = lookold->retries;
|
2001-10-10 20:38:56 -04:00
|
|
|
looknew->tsigctx = NULL;
|
2006-12-07 00:52:16 -05:00
|
|
|
looknew->need_search = lookold->need_search;
|
|
|
|
|
looknew->done_as_is = lookold->done_as_is;
|
2016-10-09 20:55:59 -04:00
|
|
|
looknew->rrcomments = lookold->rrcomments;
|
2022-03-14 02:42:08 -04:00
|
|
|
looknew->fuzzing = lookold->fuzzing;
|
|
|
|
|
looknew->fuzztime = lookold->fuzztime;
|
2023-10-16 15:54:13 -04:00
|
|
|
looknew->proxy_mode = lookold->proxy_mode;
|
|
|
|
|
looknew->proxy_plain = lookold->proxy_plain;
|
|
|
|
|
looknew->proxy_local = lookold->proxy_local;
|
|
|
|
|
looknew->proxy_src_addr = lookold->proxy_src_addr;
|
|
|
|
|
looknew->proxy_dst_addr = lookold->proxy_dst_addr;
|
2000-05-11 21:02:37 -04:00
|
|
|
|
2014-02-19 18:51:02 -05:00
|
|
|
if (lookold->ecs_addr != NULL) {
|
2022-08-26 05:58:51 -04:00
|
|
|
looknew->ecs_addr = isc_mem_get(mctx,
|
|
|
|
|
sizeof(*looknew->ecs_addr));
|
|
|
|
|
memmove(looknew->ecs_addr, lookold->ecs_addr,
|
|
|
|
|
sizeof(*looknew->ecs_addr));
|
2014-02-19 18:51:02 -05:00
|
|
|
}
|
|
|
|
|
|
2021-05-21 20:20:44 -04:00
|
|
|
dns_name_copy(dns_fixedname_name(&lookold->fdomain),
|
|
|
|
|
dns_fixedname_name(&looknew->fdomain));
|
2014-03-01 18:32:25 -05:00
|
|
|
|
2000-07-14 12:35:30 -04:00
|
|
|
if (servers) {
|
2022-01-19 06:10:08 -05: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 12:35:30 -04:00
|
|
|
clone_server_list(lookold->my_server_list,
|
|
|
|
|
&looknew->my_server_list);
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2020-11-05 09:22:38 -05:00
|
|
|
|
|
|
|
|
isc_refcount_init(&looknew->references, 1);
|
|
|
|
|
|
|
|
|
|
looknew->magic = DIG_LOOKUP_MAGIC;
|
|
|
|
|
|
2000-07-13 14:52:58 -04:00
|
|
|
return looknew;
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-27 00:57:32 -04:00
|
|
|
/*%
|
2000-07-18 14:51:40 -04: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 14:52:58 -04:00
|
|
|
dig_lookup_t *
|
2018-04-17 11:29:14 -04:00
|
|
|
requeue_lookup(dig_lookup_t *lookold, bool servers) {
|
2020-11-05 09:22:38 -05:00
|
|
|
dig_lookup_t *looknew = NULL;
|
2000-07-13 14:52:58 -04:00
|
|
|
|
|
|
|
|
debug("requeue_lookup()");
|
|
|
|
|
|
|
|
|
|
lookup_counter++;
|
|
|
|
|
if (lookup_counter > LOOKUP_LIMIT) {
|
2001-09-25 20:38:39 -04:00
|
|
|
fatal("too many lookups");
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2000-07-13 14:52:58 -04:00
|
|
|
|
|
|
|
|
looknew = clone_lookup(lookold, servers);
|
|
|
|
|
INSIST(looknew != NULL);
|
|
|
|
|
|
2001-07-27 01:26:38 -04:00
|
|
|
debug("before insertion, init@%p -> %p, new@%p -> %p", lookold,
|
2000-07-05 15:31:26 -04:00
|
|
|
lookold->link.next, looknew, looknew->link.next);
|
2000-07-14 17:33:03 -04:00
|
|
|
ISC_LIST_PREPEND(lookup_list, looknew, link);
|
2001-07-27 01:26:38 -04:00
|
|
|
debug("after insertion, init -> %p, new = %p, new -> %p", lookold,
|
2000-07-05 15:31:26 -04:00
|
|
|
looknew, looknew->link.next);
|
2000-05-11 21:02:37 -04:00
|
|
|
return looknew;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-18 10:27:50 -04:00
|
|
|
void
|
2000-07-19 13:52:27 -04:00
|
|
|
setup_text_key(void) {
|
|
|
|
|
isc_result_t result;
|
2025-02-21 16:36:57 -05:00
|
|
|
dns_fixedname_t fkey;
|
|
|
|
|
dns_name_t *keyname = dns_fixedname_initname(&fkey);
|
2000-07-19 13:52:27 -04:00
|
|
|
isc_buffer_t secretbuf;
|
2016-07-21 18:53:43 -04:00
|
|
|
unsigned int secretsize;
|
2000-07-19 13:52:27 -04:00
|
|
|
unsigned char *secretstore;
|
|
|
|
|
|
|
|
|
|
debug("setup_text_key()");
|
2020-02-02 02:35:46 -05:00
|
|
|
isc_buffer_allocate(mctx, &namebuf, MXNAME);
|
2000-07-19 13:52:27 -04:00
|
|
|
isc_buffer_putstr(namebuf, keynametext);
|
2016-07-21 18:53:43 -04:00
|
|
|
secretsize = (unsigned int)strlen(keysecret) * 3 / 4;
|
2000-07-20 13:58:59 -04:00
|
|
|
secretstore = isc_mem_allocate(mctx, secretsize);
|
2000-07-19 13:52:27 -04:00
|
|
|
isc_buffer_init(&secretbuf, secretstore, secretsize);
|
2001-03-21 19:07:07 -05:00
|
|
|
result = isc_base64_decodestring(keysecret, &secretbuf);
|
2001-07-27 01:52:45 -04:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2000-07-31 20:53:20 -04:00
|
|
|
goto failure;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2008-01-18 18:46:58 -05:00
|
|
|
|
2000-07-19 13:52:27 -04:00
|
|
|
secretsize = isc_buffer_usedlength(&secretbuf);
|
2000-07-31 21:33:37 -04:00
|
|
|
|
2023-12-07 02:07:55 -05:00
|
|
|
if (hmac_alg == DST_ALG_UNKNOWN) {
|
2011-11-06 18:18:07 -05:00
|
|
|
result = DST_R_UNSUPPORTEDALG;
|
|
|
|
|
goto failure;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-22 03:11:38 -05:00
|
|
|
result = dns_name_fromtext(keyname, namebuf, dns_rootname, 0);
|
2001-07-27 01:52:45 -04:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2000-07-31 20:53:20 -04:00
|
|
|
goto failure;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2001-07-27 01:52:45 -04:00
|
|
|
|
2025-02-21 16:36:57 -05:00
|
|
|
result = dns_tsigkey_create(keyname, hmac_alg, secretstore,
|
2023-04-11 02:46:10 -04:00
|
|
|
(int)secretsize, mctx, &tsigkey);
|
2001-07-27 01:52:45 -04:00
|
|
|
failure:
|
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
2000-07-19 13:52:27 -04:00
|
|
|
printf(";; Couldn't create key %s: %s\n", keynametext,
|
2001-07-27 01:41:46 -04:00
|
|
|
isc_result_totext(result));
|
2006-01-26 21:35:15 -05:00
|
|
|
} else {
|
2018-03-19 18:16:10 -04:00
|
|
|
dst_key_setbits(tsigkey->key, digestbits);
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2001-07-27 01:52:45 -04:00
|
|
|
|
2000-07-20 13:58:59 -04:00
|
|
|
isc_mem_free(mctx, secretstore);
|
2000-07-19 13:52:27 -04:00
|
|
|
isc_buffer_free(&namebuf);
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-13 05:13:59 -04:00
|
|
|
static isc_result_t
|
2018-03-28 08:19:37 -04:00
|
|
|
parse_uint_helper(uint32_t *uip, const char *value, uint32_t max,
|
2014-09-13 05:13:59 -04:00
|
|
|
const char *desc, int base) {
|
2018-03-28 08:19:37 -04:00
|
|
|
uint32_t n;
|
2014-09-13 05:13:59 -04:00
|
|
|
isc_result_t result = isc_parse_uint32(&n, value, base);
|
2009-09-14 23:13:44 -04:00
|
|
|
if (result == ISC_R_SUCCESS && n > max) {
|
|
|
|
|
result = ISC_R_RANGE;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2009-09-14 23:13:44 -04:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
|
printf("invalid %s '%s': %s\n", desc, value,
|
|
|
|
|
isc_result_totext(result));
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
*uip = n;
|
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-13 05:13:59 -04:00
|
|
|
isc_result_t
|
2018-03-28 08:19:37 -04:00
|
|
|
parse_uint(uint32_t *uip, const char *value, uint32_t max, const char *desc) {
|
2014-09-13 05:13:59 -04:00
|
|
|
return parse_uint_helper(uip, value, max, desc, 10);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
isc_result_t
|
2018-03-28 08:19:37 -04:00
|
|
|
parse_xint(uint32_t *uip, const char *value, uint32_t max, const char *desc) {
|
2014-09-13 05:13:59 -04:00
|
|
|
return parse_uint_helper(uip, value, max, desc, 0);
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-28 08:19:37 -04:00
|
|
|
static uint32_t
|
|
|
|
|
parse_bits(char *arg, const char *desc, uint32_t max) {
|
2009-09-15 19:48:09 -04:00
|
|
|
isc_result_t result;
|
2018-03-28 08:19:37 -04:00
|
|
|
uint32_t tmp;
|
2009-09-15 19:48:09 -04:00
|
|
|
|
|
|
|
|
result = parse_uint(&tmp, arg, max, desc);
|
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
|
fatal("couldn't parse digest bits");
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2009-09-15 19:48:09 -04:00
|
|
|
tmp = (tmp + 7) & ~0x7U;
|
|
|
|
|
return tmp;
|
2009-09-14 23:13:44 -04:00
|
|
|
}
|
|
|
|
|
|
2014-02-19 18:51:02 -05:00
|
|
|
isc_result_t
|
|
|
|
|
parse_netprefix(isc_sockaddr_t **sap, const char *value) {
|
|
|
|
|
isc_result_t result = ISC_R_SUCCESS;
|
|
|
|
|
isc_sockaddr_t *sa = NULL;
|
|
|
|
|
struct in_addr in4;
|
|
|
|
|
struct in6_addr in6;
|
2018-03-28 08:19:37 -04:00
|
|
|
uint32_t prefix_length = 0xffffffff;
|
2014-02-19 18:51:02 -05:00
|
|
|
char *slash = NULL;
|
2018-04-17 11:29:14 -04:00
|
|
|
bool parsed = false;
|
|
|
|
|
bool prefix_parsed = false;
|
2015-11-20 02:38:24 -05:00
|
|
|
char buf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:XXX.XXX.XXX.XXX/128")];
|
2014-02-19 18:51:02 -05:00
|
|
|
|
2017-02-13 23:52:40 -05:00
|
|
|
REQUIRE(sap != NULL && *sap == NULL);
|
|
|
|
|
|
2015-11-20 02:38:24 -05:00
|
|
|
if (strlcpy(buf, value, sizeof(buf)) >= sizeof(buf)) {
|
|
|
|
|
fatal("invalid prefix '%s'\n", value);
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2015-11-20 02:38:24 -05:00
|
|
|
|
2022-08-26 05:58:51 -04:00
|
|
|
sa = isc_mem_get(mctx, sizeof(*sa));
|
|
|
|
|
*sa = (isc_sockaddr_t){ .length = 0 };
|
2016-09-13 18:22:15 -04:00
|
|
|
|
|
|
|
|
if (strcmp(buf, "0") == 0) {
|
|
|
|
|
sa->type.sa.sa_family = AF_UNSPEC;
|
|
|
|
|
prefix_length = 0;
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-20 02:38:24 -05:00
|
|
|
slash = strchr(buf, '/');
|
|
|
|
|
if (slash != NULL) {
|
2014-02-19 18:51:02 -05:00
|
|
|
*slash = '\0';
|
2016-03-23 12:29:57 -04:00
|
|
|
result = isc_parse_uint32(&prefix_length, slash + 1, 10);
|
2014-02-19 18:51:02 -05:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2015-11-20 02:38:24 -05:00
|
|
|
fatal("invalid prefix length in '%s': %s\n", value,
|
2014-02-19 18:51:02 -05:00
|
|
|
isc_result_totext(result));
|
|
|
|
|
}
|
2018-04-17 11:29:14 -04:00
|
|
|
prefix_parsed = true;
|
2016-03-23 18:00:30 -04:00
|
|
|
}
|
|
|
|
|
|
2015-11-20 02:38:24 -05:00
|
|
|
if (inet_pton(AF_INET6, buf, &in6) == 1) {
|
2018-04-17 11:29:14 -04:00
|
|
|
parsed = true;
|
2015-11-20 02:38:24 -05:00
|
|
|
isc_sockaddr_fromin6(sa, &in6, 0);
|
2016-03-23 12:29:57 -04:00
|
|
|
if (prefix_length > 128) {
|
|
|
|
|
prefix_length = 128;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2015-11-20 02:38:24 -05:00
|
|
|
} else if (inet_pton(AF_INET, buf, &in4) == 1) {
|
2018-04-17 11:29:14 -04:00
|
|
|
parsed = true;
|
2014-02-19 18:51:02 -05:00
|
|
|
isc_sockaddr_fromin(sa, &in4, 0);
|
2016-03-23 12:29:57 -04:00
|
|
|
if (prefix_length > 32) {
|
|
|
|
|
prefix_length = 32;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2016-09-13 18:22:15 -04:00
|
|
|
} else if (prefix_parsed) {
|
2014-02-19 18:51:02 -05:00
|
|
|
int i;
|
|
|
|
|
|
2016-01-29 20:41:29 -05:00
|
|
|
for (i = 0; i < 3 && strlen(buf) < sizeof(buf) - 2; i++) {
|
2014-02-19 18:51:02 -05:00
|
|
|
strlcat(buf, ".0", sizeof(buf));
|
|
|
|
|
if (inet_pton(AF_INET, buf, &in4) == 1) {
|
2018-04-17 11:29:14 -04:00
|
|
|
parsed = true;
|
2014-02-19 18:51:02 -05:00
|
|
|
isc_sockaddr_fromin(sa, &in4, 0);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-01-27 22:00:36 -05:00
|
|
|
|
2016-03-23 12:29:57 -04:00
|
|
|
if (prefix_length > 32) {
|
|
|
|
|
prefix_length = 32;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2014-02-19 18:51:02 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!parsed) {
|
|
|
|
|
fatal("invalid address '%s'", value);
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2014-02-19 18:51:02 -05:00
|
|
|
|
2016-09-13 18:22:15 -04:00
|
|
|
done:
|
2016-03-23 12:29:57 -04:00
|
|
|
sa->length = prefix_length;
|
2014-02-19 18:51:02 -05:00
|
|
|
*sap = sa;
|
|
|
|
|
|
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-14 23:13:44 -04:00
|
|
|
/*
|
|
|
|
|
* Parse HMAC algorithm specification
|
|
|
|
|
*/
|
|
|
|
|
void
|
2023-04-11 22:01:31 -04:00
|
|
|
parse_hmac(const char *algname) {
|
2009-09-14 23:13:44 -04:00
|
|
|
char buf[20];
|
2016-07-21 18:53:43 -04:00
|
|
|
size_t len;
|
2009-09-14 23:13:44 -04:00
|
|
|
|
2023-04-11 22:01:31 -04:00
|
|
|
REQUIRE(algname != NULL);
|
2009-09-14 23:13:44 -04:00
|
|
|
|
2023-04-11 22:01:31 -04:00
|
|
|
len = strlen(algname);
|
2016-07-21 18:53:43 -04:00
|
|
|
if (len >= sizeof(buf)) {
|
2023-04-11 22:01:31 -04:00
|
|
|
fatal("unknown key type '%.*s'", (int)len, algname);
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2023-04-11 22:01:31 -04:00
|
|
|
strlcpy(buf, algname, sizeof(buf));
|
2009-09-14 23:13:44 -04:00
|
|
|
|
|
|
|
|
digestbits = 0;
|
|
|
|
|
|
|
|
|
|
if (strcasecmp(buf, "hmac-md5") == 0) {
|
2023-12-07 02:07:55 -05:00
|
|
|
hmac_alg = DST_ALG_HMACMD5;
|
2009-09-14 23:13:44 -04:00
|
|
|
} else if (strncasecmp(buf, "hmac-md5-", 9) == 0) {
|
2023-12-07 02:07:55 -05:00
|
|
|
hmac_alg = DST_ALG_HMACMD5;
|
2009-09-14 23:13:44 -04:00
|
|
|
digestbits = parse_bits(&buf[9], "digest-bits [0..128]", 128);
|
2016-08-18 18:02:51 -04:00
|
|
|
} else if (strcasecmp(buf, "hmac-sha1") == 0) {
|
2023-12-07 02:07:55 -05:00
|
|
|
hmac_alg = DST_ALG_HMACSHA1;
|
2009-09-14 23:13:44 -04:00
|
|
|
digestbits = 0;
|
|
|
|
|
} else if (strncasecmp(buf, "hmac-sha1-", 10) == 0) {
|
2023-12-07 02:07:55 -05:00
|
|
|
hmac_alg = DST_ALG_HMACSHA1;
|
2009-09-14 23:13:44 -04:00
|
|
|
digestbits = parse_bits(&buf[10], "digest-bits [0..160]", 160);
|
|
|
|
|
} else if (strcasecmp(buf, "hmac-sha224") == 0) {
|
2023-12-07 02:07:55 -05:00
|
|
|
hmac_alg = DST_ALG_HMACSHA224;
|
2009-09-14 23:13:44 -04:00
|
|
|
} else if (strncasecmp(buf, "hmac-sha224-", 12) == 0) {
|
2023-12-07 02:07:55 -05:00
|
|
|
hmac_alg = DST_ALG_HMACSHA224;
|
2009-09-14 23:13:44 -04:00
|
|
|
digestbits = parse_bits(&buf[12], "digest-bits [0..224]", 224);
|
|
|
|
|
} else if (strcasecmp(buf, "hmac-sha256") == 0) {
|
2023-12-07 02:07:55 -05:00
|
|
|
hmac_alg = DST_ALG_HMACSHA256;
|
2009-09-14 23:13:44 -04:00
|
|
|
} else if (strncasecmp(buf, "hmac-sha256-", 12) == 0) {
|
2023-12-07 02:07:55 -05:00
|
|
|
hmac_alg = DST_ALG_HMACSHA256;
|
2009-09-14 23:13:44 -04:00
|
|
|
digestbits = parse_bits(&buf[12], "digest-bits [0..256]", 256);
|
|
|
|
|
} else if (strcasecmp(buf, "hmac-sha384") == 0) {
|
2023-12-07 02:07:55 -05:00
|
|
|
hmac_alg = DST_ALG_HMACSHA384;
|
2009-09-14 23:13:44 -04:00
|
|
|
} else if (strncasecmp(buf, "hmac-sha384-", 12) == 0) {
|
2023-12-07 02:07:55 -05:00
|
|
|
hmac_alg = DST_ALG_HMACSHA384;
|
2009-09-14 23:13:44 -04:00
|
|
|
digestbits = parse_bits(&buf[12], "digest-bits [0..384]", 384);
|
|
|
|
|
} else if (strcasecmp(buf, "hmac-sha512") == 0) {
|
2023-12-07 02:07:55 -05:00
|
|
|
hmac_alg = DST_ALG_HMACSHA512;
|
2009-09-14 23:13:44 -04:00
|
|
|
} else if (strncasecmp(buf, "hmac-sha512-", 12) == 0) {
|
2023-12-07 02:07:55 -05:00
|
|
|
hmac_alg = DST_ALG_HMACSHA512;
|
2009-09-14 23:13:44 -04:00
|
|
|
digestbits = parse_bits(&buf[12], "digest-bits [0..512]", 512);
|
|
|
|
|
} else {
|
|
|
|
|
fprintf(stderr,
|
|
|
|
|
";; Warning, ignoring "
|
|
|
|
|
"invalid TSIG algorithm %s\n",
|
|
|
|
|
buf);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Get a key from a named.conf format keyfile
|
|
|
|
|
*/
|
|
|
|
|
static isc_result_t
|
|
|
|
|
read_confkey(void) {
|
|
|
|
|
cfg_parser_t *pctx = NULL;
|
|
|
|
|
cfg_obj_t *file = NULL;
|
2015-01-20 16:29:18 -05:00
|
|
|
const cfg_obj_t *keyobj = NULL;
|
2009-09-14 23:13:44 -04:00
|
|
|
const cfg_obj_t *secretobj = NULL;
|
|
|
|
|
const cfg_obj_t *algorithmobj = NULL;
|
|
|
|
|
const char *keyname;
|
|
|
|
|
const char *secretstr;
|
|
|
|
|
const char *algorithm;
|
|
|
|
|
isc_result_t result;
|
|
|
|
|
|
|
|
|
|
if (!isc_file_exists(keyfile)) {
|
|
|
|
|
return ISC_R_FILENOTFOUND;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2009-09-14 23:13:44 -04:00
|
|
|
|
2024-08-13 12:20:26 -04:00
|
|
|
result = cfg_parser_create(mctx, &pctx);
|
2009-09-14 23:13:44 -04:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
|
goto cleanup;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2009-09-14 23:13:44 -04:00
|
|
|
|
|
|
|
|
result = cfg_parse_file(pctx, keyfile, &cfg_type_sessionkey, &file);
|
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
|
goto cleanup;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2009-09-14 23:13:44 -04:00
|
|
|
|
2015-01-20 16:29:18 -05:00
|
|
|
result = cfg_map_get(file, "key", &keyobj);
|
2009-09-14 23:13:44 -04:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
|
goto cleanup;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2009-09-14 23:13:44 -04:00
|
|
|
|
2015-01-20 16:29:18 -05:00
|
|
|
(void)cfg_map_get(keyobj, "secret", &secretobj);
|
|
|
|
|
(void)cfg_map_get(keyobj, "algorithm", &algorithmobj);
|
2009-09-14 23:13:44 -04:00
|
|
|
if (secretobj == NULL || algorithmobj == NULL) {
|
|
|
|
|
fatal("key must have algorithm and secret");
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2009-09-14 23:13:44 -04:00
|
|
|
|
2015-01-20 16:29:18 -05:00
|
|
|
keyname = cfg_obj_asstring(cfg_map_getname(keyobj));
|
2009-09-14 23:13:44 -04:00
|
|
|
secretstr = cfg_obj_asstring(secretobj);
|
|
|
|
|
algorithm = cfg_obj_asstring(algorithmobj);
|
|
|
|
|
|
2012-10-03 02:44:03 -04:00
|
|
|
strlcpy(keynametext, keyname, sizeof(keynametext));
|
|
|
|
|
strlcpy(keysecret, secretstr, sizeof(keysecret));
|
2009-09-14 23:13:44 -04:00
|
|
|
parse_hmac(algorithm);
|
|
|
|
|
setup_text_key();
|
|
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
|
if (pctx != NULL) {
|
|
|
|
|
if (file != NULL) {
|
|
|
|
|
cfg_obj_destroy(pctx, &file);
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2009-09-14 23:13:44 -04:00
|
|
|
cfg_parser_destroy(&pctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-18 10:27:50 -04:00
|
|
|
void
|
2000-07-19 13:52:27 -04:00
|
|
|
setup_file_key(void) {
|
|
|
|
|
isc_result_t result;
|
|
|
|
|
dst_key_t *dstkey = NULL;
|
2000-07-31 21:33:37 -04:00
|
|
|
|
2000-07-19 13:52:27 -04:00
|
|
|
debug("setup_file_key()");
|
2009-09-14 23:13:44 -04:00
|
|
|
|
2022-03-13 22:43:07 -04:00
|
|
|
if (sig0key != NULL) {
|
|
|
|
|
dst_key_free(&sig0key);
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-14 23:13:44 -04:00
|
|
|
/* Try reading the key from a K* pair */
|
2009-07-19 00:18:05 -04:00
|
|
|
result = dst_key_fromnamedfile(
|
|
|
|
|
keyfile, NULL, DST_TYPE_PRIVATE | DST_TYPE_KEY, mctx, &dstkey);
|
2009-09-14 23:13:44 -04:00
|
|
|
|
|
|
|
|
/* If that didn't work, try reading it as a session.key keyfile */
|
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
|
result = read_confkey();
|
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
|
return;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2009-09-14 23:13:44 -04:00
|
|
|
}
|
|
|
|
|
|
2000-07-19 13:52:27 -04:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
|
fprintf(stderr, "Couldn't read key from %s: %s\n", keyfile,
|
|
|
|
|
isc_result_totext(result));
|
|
|
|
|
goto failure;
|
|
|
|
|
}
|
2001-07-27 01:52:45 -04:00
|
|
|
|
2006-01-26 21:35:15 -05:00
|
|
|
switch (dst_key_alg(dstkey)) {
|
|
|
|
|
case DST_ALG_HMACMD5:
|
|
|
|
|
case DST_ALG_HMACSHA1:
|
|
|
|
|
case DST_ALG_HMACSHA224:
|
|
|
|
|
case DST_ALG_HMACSHA256:
|
|
|
|
|
case DST_ALG_HMACSHA384:
|
|
|
|
|
case DST_ALG_HMACSHA512:
|
2023-12-07 02:07:55 -05:00
|
|
|
hmac_alg = dst_key_alg(dstkey);
|
2006-01-26 21:35:15 -05:00
|
|
|
break;
|
2023-04-11 22:01:31 -04:00
|
|
|
default:
|
|
|
|
|
dst_key_attach(dstkey, &sig0key);
|
|
|
|
|
dst_key_free(&dstkey);
|
|
|
|
|
return;
|
2006-01-26 21:35:15 -05:00
|
|
|
}
|
2022-03-13 22:43:07 -04:00
|
|
|
|
2023-04-11 22:01:31 -04:00
|
|
|
if (dstkey != NULL) {
|
2023-12-07 02:07:55 -05:00
|
|
|
result = dns_tsigkey_createfromkey(
|
|
|
|
|
dst_key_name(dstkey), hmac_alg, dstkey, false, false,
|
|
|
|
|
NULL, 0, 0, mctx, &tsigkey);
|
2022-03-13 22:43:07 -04:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
|
printf(";; Couldn't create key %s: %s\n", keynametext,
|
|
|
|
|
isc_result_totext(result));
|
|
|
|
|
}
|
2000-07-19 13:52:27 -04:00
|
|
|
}
|
2023-04-11 22:01:31 -04:00
|
|
|
|
2000-07-19 13:52:27 -04:00
|
|
|
failure:
|
|
|
|
|
if (dstkey != NULL) {
|
|
|
|
|
dst_key_free(&dstkey);
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2000-07-19 13:52:27 -04:00
|
|
|
}
|
|
|
|
|
|
2001-01-18 00:12:44 -05:00
|
|
|
static dig_searchlist_t *
|
|
|
|
|
make_searchlist_entry(char *domain) {
|
|
|
|
|
dig_searchlist_t *search;
|
|
|
|
|
search = isc_mem_allocate(mctx, sizeof(*search));
|
2012-10-03 02:44:03 -04:00
|
|
|
strlcpy(search->origin, domain, MXNAME);
|
2001-01-18 00:12:44 -05:00
|
|
|
search->origin[MXNAME - 1] = 0;
|
|
|
|
|
ISC_LINK_INIT(search, link);
|
|
|
|
|
return search;
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-17 21:48:13 -04:00
|
|
|
static void
|
|
|
|
|
clear_searchlist(void) {
|
|
|
|
|
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 03:04:48 -04:00
|
|
|
static void
|
2017-09-08 16:39:09 -04:00
|
|
|
create_search_list(irs_resconf_t *resconf) {
|
|
|
|
|
irs_resconf_searchlist_t *list;
|
|
|
|
|
irs_resconf_search_t *entry;
|
2002-08-12 14:25:25 -04:00
|
|
|
dig_searchlist_t *search;
|
|
|
|
|
|
|
|
|
|
debug("create_search_list()");
|
2010-05-17 21:48:13 -04:00
|
|
|
clear_searchlist();
|
2002-08-12 14:25:25 -04:00
|
|
|
|
2017-09-08 16:39:09 -04:00
|
|
|
list = irs_resconf_getsearchlist(resconf);
|
|
|
|
|
for (entry = ISC_LIST_HEAD(*list); entry != NULL;
|
|
|
|
|
entry = ISC_LIST_NEXT(entry, link))
|
|
|
|
|
{
|
|
|
|
|
search = make_searchlist_entry(entry->domain);
|
2002-08-12 14:25:25 -04:00
|
|
|
ISC_LIST_APPEND(search_list, search, link);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-13 08:31:18 -05: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
|
|
|
|
|
add_fallback_nameserver(const char *addr) {
|
|
|
|
|
dig_server_t *server = make_server(addr, addr);
|
|
|
|
|
ISC_LINK_INIT(server, link);
|
|
|
|
|
ISC_LIST_APPEND(server_list, server, link);
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-27 00:57:32 -04:00
|
|
|
/*%
|
2000-07-18 14:51:40 -04:00
|
|
|
* Setup the system as a whole, reading key information and resolv.conf
|
|
|
|
|
* settings.
|
|
|
|
|
*/
|
2000-05-09 14:05:13 -04:00
|
|
|
void
|
2018-04-17 11:29:14 -04:00
|
|
|
setup_system(bool ipv4only, bool ipv6only) {
|
2017-09-08 16:39:09 -04:00
|
|
|
irs_resconf_t *resconf = NULL;
|
2014-02-18 20:53:42 -05:00
|
|
|
isc_result_t result;
|
2000-07-31 21:33:37 -04:00
|
|
|
|
2000-07-05 15:31:26 -04:00
|
|
|
debug("setup_system()");
|
2000-06-20 21:40:42 -04:00
|
|
|
|
2015-08-11 22:50:15 -04:00
|
|
|
if (ipv4only) {
|
|
|
|
|
if (have_ipv4) {
|
|
|
|
|
isc_net_disableipv6();
|
2018-04-17 11:29:14 -04:00
|
|
|
have_ipv6 = false;
|
2015-08-11 22:50:15 -04:00
|
|
|
} else {
|
|
|
|
|
fatal("can't find IPv4 networking");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ipv6only) {
|
|
|
|
|
if (have_ipv6) {
|
|
|
|
|
isc_net_disableipv4();
|
2018-04-17 11:29:14 -04:00
|
|
|
have_ipv4 = false;
|
2015-08-11 22:50:15 -04:00
|
|
|
} else {
|
|
|
|
|
fatal("can't find IPv6 networking");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-08 16:39:09 -04:00
|
|
|
result = irs_resconf_load(mctx, RESOLV_CONF, &resconf);
|
|
|
|
|
if (result != ISC_R_SUCCESS && result != ISC_R_FILENOTFOUND) {
|
2005-06-06 21:00:00 -04:00
|
|
|
fatal("parse of %s failed", RESOLV_CONF);
|
2000-04-26 14:34:17 -04:00
|
|
|
}
|
2008-01-18 18:46:58 -05:00
|
|
|
|
2017-09-08 16:39:09 -04:00
|
|
|
create_search_list(resconf);
|
2005-09-08 19:59:45 -04:00
|
|
|
if (ndots == -1) {
|
2017-09-08 16:39:09 -04:00
|
|
|
ndots = irs_resconf_getndots(resconf);
|
2005-09-08 19:59:45 -04:00
|
|
|
debug("ndots is %d.", ndots);
|
|
|
|
|
}
|
2021-06-22 10:35:46 -04: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-26 20:03:12 -04:00
|
|
|
|
2009-06-23 22:51:29 -04:00
|
|
|
/* If user doesn't specify server use nameservers from resolv.conf. */
|
2008-12-12 21:43:25 -05:00
|
|
|
if (ISC_LIST_EMPTY(server_list)) {
|
2017-09-08 16:39:09 -04:00
|
|
|
get_server_list(resconf);
|
2008-12-12 21:43:25 -05:00
|
|
|
}
|
2000-05-02 19:23:12 -04:00
|
|
|
|
2018-11-13 08:31:18 -05: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 16:39:09 -04:00
|
|
|
irs_resconf_destroy(&resconf);
|
|
|
|
|
|
2000-07-19 13:52:27 -04:00
|
|
|
if (keyfile[0] != 0) {
|
|
|
|
|
setup_file_key();
|
|
|
|
|
} else if (keysecret[0] != 0) {
|
|
|
|
|
setup_text_key();
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2018-04-22 08:56:28 -04:00
|
|
|
|
2018-05-28 09:22:23 -04:00
|
|
|
isc_nonce_buf(cookie_secret, sizeof(cookie_secret));
|
2000-04-26 14:34:17 -04:00
|
|
|
}
|
2000-07-31 21:33:37 -04:00
|
|
|
|
2005-04-27 00:57:32 -04:00
|
|
|
/*%
|
2001-01-18 00:12:44 -05:00
|
|
|
* Override the search list derived from resolv.conf by 'domain'.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
set_search_domain(char *domain) {
|
|
|
|
|
dig_searchlist_t *search;
|
2008-01-18 18:46:58 -05:00
|
|
|
|
2001-01-18 00:12:44 -05:00
|
|
|
clear_searchlist();
|
|
|
|
|
search = make_searchlist_entry(domain);
|
|
|
|
|
ISC_LIST_APPEND(search_list, search, link);
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-27 00:57:32 -04:00
|
|
|
/*%
|
2000-07-18 14:51:40 -04:00
|
|
|
* Setup the ISC and DNS libraries for use by the system.
|
|
|
|
|
*/
|
2000-05-09 14:05:13 -04:00
|
|
|
void
|
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-26 20:03:12 -04:00
|
|
|
setup_libs(void) {
|
2000-04-26 14:34:17 -04:00
|
|
|
isc_result_t result;
|
2009-09-14 23:13:44 -04:00
|
|
|
isc_logconfig_t *logconfig = NULL;
|
2000-04-26 14:34:17 -04:00
|
|
|
|
2000-07-05 15:31:26 -04:00
|
|
|
debug("setup_libs()");
|
2000-05-11 21:02:37 -04:00
|
|
|
|
2000-04-26 14:34:17 -04:00
|
|
|
result = isc_net_probeipv4();
|
2000-11-21 16:35:32 -05:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
2018-04-17 11:29:14 -04:00
|
|
|
have_ipv4 = true;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2000-04-26 14:34:17 -04:00
|
|
|
|
|
|
|
|
result = isc_net_probeipv6();
|
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
2018-04-17 11:29:14 -04:00
|
|
|
have_ipv6 = true;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2000-11-21 16:35:32 -05:00
|
|
|
if (!have_ipv6 && !have_ipv4) {
|
|
|
|
|
fatal("can't find either v4 or v6 networking");
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2000-04-26 14:34:17 -04:00
|
|
|
|
2022-10-29 17:22:56 -04:00
|
|
|
isc_managers_create(&mctx, 1, &loopmgr, &netmgr);
|
2022-07-26 07:03:40 -04:00
|
|
|
|
2024-08-13 12:20:26 -04:00
|
|
|
logconfig = isc_logconfig_get();
|
2024-08-14 08:38:07 -04:00
|
|
|
isc_log_createandusechannel(logconfig, "debug", ISC_LOG_TOFILEDESC,
|
|
|
|
|
ISC_LOG_DYNAMIC, ISC_LOGDESTINATION_STDERR,
|
|
|
|
|
ISC_LOG_PRINTTIME, ISC_LOGCATEGORY_DEFAULT,
|
|
|
|
|
ISC_LOGMODULE_DEFAULT);
|
2024-08-13 12:20:26 -04:00
|
|
|
isc_log_setdebuglevel(0);
|
2009-09-14 23:13:44 -04:00
|
|
|
|
2022-07-26 07:03:45 -04:00
|
|
|
isc_mem_setname(mctx, "dig");
|
2022-07-26 07:03:40 -04:00
|
|
|
mainloop = isc_loop_main(loopmgr);
|
2000-04-26 14:34:17 -04:00
|
|
|
}
|
|
|
|
|
|
2017-01-20 02:46:37 -05:00
|
|
|
typedef struct dig_ednsoptname {
|
2018-03-28 08:19:37 -04:00
|
|
|
uint32_t code;
|
2017-01-20 02:46:37 -05:00
|
|
|
const char *name;
|
|
|
|
|
} dig_ednsoptname_t;
|
|
|
|
|
|
|
|
|
|
dig_ednsoptname_t optnames[] = {
|
2024-10-24 17:51:58 -04:00
|
|
|
{ 1, "LLQ" }, /* draft-sekar-dns-llq */
|
|
|
|
|
{ 2, "UL" }, /* draft-ietf-dnssd-update-lease */
|
|
|
|
|
{ 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 */
|
|
|
|
|
{ 15, "EDE" }, /* ietf-dnsop-extended-error-16 */
|
|
|
|
|
{ 16, "CLIENT-TAG" }, /* draft-bellis-dnsop-edns-tags */
|
|
|
|
|
{ 17, "SERVER-TAG" }, /* draft-bellis-dnsop-edns-tags */
|
|
|
|
|
{ 18, "REPORT-CHANNEL" }, /* RFC 9567 */
|
|
|
|
|
{ 18, "RC" }, /* shorthand */
|
|
|
|
|
{ 19, "ZONEVERSION" }, /* RFC 9660 */
|
|
|
|
|
{ 26946, "DEVICEID" }, /* Brian Hartvigsen */
|
2017-01-20 02:46:37 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#define N_EDNS_OPTNAMES (sizeof(optnames) / sizeof(optnames[0]))
|
|
|
|
|
|
2014-04-17 19:52:12 -04:00
|
|
|
void
|
|
|
|
|
save_opt(dig_lookup_t *lookup, char *code, char *value) {
|
2017-01-20 02:46:37 -05:00
|
|
|
isc_result_t result;
|
2018-03-28 08:19:37 -04:00
|
|
|
uint32_t num = 0;
|
2014-04-17 19:52:12 -04:00
|
|
|
isc_buffer_t b;
|
2018-04-17 11:29:14 -04:00
|
|
|
bool found = false;
|
2017-01-20 02:46:37 -05:00
|
|
|
unsigned int i;
|
2014-04-17 19:52:12 -04:00
|
|
|
|
2017-11-13 00:10:35 -05:00
|
|
|
if (lookup->ednsoptscnt >= EDNSOPT_OPTIONS) {
|
2014-04-17 19:52:12 -04:00
|
|
|
fatal("too many ednsopts");
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2014-04-17 19:52:12 -04:00
|
|
|
|
2017-01-20 02:46:37 -05:00
|
|
|
for (i = 0; i < N_EDNS_OPTNAMES; i++) {
|
|
|
|
|
if (strcasecmp(code, optnames[i].name) == 0) {
|
|
|
|
|
num = optnames[i].code;
|
2018-04-17 11:29:14 -04:00
|
|
|
found = true;
|
2017-01-20 02:46:37 -05:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!found) {
|
|
|
|
|
result = parse_uint(&num, code, 65535, "ednsopt");
|
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
|
fatal("bad edns code point: %s", code);
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2017-01-20 02:46:37 -05:00
|
|
|
}
|
2014-04-17 19:52:12 -04:00
|
|
|
|
2017-11-13 00:10:35 -05:00
|
|
|
if (lookup->ednsopts == NULL) {
|
|
|
|
|
cloneopts(lookup, NULL);
|
|
|
|
|
}
|
2020-06-24 20:45:02 -04:00
|
|
|
INSIST(lookup->ednsopts != NULL);
|
2017-11-13 00:10:35 -05:00
|
|
|
|
|
|
|
|
if (lookup->ednsopts[lookup->ednsoptscnt].value != NULL) {
|
|
|
|
|
isc_mem_free(mctx, lookup->ednsopts[lookup->ednsoptscnt].value);
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2017-11-13 00:10:35 -05:00
|
|
|
|
|
|
|
|
lookup->ednsopts[lookup->ednsoptscnt].code = num;
|
|
|
|
|
lookup->ednsopts[lookup->ednsoptscnt].length = 0;
|
|
|
|
|
lookup->ednsopts[lookup->ednsoptscnt].value = NULL;
|
2014-04-22 19:45:19 -04:00
|
|
|
|
2014-04-17 19:52:12 -04:00
|
|
|
if (value != NULL) {
|
|
|
|
|
char *buf;
|
2019-07-23 10:56:26 -04:00
|
|
|
buf = isc_mem_allocate(mctx, strlen(value) / 2 + 1);
|
2016-07-21 18:53:43 -04:00
|
|
|
isc_buffer_init(&b, buf, (unsigned int)strlen(value) / 2 + 1);
|
2014-04-17 19:52:12 -04:00
|
|
|
result = isc_hex_decodestring(value, &b);
|
|
|
|
|
check_result(result, "isc_hex_decodestring");
|
2017-11-13 00:10:35 -05:00
|
|
|
lookup->ednsopts[lookup->ednsoptscnt].value =
|
|
|
|
|
isc_buffer_base(&b);
|
|
|
|
|
lookup->ednsopts[lookup->ednsoptscnt].length =
|
|
|
|
|
isc_buffer_usedlength(&b);
|
2014-04-17 19:52:12 -04:00
|
|
|
}
|
2014-04-22 19:45:19 -04:00
|
|
|
|
2014-04-17 19:52:12 -04:00
|
|
|
lookup->ednsoptscnt++;
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-27 00:57:32 -04:00
|
|
|
/*%
|
2000-07-18 14:51:40 -04:00
|
|
|
* Add EDNS0 option record to a message. Currently, the only supported
|
2014-02-19 18:51:02 -05:00
|
|
|
* options are UDP buffer size, the DO bit, and EDNS options
|
2015-07-05 19:44:24 -04:00
|
|
|
* (e.g., NSID, COOKIE, client-subnet)
|
2000-07-18 14:51:40 -04:00
|
|
|
*/
|
2000-05-08 18:51:08 -04:00
|
|
|
static void
|
2018-03-28 08:19:37 -04:00
|
|
|
add_opt(dns_message_t *msg, uint16_t udpsize, uint16_t edns, unsigned int flags,
|
2015-01-20 16:29:18 -05:00
|
|
|
dns_ednsopt_t *opts, size_t count) {
|
2000-05-08 18:51:08 -04:00
|
|
|
dns_rdataset_t *rdataset = NULL;
|
|
|
|
|
isc_result_t result;
|
|
|
|
|
|
2000-07-05 15:31:26 -04:00
|
|
|
debug("add_opt()");
|
2014-02-18 20:53:42 -05:00
|
|
|
result = dns_message_buildopt(msg, &rdataset, edns, udpsize, flags,
|
2015-01-20 16:29:18 -05:00
|
|
|
opts, count);
|
2014-02-18 20:53:42 -05:00
|
|
|
check_result(result, "dns_message_buildopt");
|
2000-05-08 18:51:08 -04:00
|
|
|
result = dns_message_setopt(msg, rdataset);
|
2000-07-05 15:31:26 -04:00
|
|
|
check_result(result, "dns_message_setopt");
|
2000-05-08 18:51:08 -04:00
|
|
|
}
|
|
|
|
|
|
2005-04-27 00:57:32 -04:00
|
|
|
/*%
|
2000-07-18 14:51:40 -04:00
|
|
|
* Add a question section to a message, asking for the specified name,
|
|
|
|
|
* type, and class.
|
|
|
|
|
*/
|
2000-04-26 14:34:17 -04:00
|
|
|
static void
|
2000-07-05 19:28:32 -04:00
|
|
|
add_question(dns_message_t *message, dns_name_t *name, dns_rdataclass_t rdclass,
|
|
|
|
|
dns_rdatatype_t rdtype) {
|
2000-04-26 14:34:17 -04:00
|
|
|
dns_rdataset_t *rdataset;
|
|
|
|
|
|
2000-07-05 19:28:32 -04:00
|
|
|
debug("add_question()");
|
2000-04-26 14:34:17 -04:00
|
|
|
rdataset = NULL;
|
2022-05-16 07:28:13 -04:00
|
|
|
dns_message_gettemprdataset(message, &rdataset);
|
2000-04-26 14:34:17 -04:00
|
|
|
dns_rdataset_makequestion(rdataset, rdclass, rdtype);
|
|
|
|
|
ISC_LIST_APPEND(name->list, rdataset, link);
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-27 00:57:32 -04:00
|
|
|
/*%
|
2000-07-18 14:51:40 -04: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 19:28:32 -04:00
|
|
|
*/
|
2000-07-12 20:32:20 -04:00
|
|
|
static void
|
|
|
|
|
check_if_done(void) {
|
2020-11-05 09:22:38 -05:00
|
|
|
dig_lookup_t *lookup = NULL;
|
|
|
|
|
|
2000-07-12 20:32:20 -04:00
|
|
|
debug("check_if_done()");
|
2000-08-02 18:39:01 -04:00
|
|
|
debug("list %s", ISC_LIST_EMPTY(lookup_list) ? "empty" : "full");
|
2020-11-05 09:22:38 -05: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 14:23:16 -04:00
|
|
|
if (ISC_LIST_EMPTY(lookup_list) && current_lookup == NULL &&
|
2020-09-05 19:37:24 -04:00
|
|
|
isc_refcount_current(&sendcount) == 0)
|
|
|
|
|
{
|
|
|
|
|
INSIST(isc_refcount_current(&recvcount) == 0);
|
2000-07-12 20:32:20 -04:00
|
|
|
debug("shutting down");
|
|
|
|
|
dighost_shutdown();
|
2022-07-26 07:03:40 -04:00
|
|
|
|
|
|
|
|
if (current_lookup == NULL && keep != NULL) {
|
|
|
|
|
isc_nmhandle_detach(&keep);
|
|
|
|
|
}
|
2000-07-12 20:32:20 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-20 09:54:39 -04: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 09:22:38 -05:00
|
|
|
static void
|
|
|
|
|
_destroy_lookup(dig_lookup_t *lookup) {
|
|
|
|
|
dig_server_t *s;
|
|
|
|
|
void *ptr;
|
2020-11-04 06:40:13 -05:00
|
|
|
|
2021-04-06 19:49:14 -04:00
|
|
|
REQUIRE(lookup != NULL);
|
|
|
|
|
REQUIRE(ISC_LIST_EMPTY(lookup->q));
|
|
|
|
|
|
2020-11-05 09:22:38 -05: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 15:16:17 -04:00
|
|
|
isc_mem_put(mctx, lookup->sendspace, COMMSIZE);
|
2020-11-05 09:22:38 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (lookup->tsigctx != NULL) {
|
|
|
|
|
dst_context_destroy(&lookup->tsigctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (lookup->ecs_addr != NULL) {
|
2022-08-26 05:58:51 -04:00
|
|
|
isc_mem_put(mctx, lookup->ecs_addr, sizeof(*lookup->ecs_addr));
|
2020-11-05 09:22:38 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 09:49:27 -05:00
|
|
|
if (lookup->https_path) {
|
|
|
|
|
isc_mem_free(mctx, lookup->https_path);
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-19 06:10:08 -05: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 09:22:38 -05:00
|
|
|
isc_mem_free(mctx, lookup);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define lookup_attach(s, t) _lookup_attach(s, t, __FILE__, __LINE__)
|
2000-07-12 20:32:20 -04:00
|
|
|
static void
|
2020-11-05 09:22:38 -05: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-12 20:32:20 -04:00
|
|
|
|
2020-11-05 09:22:38 -05:00
|
|
|
debug("%s:%u:lookup_attach(%p) = %" PRIuFAST32, file, line, lookup,
|
|
|
|
|
isc_refcount_current(&lookup->references) + 1);
|
2000-07-12 20:32:20 -04:00
|
|
|
|
2020-11-05 09:22:38 -05:00
|
|
|
(void)isc_refcount_increment(&lookup->references);
|
2000-07-13 14:52:58 -04:00
|
|
|
|
2020-11-05 09:22:38 -05:00
|
|
|
*lookupp = lookup;
|
|
|
|
|
}
|
2020-09-05 19:37:24 -04:00
|
|
|
|
2020-11-05 09:22:38 -05: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 06:40:13 -05:00
|
|
|
}
|
2020-09-05 19:37:24 -04:00
|
|
|
|
2020-11-05 09:22:38 -05: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 06:40:13 -05:00
|
|
|
static void
|
2020-11-05 09:22:38 -05:00
|
|
|
destroy_query(dig_query_t *query, const char *file, unsigned int line) {
|
2020-11-04 06:40:13 -05:00
|
|
|
debug("%s:%u:destroy_query(%p) = %" PRIuFAST32, file, line, query,
|
|
|
|
|
isc_refcount_current(&query->references));
|
|
|
|
|
|
2020-11-05 09:22:38 -05:00
|
|
|
isc_refcount_destroy(&query->references);
|
|
|
|
|
|
|
|
|
|
lookup_detach(&query->lookup);
|
|
|
|
|
|
|
|
|
|
INSIST(query->recvspace != NULL);
|
|
|
|
|
|
2021-05-12 15:16:17 -04:00
|
|
|
isc_mem_put(mctx, query->recvspace, COMMSIZE);
|
|
|
|
|
isc_mem_put(mctx, query->tmpsendspace, COMMSIZE);
|
2000-07-14 13:57:27 -04:00
|
|
|
|
2020-11-04 06:40:13 -05:00
|
|
|
query->magic = 0;
|
|
|
|
|
isc_mem_free(mctx, query);
|
|
|
|
|
}
|
2000-09-21 18:46:39 -04:00
|
|
|
|
2020-11-04 06:40:13 -05:00
|
|
|
#define query_attach(s, t) _query_attach(s, t, __FILE__, __LINE__)
|
|
|
|
|
|
2020-11-04 06:40:13 -05:00
|
|
|
static void
|
2020-11-04 06:40:13 -05:00
|
|
|
_query_attach(dig_query_t *source, dig_query_t **targetp, const char *file,
|
|
|
|
|
unsigned int line) {
|
2020-11-04 06:40:13 -05:00
|
|
|
REQUIRE(DIG_VALID_QUERY(source));
|
|
|
|
|
REQUIRE(targetp != NULL && *targetp == NULL);
|
2012-10-18 18:50:07 -04:00
|
|
|
|
2020-11-04 06:40:13 -05:00
|
|
|
debug("%s:%u:query_attach(%p) = %" PRIuFAST32, file, line, source,
|
|
|
|
|
isc_refcount_current(&source->references) + 1);
|
|
|
|
|
|
2020-11-04 06:40:13 -05:00
|
|
|
(void)isc_refcount_increment(&source->references);
|
2018-11-07 13:04:13 -05:00
|
|
|
|
2020-11-04 06:40:13 -05:00
|
|
|
*targetp = source;
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-04 06:40:13 -05:00
|
|
|
#define query_detach(q) _query_detach(q, __FILE__, __LINE__)
|
|
|
|
|
|
2020-11-04 06:40:13 -05:00
|
|
|
static void
|
2020-11-04 06:40:13 -05:00
|
|
|
_query_detach(dig_query_t **queryp, const char *file, unsigned int line) {
|
2020-11-04 06:40:13 -05:00
|
|
|
dig_query_t *query = NULL;
|
|
|
|
|
dig_lookup_t *lookup = NULL;
|
|
|
|
|
|
|
|
|
|
REQUIRE(DIG_VALID_QUERY(*queryp));
|
|
|
|
|
|
|
|
|
|
query = *queryp;
|
|
|
|
|
*queryp = NULL;
|
|
|
|
|
|
2020-11-04 06:40:13 -05:00
|
|
|
lookup = query->lookup;
|
|
|
|
|
|
|
|
|
|
if (lookup->current_query == query) {
|
2020-11-05 09:22:38 -05:00
|
|
|
query_detach(&lookup->current_query);
|
2020-11-04 06:40:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
debug("%s:%u:query_detach(%p) = %" PRIuFAST32, file, line, query,
|
|
|
|
|
isc_refcount_current(&query->references) - 1);
|
2020-11-04 06:40:13 -05:00
|
|
|
|
|
|
|
|
if (isc_refcount_decrement(&query->references) == 1) {
|
2021-04-27 06:03:20 -04:00
|
|
|
INSIST(query->readhandle == NULL);
|
|
|
|
|
INSIST(query->sendhandle == NULL);
|
|
|
|
|
|
2021-03-29 13:04:12 -04:00
|
|
|
if (ISC_LINK_LINKED(query, link)) {
|
|
|
|
|
ISC_LIST_UNLINK(lookup->q, query, link);
|
|
|
|
|
}
|
2020-11-05 09:22:38 -05:00
|
|
|
destroy_query(query, file, line);
|
2017-11-13 00:10:35 -05:00
|
|
|
}
|
2000-07-12 20:32:20 -04:00
|
|
|
}
|
2000-07-31 21:33:37 -04:00
|
|
|
|
2005-04-27 00:57:32 -04:00
|
|
|
/*%
|
2000-07-12 20:32:20 -04: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-07-31 20:53:20 -04:00
|
|
|
* started yet. It also removes the lookup from the head of the queue,
|
|
|
|
|
* setting the current_lookup pointer pointing to it.
|
2000-07-12 20:32:20 -04:00
|
|
|
*/
|
2000-07-14 16:14:36 -04:00
|
|
|
void
|
|
|
|
|
start_lookup(void) {
|
|
|
|
|
debug("start_lookup()");
|
2020-11-05 09:22:38 -05:00
|
|
|
|
2022-07-26 07:03:40 -04:00
|
|
|
if (cancel_now) {
|
2000-07-14 13:57:27 -04:00
|
|
|
return;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2000-07-14 16:14:36 -04:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If there's a current lookup running, we really shouldn't get
|
|
|
|
|
* here.
|
|
|
|
|
*/
|
|
|
|
|
INSIST(current_lookup == NULL);
|
|
|
|
|
|
2000-07-31 20:53:20 -04:00
|
|
|
current_lookup = ISC_LIST_HEAD(lookup_list);
|
2020-11-05 09:22:38 -05:00
|
|
|
|
2000-07-14 16:14:36 -04:00
|
|
|
/*
|
|
|
|
|
* Put the current lookup somewhere so cancel_all can find it
|
|
|
|
|
*/
|
2000-07-31 20:53:20 -04:00
|
|
|
if (current_lookup != NULL) {
|
2020-11-05 09:22:38 -05: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-07-31 20:53:20 -04:00
|
|
|
ISC_LIST_DEQUEUE(lookup_list, current_lookup, link);
|
2014-08-21 04:05:55 -04:00
|
|
|
if (setup_lookup(current_lookup)) {
|
|
|
|
|
do_lookup(current_lookup);
|
|
|
|
|
} else if (next_origin(current_lookup)) {
|
2020-11-05 09:22:38 -05:00
|
|
|
lookup_detach(¤t_lookup);
|
|
|
|
|
start_lookup();
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2000-07-12 20:32:20 -04:00
|
|
|
} else {
|
|
|
|
|
check_if_done();
|
2000-07-31 20:53:20 -04:00
|
|
|
}
|
2000-07-12 20:32:20 -04:00
|
|
|
}
|
|
|
|
|
|
2005-04-27 00:57:32 -04:00
|
|
|
/*%
|
2000-07-18 14:51:40 -04:00
|
|
|
* If we can, clear the current lookup and start the next one running.
|
2020-11-06 10:12:17 -05:00
|
|
|
* (Note that while the reference count of current_lookup may be
|
|
|
|
|
* decremented, current_lookup will not be set to NULL.)
|
2000-07-12 20:32:20 -04:00
|
|
|
*/
|
|
|
|
|
static void
|
2021-05-04 08:25:55 -04:00
|
|
|
clear_current_lookup(void) {
|
2020-11-06 10:12:17 -05:00
|
|
|
dig_lookup_t *lookup = current_lookup;
|
2000-05-22 18:56:31 -04:00
|
|
|
|
2020-11-06 10:12:17 -05:00
|
|
|
INSIST(!free_now);
|
2020-11-05 09:22:38 -05:00
|
|
|
|
2020-11-06 10:12:17 -05:00
|
|
|
debug("clear_current_lookup()");
|
2000-07-31 21:33:37 -04:00
|
|
|
|
2021-05-04 08:25:55 -04:00
|
|
|
if (lookup == NULL) {
|
|
|
|
|
debug("current_lookup is already detached");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
DiG: fix lookup reference counting bug
When DiG finishes its work with a lookup (due to success or error), it
calls the clear_current_lookup() function, which decreases the lookup's
reference count. That decrease action is the counterpart of the initial
creation of the reference counter, so this function was designed in such
a way that it should decrease the reference count only once, when there
are no more active queries in the lookup.
The way it checks whether there are any active queries is by looking
at the queries list of the lookup object - if it's NULL then there are
no active queries. But that is not always true - the cancel_lookup()
function, when canceling the queries one by one, also removes them
from the lookup's list, but in NSSEARCH mode, when the queries are
working in parallel, some of those queries can be still active. And
when their recv_done() callback gets called, it sees that the lookup
has been canceled, calls clear_current_lookup(), which decreases the
reference count every time for each query that was still active
(because ISC_LIST_HEAD(lookup->q) is NULL) and results in a reference
counting error.
Fix the issue by introducing a new "cleared" property for the lookup,
which will ensure that the clear_current_lookup() function does its
job only once per lookup.
2022-08-03 18:21:46 -04:00
|
|
|
if (lookup->cleared) {
|
|
|
|
|
debug("current_lookup is already cleared");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2000-07-27 15:06:12 -04:00
|
|
|
if (ISC_LIST_HEAD(lookup->q) != NULL) {
|
|
|
|
|
debug("still have a worker");
|
2000-07-12 20:32:20 -04:00
|
|
|
return;
|
2000-07-27 15:06:12 -04:00
|
|
|
}
|
2020-11-05 09:22:38 -05:00
|
|
|
|
DiG: fix lookup reference counting bug
When DiG finishes its work with a lookup (due to success or error), it
calls the clear_current_lookup() function, which decreases the lookup's
reference count. That decrease action is the counterpart of the initial
creation of the reference counter, so this function was designed in such
a way that it should decrease the reference count only once, when there
are no more active queries in the lookup.
The way it checks whether there are any active queries is by looking
at the queries list of the lookup object - if it's NULL then there are
no active queries. But that is not always true - the cancel_lookup()
function, when canceling the queries one by one, also removes them
from the lookup's list, but in NSSEARCH mode, when the queries are
working in parallel, some of those queries can be still active. And
when their recv_done() callback gets called, it sees that the lookup
has been canceled, calls clear_current_lookup(), which decreases the
reference count every time for each query that was still active
(because ISC_LIST_HEAD(lookup->q) is NULL) and results in a reference
counting error.
Fix the issue by introducing a new "cleared" property for the lookup,
which will ensure that the clear_current_lookup() function does its
job only once per lookup.
2022-08-03 18:21:46 -04:00
|
|
|
lookup->cleared = true;
|
|
|
|
|
debug("lookup cleared");
|
|
|
|
|
|
2020-11-05 09:22:38 -05:00
|
|
|
lookup_detach(&lookup);
|
2000-05-11 21:02:37 -04:00
|
|
|
}
|
|
|
|
|
|
2005-04-27 00:57:32 -04:00
|
|
|
/*%
|
2000-07-18 14:51:40 -04: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 18:12:17 -05:00
|
|
|
* NS records in a reply. Returns the number of followup lookups made.
|
2000-07-18 14:51:40 -04:00
|
|
|
*/
|
2001-02-13 18:12:17 -05:00
|
|
|
static int
|
2001-07-27 01:26:38 -04:00
|
|
|
followup_lookup(dns_message_t *msg, dig_query_t *query, dns_section_t section) {
|
2000-04-28 17:41:19 -04:00
|
|
|
dig_lookup_t *lookup = NULL;
|
|
|
|
|
dig_server_t *srv = NULL;
|
|
|
|
|
dns_rdataset_t *rdataset = NULL;
|
2000-10-25 00:26:57 -04:00
|
|
|
dns_rdata_t rdata = DNS_RDATA_INIT;
|
2025-03-19 15:29:17 -04:00
|
|
|
isc_result_t result = ISC_R_NOMORE;
|
2018-04-17 11:29:14 -04:00
|
|
|
bool success = false;
|
2001-02-13 18:12:17 -05:00
|
|
|
int numLookups = 0;
|
2011-12-07 12:23:28 -05:00
|
|
|
int num;
|
|
|
|
|
isc_result_t lresult, addresses_result;
|
|
|
|
|
char bad_namestr[DNS_NAME_FORMATSIZE];
|
2004-10-06 22:21:48 -04:00
|
|
|
dns_name_t *domain;
|
2018-04-17 11:29:14 -04:00
|
|
|
bool horizontal = false, bad = false;
|
2000-04-28 17:41:19 -04:00
|
|
|
|
2000-07-12 20:32:20 -04:00
|
|
|
INSIST(!free_now);
|
|
|
|
|
|
2000-07-05 19:28:32 -04:00
|
|
|
debug("following up %s", query->lookup->textname);
|
2008-01-18 18:46:58 -05:00
|
|
|
|
2011-12-07 12:23:28 -05:00
|
|
|
addresses_result = ISC_R_SUCCESS;
|
|
|
|
|
bad_namestr[0] = '\0';
|
2001-07-27 01:26:38 -04:00
|
|
|
|
2025-03-19 15:29:17 -04:00
|
|
|
MSG_SECTION_FOREACH (msg, section, name) {
|
2004-09-15 22:10:42 -04:00
|
|
|
if (section == DNS_SECTION_AUTHORITY) {
|
|
|
|
|
rdataset = NULL;
|
|
|
|
|
result = dns_message_findtype(name, dns_rdatatype_soa,
|
|
|
|
|
0, &rdataset);
|
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
|
return 0;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2004-09-15 22:10:42 -04:00
|
|
|
}
|
2001-07-27 18:07:10 -04:00
|
|
|
rdataset = NULL;
|
|
|
|
|
result = dns_message_findtype(name, dns_rdatatype_ns, 0,
|
|
|
|
|
&rdataset);
|
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
|
continue;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2001-07-27 01:26:38 -04:00
|
|
|
|
2001-07-27 18:07:10 -04:00
|
|
|
debug("found NS set");
|
2001-07-27 01:26:38 -04:00
|
|
|
|
2004-10-06 22:21:48 -04:00
|
|
|
if (query->lookup->trace && !query->lookup->trace_root) {
|
|
|
|
|
dns_namereln_t namereln;
|
|
|
|
|
unsigned int nlabels;
|
|
|
|
|
int order;
|
|
|
|
|
|
|
|
|
|
domain = dns_fixedname_name(&query->lookup->fdomain);
|
|
|
|
|
namereln = dns_name_fullcompare(name, domain, &order,
|
|
|
|
|
&nlabels);
|
2006-12-06 20:21:04 -05:00
|
|
|
if (namereln == dns_namereln_equal) {
|
2019-08-30 00:23:29 -04:00
|
|
|
if (!horizontal) {
|
|
|
|
|
dighost_warning("BAD (HORIZONTAL) "
|
|
|
|
|
"REFERRAL");
|
|
|
|
|
}
|
2018-04-17 11:29:14 -04:00
|
|
|
horizontal = true;
|
2006-12-06 20:21:04 -05:00
|
|
|
} else if (namereln != dns_namereln_subdomain) {
|
2019-08-30 00:23:29 -04:00
|
|
|
if (!bad) {
|
|
|
|
|
dighost_warning("BAD REFERRAL");
|
|
|
|
|
}
|
2018-04-17 11:29:14 -04:00
|
|
|
bad = true;
|
2006-12-06 20:21:04 -05:00
|
|
|
continue;
|
|
|
|
|
}
|
2004-10-06 22:21:48 -04:00
|
|
|
}
|
|
|
|
|
|
2001-07-27 18:07:10 -04:00
|
|
|
for (result = dns_rdataset_first(rdataset);
|
|
|
|
|
result == ISC_R_SUCCESS;
|
2004-04-12 22:39:35 -04:00
|
|
|
result = dns_rdataset_next(rdataset))
|
|
|
|
|
{
|
2001-07-27 18:07:10 -04:00
|
|
|
char namestr[DNS_NAME_FORMATSIZE];
|
|
|
|
|
dns_rdata_ns_t ns;
|
|
|
|
|
|
|
|
|
|
if (query->lookup->trace_root &&
|
2022-11-02 14:33:14 -04:00
|
|
|
query->lookup->nsfound >= MXSERV)
|
|
|
|
|
{
|
2001-07-27 18:07:10 -04:00
|
|
|
break;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2001-07-27 18:07:10 -04:00
|
|
|
|
|
|
|
|
dns_rdataset_current(rdataset, &rdata);
|
|
|
|
|
|
|
|
|
|
query->lookup->nsfound++;
|
2008-01-14 18:24:24 -05:00
|
|
|
result = dns_rdata_tostruct(&rdata, &ns, NULL);
|
|
|
|
|
check_result(result, "dns_rdata_tostruct");
|
2001-07-27 18:07:10 -04:00
|
|
|
dns_name_format(&ns.name, namestr, sizeof(namestr));
|
|
|
|
|
dns_rdata_freestruct(&ns);
|
|
|
|
|
|
|
|
|
|
/* Initialize lookup if we've not yet */
|
2011-02-25 18:11:13 -05:00
|
|
|
debug("found NS %s", namestr);
|
2001-07-27 18:07:10 -04:00
|
|
|
if (!success) {
|
2018-04-17 11:29:14 -04:00
|
|
|
success = true;
|
2001-07-27 18:07:10 -04:00
|
|
|
lookup_counter++;
|
|
|
|
|
lookup = requeue_lookup(query->lookup, false);
|
2001-10-31 16:55:31 -05:00
|
|
|
cancel_lookup(query->lookup);
|
2018-04-17 11:29:14 -04:00
|
|
|
lookup->doing_xfr = false;
|
2001-07-29 19:23:42 -04:00
|
|
|
if (!lookup->trace_root &&
|
2022-11-02 14:33:14 -04:00
|
|
|
section == DNS_SECTION_ANSWER)
|
|
|
|
|
{
|
2018-04-17 11:29:14 -04:00
|
|
|
lookup->trace = false;
|
2001-07-29 19:23:42 -04:00
|
|
|
} else {
|
|
|
|
|
lookup->trace = query->lookup->trace;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2001-07-27 20:55:15 -04:00
|
|
|
lookup->ns_search_only =
|
|
|
|
|
query->lookup->ns_search_only;
|
2018-04-17 11:29:14 -04:00
|
|
|
lookup->trace_root = false;
|
2005-03-30 21:36:05 -05:00
|
|
|
if (lookup->ns_search_only) {
|
2018-04-17 11:29:14 -04:00
|
|
|
lookup->recurse = false;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2004-10-06 22:21:48 -04:00
|
|
|
domain = dns_fixedname_name(&lookup->fdomain);
|
2021-05-21 20:20:44 -04:00
|
|
|
dns_name_copy(name, domain);
|
2025-03-11 19:02:05 -04:00
|
|
|
lookup->edns = lookup->original_edns;
|
2000-04-28 17:41:19 -04:00
|
|
|
}
|
2011-02-25 18:11:13 -05:00
|
|
|
debug("adding server %s", namestr);
|
2011-12-07 12:23:28 -05:00
|
|
|
num = getaddresses(lookup, namestr, &lresult);
|
|
|
|
|
if (lresult != ISC_R_SUCCESS) {
|
2013-02-07 17:14:26 -05:00
|
|
|
printf("couldn't get address for '%s': %s\n",
|
|
|
|
|
namestr, isc_result_totext(lresult));
|
2011-12-07 12:23:28 -05:00
|
|
|
if (addresses_result == ISC_R_SUCCESS) {
|
|
|
|
|
addresses_result = lresult;
|
2017-09-13 03:14:37 -04:00
|
|
|
strlcpy(bad_namestr, namestr,
|
|
|
|
|
sizeof(bad_namestr));
|
2011-12-07 12:23:28 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
numLookups += num;
|
2001-07-27 18:07:10 -04:00
|
|
|
dns_rdata_reset(&rdata);
|
2000-04-28 17:41:19 -04:00
|
|
|
}
|
|
|
|
|
}
|
2011-12-07 12:23:28 -05:00
|
|
|
if (numLookups == 0 && addresses_result != ISC_R_SUCCESS) {
|
|
|
|
|
fatal("couldn't get address for '%s': %s", bad_namestr,
|
|
|
|
|
isc_result_totext(result));
|
|
|
|
|
}
|
2001-07-27 18:07:10 -04:00
|
|
|
|
|
|
|
|
if (lookup == NULL && section == DNS_SECTION_ANSWER &&
|
2000-06-22 18:37:31 -04:00
|
|
|
(query->lookup->trace || query->lookup->ns_search_only))
|
|
|
|
|
{
|
2001-07-27 18:07:10 -04:00
|
|
|
return followup_lookup(msg, query, DNS_SECTION_AUTHORITY);
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2001-02-13 18:12:17 -05:00
|
|
|
|
2004-10-06 22:21:48 -04:00
|
|
|
/*
|
|
|
|
|
* Randomize the order the nameserver will be tried.
|
|
|
|
|
*/
|
|
|
|
|
if (numLookups > 1) {
|
2018-03-28 08:19:37 -04:00
|
|
|
uint32_t i, j;
|
2004-10-06 22:21:48 -04:00
|
|
|
dig_serverlist_t my_server_list;
|
2011-03-11 01:11:27 -05:00
|
|
|
dig_server_t *next;
|
2004-10-06 22:21:48 -04:00
|
|
|
|
|
|
|
|
ISC_LIST_INIT(my_server_list);
|
|
|
|
|
|
2011-03-11 01:11:27 -05:00
|
|
|
i = numLookups;
|
|
|
|
|
for (srv = ISC_LIST_HEAD(lookup->my_server_list); srv != NULL;
|
|
|
|
|
srv = ISC_LIST_HEAD(lookup->my_server_list))
|
|
|
|
|
{
|
|
|
|
|
INSIST(i > 0);
|
2018-05-28 09:22:23 -04:00
|
|
|
j = isc_random_uniform(i);
|
2011-03-11 01:11:27 -05:00
|
|
|
next = ISC_LIST_NEXT(srv, link);
|
|
|
|
|
while (j-- > 0 && next != NULL) {
|
|
|
|
|
srv = next;
|
|
|
|
|
next = ISC_LIST_NEXT(srv, link);
|
|
|
|
|
}
|
2004-10-06 22:21:48 -04:00
|
|
|
ISC_LIST_DEQUEUE(lookup->my_server_list, srv, link);
|
|
|
|
|
ISC_LIST_APPEND(my_server_list, srv, link);
|
2011-03-11 01:11:27 -05:00
|
|
|
i--;
|
2004-10-06 22:21:48 -04:00
|
|
|
}
|
|
|
|
|
ISC_LIST_APPENDLIST(lookup->my_server_list, my_server_list,
|
|
|
|
|
link);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return numLookups;
|
2000-04-28 17:41:19 -04:00
|
|
|
}
|
|
|
|
|
|
2005-04-27 00:57:32 -04:00
|
|
|
/*%
|
2001-01-18 00:12:44 -05:00
|
|
|
* Create and queue a new lookup using the next origin from the search
|
2000-07-18 14:51:40 -04:00
|
|
|
* list, read in setup_system().
|
2001-01-18 00:12:44 -05:00
|
|
|
*
|
2018-04-17 11:29:14 -04:00
|
|
|
* Return true iff there was another searchlist entry.
|
2000-07-18 14:51:40 -04:00
|
|
|
*/
|
2018-04-17 11:29:14 -04:00
|
|
|
static bool
|
2014-08-21 04:05:55 -04:00
|
|
|
next_origin(dig_lookup_t *oldlookup) {
|
|
|
|
|
dig_lookup_t *newlookup;
|
2006-12-07 00:52:16 -05:00
|
|
|
dig_searchlist_t *search;
|
2013-09-03 23:24:11 -04:00
|
|
|
dns_fixedname_t fixed;
|
|
|
|
|
dns_name_t *name;
|
|
|
|
|
isc_result_t result;
|
2000-05-02 19:23:12 -04:00
|
|
|
|
2000-07-12 20:32:20 -04:00
|
|
|
INSIST(!free_now);
|
|
|
|
|
|
2000-07-05 15:31:26 -04:00
|
|
|
debug("next_origin()");
|
2014-08-21 04:05:55 -04:00
|
|
|
debug("following up %s", oldlookup->textname);
|
2000-05-02 19:23:12 -04:00
|
|
|
|
2000-07-24 14:07:03 -04:00
|
|
|
if (!usesearch) {
|
|
|
|
|
/*
|
|
|
|
|
* We're not using a search list, so don't even think
|
|
|
|
|
* about finding the next entry.
|
|
|
|
|
*/
|
2018-04-17 11:29:14 -04:00
|
|
|
return false;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2013-09-04 19:46:16 -04:00
|
|
|
|
2013-09-03 23:24:11 -04:00
|
|
|
/*
|
|
|
|
|
* Check for a absolute name or ndots being met.
|
|
|
|
|
*/
|
2018-03-28 08:38:09 -04:00
|
|
|
name = dns_fixedname_initname(&fixed);
|
2023-08-15 20:41:01 -04:00
|
|
|
result = dns_name_fromstring(name, oldlookup->textname, NULL, 0, NULL);
|
2013-09-03 23:24:11 -04:00
|
|
|
if (result == ISC_R_SUCCESS &&
|
|
|
|
|
(dns_name_isabsolute(name) ||
|
|
|
|
|
(int)dns_name_countlabels(name) > ndots))
|
|
|
|
|
{
|
2018-04-17 11:29:14 -04:00
|
|
|
return false;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2013-09-04 19:46:16 -04:00
|
|
|
|
2014-08-21 04:05:55 -04:00
|
|
|
if (oldlookup->origin == NULL && !oldlookup->need_search) {
|
2000-07-05 15:31:26 -04:00
|
|
|
/*
|
|
|
|
|
* Then we just did rootorg; there's nothing left.
|
|
|
|
|
*/
|
2018-04-17 11:29:14 -04:00
|
|
|
return false;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2014-08-21 04:05:55 -04:00
|
|
|
if (oldlookup->origin == NULL && oldlookup->need_search) {
|
2018-04-17 11:29:14 -04:00
|
|
|
newlookup = requeue_lookup(oldlookup, true);
|
2014-08-21 04:05:55 -04:00
|
|
|
newlookup->origin = ISC_LIST_HEAD(search_list);
|
2018-04-17 11:29:14 -04:00
|
|
|
newlookup->need_search = false;
|
2006-12-07 00:52:16 -05:00
|
|
|
} else {
|
2014-08-21 04:05:55 -04:00
|
|
|
search = ISC_LIST_NEXT(oldlookup->origin, link);
|
|
|
|
|
if (search == NULL && oldlookup->done_as_is) {
|
2018-04-17 11:29:14 -04:00
|
|
|
return false;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2018-04-17 11:29:14 -04:00
|
|
|
newlookup = requeue_lookup(oldlookup, true);
|
2014-08-21 04:05:55 -04:00
|
|
|
newlookup->origin = search;
|
2006-12-07 00:52:16 -05:00
|
|
|
}
|
2014-08-21 04:05:55 -04:00
|
|
|
cancel_lookup(oldlookup);
|
2018-04-17 11:29:14 -04:00
|
|
|
return true;
|
2000-05-02 19:23:12 -04:00
|
|
|
}
|
|
|
|
|
|
2005-04-27 00:57:32 -04:00
|
|
|
/*%
|
2000-07-18 14:51:40 -04:00
|
|
|
* Insert an SOA record into the sendmessage in a lookup. Used for
|
|
|
|
|
* creating IXFR queries.
|
|
|
|
|
*/
|
2000-06-02 14:45:33 -04:00
|
|
|
static void
|
|
|
|
|
insert_soa(dig_lookup_t *lookup) {
|
|
|
|
|
isc_result_t result;
|
|
|
|
|
dns_rdata_soa_t soa;
|
|
|
|
|
dns_rdata_t *rdata = NULL;
|
|
|
|
|
dns_rdatalist_t *rdatalist = NULL;
|
|
|
|
|
dns_rdataset_t *rdataset = NULL;
|
|
|
|
|
dns_name_t *soaname = NULL;
|
2000-07-31 21:33:37 -04:00
|
|
|
|
2000-07-05 15:31:26 -04:00
|
|
|
debug("insert_soa()");
|
2000-06-02 14:45:33 -04:00
|
|
|
soa.mctx = mctx;
|
|
|
|
|
soa.serial = lookup->ixfr_serial;
|
2001-07-27 20:55:15 -04:00
|
|
|
soa.refresh = 0;
|
|
|
|
|
soa.retry = 0;
|
|
|
|
|
soa.expire = 0;
|
|
|
|
|
soa.minimum = 0;
|
2000-07-31 20:53:20 -04:00
|
|
|
soa.common.rdclass = lookup->rdclass;
|
2000-06-02 14:45:33 -04:00
|
|
|
soa.common.rdtype = dns_rdatatype_soa;
|
|
|
|
|
|
2025-02-21 06:09:39 -05:00
|
|
|
dns_name_init(&soa.origin);
|
|
|
|
|
dns_name_init(&soa.contact);
|
2000-06-02 14:45:33 -04:00
|
|
|
|
2001-07-27 20:55:15 -04:00
|
|
|
dns_name_clone(dns_rootname, &soa.origin);
|
2001-07-29 21:09:14 -04:00
|
|
|
dns_name_clone(dns_rootname, &soa.contact);
|
2000-07-31 21:33:37 -04:00
|
|
|
|
2000-06-02 14:45:33 -04:00
|
|
|
isc_buffer_init(&lookup->rdatabuf, lookup->rdatastore,
|
2000-07-31 20:53:20 -04:00
|
|
|
sizeof(lookup->rdatastore));
|
2000-06-02 14:45:33 -04:00
|
|
|
|
2022-05-16 07:28:13 -04:00
|
|
|
dns_message_gettemprdata(lookup->sendmsg, &rdata);
|
2000-07-31 20:53:20 -04:00
|
|
|
|
|
|
|
|
result = dns_rdata_fromstruct(rdata, lookup->rdclass, dns_rdatatype_soa,
|
2000-06-02 14:45:33 -04:00
|
|
|
&soa, &lookup->rdatabuf);
|
|
|
|
|
check_result(result, "isc_rdata_fromstruct");
|
|
|
|
|
|
2022-05-16 07:28:13 -04:00
|
|
|
dns_message_gettemprdataset(lookup->sendmsg, &rdataset);
|
2000-06-02 14:45:33 -04:00
|
|
|
|
2025-03-23 16:45:04 -04:00
|
|
|
dns_message_gettemprdatalist(lookup->sendmsg, &rdatalist);
|
2000-06-02 14:45:33 -04:00
|
|
|
rdatalist->type = dns_rdatatype_soa;
|
2000-07-31 20:53:20 -04:00
|
|
|
rdatalist->rdclass = lookup->rdclass;
|
2000-06-02 14:45:33 -04:00
|
|
|
ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
|
|
|
|
|
|
|
|
|
|
dns_rdatalist_tordataset(rdatalist, rdataset);
|
|
|
|
|
|
2022-05-16 07:28:13 -04:00
|
|
|
dns_message_gettempname(lookup->sendmsg, &soaname);
|
2000-06-02 14:45:33 -04: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-18 20:53:42 -05:00
|
|
|
static void
|
2015-01-20 16:29:18 -05:00
|
|
|
compute_cookie(unsigned char *clientcookie, size_t len) {
|
2014-02-18 20:53:42 -05:00
|
|
|
/* XXXMPA need to fix, should be per server. */
|
|
|
|
|
INSIST(len >= 8U);
|
2015-01-20 16:29:18 -05:00
|
|
|
memmove(clientcookie, cookie_secret, 8);
|
2014-02-18 20:53:42 -05:00
|
|
|
}
|
|
|
|
|
|
2020-11-04 06:40:13 -05:00
|
|
|
#define new_query(l, s, u) _new_query(l, s, u, __FILE__, __LINE__)
|
|
|
|
|
|
2020-09-05 19:37:24 -04:00
|
|
|
static dig_query_t *
|
2020-11-04 06:40:13 -05:00
|
|
|
_new_query(dig_lookup_t *lookup, char *servname, char *userarg,
|
|
|
|
|
const char *file, unsigned int line) {
|
2020-09-05 19:37:24 -04: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 09:22:38 -05:00
|
|
|
*query = (dig_query_t){ .sendbuf = lookup->renderbuf,
|
2020-09-05 19:37:24 -04:00
|
|
|
.servname = servname,
|
|
|
|
|
.userarg = userarg,
|
|
|
|
|
.warn_id = true,
|
2021-05-12 15:16:17 -04:00
|
|
|
.recvspace = isc_mem_get(mctx, COMMSIZE),
|
|
|
|
|
.tmpsendspace = isc_mem_get(mctx, COMMSIZE) };
|
2020-11-04 06:40:13 -05:00
|
|
|
|
2020-11-05 09:22:38 -05:00
|
|
|
lookup_attach(lookup, &query->lookup);
|
|
|
|
|
|
|
|
|
|
isc_refcount_init(&query->references, 1);
|
|
|
|
|
|
2020-11-04 06:40:13 -05:00
|
|
|
debug("%s:%u:new_query(%p) = %" PRIuFAST32, file, line, query,
|
|
|
|
|
isc_refcount_current(&query->references));
|
|
|
|
|
|
2020-09-05 19:37:24 -04: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 00:57:32 -04:00
|
|
|
/*%
|
2000-07-18 14:51:40 -04: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 11:29:14 -04:00
|
|
|
bool
|
2000-04-26 14:34:17 -04:00
|
|
|
setup_lookup(dig_lookup_t *lookup) {
|
2000-07-31 20:53:20 -04:00
|
|
|
isc_result_t result;
|
2016-07-21 18:53:43 -04:00
|
|
|
unsigned int len;
|
2000-04-26 14:34:17 -04:00
|
|
|
dig_server_t *serv;
|
|
|
|
|
dig_query_t *query;
|
|
|
|
|
isc_buffer_t b;
|
2001-03-05 16:15:47 -05:00
|
|
|
dns_compress_t cctx;
|
2000-05-02 19:23:12 -04:00
|
|
|
char store[MXNAME];
|
2014-02-19 18:51:02 -05:00
|
|
|
char ecsbuf[20];
|
2015-07-05 19:44:24 -04:00
|
|
|
char cookiebuf[256];
|
2017-08-15 08:36:59 -04:00
|
|
|
char *origin = NULL;
|
|
|
|
|
char *textname = NULL;
|
2019-09-27 02:48:06 -04: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 08:34:35 -04:00
|
|
|
#ifdef HAVE_LIBIDN2
|
2017-08-15 08:36:59 -04: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 08:34:35 -04:00
|
|
|
#endif /* HAVE_LIBIDN2 */
|
2000-07-31 21:33:37 -04:00
|
|
|
|
2000-07-12 20:32:20 -04:00
|
|
|
INSIST(!free_now);
|
2000-07-31 21:33:37 -04:00
|
|
|
|
2000-07-31 20:53:20 -04:00
|
|
|
debug("setup_lookup(%p)", lookup);
|
2000-04-26 14:34:17 -04:00
|
|
|
|
2023-09-22 09:00:40 -04:00
|
|
|
dns_message_create(mctx, NULL, NULL, DNS_MESSAGE_INTENTRENDER,
|
|
|
|
|
&lookup->sendmsg);
|
2000-04-26 14:34:17 -04:00
|
|
|
|
2000-05-24 19:39:30 -04:00
|
|
|
if (lookup->new_search) {
|
2000-07-05 19:28:32 -04:00
|
|
|
debug("resetting lookup counter.");
|
2000-05-24 15:49:51 -04:00
|
|
|
lookup_counter = 0;
|
2000-05-24 19:39:30 -04:00
|
|
|
}
|
2000-04-26 14:34:17 -04:00
|
|
|
|
2000-07-14 12:35:30 -04: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 07:28:13 -04:00
|
|
|
dns_message_gettempname(lookup->sendmsg, &lookup->name);
|
2000-04-26 14:34:17 -04:00
|
|
|
|
2005-09-09 02:17:03 -04:00
|
|
|
/*
|
|
|
|
|
* We cannot convert `textname' and `origin' separately.
|
|
|
|
|
* `textname' doesn't contain TLD, but local mapping needs
|
|
|
|
|
* TLD.
|
|
|
|
|
*/
|
2017-08-15 08:36:59 -04: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 08:34:35 -04:00
|
|
|
#ifdef HAVE_LIBIDN2
|
2017-08-15 08:36:59 -04:00
|
|
|
if (lookup->idnin) {
|
2022-09-05 10:49:49 -04:00
|
|
|
idn_input(textname, idn_textname, sizeof(idn_textname));
|
2017-08-15 08:36:59 -04: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 08:34:35 -04:00
|
|
|
#endif /* HAVE_LIBIDN2 */
|
2005-09-09 02:17:03 -04:00
|
|
|
|
2000-07-24 14:07:03 -04:00
|
|
|
/*
|
2000-07-31 20:53:20 -04: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 14:07:03 -04: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 00:52:16 -05:00
|
|
|
if (lookup->new_search) {
|
2017-08-15 08:36:59 -04:00
|
|
|
if ((count_dots(textname) >= ndots) || !usesearch) {
|
2006-12-07 00:52:16 -05:00
|
|
|
lookup->origin = NULL; /* Force abs lookup */
|
2018-04-17 11:29:14 -04:00
|
|
|
lookup->done_as_is = true;
|
2006-12-07 00:52:16 -05:00
|
|
|
lookup->need_search = usesearch;
|
|
|
|
|
} else if (lookup->origin == NULL && usesearch) {
|
|
|
|
|
lookup->origin = ISC_LIST_HEAD(search_list);
|
2018-04-17 11:29:14 -04:00
|
|
|
lookup->need_search = false;
|
2006-12-07 00:52:16 -05:00
|
|
|
}
|
|
|
|
|
}
|
2005-08-24 20:56:08 -04:00
|
|
|
|
2000-05-02 19:23:12 -04:00
|
|
|
if (lookup->origin != NULL) {
|
2000-07-05 19:28:32 -04:00
|
|
|
debug("trying origin %s", lookup->origin->origin);
|
2022-05-16 07:28:13 -04:00
|
|
|
dns_message_gettempname(lookup->sendmsg, &lookup->oname);
|
2000-07-31 20:53:20 -04:00
|
|
|
/* XXX Helper funct to conv char* to name? */
|
2017-08-15 08:36:59 -04: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 08:34:35 -04:00
|
|
|
#ifdef HAVE_LIBIDN2
|
2017-08-15 08:36:59 -04:00
|
|
|
if (lookup->idnin) {
|
2022-09-05 10:49:49 -04:00
|
|
|
idn_input(origin, idn_origin, sizeof(idn_origin));
|
2017-08-15 08:36:59 -04: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 08:34:35 -04:00
|
|
|
#endif /* HAVE_LIBIDN2 */
|
2017-08-15 08:36:59 -04:00
|
|
|
len = (unsigned int)strlen(origin);
|
|
|
|
|
isc_buffer_init(&b, origin, len);
|
2000-05-02 19:23:12 -04:00
|
|
|
isc_buffer_add(&b, len);
|
2025-02-22 03:11:38 -05:00
|
|
|
result = dns_name_fromtext(lookup->oname, &b, dns_rootname, 0);
|
2000-05-02 19:23:12 -04:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2000-07-05 15:31:26 -04:00
|
|
|
dns_message_puttempname(lookup->sendmsg, &lookup->name);
|
2000-05-02 19:23:12 -04:00
|
|
|
dns_message_puttempname(lookup->sendmsg,
|
|
|
|
|
&lookup->oname);
|
2000-07-31 20:53:20 -04:00
|
|
|
fatal("'%s' is not in legal name syntax (%s)", origin,
|
2001-07-27 01:41:46 -04:00
|
|
|
isc_result_totext(result));
|
2000-05-02 19:23:12 -04:00
|
|
|
}
|
2001-07-27 20:11:15 -04:00
|
|
|
if (lookup->trace && lookup->trace_root) {
|
2000-07-31 20:53:20 -04:00
|
|
|
dns_name_clone(dns_rootname, lookup->name);
|
|
|
|
|
} else {
|
2014-08-21 04:05:55 -04:00
|
|
|
dns_fixedname_t fixed;
|
|
|
|
|
dns_name_t *name;
|
|
|
|
|
|
2018-03-28 08:38:09 -04:00
|
|
|
name = dns_fixedname_initname(&fixed);
|
2017-08-15 08:36:59 -04:00
|
|
|
len = (unsigned int)strlen(textname);
|
|
|
|
|
isc_buffer_init(&b, textname, len);
|
2000-05-05 21:16:07 -04:00
|
|
|
isc_buffer_add(&b, len);
|
2025-02-22 03:11:38 -05:00
|
|
|
result = dns_name_fromtext(name, &b, NULL, 0);
|
2019-09-27 02:37:26 -04:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
|
if (!dns_name_isabsolute(name)) {
|
|
|
|
|
result = dns_name_concatenate(
|
|
|
|
|
name, lookup->oname,
|
2025-02-21 03:56:47 -05:00
|
|
|
lookup->name);
|
2019-09-27 02:37:26 -04:00
|
|
|
} else {
|
2021-05-21 20:20:44 -04:00
|
|
|
dns_name_copy(name, lookup->name);
|
2019-09-27 02:37:26 -04:00
|
|
|
}
|
|
|
|
|
}
|
2014-08-21 04:05:55 -04:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
|
dns_message_puttempname(lookup->sendmsg,
|
|
|
|
|
&lookup->name);
|
|
|
|
|
dns_message_puttempname(lookup->sendmsg,
|
|
|
|
|
&lookup->oname);
|
2019-09-27 02:37:26 -04:00
|
|
|
if (result == DNS_R_NAMETOOLONG) {
|
2018-04-17 11:29:14 -04:00
|
|
|
return false;
|
2019-09-27 02:37:26 -04:00
|
|
|
}
|
2014-08-21 04:05:55 -04:00
|
|
|
fatal("'%s' is not in legal name syntax (%s)",
|
|
|
|
|
lookup->textname,
|
|
|
|
|
isc_result_totext(result));
|
|
|
|
|
}
|
2000-05-02 19:23:12 -04:00
|
|
|
}
|
|
|
|
|
dns_message_puttempname(lookup->sendmsg, &lookup->oname);
|
2017-08-15 08:36:59 -04:00
|
|
|
} else {
|
2000-07-05 19:28:32 -04:00
|
|
|
debug("using root origin");
|
2001-07-27 20:11:15 -04:00
|
|
|
if (lookup->trace && lookup->trace_root) {
|
|
|
|
|
dns_name_clone(dns_rootname, lookup->name);
|
|
|
|
|
} else {
|
2017-08-15 08:36:59 -04:00
|
|
|
len = (unsigned int)strlen(textname);
|
|
|
|
|
isc_buffer_init(&b, textname, len);
|
2000-05-05 21:16:07 -04:00
|
|
|
isc_buffer_add(&b, len);
|
|
|
|
|
result = dns_name_fromtext(lookup->name, &b,
|
2025-02-22 03:11:38 -05:00
|
|
|
dns_rootname, 0);
|
2022-05-16 07:28:13 -04: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 00:58:12 -05:00
|
|
|
#if TARGET_OS_IPHONE
|
2022-05-16 07:28:13 -04:00
|
|
|
clear_current_lookup();
|
|
|
|
|
return false;
|
2017-12-11 21:43:55 -05:00
|
|
|
#else /* if TARGET_OS_IPHONE */
|
2023-01-29 18:47:57 -05:00
|
|
|
cleanup_openssl_refs();
|
2022-05-16 07:28:13 -04:00
|
|
|
digexit();
|
2017-11-23 00:58:12 -05:00
|
|
|
#endif /* if TARGET_OS_IPHONE */
|
2022-05-16 07:28:13 -04:00
|
|
|
}
|
2000-05-02 19:23:12 -04:00
|
|
|
}
|
|
|
|
|
}
|
2001-07-27 01:26:38 -04:00
|
|
|
dns_name_format(lookup->name, store, sizeof(store));
|
2017-08-11 01:51:24 -04:00
|
|
|
dighost_trying(store, lookup);
|
2000-07-31 20:53:20 -04:00
|
|
|
INSIST(dns_name_isabsolute(lookup->name));
|
2000-04-26 14:34:17 -04:00
|
|
|
|
2018-05-28 09:22:23 -04:00
|
|
|
lookup->sendmsg->id = (dns_messageid_t)isc_random16();
|
2015-05-18 22:46:06 -04:00
|
|
|
lookup->sendmsg->opcode = lookup->opcode;
|
2000-06-06 20:13:57 -04:00
|
|
|
lookup->msgcounter = 0;
|
2019-05-13 21:38:13 -04:00
|
|
|
|
2000-05-23 23:10:24 -04:00
|
|
|
/*
|
2019-05-13 21:38:13 -04: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-23 23:10:24 -04:00
|
|
|
*/
|
2019-05-13 21:38:13 -04:00
|
|
|
if ((lookup->trace || lookup->ns_search_only) && !lookup->trace_root) {
|
2018-04-17 11:29:14 -04:00
|
|
|
lookup->recurse = false;
|
2019-05-13 21:38:13 -04:00
|
|
|
}
|
2001-07-27 20:11:15 -04:00
|
|
|
|
2001-08-06 01:50:20 -04:00
|
|
|
if (lookup->recurse && lookup->rdtype != dns_rdatatype_axfr &&
|
|
|
|
|
lookup->rdtype != dns_rdatatype_ixfr)
|
|
|
|
|
{
|
2000-07-05 19:28:32 -04:00
|
|
|
debug("recursive query");
|
2000-04-26 14:34:17 -04:00
|
|
|
lookup->sendmsg->flags |= DNS_MESSAGEFLAG_RD;
|
2000-05-03 16:27:13 -04:00
|
|
|
}
|
2000-04-26 14:34:17 -04:00
|
|
|
|
2000-07-31 20:53:20 -04:00
|
|
|
/* XXX aaflag */
|
2000-07-13 17:12:21 -04:00
|
|
|
if (lookup->aaonly) {
|
|
|
|
|
debug("AA query");
|
|
|
|
|
lookup->sendmsg->flags |= DNS_MESSAGEFLAG_AA;
|
|
|
|
|
}
|
2000-07-31 21:33:37 -04:00
|
|
|
|
2000-06-16 14:00:05 -04:00
|
|
|
if (lookup->adflag) {
|
2000-07-05 15:31:26 -04:00
|
|
|
debug("AD query");
|
2000-06-16 14:00:05 -04:00
|
|
|
lookup->sendmsg->flags |= DNS_MESSAGEFLAG_AD;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (lookup->cdflag) {
|
2000-07-05 15:31:26 -04:00
|
|
|
debug("CD query");
|
2000-06-16 14:00:05 -04:00
|
|
|
lookup->sendmsg->flags |= DNS_MESSAGEFLAG_CD;
|
|
|
|
|
}
|
2014-10-30 19:16:00 -04:00
|
|
|
|
2018-04-17 19:18:41 -04: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-30 19:16:00 -04:00
|
|
|
if (lookup->zflag) {
|
|
|
|
|
debug("Z query");
|
|
|
|
|
lookup->sendmsg->flags |= 0x0040U;
|
|
|
|
|
}
|
2000-06-16 14:00:05 -04:00
|
|
|
|
2020-05-08 15:39:16 -04:00
|
|
|
if (lookup->setqid) {
|
|
|
|
|
debug("set QID");
|
|
|
|
|
lookup->sendmsg->id = lookup->qid;
|
|
|
|
|
}
|
|
|
|
|
|
2000-04-26 14:34:17 -04:00
|
|
|
dns_message_addname(lookup->sendmsg, lookup->name,
|
|
|
|
|
DNS_SECTION_QUESTION);
|
2000-06-02 14:45:33 -04:00
|
|
|
|
2001-07-27 20:11:15 -04:00
|
|
|
if (lookup->trace && lookup->trace_root) {
|
|
|
|
|
lookup->qrdtype = lookup->rdtype;
|
|
|
|
|
lookup->rdtype = dns_rdatatype_ns;
|
|
|
|
|
}
|
2000-07-31 20:53:20 -04:00
|
|
|
|
2000-07-17 21:28:20 -04:00
|
|
|
if ((lookup->rdtype == dns_rdatatype_axfr) ||
|
|
|
|
|
(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-26 20:03:12 -04:00
|
|
|
/*
|
2007-12-02 19:21:48 -05: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-26 20:03:12 -04:00
|
|
|
*/
|
2007-12-02 19:21:48 -05:00
|
|
|
if (lookup->rdtype == dns_rdatatype_axfr) {
|
2018-04-17 11:29:14 -04:00
|
|
|
lookup->doing_xfr = true;
|
|
|
|
|
lookup->tcp_mode = true;
|
2007-12-02 19:21:48 -05:00
|
|
|
} else if (lookup->tcp_mode) {
|
2018-04-17 11:29:14 -04:00
|
|
|
lookup->doing_xfr = true;
|
2007-12-02 19:21:48 -05:00
|
|
|
}
|
2000-04-26 14:34:17 -04:00
|
|
|
}
|
2000-12-08 12:06:52 -05:00
|
|
|
|
2014-10-29 20:42:02 -04:00
|
|
|
if (!lookup->header_only) {
|
|
|
|
|
add_question(lookup->sendmsg, lookup->name, lookup->rdclass,
|
|
|
|
|
lookup->rdtype);
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2000-04-26 14:34:17 -04:00
|
|
|
|
2001-07-27 20:11:15 -04:00
|
|
|
/* add_soa */
|
2000-07-17 21:28:20 -04:00
|
|
|
if (lookup->rdtype == dns_rdatatype_ixfr) {
|
2000-06-02 14:45:33 -04:00
|
|
|
insert_soa(lookup);
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2000-06-02 14:45:33 -04:00
|
|
|
|
2000-07-31 20:53:20 -04:00
|
|
|
/* XXX Insist this? */
|
|
|
|
|
lookup->tsigctx = NULL;
|
|
|
|
|
lookup->querysig = NULL;
|
2018-03-19 18:16:10 -04:00
|
|
|
if (tsigkey != NULL) {
|
2000-07-05 19:28:32 -04:00
|
|
|
debug("initializing keys");
|
2018-03-19 18:16:10 -04:00
|
|
|
result = dns_message_settsigkey(lookup->sendmsg, tsigkey);
|
2000-06-05 20:43:17 -04:00
|
|
|
check_result(result, "dns_message_settsigkey");
|
2022-03-13 22:43:07 -04:00
|
|
|
} else if (sig0key != NULL) {
|
|
|
|
|
debug("initializing keys");
|
|
|
|
|
result = dns_message_setsig0key(lookup->sendmsg, sig0key);
|
|
|
|
|
check_result(result, "dns_message_setsig0key");
|
2000-06-05 20:43:17 -04:00
|
|
|
}
|
|
|
|
|
|
2022-03-14 02:42:08 -04:00
|
|
|
if (lookup->fuzzing) {
|
|
|
|
|
lookup->sendmsg->fuzzing = true;
|
|
|
|
|
lookup->sendmsg->fuzztime = lookup->fuzztime;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-12 15:16:17 -04:00
|
|
|
lookup->sendspace = isc_mem_get(mctx, COMMSIZE);
|
2000-07-12 21:22:38 -04:00
|
|
|
|
2022-06-23 16:53:46 -04:00
|
|
|
dns_compress_init(&cctx, mctx, 0);
|
2001-03-05 16:15:47 -05:00
|
|
|
|
2000-07-05 19:28:32 -04:00
|
|
|
debug("starting to render the message");
|
2006-12-06 20:21:04 -05:00
|
|
|
isc_buffer_init(&lookup->renderbuf, lookup->sendspace, COMMSIZE);
|
2001-03-05 16:15:47 -05:00
|
|
|
result = dns_message_renderbegin(lookup->sendmsg, &cctx,
|
2006-12-06 20:21:04 -05: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-26 20:03:12 -04:00
|
|
|
check_result(result, "dns_message_renderbegin");
|
2020-07-28 22:34:54 -04:00
|
|
|
if (lookup->udpsize > -1 || lookup->dnssec || lookup->edns > -1 ||
|
2014-02-19 18:51:02 -05:00
|
|
|
lookup->ecs_addr != NULL)
|
|
|
|
|
{
|
2017-01-04 12:16:30 -05:00
|
|
|
#define MAXOPTS (EDNSOPT_OPTIONS + DNS_EDNSOPTIONS)
|
|
|
|
|
dns_ednsopt_t opts[MAXOPTS];
|
2014-09-13 05:13:59 -04:00
|
|
|
unsigned int flags;
|
2017-01-04 12:16:30 -05:00
|
|
|
unsigned int i = 0;
|
2014-02-19 18:51:02 -05:00
|
|
|
|
2017-01-04 12:16:30 -05: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-28 22:34:54 -04:00
|
|
|
if (lookup->udpsize < 0) {
|
|
|
|
|
lookup->udpsize = DEFAULT_EDNS_BUFSIZE;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2005-06-06 20:16:01 -04:00
|
|
|
if (lookup->edns < 0) {
|
2025-03-11 19:02:05 -04:00
|
|
|
lookup->original_edns = lookup->edns =
|
|
|
|
|
DEFAULT_EDNS_VERSION;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2014-02-19 18:51:02 -05:00
|
|
|
|
2014-02-18 20:53:42 -05:00
|
|
|
if (lookup->nsid) {
|
2017-01-04 12:16:30 -05:00
|
|
|
INSIST(i < MAXOPTS);
|
2014-02-18 20:53:42 -05:00
|
|
|
opts[i].code = DNS_OPT_NSID;
|
|
|
|
|
opts[i].length = 0;
|
|
|
|
|
opts[i].value = NULL;
|
|
|
|
|
i++;
|
|
|
|
|
}
|
2014-02-19 18:51:02 -05:00
|
|
|
|
|
|
|
|
if (lookup->ecs_addr != NULL) {
|
2018-03-28 08:19:37 -04:00
|
|
|
uint8_t addr[16];
|
2018-06-04 07:41:09 -04:00
|
|
|
uint16_t family = 0;
|
2018-03-28 08:19:37 -04:00
|
|
|
uint32_t plen;
|
2014-02-19 18:51:02 -05:00
|
|
|
struct sockaddr *sa;
|
|
|
|
|
struct sockaddr_in *sin;
|
|
|
|
|
struct sockaddr_in6 *sin6;
|
|
|
|
|
size_t addrl;
|
|
|
|
|
|
|
|
|
|
sa = &lookup->ecs_addr->type.sa;
|
2016-01-29 20:41:29 -05:00
|
|
|
plen = lookup->ecs_addr->length;
|
2014-02-19 18:51:02 -05:00
|
|
|
|
|
|
|
|
/* Round up prefix len to a multiple of 8 */
|
2016-01-29 20:41:29 -05:00
|
|
|
addrl = (plen + 7) / 8;
|
2014-02-19 18:51:02 -05:00
|
|
|
|
2017-01-04 12:16:30 -05:00
|
|
|
INSIST(i < MAXOPTS);
|
2014-02-19 18:51:02 -05:00
|
|
|
opts[i].code = DNS_OPT_CLIENT_SUBNET;
|
2018-03-28 08:19:37 -04:00
|
|
|
opts[i].length = (uint16_t)addrl + 4;
|
2014-02-19 18:51:02 -05:00
|
|
|
check_result(result, "isc_buffer_allocate");
|
2016-03-23 18:00:30 -04:00
|
|
|
|
2016-09-13 18:22:15 -04: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 19:37:24 -04:00
|
|
|
* that way we can update it in start_udp()
|
|
|
|
|
* or start_tcp() once we know
|
2016-09-13 18:22:15 -04:00
|
|
|
* what it outght to be.)
|
|
|
|
|
*/
|
|
|
|
|
switch (sa->sa_family) {
|
2016-03-23 12:29:57 -04:00
|
|
|
case AF_UNSPEC:
|
|
|
|
|
INSIST(plen == 0);
|
2016-09-13 18:22:15 -04:00
|
|
|
family = 1;
|
2016-03-23 12:29:57 -04:00
|
|
|
break;
|
|
|
|
|
case AF_INET:
|
2016-09-13 18:22:15 -04:00
|
|
|
INSIST(plen <= 32);
|
2016-01-29 20:41:29 -05:00
|
|
|
family = 1;
|
2014-02-19 18:51:02 -05:00
|
|
|
sin = (struct sockaddr_in *)sa;
|
2016-09-13 18:22:15 -04:00
|
|
|
memmove(addr, &sin->sin_addr, addrl);
|
2016-03-23 12:29:57 -04:00
|
|
|
break;
|
|
|
|
|
case AF_INET6:
|
2016-09-13 18:22:15 -04:00
|
|
|
INSIST(plen <= 128);
|
2016-01-29 20:41:29 -05:00
|
|
|
family = 2;
|
2014-02-19 18:51:02 -05:00
|
|
|
sin6 = (struct sockaddr_in6 *)sa;
|
2016-09-13 18:22:15 -04:00
|
|
|
memmove(addr, &sin6->sin6_addr, addrl);
|
2016-03-23 12:29:57 -04:00
|
|
|
break;
|
|
|
|
|
default:
|
2021-10-11 06:50:17 -04:00
|
|
|
UNREACHABLE();
|
2014-02-19 18:51:02 -05:00
|
|
|
}
|
|
|
|
|
|
2016-09-13 18:22:15 -04:00
|
|
|
isc_buffer_init(&b, ecsbuf, sizeof(ecsbuf));
|
2016-01-29 20:41:29 -05: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-13 18:22:15 -04:00
|
|
|
|
2016-01-29 20:41:29 -05:00
|
|
|
/* address */
|
2016-09-13 18:22:15 -04:00
|
|
|
if (addrl > 0) {
|
|
|
|
|
/* Mask off last address byte */
|
|
|
|
|
if ((plen % 8) != 0) {
|
|
|
|
|
addr[addrl - 1] &= ~0U
|
|
|
|
|
<< (8 - (plen % 8));
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2022-09-07 11:22:47 -04:00
|
|
|
isc_buffer_putmem(&b, addr,
|
|
|
|
|
(unsigned int)addrl);
|
2016-09-13 18:22:15 -04:00
|
|
|
}
|
2016-01-29 20:41:29 -05:00
|
|
|
|
2018-03-28 08:19:37 -04:00
|
|
|
opts[i].value = (uint8_t *)ecsbuf;
|
2014-02-19 18:51:02 -05:00
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-05 19:44:24 -04:00
|
|
|
if (lookup->sendcookie) {
|
2017-01-04 12:16:30 -05:00
|
|
|
INSIST(i < MAXOPTS);
|
2015-07-05 19:44:24 -04: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-18 20:53:42 -05: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 18:51:02 -05:00
|
|
|
|
2014-02-19 22:56:20 -05:00
|
|
|
if (lookup->expire) {
|
2017-01-04 12:16:30 -05:00
|
|
|
INSIST(i < MAXOPTS);
|
2014-02-19 22:56:20 -05:00
|
|
|
opts[i].code = DNS_OPT_EXPIRE;
|
|
|
|
|
opts[i].length = 0;
|
|
|
|
|
opts[i].value = NULL;
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-04 12:16:30 -05:00
|
|
|
if (lookup->tcp_keepalive) {
|
|
|
|
|
INSIST(i < MAXOPTS);
|
|
|
|
|
opts[i].code = DNS_OPT_TCP_KEEPALIVE;
|
|
|
|
|
opts[i].length = 0;
|
|
|
|
|
opts[i].value = NULL;
|
|
|
|
|
i++;
|
|
|
|
|
}
|
2024-06-12 17:53:59 -04:00
|
|
|
|
|
|
|
|
if (lookup->zoneversion) {
|
|
|
|
|
INSIST(i < MAXOPTS);
|
|
|
|
|
opts[i].code = DNS_OPT_ZONEVERSION;
|
|
|
|
|
opts[i].length = 0;
|
|
|
|
|
opts[i].value = NULL;
|
|
|
|
|
i++;
|
|
|
|
|
}
|
2017-01-04 12:16:30 -05:00
|
|
|
|
2014-04-17 19:52:12 -04:00
|
|
|
if (lookup->ednsoptscnt != 0) {
|
2017-01-04 12:16:30 -05:00
|
|
|
INSIST(i + lookup->ednsoptscnt <= MAXOPTS);
|
2014-04-17 19:52:12 -04:00
|
|
|
memmove(&opts[i], lookup->ednsopts,
|
|
|
|
|
sizeof(dns_ednsopt_t) * lookup->ednsoptscnt);
|
|
|
|
|
i += lookup->ednsoptscnt;
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-20 02:52:41 -05:00
|
|
|
if (lookup->padding != 0 && (i >= MAXOPTS)) {
|
2017-01-04 12:16:30 -05:00
|
|
|
debug("turned off padding because of EDNS overflow");
|
|
|
|
|
lookup->padding = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-20 02:52:41 -05:00
|
|
|
if (lookup->padding != 0) {
|
2017-01-04 12:16:30 -05: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 05:13:59 -04:00
|
|
|
flags = lookup->ednsflags;
|
|
|
|
|
flags &= ~DNS_MESSAGEEXTFLAG_DO;
|
|
|
|
|
if (lookup->dnssec) {
|
|
|
|
|
flags |= DNS_MESSAGEEXTFLAG_DO;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2005-06-06 20:16:01 -04:00
|
|
|
add_opt(lookup->sendmsg, lookup->udpsize, lookup->edns, flags,
|
2014-09-13 05:13:59 -04:00
|
|
|
opts, i);
|
2000-10-11 13:44:18 -04:00
|
|
|
}
|
2000-07-31 20:53:20 -04:00
|
|
|
|
2000-04-26 14:34:17 -04: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-26 20:03:12 -04:00
|
|
|
DNS_SECTION_QUESTION, 0);
|
|
|
|
|
check_result(result, "dns_message_rendersection");
|
2000-06-02 14:45:33 -04:00
|
|
|
result = dns_message_rendersection(lookup->sendmsg,
|
|
|
|
|
DNS_SECTION_AUTHORITY, 0);
|
|
|
|
|
check_result(result, "dns_message_rendersection");
|
2000-04-26 14:34:17 -04: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-26 20:03:12 -04:00
|
|
|
check_result(result, "dns_message_renderend");
|
2000-07-05 19:28:32 -04:00
|
|
|
debug("done rendering");
|
2000-04-26 14:34:17 -04:00
|
|
|
|
2001-03-05 16:15:47 -05:00
|
|
|
dns_compress_invalidate(&cctx);
|
|
|
|
|
|
2001-01-08 15:50:04 -05:00
|
|
|
/*
|
|
|
|
|
* Force TCP mode if the request is larger than 512 bytes.
|
|
|
|
|
*/
|
2006-12-06 20:21:04 -05:00
|
|
|
if (isc_buffer_usedlength(&lookup->renderbuf) > 512) {
|
2018-04-17 11:29:14 -04:00
|
|
|
lookup->tcp_mode = true;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2001-01-08 15:50:04 -05:00
|
|
|
|
2018-04-17 11:29:14 -04:00
|
|
|
lookup->pending = false;
|
2000-04-26 14:34:17 -04:00
|
|
|
|
2000-07-31 20:53:20 -04:00
|
|
|
for (serv = ISC_LIST_HEAD(lookup->my_server_list); serv != NULL;
|
2018-11-07 13:04:13 -05:00
|
|
|
serv = ISC_LIST_NEXT(serv, link))
|
|
|
|
|
{
|
2020-09-05 19:37:24 -04: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-26 20:03:12 -04:00
|
|
|
ISC_LIST_ENQUEUE(lookup->q, query, link);
|
2000-04-26 14:34:17 -04:00
|
|
|
}
|
2014-02-19 18:51:02 -05:00
|
|
|
|
2018-04-17 11:29:14 -04:00
|
|
|
return true;
|
2000-07-31 20:53:20 -04:00
|
|
|
}
|
2000-04-26 14:34:17 -04:00
|
|
|
|
2022-06-22 10:52:26 -04:00
|
|
|
/*%
|
|
|
|
|
* NSSEARCH mode special mode handling function to start the next query in the
|
|
|
|
|
* list. The lookup lock must be held by the caller. The function will detach
|
|
|
|
|
* both the lookup and the query, and may cancel the lookup and clear the
|
|
|
|
|
* current lookup.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
nssearch_next(dig_lookup_t *l, dig_query_t *q) {
|
|
|
|
|
dig_query_t *next = ISC_LIST_NEXT(q, link);
|
|
|
|
|
bool tcp_mode = l->tcp_mode;
|
|
|
|
|
|
|
|
|
|
INSIST(l->ns_search_only && !l->trace_root);
|
|
|
|
|
INSIST(l == current_lookup);
|
|
|
|
|
|
|
|
|
|
if (next == NULL) {
|
|
|
|
|
/*
|
|
|
|
|
* If 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,
|
|
|
|
|
* cancel and clear the lookup.
|
|
|
|
|
*/
|
|
|
|
|
if (check_if_queries_done(l, q) && !l->ns_search_success) {
|
|
|
|
|
dighost_error("NS servers could not be reached");
|
|
|
|
|
if (exitcode < 9) {
|
|
|
|
|
exitcode = 9;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cancel_lookup(l);
|
|
|
|
|
query_detach(&q);
|
|
|
|
|
lookup_detach(&l);
|
|
|
|
|
clear_current_lookup();
|
|
|
|
|
} else {
|
|
|
|
|
query_detach(&q);
|
|
|
|
|
lookup_detach(&l);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
query_detach(&q);
|
|
|
|
|
lookup_detach(&l);
|
|
|
|
|
|
|
|
|
|
debug("sending next, since searching");
|
|
|
|
|
if (tcp_mode) {
|
|
|
|
|
start_tcp(next);
|
|
|
|
|
} else {
|
|
|
|
|
start_udp(next);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-27 00:57:32 -04:00
|
|
|
/*%
|
2000-07-18 14:51:40 -04:00
|
|
|
* Event handler for send completion. Track send counter, and clear out
|
|
|
|
|
* the query if the send was canceled.
|
|
|
|
|
*/
|
2000-04-26 14:34:17 -04:00
|
|
|
static void
|
2020-09-05 19:37:24 -04:00
|
|
|
send_done(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) {
|
|
|
|
|
dig_query_t *query = (dig_query_t *)arg;
|
|
|
|
|
dig_lookup_t *l = NULL;
|
2006-06-05 20:53:36 -04:00
|
|
|
|
2020-09-05 19:37:24 -04:00
|
|
|
REQUIRE(DIG_VALID_QUERY(query));
|
2020-11-04 06:40:13 -05:00
|
|
|
INSIST(query->sendhandle != NULL);
|
|
|
|
|
INSIST(handle == query->sendhandle);
|
2000-07-13 18:53:51 -04:00
|
|
|
|
2020-11-06 10:12:17 -05:00
|
|
|
debug("send_done(%p, %s, %p)", handle, isc_result_totext(eresult), arg);
|
2020-11-04 06:40:13 -05:00
|
|
|
|
2020-09-05 19:37:24 -04:00
|
|
|
isc_refcount_decrement0(&sendcount);
|
|
|
|
|
debug("sendcount=%" PRIuFAST32, isc_refcount_current(&sendcount));
|
2000-05-25 20:48:18 -04:00
|
|
|
|
2020-09-05 19:37:24 -04:00
|
|
|
INSIST(!free_now);
|
|
|
|
|
|
2020-11-05 09:22:38 -05:00
|
|
|
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-01 19:06:34 -05: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 19:37:24 -04:00
|
|
|
}
|
2020-11-05 09:22:38 -05: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-01 19:06:34 -05:00
|
|
|
lookup_detach(&l);
|
|
|
|
|
return;
|
|
|
|
|
} else if (eresult != ISC_R_SUCCESS) {
|
|
|
|
|
debug("send failed: %s", isc_result_totext(eresult));
|
2020-11-05 09:22:38 -05:00
|
|
|
}
|
2006-07-31 20:49:02 -04:00
|
|
|
|
2022-04-07 05:23:49 -04:00
|
|
|
if (l->ns_search_only && !l->trace_root) {
|
2022-06-22 10:52:26 -04:00
|
|
|
nssearch_next(l, query);
|
2022-06-21 07:54:50 -04:00
|
|
|
} else {
|
|
|
|
|
query_detach(&query);
|
|
|
|
|
lookup_detach(&l);
|
2020-11-05 09:22:38 -05:00
|
|
|
}
|
2020-11-04 06:40:13 -05:00
|
|
|
|
|
|
|
|
check_if_done();
|
2000-04-26 14:34:17 -04:00
|
|
|
}
|
|
|
|
|
|
2005-04-27 00:57:32 -04:00
|
|
|
/*%
|
2020-09-05 19:37:24 -04:00
|
|
|
* Cancel a lookup, sending canceling reads on all existing sockets.
|
2000-07-18 14:51:40 -04:00
|
|
|
*/
|
2021-04-27 06:03:20 -04:00
|
|
|
|
2000-09-26 13:21:25 -04:00
|
|
|
static void
|
2021-04-27 06:03:20 -04:00
|
|
|
_cancel_lookup(dig_lookup_t *lookup, const char *file, unsigned int line) {
|
2000-09-21 18:46:39 -04:00
|
|
|
dig_query_t *query, *next;
|
2000-04-26 14:34:17 -04:00
|
|
|
|
2021-04-27 06:03:20 -04:00
|
|
|
debug("%s:%u:%s()", file, line, __func__);
|
2000-09-21 18:46:39 -04: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 18:46:39 -04:00
|
|
|
next = ISC_LIST_NEXT(query, link);
|
2020-11-04 06:40:13 -05: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-01 19:06:34 -05:00
|
|
|
debug("canceling pending query %p, belonging to %p", query,
|
|
|
|
|
query->lookup);
|
|
|
|
|
query->canceled = true;
|
2022-05-10 16:09:59 -04:00
|
|
|
if (query->readhandle != NULL &&
|
2022-11-02 14:33:14 -04:00
|
|
|
!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-01 19:06:34 -05:00
|
|
|
isc_nm_cancelread(query->readhandle);
|
|
|
|
|
}
|
2020-11-04 06:40:13 -05:00
|
|
|
query_detach(&query);
|
2000-09-21 18:46:39 -04:00
|
|
|
query = next;
|
2000-04-26 14:34:17 -04:00
|
|
|
}
|
2018-04-17 11:29:14 -04:00
|
|
|
lookup->pending = false;
|
2000-05-11 21:02:37 -04:00
|
|
|
lookup->retries = 0;
|
2020-11-04 06:40:13 -05:00
|
|
|
check_if_done();
|
2000-04-26 14:34:17 -04:00
|
|
|
}
|
|
|
|
|
|
2024-12-17 09:02:05 -05:00
|
|
|
static inline const char *
|
|
|
|
|
get_tls_sni_hostname(dig_query_t *query) {
|
2025-03-14 15:35:39 -04:00
|
|
|
const char *hostname = query->lookup->tls_hostname_set
|
|
|
|
|
? query->lookup->tls_hostname
|
|
|
|
|
: query->userarg;
|
|
|
|
|
|
|
|
|
|
if (query->lookup->tls_hostname_set) {
|
|
|
|
|
return query->lookup->tls_hostname;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isc_tls_valid_sni_hostname(hostname)) {
|
|
|
|
|
return hostname;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
2024-12-17 09:02:05 -05:00
|
|
|
}
|
|
|
|
|
|
2022-01-19 06:10:08 -05:00
|
|
|
static isc_tlsctx_t *
|
2022-04-22 04:41:14 -04:00
|
|
|
get_create_tls_context(dig_query_t *query, const bool is_https,
|
|
|
|
|
isc_tlsctx_client_session_cache_t **psess_cache) {
|
2022-01-19 06:10:08 -05: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 04:41:14 -04:00
|
|
|
isc_tlsctx_client_session_cache_t *sess_cache = NULL,
|
|
|
|
|
*found_sess_cache = NULL;
|
2022-01-19 06:10:08 -05: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 04:41:14 -04:00
|
|
|
&found_store, &found_sess_cache);
|
2022-01-19 06:10:08 -05: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) {
|
2024-12-17 09:02:05 -05:00
|
|
|
const char *hostname = get_tls_sni_hostname(query);
|
2022-01-19 06:10:08 -05:00
|
|
|
/*
|
|
|
|
|
* 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 &&
|
2022-11-02 14:33:14 -04:00
|
|
|
query->lookup->tls_cert_file_set)
|
|
|
|
|
{
|
2022-01-19 06:10:08 -05:00
|
|
|
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-12-22 13:04:22 -05:00
|
|
|
isc_tlsctx_client_session_cache_create(
|
|
|
|
|
mctx, ctx, ISC_TLSCTX_CLIENT_SESSION_CACHE_DEFAULT_SIZE,
|
|
|
|
|
&sess_cache);
|
2022-04-22 04:41:14 -04:00
|
|
|
|
|
|
|
|
result = isc_tlsctx_cache_add(
|
|
|
|
|
query->lookup->tls_ctx_cache, tlsctxname, transport,
|
|
|
|
|
family, ctx, store, sess_cache, NULL, NULL, NULL);
|
2022-01-19 06:10:08 -05:00
|
|
|
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
2022-04-22 04:41:14 -04:00
|
|
|
if (psess_cache != NULL) {
|
|
|
|
|
INSIST(*psess_cache == NULL);
|
|
|
|
|
*psess_cache = sess_cache;
|
|
|
|
|
}
|
2022-01-19 06:10:08 -05:00
|
|
|
return ctx;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-22 04:41:14 -04:00
|
|
|
if (psess_cache != NULL) {
|
|
|
|
|
INSIST(*psess_cache == NULL);
|
|
|
|
|
*psess_cache = found_sess_cache;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-19 06:10:08 -05:00
|
|
|
INSIST(!query->lookup->tls_ca_set || found_store != NULL);
|
|
|
|
|
return found_ctx;
|
|
|
|
|
failure:
|
2022-05-24 04:25:30 -04:00
|
|
|
if (ctx != NULL) {
|
2022-01-19 06:10:08 -05:00
|
|
|
isc_tlsctx_free(&ctx);
|
|
|
|
|
}
|
2022-05-24 04:25:30 -04: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 06:10:08 -05:00
|
|
|
if (store != NULL && store != found_store) {
|
|
|
|
|
isc_tls_cert_store_free(&store);
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2000-09-21 18:46:39 -04:00
|
|
|
static void
|
2020-09-05 19:37:24 -04:00
|
|
|
tcp_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg);
|
2000-09-21 18:46:39 -04:00
|
|
|
|
2005-04-27 00:57:32 -04:00
|
|
|
/*%
|
2020-09-05 19:37:24 -04:00
|
|
|
* Unlike start_udp, this can't be called multiple times with the same
|
2000-09-21 18:46:39 -04:00
|
|
|
* query. When we retry TCP, we requeue the whole lookup, which should
|
|
|
|
|
* start anew.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
2020-09-05 19:37:24 -04:00
|
|
|
start_tcp(dig_query_t *query) {
|
2000-09-21 18:46:39 -04: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-01 19:06:34 -05:00
|
|
|
dig_query_t *next = NULL;
|
|
|
|
|
dig_query_t *connectquery = NULL;
|
2022-01-19 06:10:08 -05:00
|
|
|
isc_tlsctx_t *tlsctx = NULL;
|
|
|
|
|
bool tls_mode = false;
|
2022-04-22 04:41:14 -04:00
|
|
|
isc_tlsctx_client_session_cache_t *sess_cache = NULL;
|
2022-07-26 07:03:40 -04:00
|
|
|
int local_timeout;
|
2023-10-16 15:54:13 -04:00
|
|
|
isc_nm_proxy_type_t proxy_type = ISC_NM_PROXY_NONE;
|
|
|
|
|
isc_nm_proxyheader_info_t proxy_info = { 0 };
|
|
|
|
|
isc_nm_proxyheader_info_t *ppi = NULL;
|
2022-07-26 07:03:40 -04:00
|
|
|
|
2018-11-07 13:04:13 -05:00
|
|
|
REQUIRE(DIG_VALID_QUERY(query));
|
2000-09-21 18:46:39 -04:00
|
|
|
|
2020-09-05 19:37:24 -04:00
|
|
|
debug("start_tcp(%p)", query);
|
2000-09-21 18:46:39 -04:00
|
|
|
|
2020-11-05 09:22:38 -05:00
|
|
|
query_attach(query, &query->lookup->current_query);
|
2020-07-22 02:59:42 -04:00
|
|
|
|
2022-01-19 06:10:08 -05:00
|
|
|
tls_mode = dig_lookup_is_tls(query->lookup);
|
|
|
|
|
|
2020-07-22 02:59:42 -04:00
|
|
|
/*
|
|
|
|
|
* For TLS connections, we want to override the default
|
|
|
|
|
* port number.
|
|
|
|
|
*/
|
2021-01-27 09:49:27 -05:00
|
|
|
if (!port_set) {
|
2022-01-19 06:10:08 -05:00
|
|
|
if (tls_mode) {
|
2021-01-27 09:49:27 -05:00
|
|
|
port = 853;
|
|
|
|
|
} else if (query->lookup->https_mode &&
|
2022-11-02 14:33:14 -04:00
|
|
|
!query->lookup->http_plain)
|
|
|
|
|
{
|
2021-01-27 09:49:27 -05:00
|
|
|
port = 443;
|
|
|
|
|
} else if (query->lookup->https_mode) {
|
|
|
|
|
port = 80;
|
|
|
|
|
} else {
|
|
|
|
|
port = 53;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
debug("query->servname = %s\n", query->servname);
|
2020-07-22 02:59:42 -04:00
|
|
|
|
2008-12-15 21:57:24 -05:00
|
|
|
result = get_address(query->servname, port, &query->sockaddr);
|
2010-06-24 03:22:18 -04:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2008-12-15 21:57:24 -05: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-03 00:38:56 -05:00
|
|
|
force_next(query);
|
2008-12-15 21:57:24 -05:00
|
|
|
return;
|
|
|
|
|
}
|
2008-01-18 18:46:58 -05:00
|
|
|
|
2022-01-13 07:29:09 -05:00
|
|
|
if (isc_sockaddr_pf(&query->sockaddr) == AF_INET6 &&
|
2015-12-18 17:47:11 -05:00
|
|
|
IN6_IS_ADDR_V4MAPPED(&query->sockaddr.type.sin6.sin6_addr))
|
|
|
|
|
{
|
|
|
|
|
isc_netaddr_t netaddr;
|
|
|
|
|
char buf[ISC_NETADDR_FORMATSIZE];
|
|
|
|
|
|
|
|
|
|
isc_netaddr_fromsockaddr(&netaddr, &query->sockaddr);
|
|
|
|
|
isc_netaddr_format(&netaddr, buf, sizeof(buf));
|
2019-08-30 00:23:29 -04:00
|
|
|
dighost_warning("Skipping mapped address '%s'", buf);
|
2015-12-18 17:47:11 -05:00
|
|
|
|
2016-12-13 23:42:43 -05:00
|
|
|
if (ISC_LINK_LINKED(query, link)) {
|
|
|
|
|
next = ISC_LIST_NEXT(query, link);
|
|
|
|
|
} else {
|
|
|
|
|
next = NULL;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2020-11-04 06:40:13 -05:00
|
|
|
query_detach(&query);
|
2015-12-18 17:47:11 -05:00
|
|
|
if (next == NULL) {
|
2019-08-30 00:23:29 -04:00
|
|
|
dighost_warning("No acceptable nameservers");
|
2020-11-06 10:12:17 -05:00
|
|
|
clear_current_lookup();
|
2020-11-05 09:22:38 -05:00
|
|
|
} else {
|
|
|
|
|
start_tcp(next);
|
2015-12-18 17:47:11 -05:00
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-05 19:37:24 -04:00
|
|
|
INSIST(query->handle == NULL);
|
2013-11-06 18:50:01 -05:00
|
|
|
|
|
|
|
|
if (keep != NULL && isc_sockaddr_equal(&keepaddr, &query->sockaddr)) {
|
2020-09-05 19:37:24 -04:00
|
|
|
query->handle = keep;
|
|
|
|
|
launch_next_query(query);
|
2020-11-04 06:40:13 -05:00
|
|
|
query_detach(&query);
|
|
|
|
|
return;
|
2022-07-26 07:03:40 -04:00
|
|
|
} else if (keep != NULL) {
|
|
|
|
|
isc_nmhandle_detach(&keep);
|
|
|
|
|
}
|
2020-09-05 19:37:24 -04:00
|
|
|
|
2022-07-26 07:03:40 -04:00
|
|
|
if (timeout != 0) {
|
|
|
|
|
local_timeout = timeout * 1000;
|
|
|
|
|
} else {
|
|
|
|
|
local_timeout = TCP_TIMEOUT * 1000;
|
|
|
|
|
}
|
2020-09-05 19:37:24 -04:00
|
|
|
|
2022-07-26 07:03:40 -04:00
|
|
|
if (!specified_source) {
|
|
|
|
|
if ((isc_sockaddr_pf(&query->sockaddr) == AF_INET) && have_ipv4)
|
|
|
|
|
{
|
|
|
|
|
isc_sockaddr_any(&localaddr);
|
|
|
|
|
} else {
|
|
|
|
|
isc_sockaddr_any6(&localaddr);
|
2020-09-05 19:37:24 -04:00
|
|
|
}
|
2022-07-26 07:03:40 -04:00
|
|
|
}
|
2020-09-05 19:37:24 -04:00
|
|
|
|
2023-10-16 15:54:13 -04:00
|
|
|
if (query->lookup->proxy_mode) {
|
|
|
|
|
proxy_type = ISC_NM_PROXY_PLAIN;
|
|
|
|
|
if ((tls_mode || (query->lookup->https_mode &&
|
|
|
|
|
!query->lookup->http_plain)) &&
|
|
|
|
|
!query->lookup->proxy_plain)
|
|
|
|
|
{
|
|
|
|
|
proxy_type = ISC_NM_PROXY_ENCRYPTED;
|
|
|
|
|
}
|
|
|
|
|
if (!query->lookup->proxy_local) {
|
|
|
|
|
isc_nm_proxyheader_info_init(
|
|
|
|
|
&proxy_info, &query->lookup->proxy_src_addr,
|
|
|
|
|
&query->lookup->proxy_dst_addr, NULL);
|
|
|
|
|
ppi = &proxy_info;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-26 07:03:40 -04:00
|
|
|
REQUIRE(query != NULL);
|
2020-11-04 06:40:13 -05:00
|
|
|
|
2022-07-26 07:03:40 -04:00
|
|
|
query_attach(query, &connectquery);
|
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-01 19:06:34 -05:00
|
|
|
|
2022-07-26 07:03:40 -04:00
|
|
|
if (tls_mode) {
|
|
|
|
|
tlsctx = get_create_tls_context(connectquery, false,
|
|
|
|
|
&sess_cache);
|
|
|
|
|
if (tlsctx == NULL) {
|
|
|
|
|
goto failure_tls;
|
|
|
|
|
}
|
2022-07-12 16:08:07 -04:00
|
|
|
isc_nm_streamdnsconnect(netmgr, &localaddr, &query->sockaddr,
|
|
|
|
|
tcp_connected, connectquery,
|
2024-12-17 09:02:05 -05:00
|
|
|
local_timeout, tlsctx,
|
|
|
|
|
get_tls_sni_hostname(query), sess_cache,
|
2023-10-16 15:54:13 -04:00
|
|
|
proxy_type, ppi);
|
2022-07-26 07:03:40 -04:00
|
|
|
#if HAVE_LIBNGHTTP2
|
|
|
|
|
} else if (query->lookup->https_mode) {
|
|
|
|
|
char uri[4096] = { 0 };
|
|
|
|
|
isc_nm_http_makeuri(!query->lookup->http_plain,
|
|
|
|
|
&query->sockaddr, query->userarg, port,
|
|
|
|
|
query->lookup->https_path, uri,
|
|
|
|
|
sizeof(uri));
|
|
|
|
|
|
|
|
|
|
if (!query->lookup->http_plain) {
|
|
|
|
|
tlsctx = get_create_tls_context(connectquery, true,
|
2022-04-22 04:41:14 -04:00
|
|
|
&sess_cache);
|
2022-01-19 06:10:08 -05:00
|
|
|
if (tlsctx == NULL) {
|
|
|
|
|
goto failure_tls;
|
|
|
|
|
}
|
2020-07-22 02:59:42 -04:00
|
|
|
}
|
|
|
|
|
|
2022-07-26 07:03:40 -04:00
|
|
|
isc_nm_httpconnect(netmgr, &localaddr, &query->sockaddr, uri,
|
|
|
|
|
!query->lookup->https_get, tcp_connected,
|
2024-12-17 09:02:05 -05:00
|
|
|
connectquery, tlsctx,
|
|
|
|
|
get_tls_sni_hostname(query), sess_cache,
|
2023-10-16 15:54:13 -04:00
|
|
|
local_timeout, proxy_type, ppi);
|
2022-07-26 07:03:40 -04:00
|
|
|
#endif
|
|
|
|
|
} else {
|
2022-08-23 12:18:31 -04:00
|
|
|
isc_nm_streamdnsconnect(netmgr, &localaddr, &query->sockaddr,
|
|
|
|
|
tcp_connected, connectquery,
|
2024-12-17 08:52:18 -05:00
|
|
|
local_timeout, NULL, NULL, NULL,
|
|
|
|
|
proxy_type, ppi);
|
2020-09-05 19:37:24 -04:00
|
|
|
}
|
|
|
|
|
|
2022-01-19 06:10:08 -05:00
|
|
|
return;
|
2022-04-07 05:23:49 -04:00
|
|
|
|
2022-01-19 06:10:08 -05: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 11:12:46 -04:00
|
|
|
query_detach(&connectquery);
|
2022-01-19 06:10:08 -05:00
|
|
|
query_detach(&query);
|
|
|
|
|
if (next == NULL) {
|
|
|
|
|
clear_current_lookup();
|
|
|
|
|
} else {
|
|
|
|
|
start_tcp(next);
|
|
|
|
|
}
|
2000-09-21 18:46:39 -04:00
|
|
|
}
|
|
|
|
|
|
2019-08-30 00:23:29 -04:00
|
|
|
static void
|
|
|
|
|
print_query_size(dig_query_t *query) {
|
|
|
|
|
if (!yaml) {
|
|
|
|
|
printf(";; QUERY SIZE: %u\n\n",
|
|
|
|
|
isc_buffer_usedlength(&query->lookup->renderbuf));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-05 19:37:24 -04:00
|
|
|
static void
|
|
|
|
|
send_udp(dig_query_t *query) {
|
2020-11-04 06:40:13 -05:00
|
|
|
dig_query_t *sendquery = NULL;
|
2020-09-05 19:37:24 -04:00
|
|
|
isc_region_t r;
|
|
|
|
|
|
2020-11-04 06:40:13 -05:00
|
|
|
query_attach(query, &sendquery);
|
|
|
|
|
|
2020-09-05 19:37:24 -04:00
|
|
|
isc_buffer_usedregion(&query->sendbuf, &r);
|
|
|
|
|
debug("sending a request");
|
2021-03-20 01:50:51 -04:00
|
|
|
if (query->lookup->use_usec) {
|
2023-03-30 18:12:33 -04:00
|
|
|
query->time_sent = isc_time_now_hires();
|
2021-03-20 01:50:51 -04:00
|
|
|
} else {
|
2023-03-30 18:12:33 -04:00
|
|
|
query->time_sent = isc_time_now();
|
2021-03-20 01:50:51 -04:00
|
|
|
}
|
2020-09-05 19:37:24 -04:00
|
|
|
|
2020-11-04 06:40:13 -05:00
|
|
|
isc_nmhandle_attach(query->handle, &query->sendhandle);
|
2020-09-05 19:37:24 -04:00
|
|
|
|
2020-11-04 06:40:13 -05:00
|
|
|
isc_nm_send(query->handle, &r, send_done, sendquery);
|
2020-09-05 19:37:24 -04:00
|
|
|
isc_refcount_increment0(&sendcount);
|
2020-07-22 02:59:42 -04:00
|
|
|
debug("sendcount=%" PRIuFAST32, isc_refcount_current(&sendcount));
|
2020-09-05 19:37:24 -04:00
|
|
|
|
|
|
|
|
/* XXX qrflag, print_query, etc... */
|
2022-03-31 10:33:49 -04:00
|
|
|
if (query->lookup->qr) {
|
2020-09-05 19:37:24 -04:00
|
|
|
extrabytes = 0;
|
2022-03-31 10:33:49 -04:00
|
|
|
dighost_printmessage(query, &query->lookup->renderbuf,
|
2020-09-05 19:37:24 -04: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;
|
2022-06-15 08:57:14 -04:00
|
|
|
dig_query_t *next = NULL;
|
|
|
|
|
char sockstr[ISC_SOCKADDR_FORMATSIZE];
|
|
|
|
|
dig_lookup_t *l = NULL;
|
2020-11-04 06:40:13 -05:00
|
|
|
dig_query_t *readquery = NULL;
|
2020-11-03 00:38:56 -05:00
|
|
|
int local_timeout = timeout * 1000;
|
2020-09-05 19:37:24 -04:00
|
|
|
|
2022-03-29 16:58:15 -04:00
|
|
|
REQUIRE(DIG_VALID_QUERY(query));
|
|
|
|
|
REQUIRE(query->handle == NULL);
|
|
|
|
|
|
|
|
|
|
debug("udp_ready()");
|
|
|
|
|
|
2022-03-20 09:54:39 -04:00
|
|
|
query->started = true;
|
|
|
|
|
|
2022-07-26 07:03:40 -04:00
|
|
|
if (cancel_now) {
|
2022-04-10 20:42:49 -04:00
|
|
|
query_detach(&query);
|
2022-03-29 16:58:15 -04:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
INSIST(!free_now);
|
|
|
|
|
|
|
|
|
|
debug("udp_ready(%p, %s, %p)", handle, isc_result_totext(eresult),
|
|
|
|
|
query);
|
|
|
|
|
|
2022-06-15 08:57:14 -04:00
|
|
|
lookup_attach(query->lookup, &l);
|
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-01 19:06:34 -05:00
|
|
|
|
2022-06-15 08:57:14 -04:00
|
|
|
if (eresult == ISC_R_CANCELED || query->canceled) {
|
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-01 19:06:34 -05:00
|
|
|
debug("in cancel handler");
|
|
|
|
|
if (!query->canceled) {
|
|
|
|
|
cancel_lookup(l);
|
|
|
|
|
}
|
2022-03-06 04:16:29 -05: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-01 19:06:34 -05:00
|
|
|
lookup_detach(&l);
|
2022-06-15 08:57:14 -04:00
|
|
|
clear_current_lookup();
|
2020-09-05 19:37:24 -04:00
|
|
|
return;
|
2022-06-22 10:52:26 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (eresult != ISC_R_SUCCESS) {
|
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-01 19:06:34 -05:00
|
|
|
debug("udp setup failed: %s", isc_result_totext(eresult));
|
2022-06-15 08:57:14 -04:00
|
|
|
isc_sockaddr_format(&query->sockaddr, sockstr, sizeof(sockstr));
|
|
|
|
|
dighost_warning("UDP setup with %s(%s) for %s failed: %s.",
|
|
|
|
|
sockstr, query->servname, l->textname,
|
|
|
|
|
isc_result_totext(eresult));
|
2022-04-08 03:33:24 -04:00
|
|
|
|
2022-06-22 10:52:26 -04:00
|
|
|
/*
|
|
|
|
|
* NSSEARCH mode: if the current query failed to start properly,
|
|
|
|
|
* then send_done() will not be called, and we want to make sure
|
|
|
|
|
* that the next query gets a chance to start in order to not
|
|
|
|
|
* break the chain.
|
|
|
|
|
*/
|
|
|
|
|
if (l->ns_search_only && !l->trace_root) {
|
|
|
|
|
nssearch_next(l, query);
|
|
|
|
|
|
|
|
|
|
check_if_done();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-08 03:33:24 -04:00
|
|
|
if (exitcode < 9) {
|
|
|
|
|
exitcode = 9;
|
|
|
|
|
}
|
2022-06-15 08:57:14 -04:00
|
|
|
|
|
|
|
|
if (l->retries > 1) {
|
|
|
|
|
l->retries--;
|
|
|
|
|
debug("making new UDP 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)))
|
|
|
|
|
{
|
|
|
|
|
next = ISC_LIST_NEXT(l->current_query, link);
|
|
|
|
|
} else {
|
|
|
|
|
next = 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-01 19:06:34 -05:00
|
|
|
query_detach(&query);
|
2022-06-15 08:57:14 -04:00
|
|
|
if (next == NULL) {
|
|
|
|
|
cancel_lookup(l);
|
|
|
|
|
}
|
2021-04-06 19:49:14 -04:00
|
|
|
lookup_detach(&l);
|
2022-06-15 08:57:14 -04:00
|
|
|
|
|
|
|
|
if (next != NULL) {
|
|
|
|
|
start_udp(next);
|
2023-05-02 08:24:34 -04:00
|
|
|
check_if_done();
|
2022-06-15 08:57:14 -04:00
|
|
|
} else {
|
2024-06-16 16:10:28 -04:00
|
|
|
dighost_error("no servers could be reached");
|
2022-06-15 08:57:14 -04:00
|
|
|
clear_current_lookup();
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-05 19:37:24 -04:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-15 08:57:14 -04:00
|
|
|
exitcode = 0;
|
|
|
|
|
|
2020-11-04 06:40:13 -05:00
|
|
|
query_attach(query, &readquery);
|
|
|
|
|
|
2020-09-05 19:37:24 -04:00
|
|
|
debug("recving with lookup=%p, query=%p, handle=%p", query->lookup,
|
2022-03-31 18:00:21 -04:00
|
|
|
query, handle);
|
2020-09-05 19:37:24 -04:00
|
|
|
|
|
|
|
|
query->handle = handle;
|
|
|
|
|
isc_nmhandle_attach(handle, &query->readhandle);
|
|
|
|
|
isc_refcount_increment0(&recvcount);
|
|
|
|
|
debug("recvcount=%" PRIuFAST32, isc_refcount_current(&recvcount));
|
2020-11-03 00:38:56 -05: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 06:40:13 -05:00
|
|
|
isc_nm_read(handle, recv_done, readquery);
|
|
|
|
|
send_udp(readquery);
|
|
|
|
|
|
|
|
|
|
query_detach(&query);
|
2022-06-15 08:57:14 -04:00
|
|
|
lookup_detach(&l);
|
2020-09-05 19:37:24 -04:00
|
|
|
}
|
|
|
|
|
|
2005-04-27 00:57:32 -04:00
|
|
|
/*%
|
2000-09-21 18:46:39 -04:00
|
|
|
* Send a UDP packet to the remote nameserver, possible starting the
|
2022-07-26 07:03:45 -04:00
|
|
|
* recv action as well. Also make sure that the timer is running and
|
|
|
|
|
* is properly reset.
|
2000-09-21 18:46:39 -04:00
|
|
|
*/
|
|
|
|
|
static void
|
2020-09-05 19:37:24 -04:00
|
|
|
start_udp(dig_query_t *query) {
|
2000-09-21 18:46:39 -04:00
|
|
|
isc_result_t result;
|
2020-09-05 19:37:24 -04:00
|
|
|
dig_query_t *next = NULL;
|
2021-04-27 06:03:20 -04:00
|
|
|
dig_query_t *connectquery = NULL;
|
2020-09-05 19:37:24 -04:00
|
|
|
|
2018-11-07 13:04:13 -05:00
|
|
|
REQUIRE(DIG_VALID_QUERY(query));
|
2000-09-21 18:46:39 -04:00
|
|
|
|
2020-09-05 19:37:24 -04:00
|
|
|
debug("start_udp(%p)", query);
|
2000-09-21 18:46:39 -04:00
|
|
|
|
2020-11-05 09:22:38 -05:00
|
|
|
query_attach(query, &query->lookup->current_query);
|
2005-08-24 20:56:08 -04:00
|
|
|
debug("working on lookup %p, query %p", query->lookup, query);
|
2020-11-05 09:22:38 -05:00
|
|
|
|
2020-09-05 19:37:24 -04:00
|
|
|
if (query->handle != NULL) {
|
2020-11-05 09:22:38 -05:00
|
|
|
launch_next_query(query);
|
|
|
|
|
query_detach(&query);
|
2020-09-05 19:37:24 -04:00
|
|
|
return;
|
|
|
|
|
}
|
2000-09-21 18:46:39 -04:00
|
|
|
|
2024-10-10 06:18:05 -04:00
|
|
|
if (!port_set) {
|
|
|
|
|
port = 53;
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-05 19:37:24 -04:00
|
|
|
result = get_address(query->servname, port, &query->sockaddr);
|
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
|
/* This servname doesn't have an address. */
|
2020-11-03 00:38:56 -05:00
|
|
|
force_next(query);
|
2020-09-05 19:37:24 -04:00
|
|
|
return;
|
|
|
|
|
}
|
2015-12-18 17:47:11 -05:00
|
|
|
|
2022-01-13 07:29:09 -05:00
|
|
|
if (isc_sockaddr_pf(&query->sockaddr) == AF_INET6 &&
|
2020-09-05 19:37:24 -04:00
|
|
|
IN6_IS_ADDR_V4MAPPED(&query->sockaddr.type.sin6.sin6_addr))
|
|
|
|
|
{
|
|
|
|
|
isc_netaddr_t netaddr;
|
|
|
|
|
char buf[ISC_NETADDR_FORMATSIZE];
|
2015-12-18 17:47:11 -05:00
|
|
|
|
2020-09-05 19:37:24 -04: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 06:40:13 -05:00
|
|
|
query_detach(&query);
|
2020-09-05 19:37:24 -04:00
|
|
|
if (next == NULL) {
|
|
|
|
|
dighost_warning("No acceptable nameservers");
|
2020-11-06 10:12:17 -05:00
|
|
|
clear_current_lookup();
|
2000-09-21 18:46:39 -04:00
|
|
|
} else {
|
2020-09-05 19:37:24 -04:00
|
|
|
start_udp(next);
|
2000-07-17 21:28:20 -04:00
|
|
|
}
|
2020-09-05 19:37:24 -04:00
|
|
|
return;
|
2000-09-21 18:46:39 -04:00
|
|
|
}
|
2019-07-17 02:44:20 -04:00
|
|
|
|
2020-09-05 19:37:24 -04: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-17 02:44:20 -04:00
|
|
|
}
|
|
|
|
|
}
|
2020-09-05 19:37:24 -04:00
|
|
|
|
2021-04-27 06:03:20 -04:00
|
|
|
query_attach(query, &connectquery);
|
2023-10-16 15:54:13 -04:00
|
|
|
if (query->lookup->proxy_mode) {
|
|
|
|
|
isc_nm_proxyheader_info_t proxy_info = { 0 };
|
|
|
|
|
isc_nm_proxyheader_info_t *ppi = NULL;
|
|
|
|
|
if (!query->lookup->proxy_local) {
|
|
|
|
|
isc_nm_proxyheader_info_init(
|
|
|
|
|
&proxy_info, &query->lookup->proxy_src_addr,
|
|
|
|
|
&query->lookup->proxy_dst_addr, NULL);
|
|
|
|
|
ppi = &proxy_info;
|
|
|
|
|
}
|
|
|
|
|
isc_nm_proxyudpconnect(netmgr, &localaddr, &query->sockaddr,
|
|
|
|
|
udp_ready, connectquery,
|
|
|
|
|
(timeout ? timeout : UDP_TIMEOUT) * 1000,
|
|
|
|
|
ppi);
|
|
|
|
|
} else {
|
|
|
|
|
isc_nm_udpconnect(netmgr, &localaddr, &query->sockaddr,
|
|
|
|
|
udp_ready, connectquery,
|
|
|
|
|
(timeout ? timeout : UDP_TIMEOUT) * 1000);
|
|
|
|
|
}
|
2000-05-02 19:23:12 -04:00
|
|
|
}
|
|
|
|
|
|
2019-01-08 05:17:39 -05: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
|
|
|
|
|
try_next_server(dig_lookup_t *lookup) {
|
|
|
|
|
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 19:37:24 -04:00
|
|
|
start_tcp(next_query);
|
2019-01-08 05:17:39 -05:00
|
|
|
} else {
|
2020-09-05 19:37:24 -04:00
|
|
|
start_udp(next_query);
|
2019-01-08 05:17:39 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2000-04-26 14:34:17 -04:00
|
|
|
static void
|
2020-11-03 00:38:56 -05:00
|
|
|
force_next(dig_query_t *query) {
|
2005-10-13 21:14:08 -04:00
|
|
|
dig_lookup_t *l = NULL;
|
2000-04-26 14:34:17 -04:00
|
|
|
|
2020-11-03 00:38:56 -05:00
|
|
|
REQUIRE(DIG_VALID_QUERY(query));
|
2000-04-26 14:34:17 -04:00
|
|
|
|
2020-11-03 00:38:56 -05:00
|
|
|
debug("force_next()");
|
2000-04-28 20:12:56 -04:00
|
|
|
|
2000-07-17 21:28:20 -04:00
|
|
|
INSIST(!free_now);
|
2000-09-21 18:46:39 -04:00
|
|
|
|
2022-07-26 07:03:40 -04:00
|
|
|
if (cancel_now) {
|
2018-11-13 07:50:47 -05:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-05 09:22:38 -05:00
|
|
|
lookup_attach(query->lookup, &l);
|
|
|
|
|
|
2019-01-08 05:17:39 -05:00
|
|
|
if (try_next_server(l)) {
|
2020-11-05 09:22:38 -05:00
|
|
|
lookup_detach(&l);
|
2000-09-21 18:46:39 -04:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-05 19:37:24 -04: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 14:45:54 -05:00
|
|
|
debug("making new %s request, %d tries left",
|
|
|
|
|
l->tcp_mode ? "TCP" : "UDP", l->retries);
|
2020-09-05 19:37:24 -04:00
|
|
|
requeue_lookup(l, true);
|
2020-11-05 09:22:38 -05:00
|
|
|
lookup_detach(&l);
|
2020-09-05 19:37:24 -04:00
|
|
|
isc_refcount_decrement0(&recvcount);
|
2020-11-06 10:12:17 -05:00
|
|
|
debug("recvcount=%" PRIuFAST32,
|
|
|
|
|
isc_refcount_current(&recvcount));
|
2020-11-04 06:40:13 -05:00
|
|
|
query_detach(&query);
|
2020-11-06 10:12:17 -05:00
|
|
|
clear_current_lookup();
|
2020-09-05 19:37:24 -04:00
|
|
|
return;
|
2016-12-13 23:42:43 -05:00
|
|
|
}
|
|
|
|
|
|
2020-09-05 19:37:24 -04:00
|
|
|
if (query->readhandle != NULL) {
|
|
|
|
|
isc_refcount_decrement0(&recvcount);
|
2020-11-06 10:12:17 -05:00
|
|
|
debug("recvcount=%" PRIuFAST32,
|
|
|
|
|
isc_refcount_current(&recvcount));
|
2020-09-05 19:37:24 -04:00
|
|
|
}
|
2018-02-15 19:11:52 -05:00
|
|
|
|
2020-09-05 19:37:24 -04:00
|
|
|
if (l->ns_search_only) {
|
|
|
|
|
isc_netaddr_t netaddr;
|
|
|
|
|
char buf[ISC_NETADDR_FORMATSIZE];
|
2018-02-15 19:11:52 -05:00
|
|
|
|
2020-09-05 19:37:24 -04:00
|
|
|
isc_netaddr_fromsockaddr(&netaddr, &query->sockaddr);
|
|
|
|
|
isc_netaddr_format(&netaddr, buf, sizeof(buf));
|
|
|
|
|
|
2024-06-16 16:10:28 -04:00
|
|
|
dighost_error("no response from %s", buf);
|
2020-09-05 19:37:24 -04:00
|
|
|
} else {
|
|
|
|
|
printf("%s", l->cmdline);
|
2024-06-16 16:10:28 -04:00
|
|
|
dighost_error("no servers could be reached");
|
2000-07-17 21:28:20 -04:00
|
|
|
}
|
2020-09-05 19:37:24 -04:00
|
|
|
|
|
|
|
|
if (exitcode < 9) {
|
|
|
|
|
exitcode = 9;
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-04 06:40:13 -05:00
|
|
|
query_detach(&query);
|
2020-09-05 19:37:24 -04:00
|
|
|
cancel_lookup(l);
|
2020-11-05 09:22:38 -05:00
|
|
|
lookup_detach(&l);
|
2020-11-06 10:12:17 -05:00
|
|
|
clear_current_lookup();
|
2000-04-26 14:34:17 -04:00
|
|
|
}
|
|
|
|
|
|
2005-04-27 00:57:32 -04:00
|
|
|
/*%
|
2000-07-18 14:51:40 -04:00
|
|
|
* For transfers that involve multiple recvs (XFR's in particular),
|
|
|
|
|
* launch the next recv.
|
|
|
|
|
*/
|
2000-04-26 14:34:17 -04:00
|
|
|
static void
|
2020-09-05 19:37:24 -04:00
|
|
|
launch_next_query(dig_query_t *query) {
|
2020-11-04 06:40:13 -05:00
|
|
|
dig_query_t *readquery = NULL;
|
2020-11-03 00:38:56 -05:00
|
|
|
int local_timeout = timeout * 1000;
|
|
|
|
|
dig_lookup_t *l = NULL;
|
2018-10-29 05:15:42 -04:00
|
|
|
isc_region_t r;
|
2021-09-02 08:39:50 -04:00
|
|
|
bool xfr;
|
2000-04-26 14:34:17 -04:00
|
|
|
|
2020-09-05 19:37:24 -04:00
|
|
|
REQUIRE(DIG_VALID_QUERY(query));
|
2000-07-12 20:32:20 -04:00
|
|
|
INSIST(!free_now);
|
2000-04-28 20:12:56 -04:00
|
|
|
|
2000-07-12 20:32:20 -04:00
|
|
|
debug("launch_next_query()");
|
2000-05-22 18:56:31 -04:00
|
|
|
|
2020-11-05 09:22:38 -05:00
|
|
|
lookup_attach(query->lookup, &l);
|
|
|
|
|
|
|
|
|
|
if (!l->pending) {
|
2000-07-05 19:28:32 -04:00
|
|
|
debug("ignoring launch_next_query because !pending");
|
2020-11-04 06:40:13 -05:00
|
|
|
query_detach(&query);
|
2020-11-05 09:22:38 -05:00
|
|
|
lookup_detach(&l);
|
2020-11-06 10:12:17 -05:00
|
|
|
clear_current_lookup();
|
2000-04-26 14:34:17 -04:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-04 06:40:13 -05:00
|
|
|
isc_nmhandle_attach(query->handle, &query->readhandle);
|
2020-09-05 19:37:24 -04:00
|
|
|
isc_refcount_increment0(&recvcount);
|
|
|
|
|
debug("recvcount=%" PRIuFAST32, isc_refcount_current(&recvcount));
|
|
|
|
|
|
2020-11-03 00:38:56 -05:00
|
|
|
if (local_timeout == 0) {
|
|
|
|
|
local_timeout = TCP_TIMEOUT * 1000;
|
2020-09-05 19:37:24 -04:00
|
|
|
}
|
|
|
|
|
|
2020-11-03 00:38:56 -05:00
|
|
|
debug("have local timeout of %d", local_timeout);
|
|
|
|
|
isc_nmhandle_settimeout(query->handle, local_timeout);
|
|
|
|
|
|
2021-09-02 08:39:50 -04:00
|
|
|
xfr = query->lookup->rdtype == dns_rdatatype_ixfr ||
|
|
|
|
|
query->lookup->rdtype == dns_rdatatype_axfr;
|
2022-07-12 16:08:07 -04:00
|
|
|
if (xfr &&
|
|
|
|
|
isc_nm_socket_type(query->handle) == isc_nm_streamdnssocket &&
|
2023-01-18 05:36:34 -05:00
|
|
|
query->lookup->tls_mode)
|
2021-09-02 08:39:50 -04:00
|
|
|
{
|
2023-01-18 05:36:34 -05:00
|
|
|
isc_result_t result = isc_nm_xfr_checkperm(query->handle);
|
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
|
dighost_error("zone transfers over the established TLS "
|
|
|
|
|
"connection are not allowed: %s",
|
|
|
|
|
isc_result_totext(result));
|
|
|
|
|
isc_refcount_decrement0(&recvcount);
|
|
|
|
|
isc_nmhandle_detach(&query->readhandle);
|
|
|
|
|
cancel_lookup(l);
|
|
|
|
|
lookup_detach(&l);
|
|
|
|
|
clear_current_lookup();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-09-02 08:39:50 -04:00
|
|
|
}
|
|
|
|
|
|
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-01 19:06:34 -05:00
|
|
|
query_attach(query, &readquery);
|
|
|
|
|
|
2020-11-04 06:40:13 -05:00
|
|
|
isc_nm_read(query->handle, recv_done, readquery);
|
2020-09-05 19:37:24 -04:00
|
|
|
|
2000-04-28 20:12:56 -04:00
|
|
|
if (!query->first_soa_rcvd) {
|
2020-11-04 06:40:13 -05:00
|
|
|
dig_query_t *sendquery = NULL;
|
2000-07-18 14:51:40 -04:00
|
|
|
debug("sending a request in launch_next_query");
|
2021-03-20 01:50:51 -04:00
|
|
|
if (query->lookup->use_usec) {
|
2023-03-30 18:12:33 -04:00
|
|
|
query->time_sent = isc_time_now_hires();
|
2021-03-20 01:50:51 -04:00
|
|
|
} else {
|
2023-03-30 18:12:33 -04:00
|
|
|
query->time_sent = isc_time_now();
|
2021-03-20 01:50:51 -04:00
|
|
|
}
|
|
|
|
|
|
2020-11-04 06:40:13 -05:00
|
|
|
query_attach(query, &sendquery);
|
2020-09-05 19:37:24 -04:00
|
|
|
isc_buffer_usedregion(&query->sendbuf, &r);
|
|
|
|
|
if (keep != NULL) {
|
|
|
|
|
query->handle = keep;
|
2018-10-29 05:15:42 -04:00
|
|
|
}
|
2020-07-22 02:59:42 -04:00
|
|
|
|
2020-09-05 19:37:24 -04:00
|
|
|
isc_nmhandle_attach(query->handle, &query->sendhandle);
|
2020-11-04 06:40:13 -05:00
|
|
|
isc_nm_send(query->handle, &r, send_done, sendquery);
|
2020-09-05 19:37:24 -04:00
|
|
|
isc_refcount_increment0(&sendcount);
|
|
|
|
|
debug("sendcount=%" PRIuFAST32,
|
|
|
|
|
isc_refcount_current(&sendcount));
|
2019-07-17 02:44:20 -04:00
|
|
|
|
|
|
|
|
/* XXX qrflag, print_query, etc... */
|
2022-03-31 10:33:49 -04:00
|
|
|
if (l->qr) {
|
2019-07-17 02:44:20 -04:00
|
|
|
extrabytes = 0;
|
2022-03-31 10:33:49 -04:00
|
|
|
dighost_printmessage(query, &l->renderbuf, l->sendmsg,
|
|
|
|
|
true);
|
2020-11-05 09:22:38 -05:00
|
|
|
if (l->stats) {
|
2019-08-30 00:23:29 -04:00
|
|
|
print_query_size(query);
|
2019-07-17 02:44:20 -04:00
|
|
|
}
|
|
|
|
|
}
|
2000-04-28 20:12:56 -04:00
|
|
|
}
|
2021-01-27 09:49:27 -05:00
|
|
|
|
2020-11-05 09:22:38 -05:00
|
|
|
lookup_detach(&l);
|
2000-04-26 14:34:17 -04:00
|
|
|
return;
|
|
|
|
|
}
|
2000-07-31 21:33:37 -04:00
|
|
|
|
2005-04-27 00:57:32 -04:00
|
|
|
/*%
|
2000-07-18 14:51:40 -04: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 14:34:17 -04:00
|
|
|
static void
|
2020-09-05 19:37:24 -04: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;
|
2016-12-13 23:42:43 -05:00
|
|
|
char sockstr[ISC_SOCKADDR_FORMATSIZE];
|
2020-09-05 19:37:24 -04:00
|
|
|
dig_lookup_t *l = NULL;
|
2000-04-26 14:34:17 -04:00
|
|
|
|
2022-03-20 09:54:39 -04:00
|
|
|
REQUIRE(DIG_VALID_QUERY(query));
|
|
|
|
|
REQUIRE(query->handle == NULL);
|
|
|
|
|
|
2020-11-18 16:08:03 -05:00
|
|
|
debug("tcp_connected()");
|
|
|
|
|
|
2022-03-20 09:54:39 -04:00
|
|
|
query->started = true;
|
|
|
|
|
|
2022-07-26 07:03:40 -04:00
|
|
|
if (cancel_now) {
|
2022-04-10 20:42:49 -04:00
|
|
|
query_detach(&query);
|
2020-11-18 16:08:03 -05: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 04:32:18 -05:00
|
|
|
INSIST(!free_now);
|
|
|
|
|
|
|
|
|
|
debug("tcp_connected(%p, %s, %p)", handle, isc_result_totext(eresult),
|
|
|
|
|
query);
|
2000-05-25 15:32:11 -04:00
|
|
|
|
2023-12-06 21:36:46 -05:00
|
|
|
if (eresult == ISC_R_SHUTTINGDOWN) {
|
|
|
|
|
query_detach(&query);
|
|
|
|
|
cancel_all();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-05 09:22:38 -05:00
|
|
|
lookup_attach(query->lookup, &l);
|
2000-04-26 14:34:17 -04:00
|
|
|
|
2022-01-19 06:10:08 -05:00
|
|
|
if (eresult == ISC_R_CANCELED || eresult == ISC_R_TLSBADPEERCERT ||
|
|
|
|
|
query->canceled)
|
|
|
|
|
{
|
2000-09-14 16:11:48 -04:00
|
|
|
debug("in cancel handler");
|
2016-12-13 23:42:43 -05:00
|
|
|
isc_sockaddr_format(&query->sockaddr, sockstr, sizeof(sockstr));
|
2022-01-19 06:10:08 -05: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-01 19:06:34 -05:00
|
|
|
if (!query->canceled) {
|
|
|
|
|
cancel_lookup(l);
|
|
|
|
|
}
|
2022-01-19 06:10:08 -05:00
|
|
|
|
2020-11-04 06:40:13 -05:00
|
|
|
query_detach(&query);
|
2020-11-05 09:22:38 -05:00
|
|
|
lookup_detach(&l);
|
2020-11-06 10:12:17 -05:00
|
|
|
clear_current_lookup();
|
2000-09-14 16:11:48 -04:00
|
|
|
return;
|
2022-06-22 10:52:26 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (eresult != ISC_R_SUCCESS) {
|
2000-07-13 18:53:51 -04:00
|
|
|
debug("unsuccessful connection: %s",
|
2020-09-05 19:37:24 -04:00
|
|
|
isc_result_totext(eresult));
|
2005-08-24 20:56:08 -04: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-01 19:06:34 -05:00
|
|
|
dighost_warning("Connection to %s(%s) for %s failed: %s.",
|
|
|
|
|
sockstr, query->servname, l->textname,
|
|
|
|
|
isc_result_totext(eresult));
|
2020-09-05 19:37:24 -04:00
|
|
|
|
2022-06-22 10:52:26 -04:00
|
|
|
/*
|
|
|
|
|
* NSSEARCH mode: if the current query failed to start properly,
|
|
|
|
|
* then send_done() will not be called, and we want to make sure
|
|
|
|
|
* that the next query gets a chance to start in order to not
|
|
|
|
|
* break the chain.
|
|
|
|
|
*/
|
|
|
|
|
if (l->ns_search_only && !l->trace_root) {
|
|
|
|
|
nssearch_next(l, query);
|
|
|
|
|
check_if_done();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2000-07-31 20:53:20 -04:00
|
|
|
/* XXX Clean up exitcodes */
|
2000-08-03 13:43:06 -04:00
|
|
|
if (exitcode < 9) {
|
2000-05-08 18:51:08 -04:00
|
|
|
exitcode = 9;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2020-09-05 19:37:24 -04:00
|
|
|
|
|
|
|
|
if (l->retries > 1) {
|
2022-03-11 14:37:27 -05:00
|
|
|
l->retries--;
|
2020-09-05 19:37:24 -04: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 18:46:39 -04:00
|
|
|
next = ISC_LIST_NEXT(l->current_query, link);
|
|
|
|
|
} else {
|
|
|
|
|
next = NULL;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2020-09-05 19:37:24 -04:00
|
|
|
|
2020-11-04 06:40:13 -05:00
|
|
|
query_detach(&query);
|
2022-03-13 09:47:16 -04:00
|
|
|
if (next == NULL) {
|
|
|
|
|
cancel_lookup(l);
|
|
|
|
|
}
|
2020-11-05 09:22:38 -05:00
|
|
|
lookup_detach(&l);
|
2020-09-05 19:37:24 -04:00
|
|
|
|
2000-09-21 18:46:39 -04:00
|
|
|
if (next != NULL) {
|
2020-09-05 19:37:24 -04:00
|
|
|
start_tcp(next);
|
2023-05-02 08:24:34 -04:00
|
|
|
check_if_done();
|
2012-10-18 18:50:07 -04:00
|
|
|
} else {
|
2024-06-16 16:10:28 -04:00
|
|
|
dighost_error("no servers could be reached");
|
2020-11-06 10:12:17 -05:00
|
|
|
clear_current_lookup();
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2020-09-05 19:37:24 -04:00
|
|
|
|
2000-04-26 14:34:17 -04:00
|
|
|
return;
|
|
|
|
|
}
|
2020-09-05 19:37:24 -04:00
|
|
|
|
2018-08-24 07:49:45 -04:00
|
|
|
exitcode = 0;
|
2020-09-05 19:37:24 -04:00
|
|
|
|
|
|
|
|
query->handle = handle;
|
2013-11-06 18:50:01 -05:00
|
|
|
if (keep_open) {
|
2020-09-05 19:37:24 -04:00
|
|
|
keepaddr = query->sockaddr;
|
2013-11-06 18:50:01 -05:00
|
|
|
if (keep != NULL) {
|
2020-09-05 19:37:24 -04:00
|
|
|
isc_nmhandle_detach(&keep);
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2020-09-05 19:37:24 -04:00
|
|
|
|
|
|
|
|
isc_nmhandle_attach(handle, &keep);
|
2013-11-06 18:50:01 -05:00
|
|
|
}
|
2020-09-05 19:37:24 -04:00
|
|
|
|
|
|
|
|
launch_next_query(query);
|
2020-11-04 06:40:13 -05:00
|
|
|
query_detach(&query);
|
2020-11-05 09:22:38 -05:00
|
|
|
lookup_detach(&l);
|
2000-04-26 14:34:17 -04:00
|
|
|
}
|
|
|
|
|
|
2005-04-27 00:57:32 -04:00
|
|
|
/*%
|
2000-07-18 14:51:40 -04: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 11:29:14 -04:00
|
|
|
* false means more data is on the way, and the recv has been issued.
|
2000-06-30 18:53:07 -04:00
|
|
|
*/
|
2018-04-17 11:29:14 -04:00
|
|
|
static bool
|
2020-11-05 09:22:38 -05: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 14:45:33 -04:00
|
|
|
dns_rdataset_t *rdataset = NULL;
|
2000-10-25 00:26:57 -04:00
|
|
|
dns_rdata_t rdata = DNS_RDATA_INIT;
|
2000-06-02 14:45:33 -04:00
|
|
|
dns_rdata_soa_t soa;
|
2020-11-05 09:22:38 -05:00
|
|
|
uint32_t ixfr_serial = lookup->ixfr_serial, serial;
|
2000-06-02 14:45:33 -04:00
|
|
|
isc_result_t result;
|
2020-11-05 09:22:38 -05:00
|
|
|
bool ixfr = lookup->rdtype == dns_rdatatype_ixfr;
|
|
|
|
|
bool axfr = lookup->rdtype == dns_rdatatype_axfr;
|
2000-06-02 14:45:33 -04:00
|
|
|
|
2014-01-05 14:22:30 -05:00
|
|
|
if (ixfr) {
|
|
|
|
|
axfr = query->ixfr_axfr;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2014-01-05 14:22:30 -05:00
|
|
|
|
2000-07-05 15:31:26 -04:00
|
|
|
debug("check_for_more_data()");
|
2000-06-02 14:45:33 -04: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-07-31 21:33:37 -04:00
|
|
|
|
2002-05-29 01:31:05 -04:00
|
|
|
query->msg_count++;
|
2020-09-05 19:37:24 -04:00
|
|
|
query->byte_count += len;
|
2025-03-19 15:29:17 -04:00
|
|
|
|
|
|
|
|
if (ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) {
|
2000-06-06 18:50:44 -04:00
|
|
|
puts("; Transfer failed.");
|
2018-04-17 11:29:14 -04:00
|
|
|
return true;
|
2000-06-06 18:50:44 -04:00
|
|
|
}
|
2025-03-19 15:29:17 -04:00
|
|
|
MSG_SECTION_FOREACH (msg, DNS_SECTION_ANSWER, name) {
|
|
|
|
|
ISC_LIST_FOREACH (name->list, rdataset, link) {
|
2000-06-02 14:45:33 -04:00
|
|
|
result = dns_rdataset_first(rdataset);
|
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
|
continue;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2000-06-02 14:45:33 -04:00
|
|
|
do {
|
2000-07-20 15:41:44 -04:00
|
|
|
query->rr_count++;
|
2000-10-30 22:22:05 -05:00
|
|
|
dns_rdata_reset(&rdata);
|
2000-06-02 14:45:33 -04:00
|
|
|
dns_rdataset_current(rdataset, &rdata);
|
|
|
|
|
/*
|
|
|
|
|
* If this is the first rr, make sure
|
|
|
|
|
* it's an SOA
|
|
|
|
|
*/
|
|
|
|
|
if ((!query->first_soa_rcvd) &&
|
2022-11-02 14:33:14 -04:00
|
|
|
(rdata.type != dns_rdatatype_soa))
|
|
|
|
|
{
|
2000-06-02 14:45:33 -04:00
|
|
|
puts("; Transfer failed. "
|
2005-08-24 20:56:08 -04:00
|
|
|
"Didn't start with SOA answer.");
|
2018-04-17 11:29:14 -04:00
|
|
|
return true;
|
2000-06-02 14:45:33 -04:00
|
|
|
}
|
|
|
|
|
if ((!query->second_rr_rcvd) &&
|
2022-11-02 14:33:14 -04:00
|
|
|
(rdata.type != dns_rdatatype_soa))
|
|
|
|
|
{
|
2018-04-17 11:29:14 -04:00
|
|
|
query->second_rr_rcvd = true;
|
2000-06-02 14:45:33 -04:00
|
|
|
query->second_rr_serial = 0;
|
2000-07-05 19:28:32 -04:00
|
|
|
debug("got the second rr as nonsoa");
|
2018-04-17 11:29:14 -04:00
|
|
|
axfr = query->ixfr_axfr = true;
|
2003-07-17 03:42:00 -04:00
|
|
|
goto next_rdata;
|
2000-06-02 14:45:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If the record is anything except an SOA
|
|
|
|
|
* now, just continue on...
|
|
|
|
|
*/
|
|
|
|
|
if (rdata.type != dns_rdatatype_soa) {
|
2000-07-05 15:31:26 -04:00
|
|
|
goto next_rdata;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2011-11-30 19:53:58 -05:00
|
|
|
|
2000-06-02 14:45:33 -04:00
|
|
|
/* Now we have an SOA. Work with it. */
|
2000-07-05 19:28:32 -04:00
|
|
|
debug("got an SOA");
|
2008-01-14 18:24:24 -05:00
|
|
|
result = dns_rdata_tostruct(&rdata, &soa, NULL);
|
|
|
|
|
check_result(result, "dns_rdata_tostruct");
|
2001-07-27 01:26:38 -04:00
|
|
|
serial = soa.serial;
|
|
|
|
|
dns_rdata_freestruct(&soa);
|
2000-06-02 14:45:33 -04:00
|
|
|
if (!query->first_soa_rcvd) {
|
2018-04-17 11:29:14 -04:00
|
|
|
query->first_soa_rcvd = true;
|
2001-07-27 01:26:38 -04:00
|
|
|
query->first_rr_serial = serial;
|
2011-11-30 19:53:58 -05:00
|
|
|
debug("this is the first serial %u",
|
|
|
|
|
serial);
|
|
|
|
|
if (ixfr &&
|
|
|
|
|
isc_serial_ge(ixfr_serial, serial))
|
|
|
|
|
{
|
|
|
|
|
debug("got up to date "
|
|
|
|
|
"response");
|
2000-08-03 13:43:06 -04:00
|
|
|
goto doexit;
|
2011-11-30 19:53:58 -05:00
|
|
|
}
|
2000-07-05 15:31:26 -04:00
|
|
|
goto next_rdata;
|
2000-06-02 14:45:33 -04:00
|
|
|
}
|
2011-11-30 19:53:58 -05:00
|
|
|
if (axfr) {
|
2000-07-28 17:56:53 -04:00
|
|
|
debug("doing axfr, got second SOA");
|
2000-08-03 13:43:06 -04:00
|
|
|
goto doexit;
|
2000-07-28 17:56:53 -04:00
|
|
|
}
|
2000-06-02 14:45:33 -04:00
|
|
|
if (!query->second_rr_rcvd) {
|
2001-07-27 01:26:38 -04:00
|
|
|
if (query->first_rr_serial == serial) {
|
2000-07-28 17:56:53 -04:00
|
|
|
debug("doing ixfr, got "
|
|
|
|
|
"empty zone");
|
2000-08-03 13:43:06 -04:00
|
|
|
goto doexit;
|
2000-07-28 17:56:53 -04:00
|
|
|
}
|
2011-11-30 19:53:58 -05:00
|
|
|
debug("this is the second serial %u",
|
|
|
|
|
serial);
|
2018-04-17 11:29:14 -04:00
|
|
|
query->second_rr_rcvd = true;
|
2001-07-27 01:26:38 -04:00
|
|
|
query->second_rr_serial = serial;
|
2000-07-05 15:31:26 -04:00
|
|
|
goto next_rdata;
|
2000-06-02 14:45:33 -04:00
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* If we get to this point, we're doing an
|
|
|
|
|
* IXFR and have to start really looking
|
|
|
|
|
* at serial numbers.
|
|
|
|
|
*/
|
2001-07-27 01:26:38 -04:00
|
|
|
if (query->first_rr_serial == serial) {
|
2000-07-05 19:28:32 -04:00
|
|
|
debug("got a match for ixfr");
|
2000-06-02 14:45:33 -04:00
|
|
|
if (!query->first_repeat_rcvd) {
|
|
|
|
|
query->first_repeat_rcvd = true;
|
2000-07-05 15:31:26 -04:00
|
|
|
goto next_rdata;
|
2000-06-02 14:45:33 -04:00
|
|
|
}
|
2000-07-05 19:28:32 -04:00
|
|
|
debug("done with ixfr");
|
2000-08-03 13:43:06 -04:00
|
|
|
goto doexit;
|
2000-06-02 14:45:33 -04:00
|
|
|
}
|
2011-11-30 19:53:58 -05:00
|
|
|
debug("meaningless soa %u", serial);
|
2000-07-05 15:31:26 -04:00
|
|
|
next_rdata:
|
2000-06-02 14:45:33 -04:00
|
|
|
result = dns_rdataset_next(rdataset);
|
|
|
|
|
} while (result == ISC_R_SUCCESS);
|
|
|
|
|
}
|
2025-03-19 15:29:17 -04:00
|
|
|
}
|
|
|
|
|
|
2020-11-06 10:12:17 -05:00
|
|
|
isc_nmhandle_detach(&query->readhandle);
|
2020-09-05 19:37:24 -04:00
|
|
|
launch_next_query(query);
|
2020-11-04 06:40:13 -05:00
|
|
|
query_detach(&query);
|
2018-04-17 11:29:14 -04:00
|
|
|
return false;
|
2001-03-27 22:09:47 -05:00
|
|
|
doexit:
|
2020-09-05 19:37:24 -04:00
|
|
|
dighost_received(len, peer, query);
|
2018-04-17 11:29:14 -04:00
|
|
|
return true;
|
2000-06-02 14:45:33 -04:00
|
|
|
}
|
2000-04-26 14:34:17 -04:00
|
|
|
|
2014-02-18 20:53:42 -05:00
|
|
|
static void
|
2015-07-05 19:44:24 -04:00
|
|
|
process_cookie(dig_lookup_t *l, dns_message_t *msg, isc_buffer_t *optbuf,
|
|
|
|
|
size_t optlen) {
|
2014-02-18 20:53:42 -05:00
|
|
|
char bb[256];
|
|
|
|
|
isc_buffer_t hexbuf;
|
|
|
|
|
size_t len;
|
2015-07-05 19:44:24 -04:00
|
|
|
const unsigned char *sent;
|
2018-04-17 11:29:14 -04:00
|
|
|
bool copy = true;
|
2014-02-18 20:53:42 -05:00
|
|
|
isc_result_t result;
|
|
|
|
|
|
2015-07-05 19:44:24 -04:00
|
|
|
if (l->cookie != NULL) {
|
2014-02-18 20:53:42 -05:00
|
|
|
isc_buffer_init(&hexbuf, bb, sizeof(bb));
|
2015-07-05 19:44:24 -04:00
|
|
|
result = isc_hex_decodestring(l->cookie, &hexbuf);
|
2014-02-18 20:53:42 -05:00
|
|
|
check_result(result, "isc_hex_decodestring");
|
2015-07-05 19:44:24 -04:00
|
|
|
sent = isc_buffer_base(&hexbuf);
|
2014-02-18 20:53:42 -05:00
|
|
|
len = isc_buffer_usedlength(&hexbuf);
|
|
|
|
|
} else {
|
2015-07-05 19:44:24 -04:00
|
|
|
sent = cookie;
|
2014-02-18 20:53:42 -05:00
|
|
|
len = sizeof(cookie);
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-05 19:44:24 -04:00
|
|
|
INSIST(msg->cc_ok == 0 && msg->cc_bad == 0);
|
2019-02-05 18:08:47 -05:00
|
|
|
if (len >= 8 && optlen >= 8U) {
|
2015-08-17 21:26:44 -04:00
|
|
|
if (isc_safe_memequal(isc_buffer_current(optbuf), sent, 8)) {
|
2015-07-05 19:44:24 -04:00
|
|
|
msg->cc_ok = 1;
|
2014-02-19 23:55:09 -05:00
|
|
|
} else {
|
2019-08-30 00:23:29 -04:00
|
|
|
dighost_warning("Warning: Client COOKIE mismatch");
|
2015-07-05 19:44:24 -04:00
|
|
|
msg->cc_bad = 1;
|
2018-04-17 11:29:14 -04:00
|
|
|
copy = false;
|
2014-02-19 23:55:09 -05:00
|
|
|
}
|
|
|
|
|
} else {
|
2019-08-30 00:23:29 -04:00
|
|
|
dighost_warning("Warning: COOKIE bad token (too short)");
|
2015-07-05 19:44:24 -04:00
|
|
|
msg->cc_bad = 1;
|
2018-04-17 11:29:14 -04:00
|
|
|
copy = false;
|
2015-04-07 02:13:35 -04:00
|
|
|
}
|
2015-07-05 19:44:24 -04:00
|
|
|
if (copy) {
|
2015-04-07 02:13:35 -04:00
|
|
|
isc_region_t r;
|
|
|
|
|
|
|
|
|
|
r.base = isc_buffer_current(optbuf);
|
|
|
|
|
r.length = (unsigned int)optlen;
|
2015-07-05 19:44:24 -04:00
|
|
|
isc_buffer_init(&hexbuf, servercookie, sizeof(servercookie));
|
2015-04-07 02:13:35 -04: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-05 19:44:24 -04:00
|
|
|
l->cookie = servercookie;
|
2015-04-07 02:13:35 -04:00
|
|
|
}
|
2014-02-19 23:55:09 -05:00
|
|
|
}
|
2014-02-19 17:17:52 -05:00
|
|
|
isc_buffer_forward(optbuf, (unsigned int)optlen);
|
2014-02-18 20:53:42 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2014-02-19 23:55:09 -05:00
|
|
|
process_opt(dig_lookup_t *l, dns_message_t *msg) {
|
2014-02-18 20:53:42 -05:00
|
|
|
dns_rdata_t rdata;
|
|
|
|
|
isc_result_t result;
|
|
|
|
|
isc_buffer_t optbuf;
|
2018-03-28 08:19:37 -04:00
|
|
|
uint16_t optcode, optlen;
|
2014-02-19 23:55:09 -05:00
|
|
|
dns_rdataset_t *opt = msg->opt;
|
2018-04-17 11:29:14 -04:00
|
|
|
bool seen_cookie = false;
|
2014-02-18 20:53:42 -05: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-05 19:44:24 -04:00
|
|
|
case DNS_OPT_COOKIE:
|
2016-02-26 19:23:50 -05:00
|
|
|
/*
|
|
|
|
|
* Only process the first cookie option.
|
|
|
|
|
*/
|
|
|
|
|
if (seen_cookie) {
|
|
|
|
|
isc_buffer_forward(&optbuf, optlen);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2015-07-05 19:44:24 -04:00
|
|
|
process_cookie(l, msg, &optbuf, optlen);
|
2018-04-17 11:29:14 -04:00
|
|
|
seen_cookie = true;
|
2014-02-18 20:53:42 -05:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
isc_buffer_forward(&optbuf, optlen);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-30 08:13:12 -04:00
|
|
|
static int
|
|
|
|
|
ednsvers(dns_rdataset_t *opt) {
|
|
|
|
|
return (opt->ttl >> 16) & 0xff;
|
|
|
|
|
}
|
2014-02-18 20:53:42 -05:00
|
|
|
|
2005-04-27 00:57:32 -04:00
|
|
|
/*%
|
2000-07-18 14:51:40 -04:00
|
|
|
* Event handler for recv complete. Perform whatever actions are necessary,
|
|
|
|
|
* based on the specifics of the user's request.
|
|
|
|
|
*/
|
2000-04-26 14:34:17 -04:00
|
|
|
static void
|
2020-09-05 19:37:24 -04: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;
|
2018-10-29 05:15:42 -04:00
|
|
|
isc_buffer_t b;
|
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-26 20:03:12 -04:00
|
|
|
dns_message_t *msg = NULL;
|
2000-04-26 14:34:17 -04:00
|
|
|
isc_result_t result;
|
2020-11-05 09:22:38 -05:00
|
|
|
dig_lookup_t *n = NULL;
|
|
|
|
|
dig_lookup_t *l = NULL;
|
2018-04-17 11:29:14 -04:00
|
|
|
bool docancel = false;
|
2020-11-06 10:12:17 -05:00
|
|
|
bool donext = false;
|
2018-04-17 11:29:14 -04:00
|
|
|
bool match = true;
|
2019-02-05 18:08:47 -05:00
|
|
|
bool done_process_opt = false;
|
2001-07-27 18:07:10 -04:00
|
|
|
unsigned int parseflags;
|
2002-02-20 23:48:00 -05:00
|
|
|
dns_messageid_t id;
|
|
|
|
|
unsigned int msgflags;
|
2014-10-30 08:13:12 -04:00
|
|
|
int newedns;
|
2020-09-05 19:37:24 -04:00
|
|
|
isc_sockaddr_t peer;
|
2000-07-31 21:33:37 -04:00
|
|
|
|
2020-09-05 19:37:24 -04:00
|
|
|
REQUIRE(DIG_VALID_QUERY(query));
|
2021-01-27 09:49:27 -05:00
|
|
|
REQUIRE(query->readhandle != NULL);
|
2000-07-12 20:32:20 -04:00
|
|
|
INSIST(!free_now);
|
2000-04-26 14:34:17 -04:00
|
|
|
|
2020-11-04 06:40:13 -05:00
|
|
|
debug("recv_done(%p, %s, %p, %p)", handle, isc_result_totext(eresult),
|
|
|
|
|
region, arg);
|
2000-05-25 15:32:11 -04:00
|
|
|
|
2020-11-18 16:08:03 -05: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-01 19:06:34 -05:00
|
|
|
lookup_attach(query->lookup, &l);
|
|
|
|
|
|
2023-03-30 12:56:08 -04:00
|
|
|
if (eresult == ISC_R_CANCELED || eresult == ISC_R_SHUTTINGDOWN ||
|
|
|
|
|
query->canceled)
|
|
|
|
|
{
|
2020-09-05 19:37:24 -04:00
|
|
|
debug("recv_done: cancel");
|
2021-05-04 08:25:55 -04:00
|
|
|
isc_nmhandle_detach(&query->readhandle);
|
2023-12-03 21:21:20 -05:00
|
|
|
if (eresult == ISC_R_SHUTTINGDOWN) {
|
|
|
|
|
cancel_all();
|
|
|
|
|
} else if (!query->canceled) {
|
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-01 19:06:34 -05:00
|
|
|
cancel_lookup(l);
|
|
|
|
|
}
|
2021-05-04 08:25:55 -04: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-01 19:06:34 -05:00
|
|
|
lookup_detach(&l);
|
2022-03-29 09:01:24 -04:00
|
|
|
clear_current_lookup();
|
2021-05-04 08:25:55 -04:00
|
|
|
return;
|
2020-09-05 19:37:24 -04:00
|
|
|
}
|
|
|
|
|
|
2021-03-20 01:50:51 -04:00
|
|
|
if (query->lookup->use_usec) {
|
2023-03-30 18:12:33 -04:00
|
|
|
query->time_recv = isc_time_now_hires();
|
2021-03-20 01:50:51 -04:00
|
|
|
} else {
|
2023-03-30 18:12:33 -04:00
|
|
|
query->time_recv = isc_time_now();
|
2021-03-20 01:50:51 -04:00
|
|
|
}
|
2000-04-28 20:12:56 -04:00
|
|
|
|
2022-07-26 07:03:40 -04:00
|
|
|
if ((!l->pending && !l->ns_search_only) || cancel_now) {
|
2020-09-05 19:37:24 -04:00
|
|
|
debug("no longer pending. Got %s", isc_result_totext(eresult));
|
2000-07-31 21:33:37 -04:00
|
|
|
|
2020-11-06 10:12:17 -05:00
|
|
|
goto next_lookup;
|
2000-04-26 14:34:17 -04:00
|
|
|
}
|
2012-10-18 19:46:07 -04: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 16:44:32 -04: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) {
|
2022-06-22 10:52:26 -04:00
|
|
|
dighost_error(
|
|
|
|
|
"NS servers could not be reached");
|
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 16:44:32 -04:00
|
|
|
if (exitcode < 9) {
|
|
|
|
|
exitcode = 9;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
goto cancel_lookup;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
DiG: use the same retry and fail-over logic for different failure types
DiG implements different logic in the `recv_done()` callback function
when processing a failure:
1. For a timed-out query it applies the "retries" logic first, then,
when it fails, fail-overs to the next server.
2. For an EOF (end-of-file, or unexpected disconnect) error it tries to
make a single retry attempt (even if the user has requested more
retries), then, when it fails, fail-overs to the next server.
3. For other types of failures, DiG does not apply the "retries" logic,
and tries to fail-over to the next servers (again, even if the user
has requested to make retries).
Simplify the logic and apply the same logic (1) of first retries, and
then fail-over, for different types of failures in `recv_done()`.
2022-06-15 09:41:10 -04:00
|
|
|
if (eresult != ISC_R_SUCCESS) {
|
|
|
|
|
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));
|
|
|
|
|
|
2022-03-11 14:37:27 -05:00
|
|
|
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 09:12:40 -04:00
|
|
|
if (check_if_queries_done(l, query)) {
|
|
|
|
|
goto cancel_lookup;
|
|
|
|
|
}
|
2022-03-11 14:37:27 -05: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 09:12:40 -04:00
|
|
|
if (check_if_queries_done(l, query)) {
|
|
|
|
|
goto cancel_lookup;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-11 14:37:27 -05:00
|
|
|
goto detach_query;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Otherwise, print the cmdline and an error message,
|
|
|
|
|
* and cancel the lookup.
|
|
|
|
|
*/
|
|
|
|
|
printf("%s", l->cmdline);
|
2024-06-16 16:10:28 -04:00
|
|
|
dighost_error("no servers could be reached");
|
DiG: use the same retry and fail-over logic for different failure types
DiG implements different logic in the `recv_done()` callback function
when processing a failure:
1. For a timed-out query it applies the "retries" logic first, then,
when it fails, fail-overs to the next server.
2. For an EOF (end-of-file, or unexpected disconnect) error it tries to
make a single retry attempt (even if the user has requested more
retries), then, when it fails, fail-overs to the next server.
3. For other types of failures, DiG does not apply the "retries" logic,
and tries to fail-over to the next servers (again, even if the user
has requested to make retries).
Simplify the logic and apply the same logic (1) of first retries, and
then fail-over, for different types of failures in `recv_done()`.
2022-06-15 09:41:10 -04:00
|
|
|
|
2022-03-11 14:37:27 -05:00
|
|
|
if (exitcode < 9) {
|
|
|
|
|
exitcode = 9;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (keep != NULL) {
|
|
|
|
|
isc_nmhandle_detach(&keep);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
goto cancel_lookup;
|
|
|
|
|
}
|
2001-07-27 18:07:10 -04:00
|
|
|
}
|
|
|
|
|
|
2020-09-05 19:37:24 -04:00
|
|
|
isc_buffer_init(&b, region->base, region->length);
|
|
|
|
|
isc_buffer_add(&b, region->length);
|
|
|
|
|
|
|
|
|
|
peer = isc_nmhandle_peeraddr(handle);
|
2002-04-19 00:06:53 -04:00
|
|
|
|
2018-10-29 05:15:42 -04:00
|
|
|
result = dns_message_peekheader(&b, &id, &msgflags);
|
2002-02-20 23:48:00 -05:00
|
|
|
if (result != ISC_R_SUCCESS || l->sendmsg->id != id) {
|
2018-04-17 11:29:14 -04:00
|
|
|
match = false;
|
2002-02-20 23:48:00 -05:00
|
|
|
if (l->tcp_mode) {
|
2018-04-17 11:29:14 -04:00
|
|
|
bool fail = true;
|
2003-07-17 03:42:00 -04:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
2019-08-30 00:23:29 -04:00
|
|
|
if (!query->first_soa_rcvd || query->warn_id) {
|
|
|
|
|
dighost_warning("%s: ID mismatch: "
|
|
|
|
|
"expected ID %u, got "
|
|
|
|
|
"%u",
|
|
|
|
|
query->first_soa_rcvd
|
|
|
|
|
? "WARNING"
|
|
|
|
|
: "ERROR",
|
|
|
|
|
l->sendmsg->id, id);
|
|
|
|
|
}
|
2003-07-17 03:42:00 -04:00
|
|
|
if (query->first_soa_rcvd) {
|
2018-04-17 11:29:14 -04:00
|
|
|
fail = false;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2018-04-17 11:29:14 -04:00
|
|
|
query->warn_id = false;
|
2019-08-30 00:23:29 -04:00
|
|
|
} else {
|
|
|
|
|
dighost_warning("ERROR: short (< header size) "
|
|
|
|
|
"message");
|
|
|
|
|
}
|
2003-07-17 03:42:00 -04:00
|
|
|
if (fail) {
|
2020-11-06 10:12:17 -05:00
|
|
|
goto cancel_lookup;
|
2003-07-17 03:42:00 -04:00
|
|
|
}
|
2018-04-17 11:29:14 -04:00
|
|
|
match = true;
|
2019-08-30 00:23:29 -04:00
|
|
|
} else if (result == ISC_R_SUCCESS) {
|
|
|
|
|
dighost_warning("Warning: ID mismatch: expected ID %u,"
|
|
|
|
|
" got %u",
|
|
|
|
|
l->sendmsg->id, id);
|
|
|
|
|
} else {
|
|
|
|
|
dighost_warning("Warning: short (< header size) "
|
|
|
|
|
"message received");
|
|
|
|
|
}
|
2002-04-19 00:06:53 -04:00
|
|
|
}
|
|
|
|
|
|
2019-08-30 00:23:29 -04:00
|
|
|
if (result == ISC_R_SUCCESS && (msgflags & DNS_MESSAGEFLAG_QR) == 0) {
|
|
|
|
|
dighost_warning("Warning: query response not set");
|
|
|
|
|
}
|
2006-01-05 19:54:21 -05:00
|
|
|
|
2009-01-19 23:39:29 -05:00
|
|
|
if (!match) {
|
2020-11-04 06:40:13 -05:00
|
|
|
/*
|
|
|
|
|
* We are still attached to query and the query->readhandle is
|
|
|
|
|
* also attached
|
|
|
|
|
*/
|
2020-09-05 19:37:24 -04:00
|
|
|
isc_refcount_increment0(&recvcount);
|
2020-11-06 10:12:17 -05:00
|
|
|
debug("recvcount=%" PRIuFAST32,
|
|
|
|
|
isc_refcount_current(&recvcount));
|
2020-09-05 19:37:24 -04:00
|
|
|
isc_nm_read(handle, recv_done, query);
|
2020-11-06 10:12:17 -05:00
|
|
|
goto keep_query;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2002-02-20 23:48:00 -05:00
|
|
|
|
2023-09-22 09:00:40 -04:00
|
|
|
dns_message_create(mctx, NULL, NULL, DNS_MESSAGE_INTENTPARSE, &msg);
|
2001-07-27 18:07:10 -04:00
|
|
|
|
2018-03-19 18:16:10 -04:00
|
|
|
if (tsigkey != NULL) {
|
2001-07-27 18:07:10 -04:00
|
|
|
if (l->querysig == NULL) {
|
|
|
|
|
debug("getting initial querysig");
|
|
|
|
|
result = dns_message_getquerytsig(l->sendmsg, mctx,
|
|
|
|
|
&l->querysig);
|
|
|
|
|
check_result(result, "dns_message_getquerytsig");
|
|
|
|
|
}
|
2022-07-29 08:40:45 -04:00
|
|
|
dns_message_setquerytsig(msg, l->querysig);
|
2018-03-19 18:16:10 -04:00
|
|
|
result = dns_message_settsigkey(msg, tsigkey);
|
2001-07-27 18:07:10 -04:00
|
|
|
check_result(result, "dns_message_settsigkey");
|
|
|
|
|
msg->tsigctx = l->tsigctx;
|
2001-09-11 18:34:21 -04:00
|
|
|
l->tsigctx = NULL;
|
2001-07-27 18:07:10 -04:00
|
|
|
if (l->msgcounter != 0) {
|
|
|
|
|
msg->tcp_continuation = 1;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2001-07-27 18:07:10 -04:00
|
|
|
l->msgcounter++;
|
|
|
|
|
}
|
2001-07-27 20:11:15 -04:00
|
|
|
|
2001-07-27 18:07:10 -04:00
|
|
|
debug("before parse starts");
|
2019-07-25 06:26:13 -04:00
|
|
|
parseflags = l->dns64prefix ? 0 : DNS_MESSAGEPARSE_PRESERVEORDER;
|
2002-02-11 21:10:33 -05:00
|
|
|
if (l->besteffort) {
|
2001-07-27 18:07:10 -04:00
|
|
|
parseflags |= DNS_MESSAGEPARSE_BESTEFFORT;
|
2002-02-11 21:10:33 -05:00
|
|
|
parseflags |= DNS_MESSAGEPARSE_IGNORETRUNCATION;
|
|
|
|
|
}
|
2020-09-05 19:37:24 -04:00
|
|
|
|
2018-10-29 05:15:42 -04:00
|
|
|
result = dns_message_parse(msg, &b, parseflags);
|
2001-07-27 18:07:10 -04:00
|
|
|
if (result == DNS_R_RECOVERABLE) {
|
2019-08-30 00:23:29 -04:00
|
|
|
dighost_warning("Warning: Message parser reports malformed "
|
|
|
|
|
"message packet.");
|
2020-09-05 19:37:24 -04:00
|
|
|
} else if (result != ISC_R_SUCCESS) {
|
2019-08-30 00:23:29 -04:00
|
|
|
if (!yaml) {
|
|
|
|
|
printf(";; Got bad packet: %s\n",
|
|
|
|
|
isc_result_totext(result));
|
|
|
|
|
hex_dump(&b);
|
|
|
|
|
}
|
2020-11-06 10:12:17 -05:00
|
|
|
goto cancel_lookup;
|
2001-07-27 18:07:10 -04:00
|
|
|
}
|
2020-09-05 19:37:24 -04:00
|
|
|
|
2020-03-10 22:55:14 -04: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 09:22:38 -05:00
|
|
|
|
|
|
|
|
isc_refcount_increment0(&recvcount);
|
2020-11-06 10:12:17 -05:00
|
|
|
debug("recvcount=%" PRIuFAST32,
|
|
|
|
|
isc_refcount_current(&recvcount));
|
2020-11-05 09:22:38 -05:00
|
|
|
isc_nm_read(handle, recv_done, query);
|
2020-11-06 10:12:17 -05:00
|
|
|
goto keep_query;
|
2020-03-10 22:55:14 -04:00
|
|
|
}
|
2020-09-05 19:37:24 -04:00
|
|
|
|
2024-08-05 01:09:27 -04:00
|
|
|
if (msg->counts[DNS_SECTION_QUESTION] == 0) {
|
|
|
|
|
if (l->doing_xfr) {
|
|
|
|
|
if (query->msg_count == 0) {
|
|
|
|
|
dighost_warning("missing question section");
|
|
|
|
|
}
|
|
|
|
|
} else if (!l->header_only && msg->opcode == dns_opcode_query) {
|
|
|
|
|
dighost_warning("missing question section");
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2018-04-17 11:29:14 -04:00
|
|
|
match = true;
|
2025-03-19 15:29:17 -04:00
|
|
|
MSG_SECTION_FOREACH (msg, DNS_SECTION_QUESTION, name) {
|
2009-01-19 23:39:29 -05:00
|
|
|
dns_rdataset_t *rdataset;
|
2025-03-19 15:29:17 -04:00
|
|
|
ISC_LIST_FOREACH (name->list, rdataset, link) {
|
2009-01-19 23:39:29 -05:00
|
|
|
if (l->rdtype != rdataset->type ||
|
|
|
|
|
l->rdclass != rdataset->rdclass ||
|
|
|
|
|
!dns_name_equal(l->name, name))
|
|
|
|
|
{
|
|
|
|
|
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 00:23:29 -04:00
|
|
|
dighost_warning(";; Question section "
|
|
|
|
|
"mismatch: got "
|
|
|
|
|
"%s/%s/%s",
|
|
|
|
|
namestr, typebuf,
|
|
|
|
|
classbuf);
|
2018-04-17 11:29:14 -04:00
|
|
|
match = false;
|
2009-01-19 23:39:29 -05:00
|
|
|
}
|
|
|
|
|
}
|
2020-09-05 19:37:24 -04:00
|
|
|
|
2025-03-19 15:29:17 -04:00
|
|
|
/* Break out of the loop on mismatch */
|
|
|
|
|
if (!match) {
|
|
|
|
|
if (l->tcp_mode) {
|
|
|
|
|
goto cancel_lookup;
|
|
|
|
|
}
|
2020-11-05 09:22:38 -05:00
|
|
|
|
2025-03-19 15:29:17 -04:00
|
|
|
/*
|
|
|
|
|
* We are still attached to query and the
|
|
|
|
|
* query->readhandle is also attached
|
|
|
|
|
*/
|
|
|
|
|
isc_refcount_increment0(&recvcount);
|
|
|
|
|
debug("recvcount=%" PRIuFAST32,
|
|
|
|
|
isc_refcount_current(&recvcount));
|
|
|
|
|
isc_nm_read(handle, recv_done, query);
|
|
|
|
|
goto keep_query;
|
|
|
|
|
}
|
2009-01-19 23:39:29 -05:00
|
|
|
}
|
|
|
|
|
}
|
2020-09-05 19:37:24 -04:00
|
|
|
|
2014-10-30 08:13:12 -04:00
|
|
|
if (msg->rcode == dns_rcode_badvers && msg->opt != NULL &&
|
|
|
|
|
(newedns = ednsvers(msg->opt)) < l->edns && l->ednsneg)
|
|
|
|
|
{
|
2025-03-11 19:02:05 -04:00
|
|
|
if (l->showbadvers) {
|
|
|
|
|
dighost_printmessage(query, &b, msg, true);
|
|
|
|
|
dighost_received(isc_buffer_usedlength(&b), &peer,
|
|
|
|
|
query);
|
|
|
|
|
}
|
2014-10-30 08:13:12 -04:00
|
|
|
/*
|
|
|
|
|
* Add minimum EDNS version required checks here if needed.
|
|
|
|
|
*/
|
2019-08-30 00:23:29 -04:00
|
|
|
dighost_comments(l, "BADVERS, retrying with EDNS version %u.",
|
|
|
|
|
(unsigned int)newedns);
|
2014-10-30 08:13:12 -04:00
|
|
|
l->edns = newedns;
|
2018-04-17 11:29:14 -04:00
|
|
|
n = requeue_lookup(l, true);
|
2015-09-11 19:04:37 -04:00
|
|
|
if (l->trace && l->trace_root) {
|
|
|
|
|
n->rdtype = l->qrdtype;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2020-11-06 10:12:17 -05:00
|
|
|
goto cancel_lookup;
|
2014-10-30 08:13:12 -04:00
|
|
|
}
|
2020-09-05 19:37:24 -04:00
|
|
|
|
2005-08-24 20:40:50 -04:00
|
|
|
if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0 && !l->ignore &&
|
2022-11-02 14:33:14 -04:00
|
|
|
!l->tcp_mode)
|
|
|
|
|
{
|
2015-07-05 19:44:24 -04:00
|
|
|
if (l->cookie == NULL && l->sendcookie && msg->opt != NULL) {
|
2015-04-07 02:13:35 -04:00
|
|
|
process_opt(l, msg);
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2019-08-30 00:23:29 -04:00
|
|
|
dighost_comments(l, "Truncated, retrying in TCP mode.");
|
2018-04-17 11:29:14 -04:00
|
|
|
n = requeue_lookup(l, true);
|
|
|
|
|
n->tcp_mode = true;
|
2015-09-11 19:04:37 -04:00
|
|
|
if (l->trace && l->trace_root) {
|
|
|
|
|
n->rdtype = l->qrdtype;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2020-11-06 10:12:17 -05:00
|
|
|
goto cancel_lookup;
|
2008-01-18 18:46:58 -05:00
|
|
|
}
|
2020-09-05 19:37:24 -04:00
|
|
|
|
2015-07-05 19:44:24 -04:00
|
|
|
if (msg->rcode == dns_rcode_badcookie && !l->tcp_mode &&
|
|
|
|
|
l->sendcookie && l->badcookie)
|
|
|
|
|
{
|
|
|
|
|
process_opt(l, msg);
|
|
|
|
|
if (msg->cc_ok) {
|
2020-11-30 23:10:32 -05:00
|
|
|
if (l->showbadcookie) {
|
|
|
|
|
dighost_printmessage(query, &b, msg, true);
|
|
|
|
|
dighost_received(isc_buffer_usedlength(&b),
|
|
|
|
|
&peer, query);
|
|
|
|
|
}
|
2019-08-30 00:23:29 -04:00
|
|
|
dighost_comments(l, "BADCOOKIE, retrying%s.",
|
|
|
|
|
l->seenbadcookie ? " in TCP mode"
|
|
|
|
|
: "");
|
2018-04-17 11:29:14 -04:00
|
|
|
n = requeue_lookup(l, true);
|
2015-07-05 19:44:24 -04:00
|
|
|
if (l->seenbadcookie) {
|
2018-04-17 11:29:14 -04:00
|
|
|
n->tcp_mode = true;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2018-04-17 11:29:14 -04:00
|
|
|
n->seenbadcookie = true;
|
2015-09-11 19:04:37 -04:00
|
|
|
if (l->trace && l->trace_root) {
|
|
|
|
|
n->rdtype = l->qrdtype;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2020-11-06 10:12:17 -05:00
|
|
|
goto cancel_lookup;
|
2015-07-05 19:44:24 -04:00
|
|
|
}
|
2019-02-05 18:08:47 -05:00
|
|
|
done_process_opt = true;
|
2015-07-05 19:44:24 -04:00
|
|
|
}
|
2020-09-05 19:37:24 -04:00
|
|
|
|
2005-08-24 20:40:50 -04:00
|
|
|
if ((msg->rcode == dns_rcode_servfail && !l->servfail_stops) ||
|
|
|
|
|
(check_ra && (msg->flags & DNS_MESSAGEFLAG_RA) == 0 && l->recurse))
|
|
|
|
|
{
|
2024-01-09 06:51:34 -05:00
|
|
|
const char *err = (msg->rcode == dns_rcode_servfail &&
|
|
|
|
|
!l->servfail_stops)
|
|
|
|
|
? "SERVFAIL reply"
|
|
|
|
|
: "recursion not available";
|
2001-07-27 18:07:10 -04:00
|
|
|
dig_query_t *next = ISC_LIST_NEXT(query, link);
|
|
|
|
|
if (l->current_query == query) {
|
2020-11-05 09:22:38 -05:00
|
|
|
query_detach(&l->current_query);
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2024-01-09 06:35:11 -05:00
|
|
|
if (next != NULL && (!l->ns_search_only || l->trace_root)) {
|
2024-01-09 06:51:34 -05:00
|
|
|
dighost_comments(l,
|
|
|
|
|
"Got %s from %s, trying next server",
|
|
|
|
|
err, query->servname);
|
2020-11-04 06:40:13 -05:00
|
|
|
debug("sending query %p", next);
|
2001-07-27 18:07:10 -04:00
|
|
|
if (l->tcp_mode) {
|
2020-09-05 19:37:24 -04:00
|
|
|
start_tcp(next);
|
2001-07-27 18:07:10 -04:00
|
|
|
} else {
|
2020-09-05 19:37:24 -04:00
|
|
|
start_udp(next);
|
2020-02-13 15:48:23 -05: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 09:12:40 -04:00
|
|
|
if (check_if_queries_done(l, query)) {
|
|
|
|
|
goto cancel_lookup;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-10 12:30:34 -05:00
|
|
|
goto detach_query;
|
2024-01-09 06:51:34 -05:00
|
|
|
} else {
|
|
|
|
|
dighost_comments(l, "Got %s from %s", err,
|
|
|
|
|
query->servname);
|
2000-09-25 19:10:00 -04:00
|
|
|
}
|
2001-07-27 18:07:10 -04:00
|
|
|
}
|
2000-09-11 15:38:22 -04:00
|
|
|
|
2018-03-19 18:16:10 -04:00
|
|
|
if (tsigkey != NULL) {
|
2018-10-29 05:15:42 -04:00
|
|
|
result = dns_tsig_verify(&b, msg, NULL, NULL);
|
2001-07-27 18:07:10 -04:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2019-08-30 00:23:29 -04:00
|
|
|
dighost_warning("Couldn't verify signature: %s",
|
|
|
|
|
isc_result_totext(result));
|
2018-04-17 11:29:14 -04:00
|
|
|
validated = false;
|
2000-06-06 14:49:06 -04:00
|
|
|
}
|
2001-07-27 18:07:10 -04:00
|
|
|
l->tsigctx = msg->tsigctx;
|
2001-09-11 18:34:21 -04:00
|
|
|
msg->tsigctx = NULL;
|
2001-07-27 18:07:10 -04: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);
|
|
|
|
|
check_result(result, "dns_message_getquerytsig");
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-29 05:15:42 -04:00
|
|
|
extrabytes = isc_buffer_remaininglength(&b);
|
2005-07-03 23:03:21 -04:00
|
|
|
|
2001-07-27 18:07:10 -04:00
|
|
|
debug("after parse");
|
2001-07-27 20:11:15 -04:00
|
|
|
if (l->doing_xfr && l->xfr_q == NULL) {
|
2001-07-27 18:07:10 -04: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
|
|
|
|
|
*/
|
2022-07-26 07:03:45 -04:00
|
|
|
if (timeout != INT_MAX && query->timer != NULL) {
|
2001-07-27 20:11:15 -04:00
|
|
|
unsigned int local_timeout;
|
|
|
|
|
|
2001-07-27 18:07:10 -04:00
|
|
|
if (timeout == 0) {
|
|
|
|
|
if (l->tcp_mode) {
|
2020-11-03 00:38:56 -05:00
|
|
|
local_timeout = TCP_TIMEOUT * 4000;
|
2001-07-27 18:07:10 -04:00
|
|
|
} else {
|
2020-11-03 00:38:56 -05:00
|
|
|
local_timeout = UDP_TIMEOUT * 4000;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2001-07-27 18:07:10 -04:00
|
|
|
} else {
|
|
|
|
|
if (timeout < (INT_MAX / 4)) {
|
2020-11-03 00:38:56 -05:00
|
|
|
local_timeout = timeout * 4000;
|
2001-07-27 18:07:10 -04:00
|
|
|
} else {
|
|
|
|
|
local_timeout = INT_MAX;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2000-07-10 13:25:59 -04:00
|
|
|
}
|
2020-11-03 00:38:56 -05:00
|
|
|
|
2001-07-27 18:07:10 -04:00
|
|
|
debug("have local timeout of %d", local_timeout);
|
2020-11-03 00:38:56 -05:00
|
|
|
isc_nmhandle_settimeout(query->handle, local_timeout);
|
2000-07-10 13:25:59 -04:00
|
|
|
}
|
2001-07-27 18:07:10 -04:00
|
|
|
}
|
2001-07-27 20:11:15 -04:00
|
|
|
|
2019-02-05 18:08:47 -05:00
|
|
|
if (!done_process_opt) {
|
|
|
|
|
if (l->cookie != NULL) {
|
|
|
|
|
if (msg->opt == NULL) {
|
2019-08-30 00:23:29 -04:00
|
|
|
dighost_warning("expected opt record in "
|
|
|
|
|
"response");
|
2019-02-05 18:08:47 -05:00
|
|
|
} else {
|
|
|
|
|
process_opt(l, msg);
|
|
|
|
|
}
|
|
|
|
|
} else if (l->sendcookie && msg->opt != NULL) {
|
2014-02-19 23:55:09 -05:00
|
|
|
process_opt(l, msg);
|
2019-02-05 18:08:47 -05:00
|
|
|
}
|
|
|
|
|
}
|
2020-09-05 19:37:24 -04:00
|
|
|
|
2001-07-27 20:11:15 -04:00
|
|
|
if (!l->doing_xfr || l->xfr_q == query) {
|
2013-09-03 23:24:11 -04:00
|
|
|
if (msg->rcode == dns_rcode_nxdomain &&
|
2022-11-02 14:33:14 -04:00
|
|
|
(l->origin != NULL || l->need_search))
|
|
|
|
|
{
|
2020-11-05 09:22:38 -05:00
|
|
|
if (!next_origin(l) || showsearch) {
|
2019-07-17 02:44:20 -04:00
|
|
|
dighost_printmessage(query, &b, msg, true);
|
2018-10-29 05:15:42 -04:00
|
|
|
dighost_received(isc_buffer_usedlength(&b),
|
2020-09-05 19:37:24 -04:00
|
|
|
&peer, query);
|
2000-04-28 17:41:19 -04:00
|
|
|
}
|
2001-07-29 19:23:42 -04:00
|
|
|
} else if (!l->trace && !l->ns_search_only) {
|
2019-07-17 02:44:20 -04:00
|
|
|
dighost_printmessage(query, &b, msg, true);
|
2001-07-29 19:23:42 -04:00
|
|
|
} else if (l->trace) {
|
2015-01-20 16:29:18 -05:00
|
|
|
int nl = 0;
|
2001-07-29 19:23:42 -04:00
|
|
|
int count = msg->counts[DNS_SECTION_ANSWER];
|
|
|
|
|
|
|
|
|
|
debug("in TRACE code");
|
|
|
|
|
if (!l->ns_search_only) {
|
2019-07-17 02:44:20 -04:00
|
|
|
dighost_printmessage(query, &b, msg, true);
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2001-07-29 19:23:42 -04:00
|
|
|
|
|
|
|
|
l->rdtype = l->qrdtype;
|
2004-04-12 22:39:35 -04:00
|
|
|
if (l->trace_root || (l->ns_search_only && count > 0)) {
|
2001-07-29 19:23:42 -04:00
|
|
|
if (!l->trace_root) {
|
|
|
|
|
l->rdtype = dns_rdatatype_soa;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2015-01-20 16:29:18 -05:00
|
|
|
nl = followup_lookup(msg, query,
|
|
|
|
|
DNS_SECTION_ANSWER);
|
2018-04-17 11:29:14 -04:00
|
|
|
l->trace_root = false;
|
2001-07-29 19:23:42 -04:00
|
|
|
} else if (count == 0) {
|
2015-01-20 16:29:18 -05:00
|
|
|
nl = followup_lookup(msg, query,
|
|
|
|
|
DNS_SECTION_AUTHORITY);
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2015-01-20 16:29:18 -05:00
|
|
|
if (nl == 0) {
|
2018-04-17 11:29:14 -04:00
|
|
|
docancel = true;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2001-07-29 19:23:42 -04:00
|
|
|
} else {
|
2001-07-27 20:11:15 -04:00
|
|
|
debug("in NSSEARCH code");
|
|
|
|
|
|
|
|
|
|
if (l->trace_root) {
|
|
|
|
|
/*
|
2008-01-18 18:46:58 -05:00
|
|
|
* This is the initial NS query.
|
2001-07-27 20:11:15 -04:00
|
|
|
*/
|
2015-01-20 16:29:18 -05:00
|
|
|
int nl;
|
2001-07-27 20:11:15 -04:00
|
|
|
|
|
|
|
|
l->rdtype = dns_rdatatype_soa;
|
2015-01-20 16:29:18 -05:00
|
|
|
nl = followup_lookup(msg, query,
|
|
|
|
|
DNS_SECTION_ANSWER);
|
|
|
|
|
if (nl == 0) {
|
2018-04-17 11:29:14 -04:00
|
|
|
docancel = true;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2018-04-17 11:29:14 -04:00
|
|
|
l->trace_root = false;
|
|
|
|
|
usesearch = false;
|
2017-08-09 14:03:27 -04:00
|
|
|
} else {
|
2022-03-20 09:54:39 -04:00
|
|
|
/*
|
|
|
|
|
* This is a query in the followup lookup
|
|
|
|
|
*/
|
2019-07-17 02:44:20 -04:00
|
|
|
dighost_printmessage(query, &b, msg, true);
|
2022-03-20 09:54:39 -04:00
|
|
|
|
|
|
|
|
docancel = check_if_queries_done(l, query);
|
2004-04-12 22:39:35 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2000-07-31 21:33:37 -04:00
|
|
|
|
2001-07-27 18:07:10 -04:00
|
|
|
if (l->pending) {
|
|
|
|
|
debug("still pending.");
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2020-09-05 19:37:24 -04:00
|
|
|
|
2001-07-27 18:07:10 -04:00
|
|
|
if (l->doing_xfr) {
|
|
|
|
|
if (query != l->xfr_q) {
|
2020-11-06 10:12:17 -05:00
|
|
|
goto detach_query;
|
2001-07-27 18:07:10 -04:00
|
|
|
}
|
|
|
|
|
if (!docancel) {
|
2020-11-05 09:22:38 -05:00
|
|
|
docancel = check_for_more_data(l, query, msg, &peer,
|
2020-09-05 19:37:24 -04:00
|
|
|
region->length);
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2001-07-27 18:07:10 -04:00
|
|
|
if (docancel) {
|
2020-11-06 10:12:17 -05:00
|
|
|
goto cancel_lookup;
|
2000-04-26 14:34:17 -04:00
|
|
|
}
|
2020-11-06 10:12:17 -05: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 18:07:10 -04:00
|
|
|
} else {
|
2004-04-12 22:39:35 -04:00
|
|
|
if (msg->rcode == dns_rcode_noerror || l->origin == NULL) {
|
2020-09-05 19:37:24 -04:00
|
|
|
dighost_received(isc_buffer_usedlength(&b), &peer,
|
|
|
|
|
query);
|
2004-04-12 22:39:35 -04:00
|
|
|
}
|
|
|
|
|
|
2020-11-05 09:22:38 -05:00
|
|
|
if (!l->ns_search_only) {
|
|
|
|
|
l->pending = false;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2020-11-05 09:22:38 -05:00
|
|
|
if (!l->ns_search_only || l->trace_root || docancel) {
|
2020-11-06 10:12:17 -05:00
|
|
|
goto cancel_lookup;
|
2001-07-27 18:07:10 -04:00
|
|
|
}
|
2020-11-06 10:12:17 -05: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 15:16:15 -04:00
|
|
|
dns_message_detach(&msg);
|
2004-04-12 22:39:35 -04:00
|
|
|
}
|
2020-11-05 09:22:38 -05:00
|
|
|
lookup_detach(&l);
|
2020-11-06 10:12:17 -05:00
|
|
|
if (donext) {
|
|
|
|
|
clear_current_lookup();
|
|
|
|
|
}
|
2000-04-26 14:34:17 -04:00
|
|
|
}
|
|
|
|
|
|
2005-04-27 00:57:32 -04:00
|
|
|
/*%
|
2000-07-18 14:51:40 -04: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-15 21:57:24 -05:00
|
|
|
isc_result_t
|
2015-01-20 16:29:18 -05:00
|
|
|
get_address(char *host, in_port_t myport, isc_sockaddr_t *sockaddr) {
|
2001-11-14 17:08:38 -05:00
|
|
|
int count;
|
|
|
|
|
isc_result_t result;
|
2000-04-28 20:12:56 -04:00
|
|
|
|
2022-07-26 07:03:40 -04:00
|
|
|
isc_loopmgr_blocking(loopmgr);
|
2022-12-16 05:19:16 -05:00
|
|
|
result = isc_getaddresses(host, myport, sockaddr, 1, &count);
|
2022-07-26 07:03:40 -04:00
|
|
|
isc_loopmgr_nonblocking(loopmgr);
|
2001-11-14 17:08:38 -05:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2008-12-15 21:57:24 -05:00
|
|
|
return result;
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2008-12-15 21:57:24 -05:00
|
|
|
|
2001-11-14 17:08:38 -05:00
|
|
|
INSIST(count == 1);
|
2008-12-15 21:57:24 -05:00
|
|
|
|
|
|
|
|
return ISC_R_SUCCESS;
|
2000-04-26 14:34:17 -04:00
|
|
|
}
|
|
|
|
|
|
2011-02-25 18:11:13 -05:00
|
|
|
int
|
2011-12-07 12:23:28 -05:00
|
|
|
getaddresses(dig_lookup_t *lookup, const char *host, isc_result_t *resultp) {
|
2011-02-25 18:11:13 -05:00
|
|
|
isc_result_t result;
|
|
|
|
|
isc_sockaddr_t sockaddrs[DIG_MAX_ADDRESSES];
|
|
|
|
|
isc_netaddr_t netaddr;
|
|
|
|
|
int count, i;
|
|
|
|
|
dig_server_t *srv;
|
|
|
|
|
char tmp[ISC_NETADDR_FORMATSIZE];
|
|
|
|
|
|
2022-07-26 07:03:40 -04:00
|
|
|
isc_loopmgr_blocking(loopmgr);
|
2022-12-16 05:19:16 -05:00
|
|
|
result = isc_getaddresses(host, 0, sockaddrs, DIG_MAX_ADDRESSES,
|
|
|
|
|
&count);
|
2022-07-26 07:03:40 -04:00
|
|
|
isc_loopmgr_nonblocking(loopmgr);
|
2023-04-06 11:32:16 -04:00
|
|
|
SET_IF_NOT_NULL(resultp, result);
|
2011-12-07 12:23:28 -05:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
|
if (resultp == NULL) {
|
|
|
|
|
fatal("couldn't get address for '%s': %s", host,
|
|
|
|
|
isc_result_totext(result));
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2017-09-13 03:14:37 -04:00
|
|
|
return 0;
|
2011-12-07 12:23:28 -05:00
|
|
|
}
|
2011-02-25 18:11:13 -05: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 03:14:37 -04:00
|
|
|
return count;
|
2011-02-25 18:11:13 -05:00
|
|
|
}
|
|
|
|
|
|
2005-04-27 00:57:32 -04:00
|
|
|
/*%
|
2000-07-18 14:51:40 -04:00
|
|
|
* Initiate either a TCP or UDP lookup
|
|
|
|
|
*/
|
2000-05-11 21:02:37 -04:00
|
|
|
void
|
|
|
|
|
do_lookup(dig_lookup_t *lookup) {
|
2012-10-06 00:20:45 -04:00
|
|
|
dig_query_t *query;
|
2000-05-11 21:02:37 -04:00
|
|
|
|
2000-07-05 15:31:26 -04:00
|
|
|
REQUIRE(lookup != NULL);
|
2000-05-11 21:02:37 -04:00
|
|
|
|
2000-07-05 15:31:26 -04:00
|
|
|
debug("do_lookup()");
|
2018-04-17 11:29:14 -04:00
|
|
|
lookup->pending = true;
|
2012-10-06 00:20:45 -04:00
|
|
|
query = ISC_LIST_HEAD(lookup->q);
|
|
|
|
|
if (query != NULL) {
|
2018-11-07 13:04:13 -05:00
|
|
|
REQUIRE(DIG_VALID_QUERY(query));
|
2012-10-06 00:20:45 -04:00
|
|
|
if (lookup->tcp_mode) {
|
2020-09-05 19:37:24 -04:00
|
|
|
start_tcp(query);
|
2012-10-06 00:20:45 -04:00
|
|
|
} else {
|
2020-09-05 19:37:24 -04:00
|
|
|
start_udp(query);
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2012-10-06 00:20:45 -04:00
|
|
|
}
|
2000-05-11 21:02:37 -04:00
|
|
|
}
|
|
|
|
|
|
2005-04-27 00:57:32 -04:00
|
|
|
/*%
|
2000-07-18 14:51:40 -04:00
|
|
|
* Start everything in action upon task startup.
|
|
|
|
|
*/
|
2000-07-10 14:02:31 -04:00
|
|
|
void
|
2022-07-26 07:03:40 -04:00
|
|
|
onrun_callback(void *arg) {
|
|
|
|
|
UNUSED(arg);
|
|
|
|
|
|
|
|
|
|
start_lookup();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
run_loop(void *arg) {
|
|
|
|
|
UNUSED(arg);
|
2000-07-31 20:53:20 -04:00
|
|
|
|
2000-07-10 14:02:31 -04:00
|
|
|
start_lookup();
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-27 00:57:32 -04:00
|
|
|
/*%
|
2000-07-18 14:51:40 -04:00
|
|
|
* Make everything on the lookup queue go away. Mainly used by the
|
|
|
|
|
* SIGINT handler.
|
2000-07-12 20:32:20 -04:00
|
|
|
*/
|
2000-07-14 13:57:27 -04:00
|
|
|
void
|
2000-07-12 20:32:20 -04:00
|
|
|
cancel_all(void) {
|
2000-07-14 16:14:36 -04:00
|
|
|
dig_lookup_t *l, *n;
|
2000-09-22 19:21:32 -04:00
|
|
|
dig_query_t *q, *nq;
|
2000-04-26 14:34:17 -04:00
|
|
|
|
2000-07-12 22:14:17 -04:00
|
|
|
debug("cancel_all()");
|
2000-07-31 21:33:37 -04:00
|
|
|
|
2000-07-14 13:57:27 -04:00
|
|
|
if (free_now) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-07-26 07:03:40 -04:00
|
|
|
|
|
|
|
|
cancel_now = true;
|
|
|
|
|
|
2021-04-27 06:03:20 -04:00
|
|
|
while (current_lookup != NULL) {
|
2013-12-02 16:34:23 -05:00
|
|
|
for (q = ISC_LIST_HEAD(current_lookup->q); q != NULL; q = nq) {
|
2000-09-22 19:21:32 -04:00
|
|
|
nq = ISC_LIST_NEXT(q, link);
|
2013-12-02 16:34:23 -05: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-01 19:06:34 -05:00
|
|
|
q->canceled = true;
|
2022-05-10 16:09:59 -04:00
|
|
|
if (q->readhandle != NULL &&
|
2022-11-02 14:33:14 -04:00
|
|
|
!isc_nm_is_http_handle(q->readhandle))
|
|
|
|
|
{
|
2021-04-27 06:03:20 -04:00
|
|
|
isc_nm_cancelread(q->readhandle);
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2020-11-04 06:40:13 -05:00
|
|
|
query_detach(&q);
|
2013-12-02 16:34:23 -05:00
|
|
|
}
|
2021-05-04 08:25:55 -04:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* current_lookup could have been detached via query_detach().
|
|
|
|
|
*/
|
|
|
|
|
if (current_lookup != NULL) {
|
|
|
|
|
lookup_detach(¤t_lookup);
|
|
|
|
|
}
|
2000-07-14 16:14:36 -04: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 09:22:38 -05:00
|
|
|
lookup_detach(&l);
|
2000-07-14 16:14:36 -04:00
|
|
|
l = n;
|
2000-04-26 14:34:17 -04:00
|
|
|
}
|
2000-07-12 20:32:20 -04:00
|
|
|
}
|
|
|
|
|
|
2023-01-29 23:26:52 -05:00
|
|
|
void
|
2023-01-29 18:47:57 -05:00
|
|
|
cleanup_openssl_refs(void) {
|
|
|
|
|
if (tsigkey != NULL) {
|
|
|
|
|
debug("freeing TSIG key %p", tsigkey);
|
|
|
|
|
dns_tsigkey_detach(&tsigkey);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sig0key != NULL) {
|
|
|
|
|
debug("freeing SIG(0) key %p", sig0key);
|
|
|
|
|
dst_key_free(&sig0key);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-27 00:57:32 -04:00
|
|
|
/*%
|
2000-07-18 14:51:40 -04:00
|
|
|
* Destroy all of the libs we are using, and get everything ready for a
|
|
|
|
|
* clean shutdown.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
destroy_libs(void) {
|
|
|
|
|
debug("destroy_libs()");
|
2020-09-05 19:37:24 -04:00
|
|
|
|
|
|
|
|
isc_refcount_destroy(&recvcount);
|
|
|
|
|
isc_refcount_destroy(&sendcount);
|
2000-07-12 20:32:20 -04:00
|
|
|
|
|
|
|
|
INSIST(ISC_LIST_HEAD(lookup_list) == NULL);
|
2000-07-14 16:14:36 -04:00
|
|
|
INSIST(current_lookup == NULL);
|
2000-07-12 20:32:20 -04:00
|
|
|
INSIST(!free_now);
|
|
|
|
|
|
2018-04-17 11:29:14 -04:00
|
|
|
free_now = true;
|
2000-07-12 20:32:20 -04:00
|
|
|
|
2002-08-12 14:25:25 -04:00
|
|
|
flush_server_list();
|
|
|
|
|
|
2001-01-18 00:12:44 -05:00
|
|
|
clear_searchlist();
|
2005-09-18 03:16:24 -04:00
|
|
|
|
2023-01-29 18:47:57 -05:00
|
|
|
cleanup_openssl_refs();
|
2022-03-13 22:43:07 -04:00
|
|
|
|
2000-06-05 20:43:17 -04:00
|
|
|
if (namebuf != NULL) {
|
2022-03-13 22:43:07 -04:00
|
|
|
debug("freeing key %p", tsigkey);
|
2000-06-05 20:43:17 -04:00
|
|
|
isc_buffer_free(&namebuf);
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2000-06-12 15:33:30 -04:00
|
|
|
|
2009-09-14 23:13:44 -04:00
|
|
|
debug("Destroy memory");
|
2000-10-19 18:49:34 -04:00
|
|
|
if (memdebugging != 0) {
|
2000-07-14 13:57:27 -04:00
|
|
|
isc_mem_stats(mctx, stderr);
|
2020-02-13 15:48:23 -05:00
|
|
|
}
|
2022-07-26 07:03:40 -04:00
|
|
|
|
2022-10-29 17:22:56 -04:00
|
|
|
isc_managers_destroy(&mctx, &loopmgr, &netmgr);
|
2022-09-23 10:06:42 -04:00
|
|
|
|
2022-09-27 07:35:26 -04:00
|
|
|
#if ENABLE_LEAK_DETECTION
|
2024-08-08 06:16:50 -04:00
|
|
|
isc__crypto_setdestroycheck(true);
|
2022-09-23 10:06:42 -04:00
|
|
|
isc__uv_setdestroycheck(true);
|
|
|
|
|
isc__xml_setdestroycheck(true);
|
2022-09-27 07:35:26 -04:00
|
|
|
#endif
|
2022-09-23 10:06:42 -04:00
|
|
|
|
|
|
|
|
isc_mem_checkdestroyed(stderr);
|
2000-07-14 13:57:27 -04:00
|
|
|
}
|
2004-04-12 22:39:35 -04: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 08:34:35 -04:00
|
|
|
#ifdef HAVE_LIBIDN2
|
2022-09-05 10:49:49 -04:00
|
|
|
|
2005-09-09 02:17:03 -04:00
|
|
|
static isc_result_t
|
2022-09-07 11:22:47 -04:00
|
|
|
idn_filter(isc_buffer_t *buffer, unsigned int start) {
|
2022-09-05 10:49:49 -04:00
|
|
|
char src[MXNAME];
|
|
|
|
|
char *dst = NULL;
|
2018-07-10 08:34:35 -04:00
|
|
|
size_t srclen, dstlen;
|
2022-09-05 10:49:49 -04:00
|
|
|
int res;
|
2018-07-10 08:34:35 -04:00
|
|
|
|
2005-09-09 02:17:03 -04:00
|
|
|
/*
|
2018-07-10 08:34:35 -04:00
|
|
|
* Copy name from 'buffer' to 'src' and terminate it with NULL.
|
2005-09-09 02:17:03 -04:00
|
|
|
*/
|
2022-09-05 10:49:49 -04:00
|
|
|
srclen = isc_buffer_usedlength(buffer) - start;
|
|
|
|
|
INSIST(srclen < sizeof(src));
|
|
|
|
|
memmove(src, (char *)isc_buffer_base(buffer) + start, srclen);
|
2018-07-10 08:34:35 -04:00
|
|
|
src[srclen] = '\0';
|
2005-09-09 02:17:03 -04:00
|
|
|
|
|
|
|
|
/*
|
2022-09-05 10:49:49 -04:00
|
|
|
* Try to convert the name; leave it unchanged if conversion fails.
|
2005-09-09 02:17:03 -04:00
|
|
|
*/
|
2022-09-05 10:49:49 -04:00
|
|
|
systemlocale(LC_ALL);
|
|
|
|
|
res = idn2_to_unicode_8zlz(src, &dst, IDN2_NONTRANSITIONAL);
|
|
|
|
|
if (res == IDN2_DISALLOWED) {
|
|
|
|
|
res = idn2_to_unicode_8zlz(src, &dst, IDN2_TRANSITIONAL);
|
|
|
|
|
}
|
2021-06-22 07:05:15 -04:00
|
|
|
resetlocale(LC_ALL);
|
2022-09-05 10:49:49 -04:00
|
|
|
if (res != IDN2_OK) {
|
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
|
}
|
2021-06-22 07:05:15 -04:00
|
|
|
|
2005-09-09 02:17:03 -04:00
|
|
|
/*
|
2022-09-05 10:49:49 -04:00
|
|
|
* Copy the converted back into 'buffer' if it fits.
|
2005-09-09 02:17:03 -04:00
|
|
|
*/
|
2018-07-10 08:34:35 -04:00
|
|
|
dstlen = strlen(dst);
|
2022-09-05 10:49:49 -04:00
|
|
|
if (isc_buffer_length(buffer) < start + dstlen) {
|
|
|
|
|
return ISC_R_NOSPACE;
|
2018-07-10 08:34:35 -04:00
|
|
|
}
|
2018-07-10 08:34:35 -04:00
|
|
|
isc_buffer_subtract(buffer, srclen);
|
|
|
|
|
memmove(isc_buffer_used(buffer), dst, dstlen);
|
|
|
|
|
isc_buffer_add(buffer, dstlen);
|
|
|
|
|
|
2022-09-05 10:49:49 -04:00
|
|
|
idn2_free(dst);
|
|
|
|
|
return ISC_R_SUCCESS;
|
2005-09-09 02:17:03 -04:00
|
|
|
}
|
|
|
|
|
|
2018-07-10 08:34:35 -04: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
|
2022-09-05 10:49:49 -04:00
|
|
|
idn_input(const char *src, char *dst, size_t dstlen) {
|
|
|
|
|
char *ascii = NULL;
|
|
|
|
|
size_t len;
|
2015-09-23 10:47:37 -04:00
|
|
|
int res;
|
|
|
|
|
|
2018-07-10 08:34:35 -04:00
|
|
|
/*
|
|
|
|
|
* We trust libidn2 to return an error if 'src' is too large to be a
|
|
|
|
|
* valid domain name.
|
2018-07-10 08:34:35 -04:00
|
|
|
*
|
2022-09-05 10:49:49 -04:00
|
|
|
* If conversion fails under IDNA2008 rules, retry with transitional
|
|
|
|
|
* rules. The aim is that characters whose interpretation changed will
|
|
|
|
|
* be handled under the new rules, but we will accept characters (such
|
|
|
|
|
* as emoji) that were OK but are now forbidden.
|
2018-07-10 08:34:35 -04:00
|
|
|
*/
|
2022-09-05 10:49:49 -04:00
|
|
|
systemlocale(LC_ALL);
|
|
|
|
|
res = idn2_to_ascii_lz(src, &ascii, IDN2_NONTRANSITIONAL);
|
2022-08-26 06:24:07 -04:00
|
|
|
if (res == IDN2_DISALLOWED) {
|
2022-09-05 10:49:49 -04:00
|
|
|
res = idn2_to_ascii_lz(src, &ascii, IDN2_TRANSITIONAL);
|
2015-09-23 10:47:37 -04:00
|
|
|
}
|
2022-09-05 10:49:49 -04:00
|
|
|
resetlocale(LC_ALL);
|
2015-09-23 10:47:37 -04:00
|
|
|
|
2018-07-10 08:34:35 -04:00
|
|
|
/*
|
2022-09-05 10:49:49 -04: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.
|
2018-07-10 08:34:35 -04:00
|
|
|
*/
|
2022-09-05 10:49:49 -04:00
|
|
|
if (res == IDN2_OK && strcasecmp(src, ascii) != 0) {
|
|
|
|
|
len = strlcpy(dst, ascii, dstlen);
|
|
|
|
|
} else {
|
|
|
|
|
len = strlcpy(dst, src, dstlen);
|
2018-07-10 08:34:35 -04:00
|
|
|
}
|
2022-09-05 10:49:49 -04:00
|
|
|
INSIST(len < dstlen);
|
|
|
|
|
idn2_free(ascii);
|
2015-09-23 10:47:37 -04:00
|
|
|
}
|
2022-09-05 10:49:49 -04: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 08:34:35 -04:00
|
|
|
#endif /* HAVE_LIBIDN2 */
|
2020-09-12 16:23:52 -04:00
|
|
|
|
|
|
|
|
void
|
|
|
|
|
dig_idnsetup(dig_lookup_t *lookup, bool active) {
|
|
|
|
|
#ifdef HAVE_LIBIDN2
|
|
|
|
|
isc_result_t result;
|
|
|
|
|
result = dns_name_settotextfilter(
|
2022-09-05 10:49:49 -04:00
|
|
|
(active && lookup->idnout) ? idn_filter : NULL);
|
2020-09-12 16:23:52 -04:00
|
|
|
check_result(result, "dns_name_settotextfilter");
|
|
|
|
|
#else
|
|
|
|
|
UNUSED(lookup);
|
|
|
|
|
UNUSED(active);
|
|
|
|
|
return;
|
|
|
|
|
#endif /* HAVE_LIBIDN2 */
|
|
|
|
|
}
|
2022-01-19 06:10:08 -05: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;
|
|
|
|
|
}
|