Newer
Older
/* Copyright 1998 by the Massachusetts Institute of Technology.
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting
* documentation, and that the name of M.I.T. not be used in
* advertising or publicity pertaining to distribution of the
* software without specific, written prior permission.
* M.I.T. makes no representations about the suitability of
* this software for any purpose. It is provided "as is"
* without express or implied warranty.
*/
#include "setup.h"
#if defined(WIN32) && !defined(WATT32)
#include <iphlpapi.h>
#include <malloc.h>
#ifdef HAVE_SYS_PARAM_H
#endif
#ifdef HAVE_SYS_TIME_H
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <arpa/nameser.h>
Daniel Stenberg
committed
#ifdef HAVE_ARPA_NAMESER_COMPAT_H
#include <arpa/nameser_compat.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_PROCESS_H
#include <process.h> /* Some have getpid() here */
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <errno.h>
#include "ares.h"
#include "ares_private.h"
#include "inet_net_pton.h"
#ifdef WATT32
#undef WIN32 /* Redefined in MingW/MSVC headers */
#endif
Daniel Stenberg
committed
static int init_by_options(ares_channel channel, const struct ares_options *options,
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);
static int config_nameserver(struct server_state **servers, int *nservers,
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 void init_id_key(rc4_key* key,int key_data_len);
static int sortlist_alloc(struct apattern **sortlist, int *nsort, struct apattern *pat);
static int ip_addr(const char *s, int len, struct in_addr *addr);
static void natural_mask(struct apattern *pat);
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);
static char *try_config(char *s, const char *opt);
#endif
Daniel Stenberg
committed
#define ARES_CONFIG_CHECK(x) (x->lookups && x->nsort > -1 && \
x->nservers > -1 && \
Daniel Stenberg
committed
x->ndomains > -1 && \
x->ndots > -1 && x->timeout > -1 && \
x->tries > -1)
Daniel Stenberg
committed
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 i;
int status = ARES_SUCCESS;
struct server_state *server;
#ifdef CURLDEBUG
const char *env = getenv("CARES_MEMDEBUG");
if (env)
curl_memdebug(env);
env = getenv("CARES_MEMLIMIT");
if (env)
curl_memlimit(atoi(env));
#endif
channel = malloc(sizeof(struct ares_channeldata));
if (!channel) {
*channelptr = NULL;
/* 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->udp_port = -1;
channel->tcp_port = -1;
Steinar H. Gunderson
committed
channel->socket_send_buffer_size = -1;
channel->socket_receive_buffer_size = -1;
channel->nservers = -1;
channel->ndomains = -1;
channel->nsort = -1;
Steinar H. Gunderson
committed
channel->tcp_connection_generation = 0;
channel->lookups = NULL;
channel->queries = NULL;
Daniel Stenberg
committed
channel->domains = NULL;
channel->sortlist = NULL;
channel->servers = NULL;
Daniel Stenberg
committed
channel->sock_state_cb = NULL;
channel->sock_state_cb_data = NULL;
/* Initialize configuration by each of the four sources, from highest
* 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)));
}
if (status == ARES_SUCCESS) {
status = init_by_resolv_conf(channel);
if (status != ARES_SUCCESS)
DEBUGF(fprintf(stderr, "Error: init_by_resolv_conf failed: %s\n",
ares_strerror(status)));
}
if (status == ARES_SUCCESS) {
status = init_by_defaults(channel);
if (status != ARES_SUCCESS)
DEBUGF(fprintf(stderr, "Error: init_by_defaults failed: %s\n",
ares_strerror(status)));
}
if (status != ARES_SUCCESS)
{
/* Something failed; clean up memory we may have allocated. */
if (channel->servers)
Daniel Stenberg
committed
if (channel->domains)
{
for (i = 0; i < channel->ndomains; i++)
free(channel->domains[i]);
free(channel->domains);
}
Daniel Stenberg
committed
if (channel->sortlist)
free(channel);
return status;
}
/* Trim to one server if ARES_FLAG_PRIMARY is set. */
if ((channel->flags & ARES_FLAG_PRIMARY) && channel->nservers > 1)
channel->nservers = 1;
/* Initialize server states. */
for (i = 0; i < channel->nservers; i++)
{
server = &channel->servers[i];
server->udp_socket = ARES_SOCKET_BAD;
server->tcp_socket = ARES_SOCKET_BAD;
Steinar H. Gunderson
committed
server->tcp_connection_generation = ++channel->tcp_connection_generation;
server->tcp_lenbuf_pos = 0;
server->tcp_buffer = NULL;
server->qhead = NULL;
server->qtail = NULL;
Steinar H. Gunderson
committed
server->is_broken = 0;
init_id_key(&channel->id_key, ARES_ID_KEY_LEN);
channel->next_id = ares__generate_new_id(&channel->id_key);
channel->queries = NULL;
*channelptr = channel;
return ARES_SUCCESS;
}
Daniel Stenberg
committed
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
/* Save options from initialized channel */
int ares_save_options(ares_channel channel, struct ares_options *options,
int *optmask)
{
int i;
/* Zero everything out */
memset(options, 0, sizeof(struct ares_options));
if (!ARES_CONFIG_CHECK(channel))
return ARES_ENODATA;
(*optmask) = (ARES_OPT_FLAGS|ARES_OPT_TIMEOUT|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);
/* Copy easy stuff */
options->flags = channel->flags;
options->timeout = channel->timeout;
options->tries = channel->tries;
options->ndots = channel->ndots;
options->udp_port = channel->udp_port;
options->tcp_port = channel->tcp_port;
options->sock_state_cb = channel->sock_state_cb;
options->sock_state_cb_data = channel->sock_state_cb_data;
/* Copy servers */
Daniel Stenberg
committed
if (channel->nservers) {
options->servers =
malloc(channel->nservers * sizeof(struct server_state));
if (!options->servers && channel->nservers != 0)
return ARES_ENOMEM;
for (i = 0; i < channel->nservers; i++)
options->servers[i] = channel->servers[i].addr;
}
Daniel Stenberg
committed
options->nservers = channel->nservers;
/* copy domains */
Daniel Stenberg
committed
if (channel->ndomains) {
options->domains = malloc(channel->ndomains * sizeof(char *));
if (!options->domains)
Daniel Stenberg
committed
return ARES_ENOMEM;
Daniel Stenberg
committed
for (i = 0; i < channel->ndomains; i++)
{
options->ndomains = i;
options->domains[i] = strdup(channel->domains[i]);
if (!options->domains[i])
return ARES_ENOMEM;
}
Daniel Stenberg
committed
}
options->ndomains = channel->ndomains;
/* copy lookups */
Daniel Stenberg
committed
if (channel->lookups) {
options->lookups = strdup(channel->lookups);
if (!options->lookups && channel->lookups)
return ARES_ENOMEM;
}
Daniel Stenberg
committed
/* copy sortlist */
Daniel Stenberg
committed
if (channel->nsort) {
options->sortlist = malloc(channel->nsort * sizeof(struct apattern));
if (!options->sortlist)
return ARES_ENOMEM;
for (i = 0; i < channel->nsort; i++)
{
memcpy(&(options->sortlist[i]), &(channel->sortlist[i]),
sizeof(struct apattern));
}
Daniel Stenberg
committed
}
options->nsort = channel->nsort;
return ARES_SUCCESS;
}
static int init_by_options(ares_channel channel,
const struct ares_options *options,
{
int i;
/* Easy stuff. */
if ((optmask & ARES_OPT_FLAGS) && channel->flags == -1)
channel->flags = options->flags;
if ((optmask & ARES_OPT_TIMEOUT) && channel->timeout == -1)
channel->timeout = options->timeout;
if ((optmask & ARES_OPT_TRIES) && channel->tries == -1)
channel->tries = options->tries;
if ((optmask & ARES_OPT_NDOTS) && channel->ndots == -1)
channel->ndots = options->ndots;
if ((optmask & ARES_OPT_UDP_PORT) && channel->udp_port == -1)
channel->udp_port = options->udp_port;
if ((optmask & ARES_OPT_TCP_PORT) && channel->tcp_port == -1)
channel->tcp_port = options->tcp_port;
Daniel Stenberg
committed
if ((optmask & ARES_OPT_SOCK_STATE_CB) && channel->sock_state_cb == NULL)
{
channel->sock_state_cb = options->sock_state_cb;
channel->sock_state_cb_data = options->sock_state_cb_data;
}
Steinar H. Gunderson
committed
if ((optmask & ARES_OPT_SOCK_SNDBUF)
&& channel->socket_send_buffer_size == -1)
channel->socket_send_buffer_size = options->socket_send_buffer_size;
if ((optmask & ARES_OPT_SOCK_RCVBUF)
&& channel->socket_receive_buffer_size == -1)
channel->socket_receive_buffer_size = options->socket_receive_buffer_size;
/* Copy the servers, if given. */
if ((optmask & ARES_OPT_SERVERS) && channel->nservers == -1)
{
/* Avoid zero size allocations at any cost */
if (options->nservers > 0)
{
channel->servers =
malloc(options->nservers * sizeof(struct server_state));
if (!channel->servers)
return ARES_ENOMEM;
for (i = 0; i < options->nservers; i++)
channel->servers[i].addr = options->servers[i];
}
channel->nservers = options->nservers;
}
/* Copy the domains, if given. Keep channel->ndomains consistent so
* we can clean up in case of error.
*/
if ((optmask & ARES_OPT_DOMAINS) && channel->ndomains == -1)
{
/* Avoid zero size allocations at any cost */
if (options->ndomains > 0)
{
channel->domains = 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]);
if (!channel->domains[i])
return ARES_ENOMEM;
}
}
channel->ndomains = options->ndomains;
}
/* Set lookups, if given. */
if ((optmask & ARES_OPT_LOOKUPS) && !channel->lookups)
{
channel->lookups = strdup(options->lookups);
if (!channel->lookups)
Daniel Stenberg
committed
/* copy sortlist */
if ((optmask & ARES_OPT_SORTLIST) && channel->nsort == -1)
{
channel->sortlist = malloc(options->nsort * sizeof(struct apattern));
if (!channel->sortlist)
return ARES_ENOMEM;
for (i = 0; i < options->nsort; i++)
{
memcpy(&(channel->sortlist[i]), &(options->sortlist[i]), sizeof(struct apattern));
}
channel->nsort = options->nsort;
}
return ARES_SUCCESS;
}
static int init_by_environment(ares_channel channel)
{
const char *localdomain, *res_options;
int status;
localdomain = getenv("LOCALDOMAIN");
if (localdomain && channel->ndomains == -1)
{
status = set_search(channel, localdomain);
if (status != ARES_SUCCESS)
}
res_options = getenv("RES_OPTIONS");
if (res_options)
{
status = set_options(channel, res_options);
if (status != ARES_SUCCESS)
}
return ARES_SUCCESS;
}
#ifdef WIN32
/*
* Warning: returns a dynamically allocated buffer, the user MUST
* use free() if the function returns 1
*/
static int get_res_nt(HKEY hKey, const char *subkey, char **obuf)
/* Test for the size we need */
int result;
result = RegQueryValueEx(hKey, subkey, 0, NULL, NULL, &size);
if ((result != ERROR_SUCCESS && result != ERROR_MORE_DATA) || !size)
return 0;
*obuf = malloc(size+1);
if (RegQueryValueEx(hKey, subkey, 0, NULL,
(LPBYTE)*obuf, &size) != ERROR_SUCCESS)
{
free(*obuf);
return 0;
}
if (size == 1)
{
free(*obuf);
return 0;
}
return 1;
static int get_res_interfaces_nt(HKEY hKey, const char *subkey, char **obuf)
char enumbuf[39]; /* GUIDs are 38 chars + 1 for NULL */
int idx = 0;
HKEY hVal;
while (RegEnumKeyEx(hKey, idx++, enumbuf, &enum_size, 0,
NULL, NULL, NULL) != ERROR_NO_MORE_ITEMS)
{
enum_size = 39;
if (RegOpenKeyEx(hKey, enumbuf, 0, KEY_QUERY_VALUE, &hVal) !=
ERROR_SUCCESS)
continue;
rc = get_res_nt(hVal, subkey, obuf);
RegCloseKey(hVal);
return 1;
}
return 0;
static int get_iphlpapi_dns_info (char *ret_buf, size_t ret_size)
{
FIXED_INFO *fi = alloca (sizeof(*fi));
DWORD size = sizeof (*fi);
typedef DWORD (WINAPI* get_net_param_func) (FIXED_INFO*, DWORD*);
get_net_param_func GetNetworkParams; /* available only on Win-98/2000+ */
HMODULE handle;
IP_ADDR_STRING *ipAddr;
int i, count = 0;
int debug = 0;
size_t ip_size = sizeof("255.255.255.255,")-1;
size_t left = ret_size;
char *ret = ret_buf;
Daniel Stenberg
committed
HRESULT res;
if (!fi)
return (0);
handle = LoadLibrary ("iphlpapi.dll");
if (!handle)
return (0);
GetNetworkParams = (get_net_param_func) GetProcAddress (handle, "GetNetworkParams");
if (!GetNetworkParams)
goto quit;
Daniel Stenberg
committed
res = (*GetNetworkParams) (fi, &size);
if ((res != ERROR_BUFFER_OVERFLOW) && (res != ERROR_SUCCESS))
goto quit;
fi = alloca (size);
if (!fi || (*GetNetworkParams) (fi, &size) != ERROR_SUCCESS)
goto quit;
if (debug)
{
printf ("Host Name: %s\n", fi->HostName);
printf ("Domain Name: %s\n", fi->DomainName);
printf ("DNS Servers:\n"
" %s (primary)\n", fi->DnsServerList.IpAddress.String);
}
if (strlen(fi->DnsServerList.IpAddress.String) > 0 &&
inet_addr(fi->DnsServerList.IpAddress.String) != INADDR_NONE &&
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
left > ip_size)
{
ret += sprintf (ret, "%s,", fi->DnsServerList.IpAddress.String);
left -= ret - ret_buf;
count++;
}
for (i = 0, ipAddr = fi->DnsServerList.Next; ipAddr && left > ip_size;
ipAddr = ipAddr->Next, i++)
{
if (inet_addr(ipAddr->IpAddress.String) != INADDR_NONE)
{
ret += sprintf (ret, "%s,", ipAddr->IpAddress.String);
left -= ret - ret_buf;
count++;
}
if (debug)
printf (" %s (secondary %d)\n", ipAddr->IpAddress.String, i+1);
}
quit:
if (handle)
FreeLibrary (handle);
if (debug && left <= ip_size)
printf ("Too many nameservers. Truncating to %d addressess", count);
if (ret > ret_buf)
ret[-1] = '\0';
return (count);
}
#endif
static int init_by_resolv_conf(ares_channel channel)
{
char *line = NULL;
struct server_state *servers = NULL;
struct apattern *sortlist = NULL;
#ifdef WIN32
/*
NameServer info via IPHLPAPI (IP helper API):
GetNetworkParams() should be the trusted source for this.
Available in Win-98/2000 and later. If that fail, fall-back to
registry information.
NameServer Registry:
On Windows 9X, the DNS server can be found in:
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\VxD\MSTCP\NameServer
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\NameServer
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\DhcpNameServer
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\{AdapterID}\
NameServer
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\{AdapterID}\
DhcpNameServer
*/
HKEY mykey;
HKEY subkey;
DWORD data_type;
DWORD bytes;
DWORD result;
if (channel->nservers > -1) /* don't override ARES_OPT_SERVER */
return ARES_SUCCESS;
if (get_iphlpapi_dns_info(buf,sizeof(buf)) > 0)
{
status = config_nameserver(&servers, &nservers, buf);
if (status == ARES_SUCCESS)
HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0,
KEY_READ, &mykey
{
RegOpenKeyEx(mykey, "Interfaces", 0,
KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS, &subkey);
if (get_res_nt(mykey, NAMESERVER, &line))
{
status = config_nameserver(&servers, &nservers, line);
free(line);
}
else if (get_res_nt(mykey, DHCPNAMESERVER, &line))
{
status = config_nameserver(&servers, &nservers, line);
free(line);
}
/* Try the interfaces */
else if (get_res_interfaces_nt(subkey, NAMESERVER, &line))
status = config_nameserver(&servers, &nservers, line);
free(line);
}
else if (get_res_interfaces_nt(subkey, DHCPNAMESERVER, &line))
{
status = config_nameserver(&servers, &nservers, line);
free(line);
}
RegCloseKey(subkey);
RegCloseKey(mykey);
}
}
else
{
if (RegOpenKeyEx(
HKEY_LOCAL_MACHINE, WIN_NS_9X, 0,
KEY_READ, &mykey
) == ERROR_SUCCESS)
{
if ((result = RegQueryValueEx(
mykey, NAMESERVER, NULL, &data_type,
NULL, &bytes
result == ERROR_MORE_DATA)
{
if (bytes)
line = (char *)malloc(bytes+1);
if (RegQueryValueEx(mykey, NAMESERVER, NULL, &data_type,
(unsigned char *)line, &bytes) ==
ERROR_SUCCESS)
{
status = config_nameserver(&servers, &nservers, line);
}
free(line);
}
RegCloseKey(mykey);
status = ARES_EOF;
Daniel Stenberg
committed
else
/* Catch the case when all the above checks fail (which happens when there
is no network card or the cable is unplugged) */
status = ARES_EFILE;
#elif defined(__riscos__)
/* Under RISC OS, name servers are listed in the
system variable Inet$Resolvers, space separated. */
line = getenv("Inet$Resolvers");
status = ARES_EOF;
if (line) {
char *resolvers = strdup(line), *pos, *space;
if (!resolvers)
return ARES_ENOMEM;
pos = resolvers;
do {
space = strchr(pos, ' ');
if (space)
*space = '\0';
status = config_nameserver(&servers, &nservers, pos);
if (status != ARES_SUCCESS)
break;
pos = space + 1;
} while (space);
if (status == ARES_SUCCESS)
status = ARES_EOF;
#elif defined(WATT32)
int i;
sock_init();
for (i = 0; def_nameservers[i]; i++)
;
if (i == 0)
return ARES_SUCCESS; /* use localhost DNS server */
nservers = i;
servers = calloc(sizeof(*servers), i);
if (!servers)
return ARES_ENOMEM;
for (i = 0; def_nameservers[i]; i++)
servers[i].addr.s_addr = htonl(def_nameservers[i]);
status = ARES_EOF;
{
char *p;
FILE *fp;
int linesize;
int error;
Daniel Stenberg
committed
/* 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, "r");
if (fp) {
while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS)
{
if ((p = try_config(line, "domain")) && channel->ndomains == -1)
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")) && channel->ndomains == -1)
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) {
status = ARES_EOF;
break;
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;
}
Daniel Stenberg
committed
if ((status == ARES_EOF) && (!channel->lookups)) {
Daniel Stenberg
committed
/* Many systems (Solaris, Linux, BSD's) use nsswitch.conf */
Daniel Stenberg
committed
fp = fopen("/etc/nsswitch.conf", "r");
if (fp) {
while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS)
{
if ((p = try_config(line, "hosts:")) && !channel->lookups)
status = config_lookup(channel, p, "dns", "files");
}
fclose(fp);
}
error = ERRNO;
switch(error) {
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;
}
}
Daniel Stenberg
committed
}
Daniel Stenberg
committed
if ((status == ARES_EOF) && (!channel->lookups)) {
Daniel Stenberg
committed
/* Linux / GNU libc 2.x and possibly others have host.conf */
Daniel Stenberg
committed
fp = fopen("/etc/host.conf", "r");
if (fp) {
while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS)
{
if ((p = try_config(line, "order")) && !channel->lookups)
status = config_lookup(channel, p, "bind", "hosts");
}
fclose(fp);
}
error = ERRNO;
switch(error) {
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;
}
}
Daniel Stenberg
committed
}
if ((status == ARES_EOF) && (!channel->lookups)) {
Daniel Stenberg
committed
/* 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=")) && !channel->lookups)
status = config_lookup(channel, p, "bind", "local");
}
fclose(fp);
}
error = ERRNO;
switch(error) {
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;
}
}
Daniel Stenberg
committed
}
Daniel Stenberg
committed
if(line)
free(line);
}
#endif
/* Handle errors. */
if (status != ARES_EOF)
{
Daniel Stenberg
committed
if (servers != NULL)
free(servers);
if (sortlist != NULL)
free(sortlist);
return status;
}
/* If we got any name server entries, fill them in. */
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
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[MAXHOSTNAMELEN + 1];
if (channel->flags == -1)
channel->flags = 0;
if (channel->timeout == -1)
channel->timeout = DEFAULT_TIMEOUT;
if (channel->tries == -1)
channel->tries = DEFAULT_TRIES;
if (channel->ndots == -1)
channel->ndots = 1;
if (channel->udp_port == -1)
channel->udp_port = htons(NAMESERVER_PORT);
if (channel->tcp_port == -1)
channel->tcp_port = htons(NAMESERVER_PORT);
if (channel->nservers == -1)
{
/* If nobody specified servers, try a local named. */
channel->servers = malloc(sizeof(struct server_state));
if (!channel->servers)
channel->servers[0].addr.s_addr = htonl(INADDR_LOOPBACK);
channel->nservers = 1;
}
if (channel->ndomains == -1)
{
/* Derive a default domain search list from the kernel hostname,
* or set it to empty if the hostname isn't helpful.
*/
if (gethostname(hostname, sizeof(hostname)) == -1
|| !strchr(hostname, '.'))
{
channel->ndomains = 0;
}
{
channel->domains = malloc(sizeof(char *));
if (!channel->domains)
return ARES_ENOMEM;
channel->ndomains = 0;
channel->domains[0] = strdup(strchr(hostname, '.') + 1);
if (!channel->domains[0])
return ARES_ENOMEM;
channel->ndomains = 1;
}
}
if (channel->nsort == -1)
{
channel->sortlist = NULL;
channel->nsort = 0;
}
if (!channel->lookups)
{
Daniel Stenberg
committed
channel->lookups = strdup("fb");
}
return ARES_SUCCESS;
}
#ifndef WIN32
static int config_domain(ares_channel channel, char *str)
{
char *q;
/* Set a single search domain. */
q = str;
return set_search(channel, str);
}
Daniel Stenberg
committed
static int config_lookup(ares_channel channel, const char *str,
const char *bindch, const char *filech)
{
char lookups[3], *l;
const char *p;
/* 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)
{
Daniel Stenberg
committed
if ((*p == *bindch || *p == *filech) && l < lookups + 2) {
Daniel Stenberg
committed
else *l++ = 'f';
}
while (*p && !ISSPACE(*p) && (*p != ','))
while (*p && (ISSPACE(*p) || (*p == ',')))
channel->lookups = strdup(lookups);
return (channel->lookups) ? ARES_SUCCESS : ARES_ENOMEM;
}
#endif
static int config_nameserver(struct server_state **servers, int *nservers,
{
struct in_addr addr;
struct server_state *newserv;
/* On Windows, there may be more than one nameserver specified in the same
* registry key, so we parse it as a space or comma seperated list.
*/
#ifdef WIN32