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