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