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