Add ares_init_options() configurability for path to resolv.conf file

Add resolvconf_path to end of struct ares_options with ARES_OPT_RESOLVCONF option
so on Unix-like systems a custom path can be specified.  If no path is specified, 
/etc/resolv.conf is used like normal.

Fix By: Sarat Addepalli @SirR4T 
Fixes Bug: #220 
Review By: Brad House @bradh352
pull/223/head
Sarat Addepalli 6 years ago committed by Brad House
parent ad5852734c
commit 7e6af8efbc
  1. 2
      ares.h
  2. 5
      ares_destroy.c
  3. 41
      ares_init.c
  4. 13
      ares_init_options.3
  5. 3
      ares_private.h
  6. 34
      test/ares-test-init.cc

@ -164,6 +164,7 @@ extern "C" {
#define ARES_OPT_ROTATE (1 << 14)
#define ARES_OPT_EDNSPSZ (1 << 15)
#define ARES_OPT_NOROTATE (1 << 16)
#define ARES_OPT_RESOLVCONF (1 << 17)
/* Nameinfo flag values */
#define ARES_NI_NOFQDN (1 << 0)
@ -270,6 +271,7 @@ struct ares_options {
struct apattern *sortlist;
int nsort;
int ednspsz;
char *resolvconf_path;
};
struct hostent;

@ -36,6 +36,8 @@ void ares_destroy_options(struct ares_options *options)
ares_free(options->sortlist);
if(options->lookups)
ares_free(options->lookups);
if(options->resolvconf_path)
ares_free(options->resolvconf_path);
}
void ares_destroy(ares_channel channel)
@ -85,6 +87,9 @@ void ares_destroy(ares_channel channel)
if (channel->lookups)
ares_free(channel->lookups);
if (channel->resolvconf_path)
ares_free(channel->resolvconf_path);
ares_free(channel);
}

@ -169,6 +169,7 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options,
channel->sock_config_cb_data = NULL;
channel->sock_funcs = NULL;
channel->sock_func_cb_data = NULL;
channel->resolvconf_path = NULL;
channel->last_server = 0;
channel->last_timeout_processed = (time_t)now.tv_sec;
@ -242,6 +243,8 @@ done:
ares_free(channel->sortlist);
if(channel->lookups)
ares_free(channel->lookups);
if(channel->resolvconf_path)
ares_free(channel->resolvconf_path);
ares_free(channel);
return status;
}
@ -347,7 +350,7 @@ int ares_save_options(ares_channel channel, struct ares_options *options,
(*optmask) = (ARES_OPT_FLAGS|ARES_OPT_TRIES|ARES_OPT_NDOTS|
ARES_OPT_UDP_PORT|ARES_OPT_TCP_PORT|ARES_OPT_SOCK_STATE_CB|
ARES_OPT_SERVERS|ARES_OPT_DOMAINS|ARES_OPT_LOOKUPS|
ARES_OPT_SORTLIST|ARES_OPT_TIMEOUTMS);
ARES_OPT_SORTLIST|ARES_OPT_TIMEOUTMS|ARES_OPT_RESOLVCONF);
(*optmask) |= (channel->rotate ? ARES_OPT_ROTATE : ARES_OPT_NOROTATE);
/* Copy easy stuff */
@ -422,6 +425,13 @@ int ares_save_options(ares_channel channel, struct ares_options *options,
}
options->nsort = channel->nsort;
/* copy path for resolv.conf file */
if (channel->resolvconf_path) {
options->resolvconf_path = ares_strdup(channel->resolvconf_path);
if (!options->resolvconf_path)
return ARES_ENOMEM;
}
return ARES_SUCCESS;
}
@ -530,6 +540,14 @@ static int init_by_options(ares_channel channel,
channel->nsort = options->nsort;
}
/* Set path for resolv.conf file, if given. */
if ((optmask & ARES_OPT_RESOLVCONF) && !channel->resolvconf_path)
{
channel->resolvconf_path = ares_strdup(options->resolvconf_path);
if (!channel->resolvconf_path && options->resolvconf_path)
return ARES_ENOMEM;
}
channel->optmask = optmask;
return ARES_SUCCESS;
@ -1644,6 +1662,7 @@ static int init_by_resolv_conf(ares_channel channel)
size_t linesize;
int error;
int update_domains;
const char *resolvconf_path;
/* Don't read resolv.conf and friends if we don't have to */
if (ARES_CONFIG_CHECK(channel))
@ -1652,7 +1671,14 @@ static int init_by_resolv_conf(ares_channel channel)
/* Only update search domains if they're not already specified */
update_domains = (channel->ndomains == -1);
fp = fopen(PATH_RESOLV_CONF, "r");
/* Support path for resolvconf filename set by ares_init_options */
if(channel->resolvconf_path) {
resolvconf_path = channel->resolvconf_path;
} else {
resolvconf_path = PATH_RESOLV_CONF;
}
fp = fopen(resolvconf_path, "r");
if (fp) {
while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS)
{
@ -1663,10 +1689,10 @@ static int init_by_resolv_conf(ares_channel channel)
else if ((p = try_config(line, "search", ';')) && update_domains)
status = set_search(channel, p);
else if ((p = try_config(line, "nameserver", ';')) &&
channel->nservers == -1)
channel->nservers == -1)
status = config_nameserver(&servers, &nservers, p);
else if ((p = try_config(line, "sortlist", ';')) &&
channel->nsort == -1)
channel->nsort == -1)
status = config_sortlist(&sortlist, &nsort, p);
else if ((p = try_config(line, "options", ';')))
status = set_options(channel, p);
@ -1686,7 +1712,7 @@ static int init_by_resolv_conf(ares_channel channel)
break;
default:
DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n",
error, strerror(error)));
error, strerror(error)));
DEBUGF(fprintf(stderr, "Error opening file: %s\n", PATH_RESOLV_CONF));
status = ARES_EFILE;
}
@ -1954,6 +1980,11 @@ static int init_by_defaults(ares_channel channel)
ares_free(channel->lookups);
channel->lookups = NULL;
}
if(channel->resolvconf_path) {
ares_free(channel->resolvconf_path);
channel->resolvconf_path = NULL;
}
}
if(hostname)

