diff --git a/CHANGES b/CHANGES index 0a9afeef7e..02e21e6513 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,10 @@ +5693. [func] Restore support for reading 'timeout' and 'attempts' + options from /etc/resolv.conf, and use their values + in dig, host and nslookup. (Previously this was + supported by liblwres, and was still mentioned + in man pages, but had stopped working after liblwres + was deprecated in favor of libirs.) [GL #2785] + 5692. [bug] Fix a rare crash in the DoH code caused by detaching from an HTTP/2 session handle too early when sending data. [GL #2851] diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c index 05c7ed5598..b6131e0831 100644 --- a/bin/dig/dighost.c +++ b/bin/dig/dighost.c @@ -114,7 +114,7 @@ isc_sockaddr_t localaddr; isc_refcount_t sendcount = ATOMIC_VAR_INIT(0); isc_refcount_t recvcount = ATOMIC_VAR_INIT(0); int ndots = -1; -int tries = 3; +int tries = -1; int lookup_counter = 0; static char servercookie[256]; @@ -1276,6 +1276,17 @@ setup_system(bool ipv4only, bool ipv6only) { ndots = irs_resconf_getndots(resconf); debug("ndots is %d.", ndots); } + 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); + } /* If user doesn't specify server use nameservers from resolv.conf. */ if (ISC_LIST_EMPTY(server_list)) { diff --git a/lib/irs/include/irs/resconf.h b/lib/irs/include/irs/resconf.h index d95c150a64..f5ec355765 100644 --- a/lib/irs/include/irs/resconf.h +++ b/lib/irs/include/irs/resconf.h @@ -115,4 +115,24 @@ irs_resconf_getndots(irs_resconf_t *conf); *\li 'conf' is a valid resconf object. */ +unsigned int +irs_resconf_getattempts(irs_resconf_t *conf); +/*%< + * Return the 'attempts' value stored in 'conf'. + * + * Requires: + * + *\li 'conf' is a valid resconf object. + */ + +unsigned int +irs_resconf_gettimeout(irs_resconf_t *conf); +/*%< + * Return the 'timeout' value stored in 'conf'. + * + * Requires: + * + *\li 'conf' is a valid resconf object. + */ + ISC_LANG_ENDDECLS diff --git a/lib/irs/resconf.c b/lib/irs/resconf.c index 8aa723c21c..746f65f534 100644 --- a/lib/irs/resconf.c +++ b/lib/irs/resconf.c @@ -74,6 +74,13 @@ #define RESCONFMAXLINELEN 256U /*%< max size of a line */ #define RESCONFMAXSORTLIST 10U /*%< max 10 */ +#define CHECK(op) \ + do { \ + result = (op); \ + if (result != ISC_R_SUCCESS) \ + goto cleanup; \ + } while (0) + /*! * configuration data structure */ @@ -108,6 +115,10 @@ struct irs_resconf { uint8_t resdebug; /*%< set to n in 'options ndots:n' */ uint8_t ndots; + /*%< set to n in 'options attempts:n' */ + uint8_t attempts; + /*%< set to n in 'options timeout:n' */ + uint8_t timeout; }; static isc_result_t @@ -165,8 +176,8 @@ eatwhite(FILE *fp) { */ static int getword(FILE *fp, char *buffer, size_t size) { + char *p = NULL; int ch; - char *p; REQUIRE(buffer != NULL); REQUIRE(size > 0U); @@ -446,11 +457,26 @@ resconf_parsesortlist(irs_resconf_t *conf, FILE *fp) { return (ISC_R_SUCCESS); } +static isc_result_t +resconf_optionnumber(const char *word, uint8_t *number) { + char *p; + long n; + + n = strtol(word, &p, 10); + if (*p != '\0') { /* Bad string. */ + return (ISC_R_UNEXPECTEDTOKEN); + } + if (n < 0 || n > 0xff) { /* Out of range. */ + return (ISC_R_RANGE); + } + *number = n; + return (ISC_R_SUCCESS); +} + static isc_result_t resconf_parseoption(irs_resconf_t *conf, FILE *fp) { int delim; - long ndots; - char *p; + isc_result_t result = ISC_R_SUCCESS; char word[RESCONFMAXLINELEN]; delim = getword(fp, word, sizeof(word)); @@ -462,14 +488,11 @@ resconf_parseoption(irs_resconf_t *conf, FILE *fp) { if (strcmp("debug", word) == 0) { conf->resdebug = 1; } else if (strncmp("ndots:", word, 6) == 0) { - ndots = strtol(word + 6, &p, 10); - if (*p != '\0') { /* Bad string. */ - return (ISC_R_UNEXPECTEDTOKEN); - } - if (ndots < 0 || ndots > 0xff) { /* Out of range. */ - return (ISC_R_RANGE); - } - conf->ndots = (uint8_t)ndots; + CHECK(resconf_optionnumber(word + 6, &conf->ndots)); + } else if (strncmp("attempts:", word, 9) == 0) { + CHECK(resconf_optionnumber(word + 9, &conf->attempts)); + } else if (strncmp("timeout:", word, 8) == 0) { + CHECK(resconf_optionnumber(word + 8, &conf->timeout)); } if (delim == EOF || delim == '\n') { @@ -479,7 +502,8 @@ resconf_parseoption(irs_resconf_t *conf, FILE *fp) { } } - return (ISC_R_SUCCESS); +cleanup: + return (result); } static isc_result_t @@ -521,6 +545,8 @@ irs_resconf_load(isc_mem_t *mctx, const char *filename, irs_resconf_t **confp) { conf->sortlistnxt = 0; conf->resdebug = 0; conf->ndots = 1; + conf->attempts = 3; + conf->timeout = 0; for (i = 0; i < RESCONFMAXSEARCH; i++) { conf->search[i] = NULL; } @@ -669,3 +695,17 @@ irs_resconf_getndots(irs_resconf_t *conf) { return ((unsigned int)conf->ndots); } + +unsigned int +irs_resconf_getattempts(irs_resconf_t *conf) { + REQUIRE(IRS_RESCONF_VALID(conf)); + + return ((unsigned int)conf->attempts); +} + +unsigned int +irs_resconf_gettimeout(irs_resconf_t *conf) { + REQUIRE(IRS_RESCONF_VALID(conf)); + + return ((unsigned int)conf->timeout); +} diff --git a/lib/irs/tests/resconf_test.c b/lib/irs/tests/resconf_test.c index 8ca9762bff..4befe01f15 100644 --- a/lib/irs/tests/resconf_test.c +++ b/lib/irs/tests/resconf_test.c @@ -42,6 +42,43 @@ setup_test(void) { assert_return_code(chdir(TESTS_DIR), 0); } +static isc_result_t +check_number(unsigned int n, unsigned int expected) { + return ((n == expected) ? ISC_R_SUCCESS : ISC_R_BADNUMBER); +} + +static isc_result_t +check_attempts(irs_resconf_t *resconf) { + return (check_number(irs_resconf_getattempts(resconf), 4)); +} + +static isc_result_t +check_timeout(irs_resconf_t *resconf) { + return (check_number(irs_resconf_gettimeout(resconf), 1)); +} + +static isc_result_t +check_ndots(irs_resconf_t *resconf) { + return (check_number(irs_resconf_getndots(resconf), 2)); +} + +static isc_result_t +check_options(irs_resconf_t *resconf) { + if (irs_resconf_getattempts(resconf) != 3) { + return ISC_R_BADNUMBER; /* default value only */ + } + + if (irs_resconf_getndots(resconf) != 2) { + return ISC_R_BADNUMBER; + } + + if (irs_resconf_gettimeout(resconf) != 1) { + return ISC_R_BADNUMBER; + } + + return (ISC_R_SUCCESS); +} + /* test irs_resconf_load() */ static void irs_resconf_load_test(void **state) { @@ -61,15 +98,18 @@ irs_resconf_load_test(void **state) { ISC_R_SUCCESS }, { "testdata/nameserver-v6-scoped.conf", ISC_R_SUCCESS, NULL, ISC_R_SUCCESS }, + { "testdata/options-attempts.conf", ISC_R_SUCCESS, + check_attempts, ISC_R_SUCCESS }, { "testdata/options-debug.conf", ISC_R_SUCCESS, NULL, ISC_R_SUCCESS }, - { "testdata/options-ndots.conf", ISC_R_SUCCESS, NULL, + { "testdata/options-ndots.conf", ISC_R_SUCCESS, check_ndots, ISC_R_SUCCESS }, - { "testdata/options-timeout.conf", ISC_R_SUCCESS, NULL, + { "testdata/options-timeout.conf", ISC_R_SUCCESS, check_timeout, ISC_R_SUCCESS }, { "testdata/options-unknown.conf", ISC_R_SUCCESS, NULL, ISC_R_SUCCESS }, - { "testdata/options.conf", ISC_R_SUCCESS, NULL, ISC_R_SUCCESS }, + { "testdata/options.conf", ISC_R_SUCCESS, check_options, + ISC_R_SUCCESS }, { "testdata/options-bad-ndots.conf", ISC_R_RANGE, NULL, ISC_R_SUCCESS }, { "testdata/options-empty.conf", ISC_R_UNEXPECTEDEND, NULL, diff --git a/lib/irs/tests/testdata/options-attempts.conf b/lib/irs/tests/testdata/options-attempts.conf new file mode 100644 index 0000000000..453864331d --- /dev/null +++ b/lib/irs/tests/testdata/options-attempts.conf @@ -0,0 +1,10 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# 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/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +options attempts:4 diff --git a/lib/irs/tests/testdata/options-ndots.conf b/lib/irs/tests/testdata/options-ndots.conf index ff4c7e99ee..58b21b9f82 100644 --- a/lib/irs/tests/testdata/options-ndots.conf +++ b/lib/irs/tests/testdata/options-ndots.conf @@ -7,4 +7,4 @@ # See the COPYRIGHT file distributed with this work for additional # information regarding copyright ownership. -option ndots:2 +options ndots:2