Allow configuration value for NDots to be zero (#735)

As per Issue #734 some people use `ndots:0` in their configuration which
is allowed by the system resolver but not by c-ares. Add support for
`ndots:0` and add a test case to validate this behavior.

Fixes Issue: #734
Fix By: Brad House (@bradh352)
pull/739/head cares-1_28_0
Brad House 8 months ago committed by GitHub
parent 4cf16268bb
commit 458c937213
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 1
      RELEASE-NOTES.md
  2. 2
      docs/ares_init_options.3
  3. 7
      src/lib/ares_init.c
  4. 2
      src/lib/ares_options.c
  5. 2
      src/lib/ares_private.h
  6. 2
      src/lib/ares_sysconfig.c
  7. 3
      src/lib/ares_sysconfig_files.c
  8. 50
      test/ares-test-mock-ai.cc

@ -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:

@ -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;

@ -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;

@ -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;

@ -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,

@ -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) {

@ -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) {

@ -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<int, bool> > {
@ -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);

Loading…
Cancel
Save