Newer
Older
Daniel Stenberg
committed
goto error;
Daniel Stenberg
committed
channel->servers[0].addr.s_addr = htonl(INADDR_LOOPBACK);
channel->nservers = 1;
}
Daniel Stenberg
committed
#ifdef ENAMETOOLONG
#define toolong(x) (x == -1) && ((ENAMETOOLONG == errno) || (EINVAL == errno))
#else
#define toolong(x) (x == -1) && (EINVAL == errno)
#endif
Daniel Stenberg
committed
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.
*/
size_t len = 64;
int res;
channel->ndomains = 0; /* default to none */
Daniel Stenberg
committed
#ifdef HAVE_GETHOSTNAME
Daniel Stenberg
committed
if(!hostname) {
rc = ARES_ENOMEM;
goto error;
Daniel Stenberg
committed
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
do {
res = gethostname(hostname, len);
if(toolong(res)) {
char *p;
len *= 2;
p = realloc(hostname, len);
if(!p) {
rc = ARES_ENOMEM;
goto error;
}
hostname = p;
continue;
}
else if(res) {
rc = ARES_EBADNAME;
goto error;
}
} while(0);
if (strchr(hostname, '.')) {
/* a dot was found */
channel->domains = malloc(sizeof(char *));
if (!channel->domains) {
rc = ARES_ENOMEM;
goto error;
}
channel->domains[0] = strdup(strchr(hostname, '.') + 1);
if (!channel->domains[0]) {
rc = ARES_ENOMEM;
goto error;
}
channel->ndomains = 1;
Daniel Stenberg
committed
}
Daniel Stenberg
committed
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
if (channel->nsort == -1) {
channel->sortlist = NULL;
channel->nsort = 0;
}
if (!channel->lookups) {
channel->lookups = strdup("fb");
if (!channel->lookups)
rc = ARES_ENOMEM;
}
error:
if(rc) {
if(channel->servers)
free(channel->servers);
if(channel->domains && channel->domains[0])
free(channel->domains[0]);
if(channel->domains)
free(channel->domains);
if(channel->lookups)
free(channel->lookups);
}
if(hostname)
free(hostname);
return rc;
#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
char *p = str;
char *begin = str;
int more = 1;
while (more)
{
more = 0;
while (*p && !ISSPACE(*p) && *p != ',')
p++;
if (*p)
{
more = 1;
}
/* Skip multiple spaces or trailing spaces */
if (!*begin)
{
begin = ++p;
continue;
}
/* This is the part that actually sets the nameserver */
addr.s_addr = inet_addr(begin);
if (addr.s_addr == INADDR_NONE)
continue;
newserv = realloc(*servers, (*nservers + 1) * sizeof(struct server_state));
if (!newserv)
return ARES_ENOMEM;
newserv[*nservers].addr = addr;
*servers = newserv;
(*nservers)++;
if (!more)
break;
begin = ++p;
}
#else
/* Add a nameserver entry, if this is a valid address. */
addr.s_addr = inet_addr(str);
if (addr.s_addr == INADDR_NONE)
return ARES_SUCCESS;
newserv = realloc(*servers, (*nservers + 1) * sizeof(struct server_state));
if (!newserv)
return ARES_ENOMEM;
newserv[*nservers].addr = addr;
*servers = newserv;
(*nservers)++;
#endif
return ARES_SUCCESS;
}
#ifndef WIN32
static int config_sortlist(struct apattern **sortlist, int *nsort,
struct apattern pat;
const char *q;
/* Add sortlist entries. */
while (*str && *str != ';')
{
int bits;
char ipbuf[16], ipbufpfx[32];
/* Find just the IP */
while (*q && *q != '/' && *q != ';' && !ISSPACE(*q))
memcpy(ipbuf, str, (int)(q-str));
ipbuf[(int)(q-str)] = '\0';
/* Find the prefix */
if (*q == '/')
{
const char *str2 = q+1;
while (*q && *q != ';' && !ISSPACE(*q))
q++;
memcpy(ipbufpfx, str, (int)(q-str));
ipbufpfx[(int)(q-str)] = '\0';
str = str2;
}
else
ipbufpfx[0] = '\0';
/* Lets see if it is CIDR */
/* First we'll try IPv6 */
if ((bits = ares_inet_net_pton(AF_INET6, ipbufpfx[0] ? ipbufpfx : ipbuf,
&pat.addrV6,
sizeof(pat.addrV6))) > 0)
{
pat.type = PATTERN_CIDR;
pat.family = AF_INET6;
if (!sortlist_alloc(sortlist, nsort, &pat))
return ARES_ENOMEM;
}
if (ipbufpfx[0] &&
(bits = ares_inet_net_pton(AF_INET, ipbufpfx, &pat.addrV4,
sizeof(pat.addrV4))) > 0)
{
pat.type = PATTERN_CIDR;
pat.family = AF_INET;
if (!sortlist_alloc(sortlist, nsort, &pat))
return ARES_ENOMEM;
}
/* See if it is just a regular IP */
else if (ip_addr(ipbuf, (int)(q-str), &pat.addrV4) == 0)
if (ipbufpfx[0])
memcpy(ipbuf, str, (int)(q-str));
ipbuf[(int)(q-str)] = '\0';
if (ip_addr(ipbuf, (int)(q - str), &pat.mask.addr4) != 0)
natural_mask(&pat);
}
else
natural_mask(&pat);
pat.family = AF_INET;
pat.type = PATTERN_MASK;
if (!sortlist_alloc(sortlist, nsort, &pat))
while (*q && *q != ';' && !ISSPACE(*q))
}
return ARES_SUCCESS;
}
#endif
static int set_search(ares_channel channel, const char *str)
{
int n;
const char *p, *q;
Daniel Stenberg
committed
if(channel->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);
channel->domains = NULL;
Daniel Stenberg
committed
channel->ndomains = -1;
}
/* Count the domains given. */
n = 0;
p = str;
while (*p)
{
if (!n)
{
channel->ndomains = 0;
return ARES_SUCCESS;
}
channel->domains = malloc(n * sizeof(char *));
if (!channel->domains)
return ARES_ENOMEM;
/* Now copy the domains. */
n = 0;
p = str;
while (*p)
{
channel->ndomains = n;
q = p;
channel->domains[n] = malloc(q - p + 1);
if (!channel->domains[n])
memcpy(channel->domains[n], p, q - p);
channel->domains[n][q - p] = 0;
p = q;
n++;
}
channel->ndomains = n;
return ARES_SUCCESS;
}
static int set_options(ares_channel channel, const char *str)
{
const char *p, *q, *val;
p = str;
while (*p)
{
q = p;
val = try_option(p, q, "ndots:");
if (val && channel->ndots == -1)
val = try_option(p, q, "retrans:");
if (val && channel->timeout == -1)
val = try_option(p, q, "retry:");
if (val && channel->tries == -1)
Daniel Stenberg
committed
val = try_option(p, q, "rotate");
if (val && channel->rotate == -1)
channel->rotate = 1;
}
return ARES_SUCCESS;
}
#ifndef WIN32
static char *try_config(char *s, const char *opt)
ssize_t i;
ssize_t j;
char *p;
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
if (!s || !opt)
/* no line or no option */
return NULL;
/* trim line comment */
for (i = 0; s[i] && s[i] != '#'; ++i);
s[i] = '\0';
/* trim trailing whitespace */
for (j = i-1; j >= 0 && ISSPACE(s[j]); --j);
s[++j] = '\0';
/* skip leading whitespace */
for (i = 0; s[i] && ISSPACE(s[i]); ++i);
p = &s[i];
if (!*p)
/* empty line */
return NULL;
if ((len = strlen(opt)) == 0)
/* empty option */
return NULL;
if (strncmp(p, opt, len) != 0)
/* line and option do not match */
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
/* skip over given option name */
p += len;
if (!*p)
/* no option value */
return NULL;
if ((opt[len-1] != ':') && (opt[len-1] != '=') && !ISSPACE(*p))
/* whitespace between option name and value is mandatory
for given option names which do not end with ':' or '=' */
return NULL;
/* skip over whitespace */
while (*p && ISSPACE(*p))
p++;
if (!*p)
/* no option value */
return NULL;
/* return pointer to option value */
return p;
}
#endif
static const char *try_option(const char *p, const char *q, const char *opt)
{
size_t len = strlen(opt);
Daniel Stenberg
committed
return ((size_t)(q - p) >= len && !strncmp(p, opt, len)) ? &p[len] : NULL;
Daniel Stenberg
committed
#ifndef WIN32
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;
}
static int ip_addr(const char *ipbuf, int len, struct in_addr *addr)
{
/* Four octets and three periods yields at most 15 characters. */
if (len > 15)
return -1;
addr->s_addr = inet_addr(ipbuf);
if (addr->s_addr == INADDR_NONE && strcmp(ipbuf, "255.255.255.255") != 0)
return -1;
return 0;
}
static void natural_mask(struct apattern *pat)
{
struct in_addr addr;
/* Store a host-byte-order copy of pat in a struct in_addr. Icky,
* but portable.
*/
addr.s_addr = ntohl(pat->addrV4.s_addr);
/* This is out of date in the CIDR world, but some people might
* still rely on it.
*/
if (IN_CLASSA(addr.s_addr))
pat->mask.addr4.s_addr = htonl(IN_CLASSA_NET);
else if (IN_CLASSB(addr.s_addr))
pat->mask.addr4.s_addr = htonl(IN_CLASSB_NET);
pat->mask.addr4.s_addr = htonl(IN_CLASSC_NET);
/* initialize an rc4 key. If possible a cryptographically secure random key
is generated using a suitable function (for example win32's RtlGenRandom as
described in
http://blogs.msdn.com/michael_howard/archive/2005/01/14/353379.aspx
otherwise the code defaults to cross-platform albeit less secure mechanism
using rand
*/
static void randomize_key(unsigned char* key,int key_data_len)
{
int randomized = 0;
Daniel Stenberg
committed
int counter=0;
#ifdef WIN32
HMODULE lib=LoadLibrary("ADVAPI32.DLL");
if (lib) {
BOOLEAN (APIENTRY *pfn)(void*, ULONG) =
(BOOLEAN (APIENTRY *)(void*,ULONG))GetProcAddress(lib,"SystemFunction036");
if (pfn && pfn(key,key_data_len) )
randomized = 1;
FreeLibrary(lib);
}
Daniel Stenberg
committed
#else /* !WIN32 */
#ifdef RANDOM_FILE
FILE *f = fopen(RANDOM_FILE, "rb");
if(f) {
Daniel Stenberg
committed
counter = fread(key, 1, key_data_len, f);
Daniel Stenberg
committed
fclose(f);
}
#endif
Daniel Stenberg
committed
#endif /* WIN32 */
if ( !randomized ) {
Daniel Stenberg
committed
for (;counter<key_data_len;counter++)
key[counter]=(unsigned char)(rand() % 256);
}
}
static int init_id_key(rc4_key* key,int key_data_len)
{
unsigned char index1;
unsigned char index2;
unsigned char* state;
short counter;
unsigned char *key_data_ptr = 0;
key_data_ptr = calloc(1,key_data_len);
if (!key_data_ptr)
return ARES_ENOMEM;
state = &key->state[0];
for(counter = 0; counter < 256; counter++)
/* unnecessary AND but it keeps some compilers happier */
state[counter] = (unsigned char)(counter & 0xff);
key->x = 0;
key->y = 0;
index1 = 0;
index2 = 0;
for(counter = 0; counter < 256; counter++)
{
index2 = (unsigned char)((key_data_ptr[index1] + state[counter] +
index2) % 256);
ARES_SWAP_BYTE(&state[counter], &state[index2]);
index1 = (unsigned char)((index1 + 1) % key_data_len);
}
free(key_data_ptr);
return ARES_SUCCESS;
}
unsigned short ares__generate_new_id(rc4_key* key)
unsigned short r=0;
ares__rc4(key, (unsigned char *)&r, sizeof(r));
return r;
}
Daniel Stenberg
committed
void ares_set_socket_callback(ares_channel channel,
ares_sock_create_callback cb,
void *data)
{
channel->sock_create_cb = cb;
channel->sock_create_cb_data = data;
}