summaryrefslogtreecommitdiff
path: root/ares_init.c
diff options
context:
space:
mode:
Diffstat (limited to 'ares_init.c')
-rw-r--r--ares_init.c451
1 files changed, 300 insertions, 151 deletions
diff --git a/ares_init.c b/ares_init.c
index 9a0b6d2..f557947 100644
--- a/ares_init.c
+++ b/ares_init.c
@@ -49,6 +49,10 @@
#define MAX_DNS_PROPERTIES 8
#endif
+#if defined(CARES_USE_LIBRESOLV)
+#include <resolv.h>
+#endif
+
#include "ares.h"
#include "ares_inet_net_pton.h"
#include "ares_library_init.h"
@@ -76,17 +80,18 @@ static int set_options(ares_channel channel, const char *str);
static const char *try_option(const char *p, const char *q, const char *opt);
static int init_id_key(rc4_key* key,int key_data_len);
-#if !defined(WIN32) && !defined(WATT32) && \
- !defined(ANDROID) && !defined(__ANDROID__)
+static int config_sortlist(struct apattern **sortlist, int *nsort,
+ const char *str);
static int sortlist_alloc(struct apattern **sortlist, int *nsort,
struct apattern *pat);
static int ip_addr(const char *s, ssize_t len, struct in_addr *addr);
static void natural_mask(struct apattern *pat);
+#if !defined(WIN32) && !defined(WATT32) && \
+ !defined(ANDROID) && !defined(__ANDROID__) && !defined(CARES_USE_LIBRESOLV)
static int config_domain(ares_channel channel, char *str);
static int config_lookup(ares_channel channel, const char *str,
- const char *bindch, const char *filech);
-static int config_sortlist(struct apattern **sortlist, int *nsort,
- const char *str);
+ const char *bindch, const char *altbindch,
+ const char *filech);
static char *try_config(char *s, const char *opt, char scc);
#endif
@@ -124,9 +129,9 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options,
#endif
if (ares_library_initialized() != ARES_SUCCESS)
- return ARES_ENOTINITIALIZED;
+ return ARES_ENOTINITIALIZED; /* LCOV_EXCL_LINE: n/a on non-WinSock */
- channel = malloc(sizeof(struct ares_channeldata));
+ channel = ares_malloc(sizeof(struct ares_channeldata));
if (!channel) {
*channelptr = NULL;
return ARES_ENOMEM;
@@ -159,6 +164,8 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options,
channel->sock_state_cb_data = NULL;
channel->sock_create_cb = NULL;
channel->sock_create_cb_data = NULL;
+ channel->sock_config_cb = NULL;
+ channel->sock_config_cb_data = NULL;
channel->last_server = 0;
channel->last_timeout_processed = (time_t)now.tv_sec;
@@ -182,18 +189,17 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options,
* precedence to lowest.
*/
- if (status == ARES_SUCCESS) {
- status = init_by_options(channel, options, optmask);
- if (status != ARES_SUCCESS)
- DEBUGF(fprintf(stderr, "Error: init_by_options failed: %s\n",
- ares_strerror(status)));
- }
- if (status == ARES_SUCCESS) {
- status = init_by_environment(channel);
- if (status != ARES_SUCCESS)
- DEBUGF(fprintf(stderr, "Error: init_by_environment failed: %s\n",
- ares_strerror(status)));
+ status = init_by_options(channel, options, optmask);
+ if (status != ARES_SUCCESS) {
+ DEBUGF(fprintf(stderr, "Error: init_by_options failed: %s\n",
+ ares_strerror(status)));
+ /* If we fail to apply user-specified options, fail the whole init process */
+ goto done;
}
+ status = init_by_environment(channel);
+ if (status != ARES_SUCCESS)
+ DEBUGF(fprintf(stderr, "Error: init_by_environment failed: %s\n",
+ ares_strerror(status)));
if (status == ARES_SUCCESS) {
status = init_by_resolv_conf(channel);
if (status != ARES_SUCCESS)
@@ -221,22 +227,23 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options,
ares_strerror(status)));
}
+done:
if (status != ARES_SUCCESS)
{
/* Something failed; clean up memory we may have allocated. */
if (channel->servers)
- free(channel->servers);
+ ares_free(channel->servers);
if (channel->domains)
{
for (i = 0; i < channel->ndomains; i++)
- free(channel->domains[i]);
- free(channel->domains);
+ ares_free(channel->domains[i]);
+ ares_free(channel->domains);
}
if (channel->sortlist)
- free(channel->sortlist);
+ ares_free(channel->sortlist);
if(channel->lookups)
- free(channel->lookups);
- free(channel);
+ ares_free(channel->lookups);
+ ares_free(channel);
return status;
}
@@ -255,8 +262,8 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options,
int ares_dup(ares_channel *dest, ares_channel src)
{
struct ares_options opts;
- struct ares_addr_node *servers;
- int ipv6_nservers = 0;
+ struct ares_addr_port_node *servers;
+ int non_v4_default_port = 0;
int i, rc;
int optmask;
@@ -266,7 +273,10 @@ int ares_dup(ares_channel *dest, ares_channel src)
which is most of them */
rc = ares_save_options(src, &opts, &optmask);
if(rc)
+ {
+ ares_destroy_options(&opts);
return rc;
+ }
/* Then create the new channel with those options */
rc = ares_init_options(dest, &opts, optmask);
@@ -280,28 +290,38 @@ int ares_dup(ares_channel *dest, ares_channel src)
/* Now clone the options that ares_save_options() doesn't support. */
(*dest)->sock_create_cb = src->sock_create_cb;
(*dest)->sock_create_cb_data = src->sock_create_cb_data;
+ (*dest)->sock_config_cb = src->sock_config_cb;
+ (*dest)->sock_config_cb_data = src->sock_config_cb_data;
strncpy((*dest)->local_dev_name, src->local_dev_name,
sizeof(src->local_dev_name));
(*dest)->local_ip4 = src->local_ip4;
memcpy((*dest)->local_ip6, src->local_ip6, sizeof(src->local_ip6));
- /* Full name server cloning required when not all are IPv4 */
+ /* Full name server cloning required if there is a non-IPv4, or non-default port, nameserver */
for (i = 0; i < src->nservers; i++)
{
- if (src->servers[i].addr.family != AF_INET) {
- ipv6_nservers++;
+ if ((src->servers[i].addr.family != AF_INET) ||
+ (src->servers[i].addr.udp_port != 0) ||
+ (src->servers[i].addr.tcp_port != 0)) {
+ non_v4_default_port++;
break;
}
}
- if (ipv6_nservers) {
- rc = ares_get_servers(src, &servers);
- if (rc != ARES_SUCCESS)
+ if (non_v4_default_port) {
+ rc = ares_get_servers_ports(src, &servers);
+ if (rc != ARES_SUCCESS) {
+ ares_destroy(*dest);
+ *dest = NULL;
return rc;
- rc = ares_set_servers(*dest, servers);
+ }
+ rc = ares_set_servers_ports(*dest, servers);
ares_free_data(servers);
- if (rc != ARES_SUCCESS)
+ if (rc != ARES_SUCCESS) {
+ ares_destroy(*dest);
+ *dest = NULL;
return rc;
+ }
}
return ARES_SUCCESS; /* everything went fine */
@@ -326,8 +346,8 @@ 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) |
- (channel->optmask & ARES_OPT_ROTATE);
+ ARES_OPT_SORTLIST|ARES_OPT_TIMEOUTMS);
+ (*optmask) |= (channel->rotate ? ARES_OPT_ROTATE : ARES_OPT_NOROTATE);
/* Copy easy stuff */
options->flags = channel->flags;
@@ -342,20 +362,24 @@ int ares_save_options(ares_channel channel, struct ares_options *options,
options->sock_state_cb = channel->sock_state_cb;
options->sock_state_cb_data = channel->sock_state_cb_data;
- /* Copy IPv4 servers */
+ /* Copy IPv4 servers that use the default port */
if (channel->nservers) {
for (i = 0; i < channel->nservers; i++)
{
- if (channel->servers[i].addr.family == AF_INET)
+ if ((channel->servers[i].addr.family == AF_INET) &&
+ (channel->servers[i].addr.udp_port == 0) &&
+ (channel->servers[i].addr.tcp_port == 0))
ipv4_nservers++;
}
if (ipv4_nservers) {
- options->servers = malloc(ipv4_nservers * sizeof(struct in_addr));
+ options->servers = ares_malloc(ipv4_nservers * sizeof(struct in_addr));
if (!options->servers)
return ARES_ENOMEM;
for (i = j = 0; i < channel->nservers; i++)
{
- if (channel->servers[i].addr.family == AF_INET)
+ if ((channel->servers[i].addr.family == AF_INET) &&
+ (channel->servers[i].addr.udp_port == 0) &&
+ (channel->servers[i].addr.tcp_port == 0))
memcpy(&options->servers[j++],
&channel->servers[i].addr.addrV4,
sizeof(channel->servers[i].addr.addrV4));
@@ -366,14 +390,14 @@ int ares_save_options(ares_channel channel, struct ares_options *options,
/* copy domains */
if (channel->ndomains) {
- options->domains = malloc(channel->ndomains * sizeof(char *));
+ options->domains = ares_malloc(channel->ndomains * sizeof(char *));
if (!options->domains)
return ARES_ENOMEM;
for (i = 0; i < channel->ndomains; i++)
{
options->ndomains = i;
- options->domains[i] = strdup(channel->domains[i]);
+ options->domains[i] = ares_strdup(channel->domains[i]);
if (!options->domains[i])
return ARES_ENOMEM;
}
@@ -382,14 +406,14 @@ int ares_save_options(ares_channel channel, struct ares_options *options,
/* copy lookups */
if (channel->lookups) {
- options->lookups = strdup(channel->lookups);
+ options->lookups = ares_strdup(channel->lookups);
if (!options->lookups && channel->lookups)
return ARES_ENOMEM;
}
/* copy sortlist */
if (channel->nsort) {
- options->sortlist = malloc(channel->nsort * sizeof(struct apattern));
+ options->sortlist = ares_malloc(channel->nsort * sizeof(struct apattern));
if (!options->sortlist)
return ARES_ENOMEM;
for (i = 0; i < channel->nsort; i++)
@@ -419,6 +443,8 @@ static int init_by_options(ares_channel channel,
channel->ndots = options->ndots;
if ((optmask & ARES_OPT_ROTATE) && channel->rotate == -1)
channel->rotate = 1;
+ if ((optmask & ARES_OPT_NOROTATE) && channel->rotate == -1)
+ channel->rotate = 0;
if ((optmask & ARES_OPT_UDP_PORT) && channel->udp_port == -1)
channel->udp_port = htons(options->udp_port);
if ((optmask & ARES_OPT_TCP_PORT) && channel->tcp_port == -1)
@@ -445,12 +471,14 @@ static int init_by_options(ares_channel channel,
if (options->nservers > 0)
{
channel->servers =
- malloc(options->nservers * sizeof(struct server_state));
+ ares_malloc(options->nservers * sizeof(struct server_state));
if (!channel->servers)
return ARES_ENOMEM;
for (i = 0; i < options->nservers; i++)
{
channel->servers[i].addr.family = AF_INET;
+ channel->servers[i].addr.udp_port = 0;
+ channel->servers[i].addr.tcp_port = 0;
memcpy(&channel->servers[i].addr.addrV4,
&options->servers[i],
sizeof(channel->servers[i].addr.addrV4));
@@ -467,13 +495,13 @@ static int init_by_options(ares_channel channel,
/* Avoid zero size allocations at any cost */
if (options->ndomains > 0)
{
- channel->domains = malloc(options->ndomains * sizeof(char *));
+ channel->domains = ares_malloc(options->ndomains * sizeof(char *));
if (!channel->domains)
return ARES_ENOMEM;
for (i = 0; i < options->ndomains; i++)
{
channel->ndomains = i;
- channel->domains[i] = strdup(options->domains[i]);
+ channel->domains[i] = ares_strdup(options->domains[i]);
if (!channel->domains[i])
return ARES_ENOMEM;
}
@@ -484,19 +512,20 @@ static int init_by_options(ares_channel channel,
/* Set lookups, if given. */
if ((optmask & ARES_OPT_LOOKUPS) && !channel->lookups)
{
- channel->lookups = strdup(options->lookups);
+ channel->lookups = ares_strdup(options->lookups);
if (!channel->lookups)
return ARES_ENOMEM;
}
/* copy sortlist */
- if ((optmask & ARES_OPT_SORTLIST) && (channel->nsort == -1) &&
- (options->nsort>0)) {
- channel->sortlist = malloc(options->nsort * sizeof(struct apattern));
- if (!channel->sortlist)
- return ARES_ENOMEM;
- for (i = 0; i < options->nsort; i++)
- channel->sortlist[i] = options->sortlist[i];
+ if ((optmask & ARES_OPT_SORTLIST) && (channel->nsort == -1)) {
+ if (options->nsort > 0) {
+ channel->sortlist = ares_malloc(options->nsort * sizeof(struct apattern));
+ if (!channel->sortlist)
+ return ARES_ENOMEM;
+ for (i = 0; i < options->nsort; i++)
+ channel->sortlist[i] = options->sortlist[i];
+ }
channel->nsort = options->nsort;
}
@@ -523,7 +552,7 @@ static int init_by_environment(ares_channel channel)
{
status = set_options(channel, res_options);
if (status != ARES_SUCCESS)
- return status;
+ return status; /* LCOV_EXCL_LINE: set_options() never fails */
}
return ARES_SUCCESS;
@@ -558,7 +587,7 @@ static int get_REG_SZ(HKEY hKey, const char *leafKeyName, char **outptr)
/* Allocate buffer of indicated size plus one given that string
might have been stored without null termination */
- *outptr = malloc(size+1);
+ *outptr = ares_malloc(size+1);
if (!*outptr)
return 0;
@@ -567,7 +596,7 @@ static int get_REG_SZ(HKEY hKey, const char *leafKeyName, char **outptr)
(unsigned char *)*outptr, &size);
if ((res != ERROR_SUCCESS) || (size == 1))
{
- free(*outptr);
+ ares_free(*outptr);
*outptr = NULL;
return 0;
}
@@ -600,7 +629,7 @@ static int get_REG_SZ_9X(HKEY hKey, const char *leafKeyName, char **outptr)
/* Allocate buffer of indicated size plus one given that string
might have been stored without null termination */
- *outptr = malloc(size+1);
+ *outptr = ares_malloc(size+1);
if (!*outptr)
return 0;
@@ -609,7 +638,7 @@ static int get_REG_SZ_9X(HKEY hKey, const char *leafKeyName, char **outptr)
(unsigned char *)*outptr, &size);
if ((res != ERROR_SUCCESS) || (size == 1))
{
- free(*outptr);
+ ares_free(*outptr);
*outptr = NULL;
return 0;
}
@@ -810,16 +839,16 @@ static void commajoin(char **dst, const char *src)
if (*dst)
{
- tmp = malloc(strlen(*dst) + strlen(src) + 2);
+ tmp = ares_malloc(strlen(*dst) + strlen(src) + 2);
if (!tmp)
return;
sprintf(tmp, "%s,%s", *dst, src);
- free(*dst);
+ ares_free(*dst);
*dst = tmp;
}
else
{
- *dst = malloc(strlen(src) + 1);
+ *dst = ares_malloc(strlen(src) + 1);
if (!*dst)
return;
strcpy(*dst, src);
@@ -857,7 +886,7 @@ static int get_DNS_NetworkParams(char **outptr)
if (ares_fpGetNetworkParams == ZERO_NULL)
return 0;
- fi = malloc(size);
+ fi = ares_malloc(size);
if (!fi)
return 0;
@@ -865,7 +894,7 @@ static int get_DNS_NetworkParams(char **outptr)
if ((res != ERROR_BUFFER_OVERFLOW) && (res != ERROR_SUCCESS))
goto done;
- newfi = realloc(fi, size);
+ newfi = ares_realloc(fi, size);
if (!newfi)
goto done;
@@ -902,7 +931,7 @@ static int get_DNS_NetworkParams(char **outptr)
done:
if (fi)
- free(fi);
+ ares_free(fi);
if (!*outptr)
return 0;
@@ -950,7 +979,7 @@ static int get_DNS_AdaptersAddresses(char **outptr)
if (ares_fpGetAdaptersAddresses == ZERO_NULL)
return 0;
- ipaa = malloc(Bufsz);
+ ipaa = ares_malloc(Bufsz);
if (!ipaa)
return 0;
@@ -964,7 +993,7 @@ static int get_DNS_AdaptersAddresses(char **outptr)
{
if (Bufsz < ReqBufsz)
{
- newipaa = realloc(ipaa, ReqBufsz);
+ newipaa = ares_realloc(ipaa, ReqBufsz);
if (!newipaa)
goto done;
Bufsz = ReqBufsz;
@@ -980,6 +1009,9 @@ static int get_DNS_AdaptersAddresses(char **outptr)
for (ipaaEntry = ipaa; ipaaEntry; ipaaEntry = ipaaEntry->Next)
{
+ if(ipaaEntry->OperStatus != IfOperStatusUp)
+ continue;
+
for (ipaDNSAddr = ipaaEntry->FirstDnsServerAddress;
ipaDNSAddr;
ipaDNSAddr = ipaDNSAddr->Next)
@@ -1016,7 +1048,7 @@ static int get_DNS_AdaptersAddresses(char **outptr)
done:
if (ipaa)
- free(ipaa);
+ ares_free(ipaa);
if (!*outptr)
return 0;
@@ -1040,14 +1072,20 @@ done:
*/
static int get_DNS_Windows(char **outptr)
{
- /* Try using IP helper API GetAdaptersAddresses() */
- if (get_DNS_AdaptersAddresses(outptr))
- return 1;
-
+ /*
+ Use GetNetworkParams First in case of
+ multiple adapter is enabled on this machine.
+ GetAdaptersAddresses will retrive dummy dns servers.
+ That will slowing DNS lookup.
+ */
/* Try using IP helper API GetNetworkParams() */
if (get_DNS_NetworkParams(outptr))
return 1;
+ /* Try using IP helper API GetAdaptersAddresses() */
+ if (get_DNS_AdaptersAddresses(outptr))
+ return 1;
+
/* Fall-back to registry information */
return get_DNS_Registry(outptr);
}
@@ -1055,7 +1093,8 @@ static int get_DNS_Windows(char **outptr)
static int init_by_resolv_conf(ares_channel channel)
{
-#if !defined(ANDROID) && !defined(__ANDROID__) && !defined(WATT32)
+#if !defined(ANDROID) && !defined(__ANDROID__) && !defined(WATT32) && \
+ !defined(CARES_USE_LIBRESOLV)
char *line = NULL;
#endif
int status = -1, nservers = 0, nsort = 0;
@@ -1070,7 +1109,7 @@ static int init_by_resolv_conf(ares_channel channel)
if (get_DNS_Windows(&line))
{
status = config_nameserver(&servers, &nservers, line);
- free(line);
+ ares_free(line);
}
if (status == ARES_SUCCESS)
@@ -1088,7 +1127,7 @@ static int init_by_resolv_conf(ares_channel channel)
line = getenv("Inet$Resolvers");
status = ARES_EOF;
if (line) {
- char *resolvers = strdup(line), *pos, *space;
+ char *resolvers = ares_strdup(line), *pos, *space;
if (!resolvers)
return ARES_ENOMEM;
@@ -1107,7 +1146,7 @@ static int init_by_resolv_conf(ares_channel channel)
if (status == ARES_SUCCESS)
status = ARES_EOF;
- free(resolvers);
+ ares_free(resolvers);
}
#elif defined(WATT32)
@@ -1120,14 +1159,17 @@ static int init_by_resolv_conf(ares_channel channel)
return ARES_SUCCESS; /* use localhost DNS server */
nservers = i;
- servers = calloc(i, sizeof(struct server_state));
+ servers = ares_malloc(sizeof(struct server_state));
if (!servers)
return ARES_ENOMEM;
+ memset(servers, 0, sizeof(struct server_state));
for (i = 0; def_nameservers[i]; i++)
{
servers[i].addr.addrV4.s_addr = htonl(def_nameservers[i]);
servers[i].addr.family = AF_INET;
+ servers[i].addr.udp_port = 0;
+ servers[i].addr.tcp_port = 0;
}
status = ARES_EOF;
@@ -1147,26 +1189,87 @@ static int init_by_resolv_conf(ares_channel channel)
break;
status = ARES_EOF;
}
+#elif defined(CARES_USE_LIBRESOLV)
+ struct __res_state res;
+ memset(&res, 0, sizeof(res));
+ int result = res_ninit(&res);
+ if (result == 0 && (res.options & RES_INIT)) {
+ status = ARES_EOF;
+
+ if (channel->nservers == -1) {
+ union res_sockaddr_union addr[MAXNS];
+ int nscount = res_getservers(&res, addr, MAXNS);
+ for (int i = 0; i < nscount; ++i) {
+ char str[INET6_ADDRSTRLEN];
+ int config_status;
+ sa_family_t family = addr[i].sin.sin_family;
+ if (family == AF_INET) {
+ ares_inet_ntop(family, &addr[i].sin.sin_addr, str, sizeof(str));
+ } else if (family == AF_INET6) {
+ ares_inet_ntop(family, &addr[i].sin6.sin6_addr, str, sizeof(str));
+ } else {
+ continue;
+ }
+
+ config_status = config_nameserver(&servers, &nservers, str);
+ if (config_status != ARES_SUCCESS) {
+ status = config_status;
+ break;
+ }
+ }
+ }
+ if (channel->ndomains == -1) {
+ int entries = 0;
+ while ((entries < MAXDNSRCH) && res.dnsrch[entries])
+ entries++;
+
+ channel->domains = ares_malloc(entries * sizeof(char *));
+ if (!channel->domains) {
+ status = ARES_ENOMEM;
+ } else {
+ channel->ndomains = entries;
+ for (int i = 0; i < channel->ndomains; ++i) {
+ channel->domains[i] = ares_strdup(res.dnsrch[i]);
+ if (!channel->domains[i])
+ status = ARES_ENOMEM;
+ }
+ }
+ }
+ if (channel->ndots == -1)
+ channel->ndots = res.ndots;
+ if (channel->tries == -1)
+ channel->tries = res.retry;
+ if (channel->rotate == -1)
+ channel->rotate = res.options & RES_ROTATE;
+ if (channel->timeout == -1)
+ channel->timeout = res.retrans * 1000;
+
+ res_ndestroy(&res);
+ }
#else
{
char *p;
FILE *fp;
size_t linesize;
int error;
+ int update_domains;
/* Don't read resolv.conf and friends if we don't have to */
if (ARES_CONFIG_CHECK(channel))
return ARES_SUCCESS;
- fp = fopen(PATH_RESOLV_CONF, "re");
+ /* Only update search domains if they're not already specified */
+ update_domains = (channel->ndomains == -1);
+
+ fp = fopen(PATH_RESOLV_CONF, "r");
if (fp) {
while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS)
{
- if ((p = try_config(line, "domain", ';')))
+ if ((p = try_config(line, "domain", ';')) && update_domains)
status = config_domain(channel, p);
else if ((p = try_config(line, "lookup", ';')) && !channel->lookups)
- status = config_lookup(channel, p, "bind", "file");
- else if ((p = try_config(line, "search", ';')))
+ status = config_lookup(channel, p, "bind", NULL, "file");
+ else if ((p = try_config(line, "search", ';')) && update_domains)
status = set_search(channel, p);
else if ((p = try_config(line, "nameserver", ';')) &&
channel->nservers == -1)
@@ -1200,14 +1303,13 @@ static int init_by_resolv_conf(ares_channel channel)
if ((status == ARES_EOF) && (!channel->lookups)) {
/* Many systems (Solaris, Linux, BSD's) use nsswitch.conf */
- fp = fopen("/etc/nsswitch.conf", "re");
+ fp = fopen("/etc/nsswitch.conf", "r");
if (fp) {
while ((status = ares__read_line(fp, &line, &linesize)) ==
ARES_SUCCESS)
{
if ((p = try_config(line, "hosts:", '\0')) && !channel->lookups)
- /* ignore errors */
- (void)config_lookup(channel, p, "dns", "files");
+ (void)config_lookup(channel, p, "dns", "resolve", "files");
}
fclose(fp);
}
@@ -1216,28 +1318,29 @@ static int init_by_resolv_conf(ares_channel channel)
switch(error) {
case ENOENT:
case ESRCH:
- status = ARES_EOF;
break;
default:
DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n",
error, strerror(error)));
DEBUGF(fprintf(stderr, "Error opening file: %s\n",
"/etc/nsswitch.conf"));
- status = ARES_EFILE;
}
+
+ /* ignore error, maybe we will get luck in next if clause */
+ status = ARES_EOF;
}
}
if ((status == ARES_EOF) && (!channel->lookups)) {
/* Linux / GNU libc 2.x and possibly others have host.conf */
- fp = fopen("/etc/host.conf", "re");
+ fp = fopen("/etc/host.conf", "r");
if (fp) {
while ((status = ares__read_line(fp, &line, &linesize)) ==
ARES_SUCCESS)
{
if ((p = try_config(line, "order", '\0')) && !channel->lookups)
/* ignore errors */
- (void)config_lookup(channel, p, "bind", "hosts");
+ (void)config_lookup(channel, p, "bind", NULL, "hosts");
}
fclose(fp);
}
@@ -1246,28 +1349,29 @@ static int init_by_resolv_conf(ares_channel channel)
switch(error) {
case ENOENT:
case ESRCH:
- status = ARES_EOF;
break;
default:
DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n",
error, strerror(error)));
DEBUGF(fprintf(stderr, "Error opening file: %s\n",
"/etc/host.conf"));
- status = ARES_EFILE;
}
+
+ /* ignore error, maybe we will get luck in next if clause */
+ status = ARES_EOF;
}
}
if ((status == ARES_EOF) && (!channel->lookups)) {
/* Tru64 uses /etc/svc.conf */
- fp = fopen("/etc/svc.conf", "re");
+ fp = fopen("/etc/svc.conf", "r");
if (fp) {
while ((status = ares__read_line(fp, &line, &linesize)) ==
ARES_SUCCESS)
{
if ((p = try_config(line, "hosts=", '\0')) && !channel->lookups)
/* ignore errors */
- (void)config_lookup(channel, p, "bind", "local");
+ (void)config_lookup(channel, p, "bind", NULL, "local");
}
fclose(fp);
}
@@ -1276,19 +1380,20 @@ static int init_by_resolv_conf(ares_channel channel)
switch(error) {
case ENOENT:
case ESRCH:
- status = ARES_EOF;
break;
default:
DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n",
error, strerror(error)));
DEBUGF(fprintf(stderr, "Error opening file: %s\n", "/etc/svc.conf"));
- status = ARES_EFILE;
}
+
+ /* ignore error, default value will be chosen for `channel->lookups` */
+ status = ARES_EOF;
}
}
if(line)
- free(line);
+ ares_free(line);
}
#endif
@@ -1297,9 +1402,9 @@ static int init_by_resolv_conf(ares_channel channel)
if (status != ARES_EOF)
{
if (servers != NULL)
- free(servers);
+ ares_free(servers);
if (sortlist != NULL)
- free(sortlist);
+ ares_free(sortlist);
return status;
}
@@ -1348,13 +1453,15 @@ static int init_by_defaults(ares_channel channel)
if (channel->nservers == -1) {
/* If nobody specified servers, try a local named. */
- channel->servers = malloc(sizeof(struct server_state));
+ channel->servers = ares_malloc(sizeof(struct server_state));
if (!channel->servers) {
rc = ARES_ENOMEM;
goto error;
}
channel->servers[0].addr.family = AF_INET;
channel->servers[0].addr.addrV4.s_addr = htonl(INADDR_LOOPBACK);
+ channel->servers[0].addr.udp_port = 0;
+ channel->servers[0].addr.tcp_port = 0;
channel->nservers = 1;
}
@@ -1379,7 +1486,7 @@ static int init_by_defaults(ares_channel channel)
int res;
channel->ndomains = 0; /* default to none */
- hostname = malloc(len);
+ hostname = ares_malloc(len);
if(!hostname) {
rc = ARES_ENOMEM;
goto error;
@@ -1392,7 +1499,7 @@ static int init_by_defaults(ares_channel channel)
char *p;
len *= 2;
lenv *= 2;
- p = realloc(hostname, len);
+ p = ares_realloc(hostname, len);
if(!p) {
rc = ARES_ENOMEM;
goto error;
@@ -1405,17 +1512,17 @@ static int init_by_defaults(ares_channel channel)
goto error;
}
- } WHILE_FALSE;
+ } while (res != 0);
dot = strchr(hostname, '.');
if (dot) {
/* a dot was found */
- channel->domains = malloc(sizeof(char *));
+ channel->domains = ares_malloc(sizeof(char *));
if (!channel->domains) {
rc = ARES_ENOMEM;
goto error;
}
- channel->domains[0] = strdup(dot + 1);
+ channel->domains[0] = ares_strdup(dot + 1);
if (!channel->domains[0]) {
rc = ARES_ENOMEM;
goto error;
@@ -1431,7 +1538,7 @@ static int init_by_defaults(ares_channel channel)
}
if (!channel->lookups) {
- channel->lookups = strdup("fb");
+ channel->lookups = ares_strdup("fb");
if (!channel->lookups)
rc = ARES_ENOMEM;
}
@@ -1439,31 +1546,31 @@ static int init_by_defaults(ares_channel channel)
error:
if(rc) {
if(channel->servers) {
- free(channel->servers);
+ ares_free(channel->servers);
channel->servers = NULL;
}
if(channel->domains && channel->domains[0])
- free(channel->domains[0]);
+ ares_free(channel->domains[0]);
if(channel->domains) {
- free(channel->domains);
+ ares_free(channel->domains);
channel->domains = NULL;
}
if(channel->lookups) {
- free(channel->lookups);
+ ares_free(channel->lookups);
channel->lookups = NULL;
}
}
if(hostname)
- free(hostname);
+ ares_free(hostname);
return rc;
}
#if !defined(WIN32) && !defined(WATT32) && \
- !defined(ANDROID) && !defined(__ANDROID__)
+ !defined(ANDROID) && !defined(__ANDROID__) && !defined(CARES_USE_LIBRESOLV)
static int config_domain(ares_channel channel, char *str)
{
char *q;
@@ -1485,11 +1592,15 @@ static int config_domain(ares_channel channel, char *str)
#endif
static int config_lookup(ares_channel channel, const char *str,
- const char *bindch, const char *filech)
+ const char *bindch, const char *altbindch,
+ const char *filech)
{
char lookups[3], *l;
const char *vqualifier p;
+ if (altbindch == NULL)
+ altbindch = bindch;
+
/* Set the lookup order. Only the first letter of each work
* is relevant, and it has to be "b" for DNS or "f" for the
* host file. Ignore everything else.
@@ -1498,8 +1609,8 @@ static int config_lookup(ares_channel channel, const char *str,
p = str;
while (*p)
{
- if ((*p == *bindch || *p == *filech) && l < lookups + 2) {
- if (*p == *bindch) *l++ = 'b';
+ if ((*p == *bindch || *p == *altbindch || *p == *filech) && l < lookups + 2) {
+ if (*p == *bindch || *p == *altbindch) *l++ = 'b';
else *l++ = 'f';
}
while (*p && !ISSPACE(*p) && (*p != ','))
@@ -1508,10 +1619,10 @@ static int config_lookup(ares_channel channel, const char *str,
p++;
}
*l = '\0';
- channel->lookups = strdup(lookups);
+ channel->lookups = ares_strdup(lookups);
return (channel->lookups) ? ARES_SUCCESS : ARES_ENOMEM;
}
-#endif /* !WIN32 & !WATT32 & !ANDROID & !__ANDROID__ */
+#endif /* !WIN32 & !WATT32 & !ANDROID & !__ANDROID__ & !CARES_USE_LIBRESOLV */
#ifndef WATT32
static int config_nameserver(struct server_state **servers, int *nservers,
@@ -1554,13 +1665,15 @@ static int config_nameserver(struct server_state **servers, int *nservers,
continue;
/* Resize servers state array. */
- newserv = realloc(*servers, (*nservers + 1) *
- sizeof(struct server_state));
+ newserv = ares_realloc(*servers, (*nservers + 1) *
+ sizeof(struct server_state));
if (!newserv)
return ARES_ENOMEM;
/* Store address data. */
newserv[*nservers].addr.family = host.family;
+ newserv[*nservers].addr.udp_port = 0;
+ newserv[*nservers].addr.tcp_port = 0;
if (host.family == AF_INET)
memcpy(&newserv[*nservers].addr.addrV4, &host.addrV4,
sizeof(host.addrV4));
@@ -1575,8 +1688,8 @@ static int config_nameserver(struct server_state **servers, int *nservers,
return ARES_SUCCESS;
}
+#endif /* !WATT32 */
-#if !defined(WIN32) && !defined(ANDROID) && !defined(__ANDROID__)
static int config_sortlist(struct apattern **sortlist, int *nsort,
const char *str)
{
@@ -1615,8 +1728,11 @@ static int config_sortlist(struct apattern **sortlist, int *nsort,
pat.type = PATTERN_CIDR;
pat.mask.bits = (unsigned short)bits;
pat.family = AF_INET6;
- if (!sortlist_alloc(sortlist, nsort, &pat))
+ if (!sortlist_alloc(sortlist, nsort, &pat)) {
+ ares_free(*sortlist);
+ *sortlist = NULL;
return ARES_ENOMEM;
+ }
}
else if (ipbufpfx[0] &&
(bits = ares_inet_net_pton(AF_INET, ipbufpfx, &pat.addrV4,
@@ -1625,8 +1741,11 @@ static int config_sortlist(struct apattern **sortlist, int *nsort,
pat.type = PATTERN_CIDR;
pat.mask.bits = (unsigned short)bits;
pat.family = AF_INET;
- if (!sortlist_alloc(sortlist, nsort, &pat))
+ if (!sortlist_alloc(sortlist, nsort, &pat)) {
+ ares_free(*sortlist);
+ *sortlist = NULL;
return ARES_ENOMEM;
+ }
}
/* See if it is just a regular IP */
else if (ip_addr(ipbuf, q-str, &pat.addrV4) == 0)
@@ -1642,8 +1761,11 @@ static int config_sortlist(struct apattern **sortlist, int *nsort,
natural_mask(&pat);
pat.family = AF_INET;
pat.type = PATTERN_MASK;
- if (!sortlist_alloc(sortlist, nsort, &pat))
+ if (!sortlist_alloc(sortlist, nsort, &pat)) {
+ ares_free(*sortlist);
+ *sortlist = NULL;
return ARES_ENOMEM;
+ }
}
else
{
@@ -1657,8 +1779,6 @@ static int config_sortlist(struct apattern **sortlist, int *nsort,
return ARES_SUCCESS;
}
-#endif /* !WIN32 & !ANDROID & !__ANDROID__ */
-#endif /* !WATT32 */
static int set_search(ares_channel channel, const char *str)
{
@@ -1666,13 +1786,14 @@ static int set_search(ares_channel channel, const char *str)
const char *p, *q;
if(channel->ndomains != -1) {
+ /* LCOV_EXCL_START: all callers check ndomains == -1 */
/* if we already have some domains present, free them first */
for(n=0; n < channel->ndomains; n++)
- free(channel->domains[n]);
- free(channel->domains);
+ ares_free(channel->domains[n]);
+ ares_free(channel->domains);
channel->domains = NULL;
channel->ndomains = -1;
- }
+ } /* LCOV_EXCL_STOP */
/* Count the domains given. */
n = 0;
@@ -1692,7 +1813,7 @@ static int set_search(ares_channel channel, const char *str)
return ARES_SUCCESS;
}
- channel->domains = malloc(n * sizeof(char *));
+ channel->domains = ares_malloc(n * sizeof(char *));
if (!channel->domains)
return ARES_ENOMEM;
@@ -1705,7 +1826,7 @@ static int set_search(ares_channel channel, const char *str)
q = p;
while (*q && !ISSPACE(*q))
q++;
- channel->domains[n] = malloc(q - p + 1);
+ channel->domains[n] = ares_malloc(q - p + 1);
if (!channel->domains[n])
return ARES_ENOMEM;
memcpy(channel->domains[n], p, q - p);
@@ -1757,7 +1878,7 @@ static const char *try_option(const char *p, const char *q, const char *opt)
}
#if !defined(WIN32) && !defined(WATT32) && \
- !defined(ANDROID) && !defined(__ANDROID__)
+ !defined(ANDROID) && !defined(__ANDROID__) && !defined(CARES_USE_LIBRESOLV)
static char *try_config(char *s, const char *opt, char scc)
{
size_t len;
@@ -1766,7 +1887,7 @@ static char *try_config(char *s, const char *opt, char scc)
if (!s || !opt)
/* no line or no option */
- return NULL;
+ return NULL; /* LCOV_EXCL_LINE */
/* Hash '#' character is always used as primary comment char, additionally
a not-NUL secondary comment char will be considered when specified. */
@@ -1798,7 +1919,7 @@ static char *try_config(char *s, const char *opt, char scc)
if ((len = strlen(opt)) == 0)
/* empty option */
- return NULL;
+ return NULL; /* LCOV_EXCL_LINE */
if (strncmp(p, opt, len) != 0)
/* line and option do not match */
@@ -1809,7 +1930,7 @@ static char *try_config(char *s, const char *opt, char scc)
if (!*p)
/* no option value */
- return NULL;
+ return NULL; /* LCOV_EXCL_LINE */
if ((opt[len-1] != ':') && (opt[len-1] != '=') && !ISSPACE(*p))
/* whitespace between option name and value is mandatory
@@ -1827,19 +1948,7 @@ static char *try_config(char *s, const char *opt, char scc)
/* return pointer to option value */
return p;
}
-
-static int sortlist_alloc(struct apattern **sortlist, int *nsort,
- struct apattern *pat)
-{
- struct apattern *newsort;
- newsort = realloc(*sortlist, (*nsort + 1) * sizeof(struct apattern));
- if (!newsort)
- return 0;
- newsort[*nsort] = *pat;
- *sortlist = newsort;
- (*nsort)++;
- return 1;
-}
+#endif /* !WIN32 & !WATT32 & !ANDROID & !__ANDROID__ */
static int ip_addr(const char *ipbuf, ssize_t len, struct in_addr *addr)
{
@@ -1873,7 +1982,19 @@ static void natural_mask(struct apattern *pat)
else
pat->mask.addr4.s_addr = htonl(IN_CLASSC_NET);
}
-#endif /* !WIN32 & !WATT32 & !ANDROID & !__ANDROID__ */
+
+static int sortlist_alloc(struct apattern **sortlist, int *nsort,
+ struct apattern *pat)
+{
+ struct apattern *newsort;
+ newsort = ares_realloc(*sortlist, (*nsort + 1) * sizeof(struct apattern));
+ if (!newsort)
+ return 0;
+ newsort[*nsort] = *pat;
+ *sortlist = newsort;
+ (*nsort)++;
+ return 1;
+}
/* initialize an rc4 key. If possible a cryptographically secure random key
is generated using a suitable function (for example win32's RtlGenRandom as
@@ -1896,7 +2017,7 @@ static void randomize_key(unsigned char* key,int key_data_len)
}
#else /* !WIN32 */
#ifdef RANDOM_FILE
- FILE *f = fopen(RANDOM_FILE, "rbe");
+ FILE *f = fopen(RANDOM_FILE, "rb");
if(f) {
counter = aresx_uztosi(fread(key, 1, key_data_len, f));
fclose(f);
@@ -1906,7 +2027,7 @@ static void randomize_key(unsigned char* key,int key_data_len)
if (!randomized) {
for (;counter<key_data_len;counter++)
- key[counter]=(unsigned char)(rand() % 256);
+ key[counter]=(unsigned char)(rand() % 256); /* LCOV_EXCL_LINE */
}
}
@@ -1918,9 +2039,10 @@ static int init_id_key(rc4_key* key,int key_data_len)
short counter;
unsigned char *key_data_ptr = 0;
- key_data_ptr = calloc(1,key_data_len);
+ key_data_ptr = ares_malloc(key_data_len);
if (!key_data_ptr)
return ARES_ENOMEM;
+ memset(key_data_ptr, 0, key_data_len);
state = &key->state[0];
for(counter = 0; counter < 256; counter++)
@@ -1939,7 +2061,7 @@ static int init_id_key(rc4_key* key,int key_data_len)
index1 = (unsigned char)((index1 + 1) % key_data_len);
}
- free(key_data_ptr);
+ ares_free(key_data_ptr);
return ARES_SUCCESS;
}
@@ -1973,6 +2095,33 @@ void ares_set_socket_callback(ares_channel channel,
channel->sock_create_cb_data = data;
}
+void ares_set_socket_configure_callback(ares_channel channel,
+ ares_sock_config_callback cb,
+ void *data)
+{
+ channel->sock_config_cb = cb;
+ channel->sock_config_cb_data = data;
+}
+
+int ares_set_sortlist(ares_channel channel, const char *sortstr)
+{
+ int nsort = 0;
+ struct apattern *sortlist = NULL;
+ int status;
+
+ if (!channel)
+ return ARES_ENODATA;
+
+ status = config_sortlist(&sortlist, &nsort, sortstr);
+ if (status == ARES_SUCCESS && sortlist) {
+ if (channel->sortlist)
+ ares_free(channel->sortlist);
+ channel->sortlist = sortlist;
+ channel->nsort = nsort;
+ }
+ return status;
+}
+
void ares__init_servers_state(ares_channel channel)
{
struct server_state *server;