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