avoid use of alloca()
[platform/upstream/c-ares.git] / ares_init.c
1 /* $Id$ */
2
3 /* Copyright 1998 by the Massachusetts Institute of Technology.
4  * Copyright (C) 2007-2009 by Daniel Stenberg
5  *
6  * Permission to use, copy, modify, and distribute this
7  * software and its documentation for any purpose and without
8  * fee is hereby granted, provided that the above copyright
9  * notice appear in all copies and that both that copyright
10  * notice and this permission notice appear in supporting
11  * documentation, and that the name of M.I.T. not be used in
12  * advertising or publicity pertaining to distribution of the
13  * software without specific, written prior permission.
14  * M.I.T. makes no representations about the suitability of
15  * this software for any purpose.  It is provided "as is"
16  * without express or implied warranty.
17  */
18
19 #include "setup.h"
20
21 #if defined(WIN32) && !defined(WATT32)
22 #include <iphlpapi.h>
23 #endif
24
25 #ifdef HAVE_SYS_PARAM_H
26 #include <sys/param.h>
27 #endif
28
29 #ifdef HAVE_SYS_TIME_H
30 #include <sys/time.h>
31 #endif
32
33 #ifdef HAVE_SYS_SOCKET_H
34 #include <sys/socket.h>
35 #endif
36
37 #ifdef HAVE_NETINET_IN_H
38 #include <netinet/in.h>
39 #endif
40
41 #ifdef HAVE_NETDB_H
42 #include <netdb.h>
43 #endif
44
45 #ifdef HAVE_ARPA_INET_H
46 #include <arpa/inet.h>
47 #endif
48
49 #ifdef HAVE_ARPA_NAMESER_H
50 #  include <arpa/nameser.h>
51 #else
52 #  include "nameser.h"
53 #endif
54 #ifdef HAVE_ARPA_NAMESER_COMPAT_H
55 #  include <arpa/nameser_compat.h>
56 #endif
57
58 #ifdef HAVE_UNISTD_H
59 #include <unistd.h>
60 #endif
61
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <string.h>
65 #include <ctype.h>
66 #include <time.h>
67 #include <errno.h>
68 #include "ares.h"
69 #include "inet_net_pton.h"
70 #include "ares_private.h"
71
72 #ifdef WATT32
73 #undef WIN32  /* Redefined in MingW/MSVC headers */
74 #endif
75
76 static int init_by_options(ares_channel channel, const struct ares_options *options,
77                            int optmask);
78 static int init_by_environment(ares_channel channel);
79 static int init_by_resolv_conf(ares_channel channel);
80 static int init_by_defaults(ares_channel channel);
81
82 static int config_nameserver(struct server_state **servers, int *nservers,
83                              char *str);
84 static int set_search(ares_channel channel, const char *str);
85 static int set_options(ares_channel channel, const char *str);
86 static const char *try_option(const char *p, const char *q, const char *opt);
87 static int init_id_key(rc4_key* key,int key_data_len);
88
89 #ifndef WIN32
90 static int sortlist_alloc(struct apattern **sortlist, int *nsort, struct apattern *pat);
91 static int ip_addr(const char *s, int len, struct in_addr *addr);
92 static void natural_mask(struct apattern *pat);
93 static int config_domain(ares_channel channel, char *str);
94 static int config_lookup(ares_channel channel, const char *str,
95                          const char *bindch, const char *filech);
96 static int config_sortlist(struct apattern **sortlist, int *nsort,
97                            const char *str);
98 static char *try_config(char *s, const char *opt);
99 #endif
100
101 #define ARES_CONFIG_CHECK(x) (x->lookups && x->nsort > -1 && \
102                              x->nservers > -1 && \
103                              x->ndomains > -1 && \
104                              x->ndots > -1 && x->timeout > -1 && \
105                              x->tries > -1)
106
107 int ares_init(ares_channel *channelptr)
108 {
109   return ares_init_options(channelptr, NULL, 0);
110 }
111
112 int ares_init_options(ares_channel *channelptr, struct ares_options *options,
113                       int optmask)
114 {
115   ares_channel channel;
116   int i;
117   int status = ARES_SUCCESS;
118   struct server_state *server;
119   struct timeval now;
120
121 #ifdef CURLDEBUG
122   const char *env = getenv("CARES_MEMDEBUG");
123
124   if (env)
125     curl_memdebug(env);
126   env = getenv("CARES_MEMLIMIT");
127   if (env)
128     curl_memlimit(atoi(env));
129 #endif
130
131   channel = malloc(sizeof(struct ares_channeldata));
132   if (!channel) {
133     *channelptr = NULL;
134     return ARES_ENOMEM;
135   }
136
137   now = ares__tvnow();
138
139   /* Set everything to distinguished values so we know they haven't
140    * been set yet.
141    */
142   channel->flags = -1;
143   channel->timeout = -1;
144   channel->tries = -1;
145   channel->ndots = -1;
146   channel->rotate = -1;
147   channel->udp_port = -1;
148   channel->tcp_port = -1;
149   channel->socket_send_buffer_size = -1;
150   channel->socket_receive_buffer_size = -1;
151   channel->nservers = -1;
152   channel->ndomains = -1;
153   channel->nsort = -1;
154   channel->tcp_connection_generation = 0;
155   channel->lookups = NULL;
156   channel->domains = NULL;
157   channel->sortlist = NULL;
158   channel->servers = NULL;
159   channel->sock_state_cb = NULL;
160   channel->sock_state_cb_data = NULL;
161   channel->sock_create_cb = NULL;
162   channel->sock_create_cb_data = NULL;
163
164   channel->last_server = 0;
165   channel->last_timeout_processed = (time_t)now.tv_sec;
166
167   /* Initialize our lists of queries */
168   ares__init_list_head(&(channel->all_queries));
169   for (i = 0; i < ARES_QID_TABLE_SIZE; i++)
170     {
171       ares__init_list_head(&(channel->queries_by_qid[i]));
172     }
173   for (i = 0; i < ARES_TIMEOUT_TABLE_SIZE; i++)
174     {
175       ares__init_list_head(&(channel->queries_by_timeout[i]));
176     }
177
178   /* Initialize configuration by each of the four sources, from highest
179    * precedence to lowest.
180    */
181
182   if (status == ARES_SUCCESS) {
183     status = init_by_options(channel, options, optmask);
184     if (status != ARES_SUCCESS)
185       DEBUGF(fprintf(stderr, "Error: init_by_options failed: %s\n",
186                      ares_strerror(status)));
187   }
188   if (status == ARES_SUCCESS) {
189     status = init_by_environment(channel);
190     if (status != ARES_SUCCESS)
191       DEBUGF(fprintf(stderr, "Error: init_by_environment failed: %s\n",
192                      ares_strerror(status)));
193   }
194   if (status == ARES_SUCCESS) {
195     status = init_by_resolv_conf(channel);
196     if (status != ARES_SUCCESS)
197       DEBUGF(fprintf(stderr, "Error: init_by_resolv_conf failed: %s\n",
198                      ares_strerror(status)));
199   }
200   if (status == ARES_SUCCESS) {
201     status = init_by_defaults(channel);
202     if (status != ARES_SUCCESS)
203       DEBUGF(fprintf(stderr, "Error: init_by_defaults failed: %s\n",
204                      ares_strerror(status)));
205   }
206
207   /* Generate random key */
208
209   if (status == ARES_SUCCESS) {
210     status = init_id_key(&channel->id_key, ARES_ID_KEY_LEN);
211     if (status == ARES_SUCCESS)
212       channel->next_id = ares__generate_new_id(&channel->id_key);
213     else
214       DEBUGF(fprintf(stderr, "Error: init_id_key failed: %s\n",
215                      ares_strerror(status)));
216   }
217
218   if (status != ARES_SUCCESS)
219     {
220       /* Something failed; clean up memory we may have allocated. */
221       if (channel->servers)
222         free(channel->servers);
223       if (channel->domains)
224         {
225           for (i = 0; i < channel->ndomains; i++)
226             free(channel->domains[i]);
227           free(channel->domains);
228         }
229       if (channel->sortlist)
230         free(channel->sortlist);
231       if(channel->lookups)
232         free(channel->lookups);
233       free(channel);
234       return status;
235     }
236
237   /* Trim to one server if ARES_FLAG_PRIMARY is set. */
238   if ((channel->flags & ARES_FLAG_PRIMARY) && channel->nservers > 1)
239     channel->nservers = 1;
240
241   /* Initialize server states. */
242   for (i = 0; i < channel->nservers; i++)
243     {
244       server = &channel->servers[i];
245       server->udp_socket = ARES_SOCKET_BAD;
246       server->tcp_socket = ARES_SOCKET_BAD;
247       server->tcp_connection_generation = ++channel->tcp_connection_generation;
248       server->tcp_lenbuf_pos = 0;
249       server->tcp_buffer = NULL;
250       server->qhead = NULL;
251       server->qtail = NULL;
252       ares__init_list_head(&(server->queries_to_server));
253       server->channel = channel;
254       server->is_broken = 0;
255     }
256
257   *channelptr = channel;
258   return ARES_SUCCESS;
259 }
260
261 /* ares_dup() duplicates a channel handle with all its options and returns a
262    new channel handle */
263 int ares_dup(ares_channel *dest, ares_channel src)
264 {
265   struct ares_options opts;
266   int rc;
267   int optmask;
268
269   *dest = NULL; /* in case of failure return NULL explicitly */
270
271   /* First get the options supported by the old ares_save_options() function,
272      which is most of them */
273   rc = ares_save_options(src, &opts, &optmask);
274   if(rc)
275     return rc;
276
277   /* Then create the new channel with those options */
278   rc = ares_init_options(dest, &opts, optmask);
279
280   /* destroy the options copy to not leak any memory */
281   ares_destroy_options(&opts);
282
283   if(rc)
284     return rc;
285
286   /* Now clone the options that ares_save_options() doesn't support. */
287   (*dest)->sock_create_cb      = src->sock_create_cb;
288   (*dest)->sock_create_cb_data = src->sock_create_cb_data;
289
290
291   return ARES_SUCCESS; /* everything went fine */
292
293 }
294
295 /* Save options from initialized channel */
296 int ares_save_options(ares_channel channel, struct ares_options *options,
297                       int *optmask)
298 {
299   int i;
300
301   /* Zero everything out */
302   memset(options, 0, sizeof(struct ares_options));
303
304   if (!ARES_CONFIG_CHECK(channel))
305     return ARES_ENODATA;
306
307   /* Traditionally the optmask wasn't saved in the channel struct so it was
308      recreated here. ROTATE is the first option that has no struct field of
309      its own in the public config struct */
310   (*optmask) = (ARES_OPT_FLAGS|ARES_OPT_TRIES|ARES_OPT_NDOTS|
311                 ARES_OPT_UDP_PORT|ARES_OPT_TCP_PORT|ARES_OPT_SOCK_STATE_CB|
312                 ARES_OPT_SERVERS|ARES_OPT_DOMAINS|ARES_OPT_LOOKUPS|
313                 ARES_OPT_SORTLIST|ARES_OPT_TIMEOUTMS) |
314     (channel->optmask & ARES_OPT_ROTATE);
315
316   /* Copy easy stuff */
317   options->flags   = channel->flags;
318
319   /* We return full millisecond resolution but that's only because we don't
320      set the ARES_OPT_TIMEOUT anymore, only the new ARES_OPT_TIMEOUTMS */
321   options->timeout = channel->timeout;
322   options->tries   = channel->tries;
323   options->ndots   = channel->ndots;
324   options->udp_port = (unsigned short)channel->udp_port;
325   options->tcp_port = (unsigned short)channel->tcp_port;
326   options->sock_state_cb     = channel->sock_state_cb;
327   options->sock_state_cb_data = channel->sock_state_cb_data;
328
329   /* Copy servers */
330   if (channel->nservers) {
331     options->servers =
332       malloc(channel->nservers * sizeof(struct server_state));
333     if (!options->servers && channel->nservers != 0)
334       return ARES_ENOMEM;
335     for (i = 0; i < channel->nservers; i++)
336       options->servers[i] = channel->servers[i].addr;
337   }
338   options->nservers = channel->nservers;
339
340   /* copy domains */
341   if (channel->ndomains) {
342     options->domains = malloc(channel->ndomains * sizeof(char *));
343     if (!options->domains)
344       return ARES_ENOMEM;
345
346     for (i = 0; i < channel->ndomains; i++)
347     {
348       options->ndomains = i;
349       options->domains[i] = strdup(channel->domains[i]);
350       if (!options->domains[i])
351         return ARES_ENOMEM;
352     }
353   }
354   options->ndomains = channel->ndomains;
355
356   /* copy lookups */
357   if (channel->lookups) {
358     options->lookups = strdup(channel->lookups);
359     if (!options->lookups && channel->lookups)
360       return ARES_ENOMEM;
361   }
362
363   /* copy sortlist */
364   if (channel->nsort) {
365     options->sortlist = malloc(channel->nsort * sizeof(struct apattern));
366     if (!options->sortlist)
367       return ARES_ENOMEM;
368     for (i = 0; i < channel->nsort; i++)
369     {
370       memcpy(&(options->sortlist[i]), &(channel->sortlist[i]),
371              sizeof(struct apattern));
372     }
373   }
374   options->nsort = channel->nsort;
375
376   return ARES_SUCCESS;
377 }
378
379 static int init_by_options(ares_channel channel,
380                            const struct ares_options *options,
381                            int optmask)
382 {
383   int i;
384
385   /* Easy stuff. */
386   if ((optmask & ARES_OPT_FLAGS) && channel->flags == -1)
387     channel->flags = options->flags;
388   if ((optmask & ARES_OPT_TIMEOUTMS) && channel->timeout == -1)
389     channel->timeout = options->timeout;
390   else if ((optmask & ARES_OPT_TIMEOUT) && channel->timeout == -1)
391     channel->timeout = options->timeout * 1000;
392   if ((optmask & ARES_OPT_TRIES) && channel->tries == -1)
393     channel->tries = options->tries;
394   if ((optmask & ARES_OPT_NDOTS) && channel->ndots == -1)
395     channel->ndots = options->ndots;
396   if ((optmask & ARES_OPT_ROTATE) && channel->rotate == -1)
397     channel->rotate = 1;
398   if ((optmask & ARES_OPT_UDP_PORT) && channel->udp_port == -1)
399     channel->udp_port = options->udp_port;
400   if ((optmask & ARES_OPT_TCP_PORT) && channel->tcp_port == -1)
401     channel->tcp_port = options->tcp_port;
402   if ((optmask & ARES_OPT_SOCK_STATE_CB) && channel->sock_state_cb == NULL)
403     {
404       channel->sock_state_cb = options->sock_state_cb;
405       channel->sock_state_cb_data = options->sock_state_cb_data;
406     }
407   if ((optmask & ARES_OPT_SOCK_SNDBUF)
408       && channel->socket_send_buffer_size == -1)
409     channel->socket_send_buffer_size = options->socket_send_buffer_size;
410   if ((optmask & ARES_OPT_SOCK_RCVBUF)
411       && channel->socket_receive_buffer_size == -1)
412     channel->socket_receive_buffer_size = options->socket_receive_buffer_size;
413
414   /* Copy the servers, if given. */
415   if ((optmask & ARES_OPT_SERVERS) && channel->nservers == -1)
416     {
417       /* Avoid zero size allocations at any cost */
418       if (options->nservers > 0)
419         {
420           channel->servers =
421             malloc(options->nservers * sizeof(struct server_state));
422           if (!channel->servers)
423             return ARES_ENOMEM;
424           for (i = 0; i < options->nservers; i++)
425             channel->servers[i].addr = options->servers[i];
426         }
427       channel->nservers = options->nservers;
428     }
429
430   /* Copy the domains, if given.  Keep channel->ndomains consistent so
431    * we can clean up in case of error.
432    */
433   if ((optmask & ARES_OPT_DOMAINS) && channel->ndomains == -1)
434     {
435       /* Avoid zero size allocations at any cost */
436       if (options->ndomains > 0)
437       {
438         channel->domains = malloc(options->ndomains * sizeof(char *));
439         if (!channel->domains)
440           return ARES_ENOMEM;
441         for (i = 0; i < options->ndomains; i++)
442           {
443             channel->ndomains = i;
444             channel->domains[i] = strdup(options->domains[i]);
445             if (!channel->domains[i])
446               return ARES_ENOMEM;
447           }
448       }
449       channel->ndomains = options->ndomains;
450     }
451
452   /* Set lookups, if given. */
453   if ((optmask & ARES_OPT_LOOKUPS) && !channel->lookups)
454     {
455       channel->lookups = strdup(options->lookups);
456       if (!channel->lookups)
457         return ARES_ENOMEM;
458     }
459
460   /* copy sortlist */
461   if ((optmask & ARES_OPT_SORTLIST) && channel->nsort == -1)
462     {
463       channel->sortlist = malloc(options->nsort * sizeof(struct apattern));
464       if (!channel->sortlist)
465         return ARES_ENOMEM;
466       for (i = 0; i < options->nsort; i++)
467         {
468           memcpy(&(channel->sortlist[i]), &(options->sortlist[i]),
469                  sizeof(struct apattern));
470         }
471       channel->nsort = options->nsort;
472     }
473
474   channel->optmask = optmask;
475
476   return ARES_SUCCESS;
477 }
478
479 static int init_by_environment(ares_channel channel)
480 {
481   const char *localdomain, *res_options;
482   int status;
483
484   localdomain = getenv("LOCALDOMAIN");
485   if (localdomain && channel->ndomains == -1)
486     {
487       status = set_search(channel, localdomain);
488       if (status != ARES_SUCCESS)
489         return status;
490     }
491
492   res_options = getenv("RES_OPTIONS");
493   if (res_options)
494     {
495       status = set_options(channel, res_options);
496       if (status != ARES_SUCCESS)
497         return status;
498     }
499
500   return ARES_SUCCESS;
501 }
502
503 #ifdef WIN32
504 /*
505  * Warning: returns a dynamically allocated buffer, the user MUST
506  * use free() if the function returns 1
507  */
508 static int get_res_nt(HKEY hKey, const char *subkey, char **obuf)
509 {
510   /* Test for the size we need */
511   DWORD size = 0;
512   int result;
513
514   result = RegQueryValueEx(hKey, subkey, 0, NULL, NULL, &size);
515   if ((result != ERROR_SUCCESS && result != ERROR_MORE_DATA) || !size)
516     return 0;
517   *obuf = malloc(size+1);
518   if (!*obuf)
519     return 0;
520
521   if (RegQueryValueEx(hKey, subkey, 0, NULL,
522                       (LPBYTE)*obuf, &size) != ERROR_SUCCESS)
523   {
524     free(*obuf);
525     return 0;
526   }
527   if (size == 1)
528   {
529     free(*obuf);
530     return 0;
531   }
532   return 1;
533 }
534
535 static int get_res_interfaces_nt(HKEY hKey, const char *subkey, char **obuf)
536 {
537   char enumbuf[39]; /* GUIDs are 38 chars + 1 for NULL */
538   DWORD enum_size = 39;
539   int idx = 0;
540   HKEY hVal;
541
542   while (RegEnumKeyEx(hKey, idx++, enumbuf, &enum_size, 0,
543                       NULL, NULL, NULL) != ERROR_NO_MORE_ITEMS)
544   {
545     int rc;
546
547     enum_size = 39;
548     if (RegOpenKeyEx(hKey, enumbuf, 0, KEY_QUERY_VALUE, &hVal) !=
549         ERROR_SUCCESS)
550       continue;
551     rc = get_res_nt(hVal, subkey, obuf);
552       RegCloseKey(hVal);
553     if (rc)
554       return 1;
555     }
556   return 0;
557 }
558
559 static int get_iphlpapi_dns_info (char *ret_buf, size_t ret_size)
560 {
561   FIXED_INFO    *fi, *newfi;
562   DWORD          size = sizeof (*fi);
563   typedef DWORD (WINAPI* get_net_param_func) (FIXED_INFO*, DWORD*);
564   get_net_param_func fpGetNetworkParams;  /* available only on Win-98/2000+ */
565   HMODULE        handle;
566   IP_ADDR_STRING *ipAddr;
567   int            i, count = 0;
568   int            debug  = 0;
569   size_t         ip_size = sizeof("255.255.255.255,")-1;
570   size_t         left = ret_size;
571   char          *ret = ret_buf;
572   HRESULT        res;
573
574   fi = malloc(size);
575   if (!fi)
576      return (0);
577
578   handle = LoadLibrary ("iphlpapi.dll");
579   if (!handle)
580      goto quit;
581
582   fpGetNetworkParams = (get_net_param_func) GetProcAddress (handle, "GetNetworkParams");
583   if (!fpGetNetworkParams)
584      goto quit;
585
586   res = (*fpGetNetworkParams) (fi, &size);
587   if ((res != ERROR_BUFFER_OVERFLOW) && (res != ERROR_SUCCESS))
588      goto quit;
589
590   newfi = realloc(fi, size);
591   if (!newfi)
592      goto quit;
593
594   fi = newfi;
595   res = (*fpGetNetworkParams) (fi, &size);
596   if (res != ERROR_SUCCESS)
597      goto quit;
598
599   if (debug)
600   {
601     printf ("Host Name: %s\n", fi->HostName);
602     printf ("Domain Name: %s\n", fi->DomainName);
603     printf ("DNS Servers:\n"
604             "    %s (primary)\n", fi->DnsServerList.IpAddress.String);
605   }
606   if (strlen(fi->DnsServerList.IpAddress.String) > 0 &&
607       inet_addr(fi->DnsServerList.IpAddress.String) != INADDR_NONE &&
608       left > ip_size)
609   {
610     ret += sprintf (ret, "%s,", fi->DnsServerList.IpAddress.String);
611     left -= ret - ret_buf;
612     count++;
613   }
614
615   for (i = 0, ipAddr = fi->DnsServerList.Next; ipAddr && left > ip_size;
616        ipAddr = ipAddr->Next, i++)
617   {
618     if (inet_addr(ipAddr->IpAddress.String) != INADDR_NONE)
619     {
620        ret += sprintf (ret, "%s,", ipAddr->IpAddress.String);
621        left -= ret - ret_buf;
622        count++;
623     }
624     if (debug)
625        printf ("    %s (secondary %d)\n", ipAddr->IpAddress.String, i+1);
626   }
627
628 quit:
629   if (fi)
630      free(fi);
631   if (handle)
632      FreeLibrary (handle);
633
634   if (debug && left <= ip_size)
635      printf ("Too many nameservers. Truncating to %d addressess", count);
636   if (ret > ret_buf)
637      ret[-1] = '\0';
638   return (count);
639 }
640 #endif
641
642 static int init_by_resolv_conf(ares_channel channel)
643 {
644   char *line = NULL;
645   int status = -1, nservers = 0, nsort = 0;
646   struct server_state *servers = NULL;
647   struct apattern *sortlist = NULL;
648
649 #ifdef WIN32
650
651     /*
652   NameServer info via IPHLPAPI (IP helper API):
653     GetNetworkParams() should be the trusted source for this.
654     Available in Win-98/2000 and later. If that fail, fall-back to
655     registry information.
656
657   NameServer Registry:
658
659    On Windows 9X, the DNS server can be found in:
660 HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\VxD\MSTCP\NameServer
661
662         On Windows NT/2000/XP/2003:
663 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\NameServer
664         or
665 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\DhcpNameServer
666         or
667 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\{AdapterID}\
668 NameServer
669         or
670 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\{AdapterID}\
671 DhcpNameServer
672    */
673
674   HKEY mykey;
675   HKEY subkey;
676   DWORD data_type;
677   DWORD bytes;
678   DWORD result;
679   char  buf[256];
680
681   if (channel->nservers > -1)  /* don't override ARES_OPT_SERVER */
682      return ARES_SUCCESS;
683
684   if (get_iphlpapi_dns_info(buf,sizeof(buf)) > 0)
685   {
686     status = config_nameserver(&servers, &nservers, buf);
687     if (status == ARES_SUCCESS)
688       goto okay;
689   }
690
691   if (IS_NT())
692   {
693     if (RegOpenKeyEx(
694           HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0,
695           KEY_READ, &mykey
696           ) == ERROR_SUCCESS)
697     {
698       RegOpenKeyEx(mykey, "Interfaces", 0,
699                    KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS, &subkey);
700       if (get_res_nt(mykey, NAMESERVER, &line))
701       {
702         status = config_nameserver(&servers, &nservers, line);
703         free(line);
704       }
705       else if (get_res_nt(mykey, DHCPNAMESERVER, &line))
706       {
707         status = config_nameserver(&servers, &nservers, line);
708         free(line);
709       }
710       /* Try the interfaces */
711       else if (get_res_interfaces_nt(subkey, NAMESERVER, &line))
712       {
713         status = config_nameserver(&servers, &nservers, line);
714         free(line);
715       }
716       else if (get_res_interfaces_nt(subkey, DHCPNAMESERVER, &line))
717       {
718         status = config_nameserver(&servers, &nservers, line);
719         free(line);
720       }
721       RegCloseKey(subkey);
722       RegCloseKey(mykey);
723     }
724   }
725   else
726   {
727     if (RegOpenKeyEx(
728           HKEY_LOCAL_MACHINE, WIN_NS_9X, 0,
729           KEY_READ, &mykey
730           ) == ERROR_SUCCESS)
731     {
732       if ((result = RegQueryValueEx(
733              mykey, NAMESERVER, NULL, &data_type,
734              NULL, &bytes
735              )
736             ) == ERROR_SUCCESS ||
737           result == ERROR_MORE_DATA)
738       {
739         if (bytes)
740         {
741           line = malloc(bytes+1);
742           if (RegQueryValueEx(mykey, NAMESERVER, NULL, &data_type,
743                               (unsigned char *)line, &bytes) ==
744               ERROR_SUCCESS)
745           {
746             status = config_nameserver(&servers, &nservers, line);
747           }
748           free(line);
749         }
750       }
751     }
752     RegCloseKey(mykey);
753   }
754
755   if (status == ARES_SUCCESS)
756     status = ARES_EOF;
757   else
758     /* Catch the case when all the above checks fail (which happens when there
759        is no network card or the cable is unplugged) */
760     status = ARES_EFILE;
761
762 #elif defined(__riscos__)
763
764   /* Under RISC OS, name servers are listed in the
765      system variable Inet$Resolvers, space separated. */
766
767   line = getenv("Inet$Resolvers");
768   status = ARES_EOF;
769   if (line) {
770     char *resolvers = strdup(line), *pos, *space;
771
772     if (!resolvers)
773       return ARES_ENOMEM;
774
775     pos = resolvers;
776     do {
777       space = strchr(pos, ' ');
778       if (space)
779         *space = '\0';
780       status = config_nameserver(&servers, &nservers, pos);
781       if (status != ARES_SUCCESS)
782         break;
783       pos = space + 1;
784     } while (space);
785
786     if (status == ARES_SUCCESS)
787       status = ARES_EOF;
788
789     free(resolvers);
790   }
791
792 #elif defined(WATT32)
793   int i;
794
795   sock_init();
796   for (i = 0; def_nameservers[i]; i++)
797       ;
798   if (i == 0)
799     return ARES_SUCCESS; /* use localhost DNS server */
800
801   nservers = i;
802   servers = calloc(sizeof(*servers), i);
803   if (!servers)
804      return ARES_ENOMEM;
805
806   for (i = 0; def_nameservers[i]; i++)
807       servers[i].addr.s_addr = htonl(def_nameservers[i]);
808   status = ARES_EOF;
809
810 #else
811   {
812     char *p;
813     FILE *fp;
814     int linesize;
815     int error;
816
817     /* Don't read resolv.conf and friends if we don't have to */
818     if (ARES_CONFIG_CHECK(channel))
819         return ARES_SUCCESS;
820
821     fp = fopen(PATH_RESOLV_CONF, "r");
822     if (fp) {
823       while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS)
824       {
825         if ((p = try_config(line, "domain")) && channel->ndomains == -1)
826           status = config_domain(channel, p);
827         else if ((p = try_config(line, "lookup")) && !channel->lookups)
828           status = config_lookup(channel, p, "bind", "file");
829         else if ((p = try_config(line, "search")) && channel->ndomains == -1)
830           status = set_search(channel, p);
831         else if ((p = try_config(line, "nameserver")) && channel->nservers == -1)
832           status = config_nameserver(&servers, &nservers, p);
833         else if ((p = try_config(line, "sortlist")) && channel->nsort == -1)
834           status = config_sortlist(&sortlist, &nsort, p);
835         else if ((p = try_config(line, "options")))
836           status = set_options(channel, p);
837         else
838           status = ARES_SUCCESS;
839         if (status != ARES_SUCCESS)
840           break;
841       }
842       fclose(fp);
843     }
844     else {
845       error = ERRNO;
846       switch(error) {
847       case ENOENT:
848       case ESRCH:
849         status = ARES_EOF;
850         break;
851       default:
852         DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n",
853                        error, strerror(error)));
854         DEBUGF(fprintf(stderr, "Error opening file: %s\n", PATH_RESOLV_CONF));
855         status = ARES_EFILE;
856       }
857     }
858
859     if ((status == ARES_EOF) && (!channel->lookups)) {
860       /* Many systems (Solaris, Linux, BSD's) use nsswitch.conf */
861       fp = fopen("/etc/nsswitch.conf", "r");
862       if (fp) {
863         while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS)
864         {
865           if ((p = try_config(line, "hosts:")) && !channel->lookups)
866             status = config_lookup(channel, p, "dns", "files");
867         }
868         fclose(fp);
869       }
870       else {
871         error = ERRNO;
872         switch(error) {
873         case ENOENT:
874         case ESRCH:
875           status = ARES_EOF;
876           break;
877         default:
878           DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n",
879                          error, strerror(error)));
880           DEBUGF(fprintf(stderr, "Error opening file: %s\n", "/etc/nsswitch.conf"));
881           status = ARES_EFILE;
882         }
883       }
884     }
885
886     if ((status == ARES_EOF) && (!channel->lookups)) {
887       /* Linux / GNU libc 2.x and possibly others have host.conf */
888       fp = fopen("/etc/host.conf", "r");
889       if (fp) {
890         while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS)
891         {
892           if ((p = try_config(line, "order")) && !channel->lookups)
893             status = config_lookup(channel, p, "bind", "hosts");
894         }
895         fclose(fp);
896       }
897       else {
898         error = ERRNO;
899         switch(error) {
900         case ENOENT:
901         case ESRCH:
902           status = ARES_EOF;
903           break;
904         default:
905           DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n",
906                          error, strerror(error)));
907           DEBUGF(fprintf(stderr, "Error opening file: %s\n", "/etc/host.conf"));
908           status = ARES_EFILE;
909         }
910       }
911     }
912
913     if ((status == ARES_EOF) && (!channel->lookups)) {
914       /* Tru64 uses /etc/svc.conf */
915       fp = fopen("/etc/svc.conf", "r");
916       if (fp) {
917         while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS)
918         {
919           if ((p = try_config(line, "hosts=")) && !channel->lookups)
920             status = config_lookup(channel, p, "bind", "local");
921         }
922         fclose(fp);
923       }
924       else {
925         error = ERRNO;
926         switch(error) {
927         case ENOENT:
928         case ESRCH:
929           status = ARES_EOF;
930           break;
931         default:
932           DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n",
933                          error, strerror(error)));
934           DEBUGF(fprintf(stderr, "Error opening file: %s\n", "/etc/svc.conf"));
935           status = ARES_EFILE;
936         }
937       }
938     }
939
940     if(line)
941       free(line);
942   }
943
944 #endif
945
946   /* Handle errors. */
947   if (status != ARES_EOF)
948     {
949       if (servers != NULL)
950         free(servers);
951       if (sortlist != NULL)
952         free(sortlist);
953       return status;
954     }
955
956   /* If we got any name server entries, fill them in. */
957 #ifdef WIN32
958 okay:
959 #endif
960   if (servers)
961     {
962       channel->servers = servers;
963       channel->nservers = nservers;
964     }
965
966   /* If we got any sortlist entries, fill them in. */
967   if (sortlist)
968     {
969       channel->sortlist = sortlist;
970       channel->nsort = nsort;
971     }
972
973   return ARES_SUCCESS;
974 }
975
976 static int init_by_defaults(ares_channel channel)
977 {
978   char *hostname = NULL;
979   int rc = ARES_SUCCESS;
980
981   if (channel->flags == -1)
982     channel->flags = 0;
983   if (channel->timeout == -1)
984     channel->timeout = DEFAULT_TIMEOUT;
985   if (channel->tries == -1)
986     channel->tries = DEFAULT_TRIES;
987   if (channel->ndots == -1)
988     channel->ndots = 1;
989   if (channel->rotate == -1)
990     channel->rotate = 0;
991   if (channel->udp_port == -1)
992     channel->udp_port = htons(NAMESERVER_PORT);
993   if (channel->tcp_port == -1)
994     channel->tcp_port = htons(NAMESERVER_PORT);
995
996   if (channel->nservers == -1) {
997     /* If nobody specified servers, try a local named. */
998     channel->servers = malloc(sizeof(struct server_state));
999     if (!channel->servers) {
1000       rc = ARES_ENOMEM;
1001       goto error;
1002     }
1003     channel->servers[0].addr.s_addr = htonl(INADDR_LOOPBACK);
1004     channel->nservers = 1;
1005   }
1006
1007 #ifdef ENAMETOOLONG
1008 #define toolong(x) (x == -1) && ((ENAMETOOLONG == errno) || (EINVAL == errno))
1009 #else
1010 #define toolong(x) (x == -1) && (EINVAL == errno)
1011 #endif
1012
1013   if (channel->ndomains == -1) {
1014     /* Derive a default domain search list from the kernel hostname,
1015      * or set it to empty if the hostname isn't helpful.
1016      */
1017     size_t len = 64;
1018     int res;
1019     channel->ndomains = 0; /* default to none */
1020
1021 #ifdef HAVE_GETHOSTNAME
1022     hostname = malloc(len);
1023     if(!hostname) {
1024       rc = ARES_ENOMEM;
1025       goto error;
1026     }
1027
1028     do {
1029       res = gethostname(hostname, len);
1030
1031       if(toolong(res)) {
1032         char *p;
1033         len *= 2;
1034         p = realloc(hostname, len);
1035         if(!p) {
1036           rc = ARES_ENOMEM;
1037           goto error;
1038         }
1039         hostname = p;
1040         continue;
1041       }
1042       else if(res) {
1043         rc = ARES_EBADNAME;
1044         goto error;
1045       }
1046
1047     } while(0);
1048
1049     if (strchr(hostname, '.'))  {
1050       /* a dot was found */
1051
1052       channel->domains = malloc(sizeof(char *));
1053       if (!channel->domains) {
1054         rc = ARES_ENOMEM;
1055         goto error;
1056       }
1057       channel->domains[0] = strdup(strchr(hostname, '.') + 1);
1058       if (!channel->domains[0]) {
1059         rc = ARES_ENOMEM;
1060         goto error;
1061       }
1062       channel->ndomains = 1;
1063     }
1064 #endif
1065   }
1066
1067   if (channel->nsort == -1) {
1068     channel->sortlist = NULL;
1069     channel->nsort = 0;
1070   }
1071
1072   if (!channel->lookups) {
1073     channel->lookups = strdup("fb");
1074     if (!channel->lookups)
1075       rc = ARES_ENOMEM;
1076   }
1077
1078   error:
1079   if(rc) {
1080     if(channel->servers)
1081       free(channel->servers);
1082
1083     if(channel->domains && channel->domains[0])
1084       free(channel->domains[0]);
1085     if(channel->domains)
1086       free(channel->domains);
1087     if(channel->lookups)
1088       free(channel->lookups);
1089   }
1090
1091   if(hostname)
1092     free(hostname);
1093
1094   return rc;
1095 }
1096
1097 #ifndef WIN32
1098 static int config_domain(ares_channel channel, char *str)
1099 {
1100   char *q;
1101
1102   /* Set a single search domain. */
1103   q = str;
1104   while (*q && !ISSPACE(*q))
1105     q++;
1106   *q = '\0';
1107   return set_search(channel, str);
1108 }
1109
1110 static int config_lookup(ares_channel channel, const char *str,
1111                          const char *bindch, const char *filech)
1112 {
1113   char lookups[3], *l;
1114   const char *p;
1115
1116   /* Set the lookup order.  Only the first letter of each work
1117    * is relevant, and it has to be "b" for DNS or "f" for the
1118    * host file.  Ignore everything else.
1119    */
1120   l = lookups;
1121   p = str;
1122   while (*p)
1123     {
1124       if ((*p == *bindch || *p == *filech) && l < lookups + 2) {
1125         if (*p == *bindch) *l++ = 'b';
1126         else *l++ = 'f';
1127       }
1128       while (*p && !ISSPACE(*p) && (*p != ','))
1129         p++;
1130       while (*p && (ISSPACE(*p) || (*p == ',')))
1131         p++;
1132     }
1133   *l = '\0';
1134   channel->lookups = strdup(lookups);
1135   return (channel->lookups) ? ARES_SUCCESS : ARES_ENOMEM;
1136 }
1137
1138 #endif
1139
1140 static int config_nameserver(struct server_state **servers, int *nservers,
1141                              char *str)
1142 {
1143   struct in_addr addr;
1144   struct server_state *newserv;
1145   /* On Windows, there may be more than one nameserver specified in the same
1146    * registry key, so we parse it as a space or comma seperated list.
1147    */
1148 #ifdef WIN32
1149   char *p = str;
1150   char *begin = str;
1151   int more = 1;
1152   while (more)
1153   {
1154     more = 0;
1155     while (*p && !ISSPACE(*p) && *p != ',')
1156       p++;
1157
1158     if (*p)
1159     {
1160       *p = '\0';
1161       more = 1;
1162     }
1163
1164     /* Skip multiple spaces or trailing spaces */
1165     if (!*begin)
1166     {
1167       begin = ++p;
1168       continue;
1169     }
1170
1171     /* This is the part that actually sets the nameserver */
1172     addr.s_addr = inet_addr(begin);
1173     if (addr.s_addr == INADDR_NONE)
1174       continue;
1175     newserv = realloc(*servers, (*nservers + 1) * sizeof(struct server_state));
1176     if (!newserv)
1177       return ARES_ENOMEM;
1178     newserv[*nservers].addr = addr;
1179     *servers = newserv;
1180     (*nservers)++;
1181
1182     if (!more)
1183       break;
1184     begin = ++p;
1185   }
1186 #else
1187   /* Add a nameserver entry, if this is a valid address. */
1188   addr.s_addr = inet_addr(str);
1189   if (addr.s_addr == INADDR_NONE)
1190     return ARES_SUCCESS;
1191   newserv = realloc(*servers, (*nservers + 1) * sizeof(struct server_state));
1192   if (!newserv)
1193     return ARES_ENOMEM;
1194   newserv[*nservers].addr = addr;
1195   *servers = newserv;
1196   (*nservers)++;
1197 #endif
1198   return ARES_SUCCESS;
1199 }
1200
1201 #ifndef WIN32
1202 static int config_sortlist(struct apattern **sortlist, int *nsort,
1203                            const char *str)
1204 {
1205   struct apattern pat;
1206   const char *q;
1207
1208   /* Add sortlist entries. */
1209   while (*str && *str != ';')
1210     {
1211       int bits;
1212       char ipbuf[16], ipbufpfx[32];
1213       /* Find just the IP */
1214       q = str;
1215       while (*q && *q != '/' && *q != ';' && !ISSPACE(*q))
1216         q++;
1217       memcpy(ipbuf, str, (int)(q-str));
1218       ipbuf[(int)(q-str)] = '\0';
1219       /* Find the prefix */
1220       if (*q == '/')
1221         {
1222           const char *str2 = q+1;
1223           while (*q && *q != ';' && !ISSPACE(*q))
1224             q++;
1225           memcpy(ipbufpfx, str, (int)(q-str));
1226           ipbufpfx[(int)(q-str)] = '\0';
1227           str = str2;
1228         }
1229       else
1230         ipbufpfx[0] = '\0';
1231       /* Lets see if it is CIDR */
1232       /* First we'll try IPv6 */
1233       if ((bits = ares_inet_net_pton(AF_INET6, ipbufpfx[0] ? ipbufpfx : ipbuf,
1234                                      &pat.addrV6,
1235                                      sizeof(pat.addrV6))) > 0)
1236         {
1237           pat.type = PATTERN_CIDR;
1238           pat.mask.bits = (unsigned short)bits;
1239           pat.family = AF_INET6;
1240           if (!sortlist_alloc(sortlist, nsort, &pat))
1241             return ARES_ENOMEM;
1242         }
1243       if (ipbufpfx[0] &&
1244           (bits = ares_inet_net_pton(AF_INET, ipbufpfx, &pat.addrV4,
1245                                      sizeof(pat.addrV4))) > 0)
1246         {
1247           pat.type = PATTERN_CIDR;
1248           pat.mask.bits = (unsigned short)bits;
1249           pat.family = AF_INET;
1250           if (!sortlist_alloc(sortlist, nsort, &pat))
1251             return ARES_ENOMEM;
1252         }
1253       /* See if it is just a regular IP */
1254       else if (ip_addr(ipbuf, (int)(q-str), &pat.addrV4) == 0)
1255         {
1256           if (ipbufpfx[0])
1257             {
1258               memcpy(ipbuf, str, (int)(q-str));
1259               ipbuf[(int)(q-str)] = '\0';
1260               if (ip_addr(ipbuf, (int)(q - str), &pat.mask.addr4) != 0)
1261                 natural_mask(&pat);
1262             }
1263           else
1264             natural_mask(&pat);
1265           pat.family = AF_INET;
1266           pat.type = PATTERN_MASK;
1267           if (!sortlist_alloc(sortlist, nsort, &pat))
1268             return ARES_ENOMEM;
1269         }
1270       else
1271         {
1272           while (*q && *q != ';' && !ISSPACE(*q))
1273             q++;
1274         }
1275       str = q;
1276       while (ISSPACE(*str))
1277         str++;
1278     }
1279
1280   return ARES_SUCCESS;
1281 }
1282 #endif
1283
1284 static int set_search(ares_channel channel, const char *str)
1285 {
1286   int n;
1287   const char *p, *q;
1288
1289   if(channel->ndomains != -1) {
1290     /* if we already have some domains present, free them first */
1291     for(n=0; n < channel->ndomains; n++)
1292       free(channel->domains[n]);
1293     free(channel->domains);
1294     channel->domains = NULL;
1295     channel->ndomains = -1;
1296   }
1297
1298   /* Count the domains given. */
1299   n = 0;
1300   p = str;
1301   while (*p)
1302     {
1303       while (*p && !ISSPACE(*p))
1304         p++;
1305       while (ISSPACE(*p))
1306         p++;
1307       n++;
1308     }
1309
1310   if (!n)
1311     {
1312       channel->ndomains = 0;
1313       return ARES_SUCCESS;
1314     }
1315
1316   channel->domains = malloc(n * sizeof(char *));
1317   if (!channel->domains)
1318     return ARES_ENOMEM;
1319
1320   /* Now copy the domains. */
1321   n = 0;
1322   p = str;
1323   while (*p)
1324     {
1325       channel->ndomains = n;
1326       q = p;
1327       while (*q && !ISSPACE(*q))
1328         q++;
1329       channel->domains[n] = malloc(q - p + 1);
1330       if (!channel->domains[n])
1331         return ARES_ENOMEM;
1332       memcpy(channel->domains[n], p, q - p);
1333       channel->domains[n][q - p] = 0;
1334       p = q;
1335       while (ISSPACE(*p))
1336         p++;
1337       n++;
1338     }
1339   channel->ndomains = n;
1340
1341   return ARES_SUCCESS;
1342 }
1343
1344 static int set_options(ares_channel channel, const char *str)
1345 {
1346   const char *p, *q, *val;
1347
1348   p = str;
1349   while (*p)
1350     {
1351       q = p;
1352       while (*q && !ISSPACE(*q))
1353         q++;
1354       val = try_option(p, q, "ndots:");
1355       if (val && channel->ndots == -1)
1356         channel->ndots = atoi(val);
1357       val = try_option(p, q, "retrans:");
1358       if (val && channel->timeout == -1)
1359         channel->timeout = atoi(val);
1360       val = try_option(p, q, "retry:");
1361       if (val && channel->tries == -1)
1362         channel->tries = atoi(val);
1363       val = try_option(p, q, "rotate");
1364       if (val && channel->rotate == -1)
1365         channel->rotate = 1;
1366       p = q;
1367       while (ISSPACE(*p))
1368         p++;
1369     }
1370
1371   return ARES_SUCCESS;
1372 }
1373
1374 #ifndef WIN32
1375 static char *try_config(char *s, const char *opt)
1376 {
1377   size_t len;
1378   ssize_t i;
1379   ssize_t j;
1380   char *p;
1381
1382   if (!s || !opt)
1383     /* no line or no option */
1384     return NULL;
1385
1386   /* trim line comment */
1387   for (i = 0; s[i] && s[i] != '#'; ++i);
1388   s[i] = '\0';
1389
1390   /* trim trailing whitespace */
1391   for (j = i-1; j >= 0 && ISSPACE(s[j]); --j);
1392   s[++j] = '\0';
1393
1394   /* skip leading whitespace */
1395   for (i = 0; s[i] && ISSPACE(s[i]); ++i);
1396   p = &s[i];
1397
1398   if (!*p)
1399     /* empty line */
1400     return NULL;
1401
1402   if ((len = strlen(opt)) == 0)
1403     /* empty option */
1404     return NULL;
1405
1406   if (strncmp(p, opt, len) != 0)
1407     /* line and option do not match */
1408     return NULL;
1409
1410   /* skip over given option name */
1411   p += len;
1412
1413   if (!*p)
1414     /* no option value */
1415     return NULL;
1416
1417   if ((opt[len-1] != ':') && (opt[len-1] != '=') && !ISSPACE(*p))
1418     /* whitespace between option name and value is mandatory
1419        for given option names which do not end with ':' or '=' */
1420     return NULL;
1421
1422   /* skip over whitespace */
1423   while (*p && ISSPACE(*p))
1424     p++;
1425
1426   if (!*p)
1427     /* no option value */
1428     return NULL;
1429
1430   /* return pointer to option value */
1431   return p;
1432 }
1433 #endif
1434
1435 static const char *try_option(const char *p, const char *q, const char *opt)
1436 {
1437   size_t len = strlen(opt);
1438   return ((size_t)(q - p) >= len && !strncmp(p, opt, len)) ? &p[len] : NULL;
1439 }
1440
1441 #ifndef WIN32
1442 static int sortlist_alloc(struct apattern **sortlist, int *nsort,
1443                           struct apattern *pat)
1444 {
1445   struct apattern *newsort;
1446   newsort = realloc(*sortlist, (*nsort + 1) * sizeof(struct apattern));
1447   if (!newsort)
1448     return 0;
1449   newsort[*nsort] = *pat;
1450   *sortlist = newsort;
1451   (*nsort)++;
1452   return 1;
1453 }
1454
1455 static int ip_addr(const char *ipbuf, int len, struct in_addr *addr)
1456 {
1457
1458   /* Four octets and three periods yields at most 15 characters. */
1459   if (len > 15)
1460     return -1;
1461
1462   addr->s_addr = inet_addr(ipbuf);
1463   if (addr->s_addr == INADDR_NONE && strcmp(ipbuf, "255.255.255.255") != 0)
1464     return -1;
1465   return 0;
1466 }
1467
1468 static void natural_mask(struct apattern *pat)
1469 {
1470   struct in_addr addr;
1471
1472   /* Store a host-byte-order copy of pat in a struct in_addr.  Icky,
1473    * but portable.
1474    */
1475   addr.s_addr = ntohl(pat->addrV4.s_addr);
1476
1477   /* This is out of date in the CIDR world, but some people might
1478    * still rely on it.
1479    */
1480   if (IN_CLASSA(addr.s_addr))
1481     pat->mask.addr4.s_addr = htonl(IN_CLASSA_NET);
1482   else if (IN_CLASSB(addr.s_addr))
1483     pat->mask.addr4.s_addr = htonl(IN_CLASSB_NET);
1484   else
1485     pat->mask.addr4.s_addr = htonl(IN_CLASSC_NET);
1486 }
1487 #endif
1488 /* initialize an rc4 key. If possible a cryptographically secure random key
1489    is generated using a suitable function (for example win32's RtlGenRandom as
1490    described in
1491    http://blogs.msdn.com/michael_howard/archive/2005/01/14/353379.aspx
1492    otherwise the code defaults to cross-platform albeit less secure mechanism
1493    using rand
1494 */
1495 static void randomize_key(unsigned char* key,int key_data_len)
1496 {
1497   int randomized = 0;
1498   int counter=0;
1499 #ifdef WIN32
1500   HMODULE lib=LoadLibrary("ADVAPI32.DLL");
1501   if (lib) {
1502     BOOLEAN (APIENTRY *pfn)(void*, ULONG) =
1503       (BOOLEAN (APIENTRY *)(void*,ULONG))GetProcAddress(lib,"SystemFunction036");
1504     if (pfn && pfn(key,key_data_len) )
1505       randomized = 1;
1506
1507     FreeLibrary(lib);
1508   }
1509 #else /* !WIN32 */
1510 #ifdef RANDOM_FILE
1511   FILE *f = fopen(RANDOM_FILE, "rb");
1512   if(f) {
1513     counter = fread(key, 1, key_data_len, f);
1514     fclose(f);
1515   }
1516 #endif
1517 #endif /* WIN32 */
1518
1519   if ( !randomized ) {
1520     for (;counter<key_data_len;counter++)
1521       key[counter]=(unsigned char)(rand() % 256);
1522   }
1523 }
1524
1525 static int init_id_key(rc4_key* key,int key_data_len)
1526 {
1527   unsigned char index1;
1528   unsigned char index2;
1529   unsigned char* state;
1530   short counter;
1531   unsigned char *key_data_ptr = 0;
1532
1533   key_data_ptr = calloc(1,key_data_len);
1534   if (!key_data_ptr)
1535     return ARES_ENOMEM;
1536
1537   state = &key->state[0];
1538   for(counter = 0; counter < 256; counter++)
1539     /* unnecessary AND but it keeps some compilers happier */
1540     state[counter] = (unsigned char)(counter & 0xff);
1541   randomize_key(key->state,key_data_len);
1542   key->x = 0;
1543   key->y = 0;
1544   index1 = 0;
1545   index2 = 0;
1546   for(counter = 0; counter < 256; counter++)
1547   {
1548     index2 = (unsigned char)((key_data_ptr[index1] + state[counter] +
1549                               index2) % 256);
1550     ARES_SWAP_BYTE(&state[counter], &state[index2]);
1551
1552     index1 = (unsigned char)((index1 + 1) % key_data_len);
1553   }
1554   free(key_data_ptr);
1555   return ARES_SUCCESS;
1556 }
1557
1558 unsigned short ares__generate_new_id(rc4_key* key)
1559 {
1560   unsigned short r=0;
1561   ares__rc4(key, (unsigned char *)&r, sizeof(r));
1562   return r;
1563 }
1564
1565 void ares_set_socket_callback(ares_channel channel,
1566                               ares_sock_create_callback cb,
1567                               void *data)
1568 {
1569   channel->sock_create_cb = cb;
1570   channel->sock_create_cb_data = data;
1571 }