Alien-cares
view release on metacpan or search on metacpan
libcares/ares_init.c view on Meta::CPAN
#endif
#ifdef HAVE_ARPA_NAMESER_H
# include <arpa/nameser.h>
#else
# include "nameser.h"
#endif
#ifdef HAVE_ARPA_NAMESER_COMPAT_H
# include <arpa/nameser_compat.h>
#endif
#if defined(ANDROID) || defined(__ANDROID__)
#include <sys/system_properties.h>
#include "ares_android.h"
/* From the Bionic sources */
#define DNS_PROP_NAME_PREFIX "net.dns"
#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"
#include "ares_nowarn.h"
#include "ares_platform.h"
#include "ares_private.h"
#ifdef WATT32
#undef WIN32 /* Redefined in MingW/MSVC headers */
#endif
static int init_by_options(ares_channel channel,
const struct ares_options *options,
int optmask);
static int init_by_environment(ares_channel channel);
static int init_by_resolv_conf(ares_channel channel);
static int init_by_defaults(ares_channel channel);
#ifndef WATT32
static int config_nameserver(struct server_state **servers, int *nservers,
char *str);
#endif
static int set_search(ares_channel channel, const char *str);
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);
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, ares_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 *altbindch,
const char *filech);
static char *try_config(char *s, const char *opt, char scc);
#endif
#define ARES_CONFIG_CHECK(x) (x->lookups && x->nsort > -1 && \
x->nservers > -1 && \
x->ndomains > -1 && \
x->ndots > -1 && x->timeout > -1 && \
x->tries > -1)
int ares_init(ares_channel *channelptr)
{
return ares_init_options(channelptr, NULL, 0);
}
int ares_init_options(ares_channel *channelptr, struct ares_options *options,
int optmask)
{
ares_channel channel;
int i;
int status = ARES_SUCCESS;
struct timeval now;
#ifdef CURLDEBUG
const char *env = getenv("CARES_MEMDEBUG");
if (env)
curl_memdebug(env);
env = getenv("CARES_MEMLIMIT");
if (env) {
char *endptr;
long num = strtol(env, &endptr, 10);
if((endptr != env) && (endptr == env + strlen(env)) && (num > 0))
curl_memlimit(num);
}
#endif
if (ares_library_initialized() != ARES_SUCCESS)
return ARES_ENOTINITIALIZED; /* LCOV_EXCL_LINE: n/a on non-WinSock */
channel = ares_malloc(sizeof(struct ares_channeldata));
if (!channel) {
*channelptr = NULL;
return ARES_ENOMEM;
}
now = ares__tvnow();
/* Set everything to distinguished values so we know they haven't
* been set yet.
*/
channel->flags = -1;
channel->timeout = -1;
channel->tries = -1;
channel->ndots = -1;
channel->rotate = -1;
channel->udp_port = -1;
channel->tcp_port = -1;
channel->ednspsz = -1;
channel->socket_send_buffer_size = -1;
libcares/ares_init.c view on Meta::CPAN
}
}
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;
const char *resolvconf_path;
/* Don't read resolv.conf and friends if we don't have to */
if (ARES_CONFIG_CHECK(channel))
return ARES_SUCCESS;
/* Only update search domains if they're not already specified */
update_domains = (channel->ndomains == -1);
/* 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)
{
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", 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)
status = config_nameserver(&servers, &nservers, p);
else if ((p = try_config(line, "sortlist", ';')) &&
channel->nsort == -1)
status = config_sortlist(&sortlist, &nsort, p);
else if ((p = try_config(line, "options", ';')))
status = set_options(channel, p);
else
status = ARES_SUCCESS;
if (status != ARES_SUCCESS)
break;
}
fclose(fp);
}
else {
error = ERRNO;
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", PATH_RESOLV_CONF));
status = ARES_EFILE;
}
}
if ((status == ARES_EOF) && (!channel->lookups)) {
/* Many systems (Solaris, Linux, BSD's) use nsswitch.conf */
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)
(void)config_lookup(channel, p, "dns", "resolve", "files");
}
fclose(fp);
}
else {
error = ERRNO;
switch(error) {
case ENOENT:
case ESRCH:
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"));
}
/* 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", "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", NULL, "hosts");
}
fclose(fp);
}
else {
error = ERRNO;
switch(error) {
case ENOENT:
case ESRCH:
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"));
}
/* 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", "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", NULL, "local");
}
fclose(fp);
}
else {
error = ERRNO;
switch(error) {
case ENOENT:
case ESRCH:
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"));
}
/* ignore error, default value will be chosen for `channel->lookups` */
status = ARES_EOF;
}
}
if(line)
ares_free(line);
}
#endif
/* Handle errors. */
if (status != ARES_EOF)
{
if (servers != NULL)
ares_free(servers);
if (sortlist != NULL)
ares_free(sortlist);
return status;
}
/* If we got any name server entries, fill them in. */
if (servers)
{
channel->servers = servers;
channel->nservers = nservers;
}
/* If we got any sortlist entries, fill them in. */
if (sortlist)
{
channel->sortlist = sortlist;
channel->nsort = nsort;
}
return ARES_SUCCESS;
}
static int init_by_defaults(ares_channel channel)
{
char *hostname = NULL;
int rc = ARES_SUCCESS;
#ifdef HAVE_GETHOSTNAME
char *dot;
#endif
libcares/ares_init.c view on Meta::CPAN
if (!channel->lookups) {
channel->lookups = ares_strdup("fb");
if (!channel->lookups)
rc = ARES_ENOMEM;
}
error:
if(rc) {
if(channel->servers) {
ares_free(channel->servers);
channel->servers = NULL;
}
if(channel->domains && channel->domains[0])
ares_free(channel->domains[0]);
if(channel->domains) {
ares_free(channel->domains);
channel->domains = NULL;
}
if(channel->lookups) {
ares_free(channel->lookups);
channel->lookups = NULL;
}
if(channel->resolvconf_path) {
ares_free(channel->resolvconf_path);
channel->resolvconf_path = NULL;
}
}
if(hostname)
ares_free(hostname);
return rc;
}
#if !defined(WIN32) && !defined(WATT32) && \
!defined(ANDROID) && !defined(__ANDROID__) && !defined(CARES_USE_LIBRESOLV)
static int config_domain(ares_channel channel, char *str)
{
char *q;
/* Set a single search domain. */
q = str;
while (*q && !ISSPACE(*q))
q++;
*q = '\0';
return set_search(channel, str);
}
#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \
defined(__OPTIMIZE__) && defined(__unix__) && defined(__i386__)
/* workaround icc 9.1 optimizer issue */
# define vqualifier volatile
#else
# define vqualifier
#endif
static int config_lookup(ares_channel channel, const char *str,
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.
*/
l = lookups;
p = str;
while (*p)
{
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 != ','))
p++;
while (*p && (ISSPACE(*p) || (*p == ',')))
p++;
}
*l = '\0';
channel->lookups = ares_strdup(lookups);
return (channel->lookups) ? ARES_SUCCESS : ARES_ENOMEM;
}
#endif /* !WIN32 & !WATT32 & !ANDROID & !__ANDROID__ & !CARES_USE_LIBRESOLV */
#ifndef WATT32
/* Validate that the ip address matches the subnet (network base and network
* mask) specified. Addresses are specified in standard Network Byte Order as
* 16 bytes, and the netmask is 0 to 128 (bits).
*/
static int ares_ipv6_subnet_matches(const unsigned char netbase[16],
unsigned char netmask,
const unsigned char ipaddr[16])
{
unsigned char mask[16] = { 0 };
unsigned char i;
/* Misuse */
if (netmask > 128)
return 0;
/* Quickly set whole bytes */
memset(mask, 0xFF, netmask / 8);
/* Set remaining bits */
if(netmask % 8) {
mask[netmask / 8] = (unsigned char)(0xff << (8 - (netmask % 8)));
}
for (i=0; i<16; i++) {
if ((netbase[i] & mask[i]) != (ipaddr[i] & mask[i]))
return 0;
}
return 1;
}
/* Return true iff the IPv6 ipaddr is blacklisted. */
static int ares_ipv6_server_blacklisted(const unsigned char ipaddr[16])
{
/* A list of blacklisted IPv6 subnets. */
const struct {
const unsigned char netbase[16];
unsigned char netmask;
} blacklist[] = {
/* fec0::/10 was deprecated by [RFC3879] in September 2004. Formerly a
* Site-Local scoped address prefix. These are never valid DNS servers,
* but are known to be returned at least sometimes on Windows and Android.
*/
{
{
0xfe, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
( run in 0.504 second using v1.01-cache-2.11-cpan-2398b32b56e )