diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 96e6e89b..f4dc42a3 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -28,6 +28,7 @@ Bugfixes: * Fix a potential memory leak in `ares_init()`. [Issue #724](https://github.com/c-ares/c-ares/issues/724) * Some platforms don't have the `isascii()` function. Implement as a macro. [PR #721](https://github.com/c-ares/c-ares/pull/721) * CMake: Fix Chain building if CMAKE runtime paths not set +* NDots configuration should allow a value of zero. [PR #735](https://github.com/c-ares/c-ares/pull/735) Thanks go to these friendly people for their efforts and contributions for this release: diff --git a/docs/ares_init_options.3 b/docs/ares_init_options.3 index 000cc1d9..72889b5b 100644 --- a/docs/ares_init_options.3 +++ b/docs/ares_init_options.3 @@ -158,7 +158,7 @@ before giving up. The default is three tries. The number of dots which must be present in a domain name for it to be queried for "as is" prior to querying for it with the default domain extensions appended. The default value is 1 unless set otherwise by -resolv.conf or the RES_OPTIONS environment variable. +resolv.conf or the RES_OPTIONS environment variable. Valid range is 0-15. .TP 18 .B ARES_OPT_MAXTIMEOUTMS .B int \fImaxtimeout\fP; diff --git a/src/lib/ares_init.c b/src/lib/ares_init.c index 78a81b01..28a509ea 100644 --- a/src/lib/ares_init.c +++ b/src/lib/ares_init.c @@ -152,10 +152,6 @@ static ares_status_t init_by_defaults(ares_channel_t *channel) channel->tries = DEFAULT_TRIES; } - if (channel->ndots == 0) { - channel->ndots = 1; - } - if (ares__slist_len(channel->servers) == 0) { /* Add a default local named server to the channel unless configured not * to (in which case return an error). @@ -284,6 +280,9 @@ int ares_init_options(ares_channel_t **channelptr, return ARES_ENOMEM; } + /* One option where zero is valid, so set default value here */ + channel->ndots = 1; + status = ares__channel_threading_init(channel); if (status != ARES_SUCCESS) { goto done; diff --git a/src/lib/ares_options.c b/src/lib/ares_options.c index 342d2ea1..adc3e062 100644 --- a/src/lib/ares_options.c +++ b/src/lib/ares_options.c @@ -316,7 +316,7 @@ ares_status_t ares__init_by_options(ares_channel_t *channel, } if (optmask & ARES_OPT_NDOTS) { - if (options->ndots <= 0) { + if (options->ndots < 0) { optmask &= ~(ARES_OPT_NDOTS); } else { channel->ndots = (size_t)options->ndots; diff --git a/src/lib/ares_private.h b/src/lib/ares_private.h index ca85a9c5..6a9e04af 100644 --- a/src/lib/ares_private.h +++ b/src/lib/ares_private.h @@ -581,7 +581,7 @@ void ares_queue_notify_empty(ares_channel_t *channel); } while (0) #define ARES_CONFIG_CHECK(x) \ - (x && x->lookups && ares__slist_len(x->servers) > 0 && x->ndots > 0 && \ + (x && x->lookups && ares__slist_len(x->servers) > 0 && \ x->timeout > 0 && x->tries > 0) ares_bool_t ares__subnet_match(const struct ares_addr *addr, diff --git a/src/lib/ares_sysconfig.c b/src/lib/ares_sysconfig.c index d7c19c75..47453451 100644 --- a/src/lib/ares_sysconfig.c +++ b/src/lib/ares_sysconfig.c @@ -954,7 +954,7 @@ static ares_status_t ares__init_sysconfig_libresolv(ares_sysconfig_t *sysconfig) } } - if (res.ndots > 0) { + if (res.ndots >= 0) { sysconfig->ndots = (size_t)res.ndots; } if (res.retry > 0) { diff --git a/src/lib/ares_sysconfig_files.c b/src/lib/ares_sysconfig_files.c index 88208858..557888bc 100644 --- a/src/lib/ares_sysconfig_files.c +++ b/src/lib/ares_sysconfig_files.c @@ -414,9 +414,6 @@ static ares_status_t process_option(ares_sysconfig_t *sysconfig, } if (strcmp(key, "ndots") == 0) { - if (valint == 0) { - return ARES_EFORMERR; - } sysconfig->ndots = valint; } else if (strcmp(key, "retrans") == 0 || strcmp(key, "timeout") == 0) { if (valint == 0) { diff --git a/test/ares-test-mock-ai.cc b/test/ares-test-mock-ai.cc index 87716f4b..02f64a48 100644 --- a/test/ares-test-mock-ai.cc +++ b/test/ares-test-mock-ai.cc @@ -354,6 +354,53 @@ TEST_P(MockExtraOptsNDots5TestAI, SimpleQuery) { EXPECT_THAT(result.ai_, IncludesV4Address("123.45.67.8")); } +class MockExtraOptsNDots0TestAI : public MockExtraOptsNDotsTestAI { + public: + MockExtraOptsNDots0TestAI() : MockExtraOptsNDotsTestAI(0) {} +}; + +TEST_P(MockExtraOptsNDots0TestAI, SimpleQuery) { + DNSPacket rsp_ndots0; + rsp_ndots0.set_response().set_aa() + .add_question(new DNSQuestion("ndots0", T_A)) + .add_answer(new DNSARR("ndots0", 100, {1, 2, 3, 4})); + ON_CALL(server_, OnRequest("ndots0", T_A)) + .WillByDefault(SetReply(&server_, &rsp_ndots0)); + + DNSPacket rsp_ndots0_first; + rsp_ndots0_first.set_response().set_aa() + .add_question(new DNSQuestion("ndots0.first.com", T_A)) + .add_answer(new DNSARR("ndots0.first.com", 100, {99, 99, 99, 99})); + ON_CALL(server_, OnRequest("ndots0.first.com", T_A)) + .WillByDefault(SetReply(&server_, &rsp_ndots0_first)); + + DNSPacket rsp_ndots0_second; + rsp_ndots0_second.set_response().set_aa() + .add_question(new DNSQuestion("ndots0.second.org", T_A)) + .add_answer(new DNSARR("ndots0.second.org", 100, {98, 98, 98, 98})); + ON_CALL(server_, OnRequest("ndots0.second.org", T_A)) + .WillByDefault(SetReply(&server_, &rsp_ndots0_second)); + + DNSPacket rsp_ndots0_third; + rsp_ndots0_third.set_response().set_aa() + .add_question(new DNSQuestion("ndots0.third.gov", T_A)) + .add_answer(new DNSARR("ndots0.third.gov", 100, {97, 97, 97, 97})); + ON_CALL(server_, OnRequest("ndots0.third.gov", T_A)) + .WillByDefault(SetReply(&server_, &rsp_ndots0_third)); + + AddrInfoResult result; + struct ares_addrinfo_hints hints = {}; + hints.ai_family = AF_INET; + hints.ai_flags = ARES_AI_NOSORT; + ares_getaddrinfo(channel_, "ndots0", NULL, &hints, AddrInfoCallback, &result); + Process(); + EXPECT_TRUE(result.done_); + EXPECT_EQ(ARES_SUCCESS, result.status_); + std::stringstream ss; + ss << result.ai_; + EXPECT_EQ("{addr=[1.2.3.4]}", ss.str()); +} + class MockFlagsChannelOptsTestAI : public MockChannelOptsTest, public ::testing::WithParamInterface< std::pair > { @@ -762,6 +809,9 @@ INSTANTIATE_TEST_SUITE_P(AddressFamiliesAI, MockExtraOptsTestAI, INSTANTIATE_TEST_SUITE_P(AddressFamiliesAI, MockExtraOptsNDots5TestAI, ::testing::ValuesIn(ares::test::families_modes), PrintFamilyMode); +INSTANTIATE_TEST_SUITE_P(AddressFamiliesAI, MockExtraOptsNDots0TestAI, + ::testing::ValuesIn(ares::test::families_modes), PrintFamilyMode); + INSTANTIATE_TEST_SUITE_P(AddressFamiliesAI, MockNoCheckRespChannelTestAI, ::testing::ValuesIn(ares::test::families_modes), PrintFamilyMode);