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