Moved potential inclusion of system's malloc.h and memory.h header files to
[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   = alloca (sizeof(*fi));
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   if (!fi)
575      return (0);
576
577   handle = LoadLibrary ("iphlpapi.dll");
578   if (!handle)
579      return (0);
580
581   fpGetNetworkParams = (get_net_param_func) GetProcAddress (handle, "GetNetworkParams");
582   if (!fpGetNetworkParams)
583      goto quit;
584
585   res = (*fpGetNetworkParams) (fi, &size);
586   if ((res != ERROR_BUFFER_OVERFLOW) && (res != ERROR_SUCCESS))
587      goto quit;
588
589   fi = alloca (size);
590   if (!fi || (*fpGetNetworkParams) (fi, &size) != ERROR_SUCCESS)
591      goto quit;
592
593   if (debug)
594   {
595     printf ("Host Name: %s\n", fi->HostName);
596     printf ("Domain Name: %s\n", fi->DomainName);
597     printf ("DNS Servers:\n"
598             "    %s (primary)\n", fi->DnsServerList.IpAddress.String);
599   }
600   if (strlen(fi->DnsServerList.IpAddress.String) > 0 &&
601       inet_addr(fi->DnsServerList.IpAddress.String) != INADDR_NONE &&
602       left > ip_size)
603   {
604     ret += sprintf (ret, "%s,", fi->DnsServerList.IpAddress.String);
605     left -= ret - ret_buf;
606     count++;
607   }
608
609   for (i = 0, ipAddr = fi->DnsServerList.Next; ipAddr && left > ip_size;
610        ipAddr = ipAddr->Next, i++)
611   {
612     if (inet_addr(ipAddr->IpAddress.String) != INADDR_NONE)
613     {
614        ret += sprintf (ret, "%s,", ipAddr->IpAddress.String);
615        left -= ret - ret_buf;
616        count++;
617     }
618     if (debug)
619        printf ("    %s (secondary %d)\n", ipAddr->IpAddress.String, i+1);
620   }
621
622 quit:
623   if (handle)
624      FreeLibrary (handle);
625
626   if (debug && left <= ip_size)
627      printf ("Too many nameservers. Truncating to %d addressess", count);
628   if (ret > ret_buf)
629      ret[-1] = '\0';
630   return (count);
631 }
632 #endif
633
634 static int init_by_resolv_conf(ares_channel channel)
635 {
636   char *line = NULL;
637   int status = -1, nservers = 0, nsort = 0;
638   struct server_state *servers = NULL;
639   struct apattern *sortlist = NULL;
640
641 #ifdef WIN32
642
643     /*
644   NameServer info via IPHLPAPI (IP helper API):
645     GetNetworkParams() should be the trusted source for this.
646     Available in Win-98/2000 and later. If that fail, fall-back to
647     registry information.
648
649   NameServer Registry:
650
651    On Windows 9X, the DNS server can be found in:
652 HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\VxD\MSTCP\NameServer
653
654         On Windows NT/2000/XP/2003:
655 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\NameServer
656         or
657 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\DhcpNameServer
658         or
659 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\{AdapterID}\
660 NameServer
661         or
662 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\{AdapterID}\
663 DhcpNameServer
664    */
665
666   HKEY mykey;
667   HKEY subkey;
668   DWORD data_type;
669   DWORD bytes;
670   DWORD result;
671   char  buf[256];
672
673   if (channel->nservers > -1)  /* don't override ARES_OPT_SERVER */
674      return ARES_SUCCESS;
675
676   if (get_iphlpapi_dns_info(buf,sizeof(buf)) > 0)
677   {
678     status = config_nameserver(&servers, &nservers, buf);
679     if (status == ARES_SUCCESS)
680       goto okay;
681   }
682
683   if (IS_NT())
684   {
685     if (RegOpenKeyEx(
686           HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0,
687           KEY_READ, &mykey
688           ) == ERROR_SUCCESS)
689     {
690       RegOpenKeyEx(mykey, "Interfaces", 0,
691                    KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS, &subkey);
692       if (get_res_nt(mykey, NAMESERVER, &line))
693       {
694         status = config_nameserver(&servers, &nservers, line);
695         free(line);
696       }
697       else if (get_res_nt(mykey, DHCPNAMESERVER, &line))
698       {
699         status = config_nameserver(&servers, &nservers, line);
700         free(line);
701       }
702       /* Try the interfaces */
703       else if (get_res_interfaces_nt(subkey, NAMESERVER, &line))
704       {
705         status = config_nameserver(&servers, &nservers, line);
706         free(line);
707       }
708       else if (get_res_interfaces_nt(subkey, DHCPNAMESERVER, &line))
709       {
710         status = config_nameserver(&servers, &nservers, line);
711         free(line);
712       }
713       RegCloseKey(subkey);
714       RegCloseKey(mykey);
715     }
716   }
717   else
718   {
719     if (RegOpenKeyEx(
720           HKEY_LOCAL_MACHINE, WIN_NS_9X, 0,
721           KEY_READ, &mykey
722           ) == ERROR_SUCCESS)
723     {
724       if ((result = RegQueryValueEx(
725              mykey, NAMESERVER, NULL, &data_type,
726              NULL, &bytes
727              )
728             ) == ERROR_SUCCESS ||
729           result == ERROR_MORE_DATA)
730       {
731         if (bytes)
732         {
733           line = malloc(bytes+1);
734           if (RegQueryValueEx(mykey, NAMESERVER, NULL, &data_type,
735                               (unsigned char *)line, &bytes) ==
736               ERROR_SUCCESS)
737           {
738             status = config_nameserver(&servers, &nservers, line);
739           }
740           free(line);
741         }
742       }
743     }
744     RegCloseKey(mykey);
745   }
746
747   if (status == ARES_SUCCESS)
748     status = ARES_EOF;
749   else
750     /* Catch the case when all the above checks fail (which happens when there
751        is no network card or the cable is unplugged) */
752     status = ARES_EFILE;
753
754 #elif defined(__riscos__)
755
756   /* Under RISC OS, name servers are listed in the
757      system variable Inet$Resolvers, space separated. */
758
759   line = getenv("Inet$Resolvers");
760   status = ARES_EOF;
761   if (line) {
762     char *resolvers = strdup(line), *pos, *space;
763
764     if (!resolvers)
765       return ARES_ENOMEM;
766
767     pos = resolvers;
768     do {
769       space = strchr(pos, ' ');
770       if (space)
771         *space = '\0';
772       status = config_nameserver(&servers, &nservers, pos);
773       if (status != ARES_SUCCESS)
774         break;
775       pos = space + 1;
776     } while (space);
777
778     if (status == ARES_SUCCESS)
779       status = ARES_EOF;
780
781     free(resolvers);
782   }
783
784 #elif defined(WATT32)
785   int i;
786
787   sock_init();
788   for (i = 0; def_nameservers[i]; i++)
789       ;
790   if (i == 0)
791     return ARES_SUCCESS; /* use localhost DNS server */
792
793   nservers = i;
794   servers = calloc(sizeof(*servers), i);
795   if (!servers)
796      return ARES_ENOMEM;
797
798   for (i = 0; def_nameservers[i]; i++)
799       servers[i].addr.s_addr = htonl(def_nameservers[i]);
800   status = ARES_EOF;
801
802 #else
803   {
804     char *p;
805     FILE *fp;
806     int linesize;
807     int error;
808
809     /* Don't read resolv.conf and friends if we don't have to */
810     if (ARES_CONFIG_CHECK(channel))
811         return ARES_SUCCESS;
812
813     fp = fopen(PATH_RESOLV_CONF, "r");
814     if (fp) {
815       while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS)
816       {
817         if ((p = try_config(line, "domain")) && channel->ndomains == -1)
818           status = config_domain(channel, p);
819         else if ((p = try_config(line, "lookup")) && !channel->lookups)
820           status = config_lookup(channel, p, "bind", "file");
821         else if ((p = try_config(line, "search")) && channel->ndomains == -1)
822           status = set_search(channel, p);
823         else if ((p = try_config(line, "nameserver")) && channel->nservers == -1)
824           status = config_nameserver(&servers, &nservers, p);
825         else if ((p = try_config(line, "sortlist")) && channel->nsort == -1)
826           status = config_sortlist(&sortlist, &nsort, p);
827         else if ((p = try_config(line, "options")))
828           status = set_options(channel, p);
829         else
830           status = ARES_SUCCESS;
831         if (status != ARES_SUCCESS)
832           break;
833       }
834       fclose(fp);
835     }
836     else {
837       error = ERRNO;
838       switch(error) {
839       case ENOENT:
840       case ESRCH:
841         status = ARES_EOF;
842         break;
843       default:
844         DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n",
845                        error, strerror(error)));
846         DEBUGF(fprintf(stderr, "Error opening file: %s\n", PATH_RESOLV_CONF));
847         status = ARES_EFILE;
848       }
849     }
850
851     if ((status == ARES_EOF) && (!channel->lookups)) {
852       /* Many systems (Solaris, Linux, BSD's) use nsswitch.conf */
853       fp = fopen("/etc/nsswitch.conf", "r");
854       if (fp) {
855         while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS)
856         {
857           if ((p = try_config(line, "hosts:")) && !channel->lookups)
858             status = config_lookup(channel, p, "dns", "files");
859         }
860         fclose(fp);
861       }
862       else {
863         error = ERRNO;
864         switch(error) {
865         case ENOENT:
866         case ESRCH:
867           status = ARES_EOF;
868           break;
869         default:
870           DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n",
871                          error, strerror(error)));
872           DEBUGF(fprintf(stderr, "Error opening file: %s\n", "/etc/nsswitch.conf"));
873           status = ARES_EFILE;
874         }
875       }
876     }
877
878     if ((status == ARES_EOF) && (!channel->lookups)) {
879       /* Linux / GNU libc 2.x and possibly others have host.conf */
880       fp = fopen("/etc/host.conf", "r");
881       if (fp) {
882         while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS)
883         {
884           if ((p = try_config(line, "order")) && !channel->lookups)
885             status = config_lookup(channel, p, "bind", "hosts");
886         }
887         fclose(fp);
888       }
889       else {
890         error = ERRNO;
891         switch(error) {
892         case ENOENT:
893         case ESRCH:
894           status = ARES_EOF;
895           break;
896         default:
897           DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n",
898                          error, strerror(error)));
899           DEBUGF(fprintf(stderr, "Error opening file: %s\n", "/etc/host.conf"));
900           status = ARES_EFILE;
901         }
902       }
903     }
904
905     if ((status == ARES_EOF) && (!channel->lookups)) {
906       /* Tru64 uses /etc/svc.conf */
907       fp = fopen("/etc/svc.conf", "r");
908       if (fp) {
909         while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS)
910         {
911           if ((p = try_config(line, "hosts=")) && !channel->lookups)
912             status = config_lookup(channel, p, "bind", "local");
913         }
914         fclose(fp);
915       }
916       else {
917         error = ERRNO;
918         switch(error) {
919         case ENOENT:
920         case ESRCH:
921           status = ARES_EOF;
922           break;
923         default:
924           DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n",
925                          error, strerror(error)));
926           DEBUGF(fprintf(stderr, "Error opening file: %s\n", "/etc/svc.conf"));
927           status = ARES_EFILE;
928         }
929       }
930     }
931
932     if(line)
933       free(line);
934   }
935
936 #endif
937
938   /* Handle errors. */
939   if (status != ARES_EOF)
940     {
941       if (servers != NULL)
942         free(servers);
943       if (sortlist != NULL)
944         free(sortlist);
945       return status;
946     }
947
948   /* If we got any name server entries, fill them in. */
949 #ifdef WIN32
950 okay:
951 #endif
952   if (servers)
953     {
954       channel->servers = servers;
955       channel->nservers = nservers;
956     }
957
958   /* If we got any sortlist entries, fill them in. */
959   if (sortlist)
960     {
961       channel->sortlist = sortlist;
962       channel->nsort = nsort;
963     }
964
965   return ARES_SUCCESS;
966 }
967
968 static int init_by_defaults(ares_channel channel)
969 {
970   char *hostname = NULL;
971   int rc = ARES_SUCCESS;
972
973   if (channel->flags == -1)
974     channel->flags = 0;
975   if (channel->timeout == -1)
976     channel->timeout = DEFAULT_TIMEOUT;
977   if (channel->tries == -1)
978     channel->tries = DEFAULT_TRIES;
979   if (channel->ndots == -1)
980     channel->ndots = 1;
981   if (channel->rotate == -1)
982     channel->rotate = 0;
983   if (channel->udp_port == -1)
984     channel->udp_port = htons(NAMESERVER_PORT);
985   if (channel->tcp_port == -1)
986     channel->tcp_port = htons(NAMESERVER_PORT);
987
988   if (channel->nservers == -1) {
989     /* If nobody specified servers, try a local named. */
990     channel->servers = malloc(sizeof(struct server_state));
991     if (!channel->servers) {
992       rc = ARES_ENOMEM;
993       goto error;
994     }
995     channel->servers[0].addr.s_addr = htonl(INADDR_LOOPBACK);
996     channel->nservers = 1;
997   }
998
999 #ifdef ENAMETOOLONG
1000 #define toolong(x) (x == -1) && ((ENAMETOOLONG == errno) || (EINVAL == errno))
1001 #else
1002 #define toolong(x) (x == -1) && (EINVAL == errno)
1003 #endif
1004
1005   if (channel->ndomains == -1) {
1006     /* Derive a default domain search list from the kernel hostname,
1007      * or set it to empty if the hostname isn't helpful.
1008      */
1009     size_t len = 64;
1010     int res;
1011     channel->ndomains = 0; /* default to none */
1012
1013 #ifdef HAVE_GETHOSTNAME
1014     hostname = malloc(len);
1015     if(!hostname) {
1016       rc = ARES_ENOMEM;
1017       goto error;
1018     }
1019
1020     do {
1021       res = gethostname(hostname, len);
1022
1023       if(toolong(res)) {
1024         char *p;
1025         len *= 2;
1026         p = realloc(hostname, len);
1027         if(!p) {
1028           rc = ARES_ENOMEM;
1029           goto error;
1030         }
1031         hostname = p;
1032         continue;
1033       }
1034       else if(res) {
1035         rc = ARES_EBADNAME;
1036         goto error;
1037       }
1038
1039     } while(0);
1040
1041     if (strchr(hostname, '.'))  {
1042       /* a dot was found */
1043
1044       channel->domains = malloc(sizeof(char *));
1045       if (!channel->domains) {
1046         rc = ARES_ENOMEM;
1047         goto error;
1048       }
1049       channel->domains[0] = strdup(strchr(hostname, '.') + 1);
1050       if (!channel->domains[0]) {
1051         rc = ARES_ENOMEM;
1052         goto error;
1053       }
1054       channel->ndomains = 1;
1055     }
1056 #endif
1057   }
1058
1059   if (channel->nsort == -1) {
1060     channel->sortlist = NULL;
1061     channel->nsort = 0;
1062   }
1063
1064   if (!channel->lookups) {
1065     channel->lookups = strdup("fb");
1066     if (!channel->lookups)
1067       rc = ARES_ENOMEM;
1068   }
1069
1070   error:
1071   if(rc) {
1072     if(channel->servers)
1073       free(channel->servers);
1074
1075     if(channel->domains && channel->domains[0])
1076       free(channel->domains[0]);
1077     if(channel->domains)
1078       free(channel->domains);
1079     if(channel->lookups)
1080       free(channel->lookups);
1081   }
1082
1083   if(hostname)
1084     free(hostname);
1085
1086   return rc;
1087 }
1088
1089 #ifndef WIN32
1090 static int config_domain(ares_channel channel, char *str)
1091 {
1092   char *q;
1093
1094   /* Set a single search domain. */
1095   q = str;
1096   while (*q && !ISSPACE(*q))
1097     q++;
1098   *q = '\0';
1099   return set_search(channel, str);
1100 }
1101
1102 static int config_lookup(ares_channel channel, const char *str,
1103                          const char *bindch, const char *filech)
1104 {
1105   char lookups[3], *l;
1106   const char *p;
1107
1108   /* Set the lookup order.  Only the first letter of each work
1109    * is relevant, and it has to be "b" for DNS or "f" for the
1110    * host file.  Ignore everything else.
1111    */
1112   l = lookups;
1113   p = str;
1114   while (*p)
1115     {
1116       if ((*p == *bindch || *p == *filech) && l < lookups + 2) {
1117         if (*p == *bindch) *l++ = 'b';
1118         else *l++ = 'f';
1119       }
1120       while (*p && !ISSPACE(*p) && (*p != ','))
1121         p++;
1122       while (*p && (ISSPACE(*p) || (*p == ',')))
1123         p++;
1124     }
1125   *l = '\0';
1126   channel->lookups = strdup(lookups);
1127   return (channel->lookups) ? ARES_SUCCESS : ARES_ENOMEM;
1128 }
1129
1130 #endif
1131
1132 static int config_nameserver(struct server_state **servers, int *nservers,
1133                              char *str)
1134 {
1135   struct in_addr addr;
1136   struct server_state *newserv;
1137   /* On Windows, there may be more than one nameserver specified in the same
1138    * registry key, so we parse it as a space or comma seperated list.
1139    */
1140 #ifdef WIN32
1141   char *p = str;
1142   char *begin = str;
1143   int more = 1;
1144   while (more)
1145   {
1146     more = 0;
1147     while (*p && !ISSPACE(*p) && *p != ',')
1148       p++;
1149
1150     if (*p)
1151     {
1152       *p = '\0';
1153       more = 1;
1154     }
1155
1156     /* Skip multiple spaces or trailing spaces */
1157     if (!*begin)
1158     {
1159       begin = ++p;
1160       continue;
1161     }
1162
1163     /* This is the part that actually sets the nameserver */
1164     addr.s_addr = inet_addr(begin);
1165     if (addr.s_addr == INADDR_NONE)
1166       continue;
1167     newserv = realloc(*servers, (*nservers + 1) * sizeof(struct server_state));
1168     if (!newserv)
1169       return ARES_ENOMEM;
1170     newserv[*nservers].addr = addr;
1171     *servers = newserv;
1172     (*nservers)++;
1173
1174     if (!more)
1175       break;
1176     begin = ++p;
1177   }
1178 #else
1179   /* Add a nameserver entry, if this is a valid address. */
1180   addr.s_addr = inet_addr(str);
1181   if (addr.s_addr == INADDR_NONE)
1182     return ARES_SUCCESS;
1183   newserv = realloc(*servers, (*nservers + 1) * sizeof(struct server_state));
1184   if (!newserv)
1185     return ARES_ENOMEM;
1186   newserv[*nservers].addr = addr;
1187   *servers = newserv;
1188   (*nservers)++;
1189 #endif
1190   return ARES_SUCCESS;
1191 }
1192
1193 #ifndef WIN32
1194 static int config_sortlist(struct apattern **sortlist, int *nsort,
1195                            const char *str)
1196 {
1197   struct apattern pat;
1198   const char *q;
1199
1200   /* Add sortlist entries. */
1201   while (*str && *str != ';')
1202     {
1203       int bits;
1204       char ipbuf[16], ipbufpfx[32];
1205       /* Find just the IP */
1206       q = str;
1207       while (*q && *q != '/' && *q != ';' && !ISSPACE(*q))
1208         q++;
1209       memcpy(ipbuf, str, (int)(q-str));
1210       ipbuf[(int)(q-str)] = '\0';
1211       /* Find the prefix */
1212       if (*q == '/')
1213         {
1214           const char *str2 = q+1;
1215           while (*q && *q != ';' && !ISSPACE(*q))
1216             q++;
1217           memcpy(ipbufpfx, str, (int)(q-str));
1218           ipbufpfx[(int)(q-str)] = '\0';
1219           str = str2;
1220         }
1221       else
1222         ipbufpfx[0] = '\0';
1223       /* Lets see if it is CIDR */
1224       /* First we'll try IPv6 */
1225       if ((bits = ares_inet_net_pton(AF_INET6, ipbufpfx[0] ? ipbufpfx : ipbuf,
1226                                      &pat.addrV6,
1227                                      sizeof(pat.addrV6))) > 0)
1228         {
1229           pat.type = PATTERN_CIDR;
1230           pat.mask.bits = (unsigned short)bits;
1231           pat.family = AF_INET6;
1232           if (!sortlist_alloc(sortlist, nsort, &pat))
1233             return ARES_ENOMEM;
1234         }
1235       if (ipbufpfx[0] &&
1236           (bits = ares_inet_net_pton(AF_INET, ipbufpfx, &pat.addrV4,
1237                                      sizeof(pat.addrV4))) > 0)
1238         {
1239           pat.type = PATTERN_CIDR;
1240           pat.mask.bits = (unsigned short)bits;
1241           pat.family = AF_INET;
1242           if (!sortlist_alloc(sortlist, nsort, &pat))
1243             return ARES_ENOMEM;
1244         }
1245       /* See if it is just a regular IP */
1246       else if (ip_addr(ipbuf, (int)(q-str), &pat.addrV4) == 0)
1247         {
1248           if (ipbufpfx[0])
1249             {
1250               memcpy(ipbuf, str, (int)(q-str));
1251               ipbuf[(int)(q-str)] = '\0';
1252               if (ip_addr(ipbuf, (int)(q - str), &pat.mask.addr4) != 0)
1253                 natural_mask(&pat);
1254             }
1255           else
1256             natural_mask(&pat);
1257           pat.family = AF_INET;
1258           pat.type = PATTERN_MASK;
1259           if (!sortlist_alloc(sortlist, nsort, &pat))
1260             return ARES_ENOMEM;
1261         }
1262       else
1263         {
1264           while (*q && *q != ';' && !ISSPACE(*q))
1265             q++;
1266         }
1267       str = q;
1268       while (ISSPACE(*str))
1269         str++;
1270     }
1271
1272   return ARES_SUCCESS;
1273 }
1274 #endif
1275
1276 static int set_search(ares_channel channel, const char *str)
1277 {
1278   int n;
1279   const char *p, *q;
1280
1281   if(channel->ndomains != -1) {
1282     /* if we already have some domains present, free them first */
1283     for(n=0; n < channel->ndomains; n++)
1284       free(channel->domains[n]);
1285     free(channel->domains);
1286     channel->domains = NULL;
1287     channel->ndomains = -1;
1288   }
1289
1290   /* Count the domains given. */
1291   n = 0;
1292   p = str;
1293   while (*p)
1294     {
1295       while (*p && !ISSPACE(*p))
1296         p++;
1297       while (ISSPACE(*p))
1298         p++;
1299       n++;
1300     }
1301
1302   if (!n)
1303     {
1304       channel->ndomains = 0;
1305       return ARES_SUCCESS;
1306     }
1307
1308   channel->domains = malloc(n * sizeof(char *));
1309   if (!channel->domains)
1310     return ARES_ENOMEM;
1311
1312   /* Now copy the domains. */
1313   n = 0;
1314   p = str;
1315   while (*p)
1316     {
1317       channel->ndomains = n;
1318       q = p;
1319       while (*q && !ISSPACE(*q))
1320         q++;
1321       channel->domains[n] = malloc(q - p + 1);
1322       if (!channel->domains[n])
1323         return ARES_ENOMEM;
1324       memcpy(channel->domains[n], p, q - p);
1325       channel->domains[n][q - p] = 0;
1326       p = q;
1327       while (ISSPACE(*p))
1328         p++;
1329       n++;
1330     }
1331   channel->ndomains = n;
1332
1333   return ARES_SUCCESS;
1334 }
1335
1336 static int set_options(ares_channel channel, const char *str)
1337 {
1338   const char *p, *q, *val;
1339
1340   p = str;
1341   while (*p)
1342     {
1343       q = p;
1344       while (*q && !ISSPACE(*q))
1345         q++;
1346       val = try_option(p, q, "ndots:");
1347       if (val && channel->ndots == -1)
1348         channel->ndots = atoi(val);
1349       val = try_option(p, q, "retrans:");
1350       if (val && channel->timeout == -1)
1351         channel->timeout = atoi(val);
1352       val = try_option(p, q, "retry:");
1353       if (val && channel->tries == -1)
1354         channel->tries = atoi(val);
1355       val = try_option(p, q, "rotate");
1356       if (val && channel->rotate == -1)
1357         channel->rotate = 1;
1358       p = q;
1359       while (ISSPACE(*p))
1360         p++;
1361     }
1362
1363   return ARES_SUCCESS;
1364 }
1365
1366 #ifndef WIN32
1367 static char *try_config(char *s, const char *opt)
1368 {
1369   size_t len;
1370   ssize_t i;
1371   ssize_t j;
1372   char *p;
1373
1374   if (!s || !opt)
1375     /* no line or no option */
1376     return NULL;
1377
1378   /* trim line comment */
1379   for (i = 0; s[i] && s[i] != '#'; ++i);
1380   s[i] = '\0';
1381
1382   /* trim trailing whitespace */
1383   for (j = i-1; j >= 0 && ISSPACE(s[j]); --j);
1384   s[++j] = '\0';
1385
1386   /* skip leading whitespace */
1387   for (i = 0; s[i] && ISSPACE(s[i]); ++i);
1388   p = &s[i];
1389
1390   if (!*p)
1391     /* empty line */
1392     return NULL;
1393
1394   if ((len = strlen(opt)) == 0)
1395     /* empty option */
1396     return NULL;
1397
1398   if (strncmp(p, opt, len) != 0)
1399     /* line and option do not match */
1400     return NULL;
1401
1402   /* skip over given option name */
1403   p += len;
1404
1405   if (!*p)
1406     /* no option value */
1407     return NULL;
1408
1409   if ((opt[len-1] != ':') && (opt[len-1] != '=') && !ISSPACE(*p))
1410     /* whitespace between option name and value is mandatory
1411        for given option names which do not end with ':' or '=' */
1412     return NULL;
1413
1414   /* skip over whitespace */
1415   while (*p && ISSPACE(*p))
1416     p++;
1417
1418   if (!*p)
1419     /* no option value */
1420     return NULL;
1421
1422   /* return pointer to option value */
1423   return p;
1424 }
1425 #endif
1426
1427 static const char *try_option(const char *p, const char *q, const char *opt)
1428 {
1429   size_t len = strlen(opt);
1430   return ((size_t)(q - p) >= len && !strncmp(p, opt, len)) ? &p[len] : NULL;
1431 }
1432
1433 #ifndef WIN32
1434 static int sortlist_alloc(struct apattern **sortlist, int *nsort,
1435                           struct apattern *pat)
1436 {
1437   struct apattern *newsort;
1438   newsort = realloc(*sortlist, (*nsort + 1) * sizeof(struct apattern));
1439   if (!newsort)
1440     return 0;
1441   newsort[*nsort] = *pat;
1442   *sortlist = newsort;
1443   (*nsort)++;
1444   return 1;
1445 }
1446
1447 static int ip_addr(const char *ipbuf, int len, struct in_addr *addr)
1448 {
1449
1450   /* Four octets and three periods yields at most 15 characters. */
1451   if (len > 15)
1452     return -1;
1453
1454   addr->s_addr = inet_addr(ipbuf);
1455   if (addr->s_addr == INADDR_NONE && strcmp(ipbuf, "255.255.255.255") != 0)
1456     return -1;
1457   return 0;
1458 }
1459
1460 static void natural_mask(struct apattern *pat)
1461 {
1462   struct in_addr addr;
1463
1464   /* Store a host-byte-order copy of pat in a struct in_addr.  Icky,
1465    * but portable.
1466    */
1467   addr.s_addr = ntohl(pat->addrV4.s_addr);
1468
1469   /* This is out of date in the CIDR world, but some people might
1470    * still rely on it.
1471    */
1472   if (IN_CLASSA(addr.s_addr))
1473     pat->mask.addr4.s_addr = htonl(IN_CLASSA_NET);
1474   else if (IN_CLASSB(addr.s_addr))
1475     pat->mask.addr4.s_addr = htonl(IN_CLASSB_NET);
1476   else
1477     pat->mask.addr4.s_addr = htonl(IN_CLASSC_NET);
1478 }
1479 #endif
1480 /* initialize an rc4 key. If possible a cryptographically secure random key
1481    is generated using a suitable function (for example win32's RtlGenRandom as
1482    described in
1483    http://blogs.msdn.com/michael_howard/archive/2005/01/14/353379.aspx
1484    otherwise the code defaults to cross-platform albeit less secure mechanism
1485    using rand
1486 */
1487 static void randomize_key(unsigned char* key,int key_data_len)
1488 {
1489   int randomized = 0;
1490   int counter=0;
1491 #ifdef WIN32
1492   HMODULE lib=LoadLibrary("ADVAPI32.DLL");
1493   if (lib) {
1494     BOOLEAN (APIENTRY *pfn)(void*, ULONG) =
1495       (BOOLEAN (APIENTRY *)(void*,ULONG))GetProcAddress(lib,"SystemFunction036");
1496     if (pfn && pfn(key,key_data_len) )
1497       randomized = 1;
1498
1499     FreeLibrary(lib);
1500   }
1501 #else /* !WIN32 */
1502 #ifdef RANDOM_FILE
1503   FILE *f = fopen(RANDOM_FILE, "rb");
1504   if(f) {
1505     counter = fread(key, 1, key_data_len, f);
1506     fclose(f);
1507   }
1508 #endif
1509 #endif /* WIN32 */
1510
1511   if ( !randomized ) {
1512     for (;counter<key_data_len;counter++)
1513       key[counter]=(unsigned char)(rand() % 256);
1514   }
1515 }
1516
1517 static int init_id_key(rc4_key* key,int key_data_len)
1518 {
1519   unsigned char index1;
1520   unsigned char index2;
1521   unsigned char* state;
1522   short counter;
1523   unsigned char *key_data_ptr = 0;
1524
1525   key_data_ptr = calloc(1,key_data_len);
1526   if (!key_data_ptr)
1527     return ARES_ENOMEM;
1528
1529   state = &key->state[0];
1530   for(counter = 0; counter < 256; counter++)
1531     /* unnecessary AND but it keeps some compilers happier */
1532     state[counter] = (unsigned char)(counter & 0xff);
1533   randomize_key(key->state,key_data_len);
1534   key->x = 0;
1535   key->y = 0;
1536   index1 = 0;
1537   index2 = 0;
1538   for(counter = 0; counter < 256; counter++)
1539   {
1540     index2 = (unsigned char)((key_data_ptr[index1] + state[counter] +
1541                               index2) % 256);
1542     ARES_SWAP_BYTE(&state[counter], &state[index2]);
1543
1544     index1 = (unsigned char)((index1 + 1) % key_data_len);
1545   }
1546   free(key_data_ptr);
1547   return ARES_SUCCESS;
1548 }
1549
1550 unsigned short ares__generate_new_id(rc4_key* key)
1551 {
1552   unsigned short r=0;
1553   ares__rc4(key, (unsigned char *)&r, sizeof(r));
1554   return r;
1555 }
1556
1557 void ares_set_socket_callback(ares_channel channel,
1558                               ares_sock_create_callback cb,
1559                               void *data)
1560 {
1561   channel->sock_create_cb = cb;
1562   channel->sock_create_cb_data = data;
1563 }