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