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