diff options
Diffstat (limited to 'ares_init.c')
-rw-r--r-- | ares_init.c | 451 |
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; |