@ -40,6 +40,7 @@ struct ares_options {
struct apattern *sortlist;
int nsort;
int ednspsz;
char *resolvconf_path;
};
int ares_init_options(ares_channel *\fIchannelptr\fP,
@ -181,6 +182,15 @@ The receive buffer size to set for the socket.
.B ARES_OPT_EDNSPSZ
.B int \fIednspsz\fP;
.br
.TP 18
.B ARES_OPT_RESOLVCONF
.B char *\fIresolvconf_path\fP;
The path to use for reading the resolv.conf file. The
.I resolvconf_path
should be set to a path string, and will be honoured on *nix like systems. The
default is
.B /etc/resolv.conf
.br
The message size to be advertized in EDNS; only takes effect if the
.B ARES_FLAG_EDNS
flag is set.
@ -259,6 +269,9 @@ c-ares library initialization not yet performed.
.SH NOTES
When initializing from
.B /etc/resolv.conf,
(or, alternatively when specified by the
.I resolvconf_path
path location)
\fBares_init_options(3)\fP reads the \fIdomain\fP and \fIsearch\fP directives
to allow lookups of short names relative to the domains specified. The
\fIdomain\fP and \fIsearch\fP directives override one another. If more that

@ -325,6 +325,9 @@ struct ares_channeldata {
const struct ares_socket_functions * sock_funcs;
void *sock_func_cb_data;
/* Path for resolv.conf file, configurable via ares_options */
char *resolvconf_path;
};
/* Memory management functions */

@ -86,6 +86,8 @@ TEST_F(LibraryTest, OptionsChannelInit) {
opts.lookups = strdup("b");
optmask |= ARES_OPT_LOOKUPS;
optmask |= ARES_OPT_ROTATE;
opts.resolvconf_path = strdup("/etc/resolv.conf");
optmask |= ARES_OPT_RESOLVCONF;
ares_channel channel = nullptr;
EXPECT_EQ(ARES_SUCCESS, ares_init_options(&channel, &opts, optmask));
@ -112,6 +114,7 @@ TEST_F(LibraryTest, OptionsChannelInit) {
EXPECT_EQ(std::string(opts.domains[0]), std::string(opts2.domains[0]));
EXPECT_EQ(std::string(opts.domains[1]), std::string(opts2.domains[1]));
EXPECT_EQ(std::string(opts.lookups), std::string(opts2.lookups));
EXPECT_EQ(std::string(opts.resolvconf_path), std::string(opts2.resolvconf_path));
ares_destroy_options(&opts);
ares_destroy_options(&opts2);
@ -169,6 +172,8 @@ TEST_F(LibraryTest, OptionsChannelAllocFail) {
opts.lookups = strdup("b");
optmask |= ARES_OPT_LOOKUPS;
optmask |= ARES_OPT_ROTATE;
opts.resolvconf_path = strdup("/etc/resolv.conf");
optmask |= ARES_OPT_RESOLVCONF;
ares_channel channel = nullptr;
for (int ii = 1; ii <= 8; ii++) {
@ -396,6 +401,35 @@ CONTAINED_TEST_F(LibraryTest, ContainerFullResolvInit,
return HasFailure();
}
// Allow path for resolv.conf to be configurable
NameContentList myresolvconf = {
{"/tmp/myresolv.cnf", " nameserver 1.2.3.4 \n"
"search first.com second.com\n"
"lookup bind\n"
"options debug ndots:5\n"
"sortlist 1.2.3.4/16 2.3.4.5\n"}};
CONTAINED_TEST_F(LibraryTest, ContainerMyResolvConfInit,
"myhostname", "mydomain.org", myresolvconf) {
char filename[] = "/tmp/myresolv.cnf";
ares_channel channel = nullptr;
struct ares_options options = {0};
options.resolvconf_path = strdup(filename);
int optmask = ARES_OPT_RESOLVCONF;
EXPECT_EQ(ARES_SUCCESS, ares_init_options(&channel, &options, optmask));
optmask = 0;
free(options.resolvconf_path);
options.resolvconf_path = NULL;
EXPECT_EQ(ARES_SUCCESS, ares_save_options(channel, &options, &optmask));
EXPECT_EQ(ARES_OPT_RESOLVCONF, (optmask & ARES_OPT_RESOLVCONF));
EXPECT_EQ(std::string(filename), std::string(options.resolvconf_path));
ares_destroy_options(&options);
ares_destroy(channel);
return HasFailure();
}
NameContentList hostconf = {
{"/etc/resolv.conf", "nameserver 1.2.3.4\n"
"sortlist1.2.3.4\n" // malformed line

Loading…
Cancel
Save