Newer
Older
Daniel Stenberg
committed
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
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.addr.addr6,
sizeof(pat.addr.addr6))) > 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.addr.addr4,
sizeof(pat.addr.addr4))) > 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.addr.addr4) == 0)
if (ipbufpfx[0])
memcpy(ipbuf, str, (int)(q-str));
ipbuf[(int)(q-str)] = '\0';
if (ip_addr(ipbuf, (int)(q - str), &pat.mask.addr.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)
}
return ARES_SUCCESS;
}
#ifndef WIN32
static char *try_config(char *s, const char *opt)
ssize_t i;
ssize_t j;
char *p;
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
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 */
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
/* 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);
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->addr.addr4.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.addr.addr4.s_addr = htonl(IN_CLASSA_NET);
else if (IN_CLASSB(addr.s_addr))
pat->mask.addr.addr4.s_addr = htonl(IN_CLASSB_NET);
pat->mask.addr.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;
randomize_key(key->state,key_data_len);
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;
}
short ares__generate_new_id(rc4_key* key)
{
ares__rc4(key, (unsigned char *)&r, sizeof(r));
return r;
}