dirmngr: Implement CERT record lookup via libdns.
[gnupg.git] / dirmngr / dns-stuff.c
1 /* dns-stuff.c - DNS related code including CERT RR (rfc-4398)
2  * Copyright (C) 2003, 2005, 2006, 2009 Free Software Foundation, Inc.
3  * Copyright (C) 2005, 2006, 2009, 2015. 2016 Werner Koch
4  *
5  * This file is part of GnuPG.
6  *
7  * This file is free software; you can redistribute it and/or modify
8  * it under the terms of either
9  *
10  *   - the GNU Lesser General Public License as published by the Free
11  *     Software Foundation; either version 3 of the License, or (at
12  *     your option) any later version.
13  *
14  * or
15  *
16  *   - the GNU General Public License as published by the Free
17  *     Software Foundation; either version 2 of the License, or (at
18  *     your option) any later version.
19  *
20  * or both in parallel, as here.
21  *
22  * This file is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program; if not, see <https://www.gnu.org/licenses/>.
29  */
30
31 #include <config.h>
32 #include <sys/types.h>
33 #ifdef HAVE_W32_SYSTEM
34 # ifdef HAVE_WINSOCK2_H
35 #  include <winsock2.h>
36 # endif
37 # include <windows.h>
38 #else
39 # if HAVE_SYSTEM_RESOLVER
40 #  include <netinet/in.h>
41 #  include <arpa/nameser.h>
42 #  include <resolv.h>
43 # endif
44 # include <netdb.h>
45 #endif
46 #include <string.h>
47 #include <unistd.h>
48
49 /* William Ahern's DNS library, included as a source copy.  */
50 #include "dns.h"
51
52 /* dns.c has a dns_p_free but it is not exported.  We use our own
53  * wrapper here so that we do not accidentally use xfree which would
54  * be wrong for dns.c allocated data.  */
55 #define dns_free(a)  free ((a))
56
57
58 #ifdef WITHOUT_NPTH /* Give the Makefile a chance to build without Pth.  */
59 # undef USE_NPTH
60 #endif
61 #ifdef USE_NPTH
62 # include <npth.h>
63 #endif
64
65 #include "./dirmngr-err.h"
66 #include "util.h"
67 #include "host2net.h"
68 #include "dns-stuff.h"
69
70 #ifdef USE_NPTH
71 # define my_unprotect()        npth_unprotect ()
72 # define my_protect()          npth_protect ()
73 #else
74 # define my_unprotect()        do { } while(0)
75 # define my_protect()          do { } while(0)
76 #endif
77
78 /* We allow the use of 0 instead of AF_UNSPEC - check this assumption.  */
79 #if AF_UNSPEC != 0
80 # error AF_UNSPEC does not have the value 0
81 #endif
82
83 /* Windows does not support the AI_ADDRCONFIG flag - use zero instead.  */
84 #ifndef AI_ADDRCONFIG
85 # define AI_ADDRCONFIG 0
86 #endif
87
88 /* Not every installation has gotten around to supporting SRVs or
89    CERTs yet... */
90 #ifndef T_SRV
91 #define T_SRV 33
92 #endif
93 #ifndef T_CERT
94 # define T_CERT 37
95 #endif
96
97
98 /* The default nameserver used in Tor mode.  */
99 #define DEFAULT_NAMESERVER "8.8.8.8"
100
101 /* If set force the use of the standard resolver.  */
102 static int standard_resolver;
103
104 /* If set Tor mode shall be used.  */
105 static int tor_mode;
106
107 /* A string with the nameserver IP address used with Tor.
108   (40 should be sufficient for v6 but we add some extra for a scope.) */
109 static char tor_nameserver[40+20];
110
111 /* A string to hold the credentials presented to Tor.  */
112 static char tor_credentials[50];
113
114 /* Libdns gobal data.  */
115 struct
116 {
117   struct dns_resolv_conf *resolv_conf;
118   struct dns_hosts *hosts;
119   struct dns_hints *hints;
120
121   struct sockaddr_storage socks_host;
122 } libdns;
123
124
125 /* Calling this function with YES set to True forces the use of the
126  * standard resolver even if dirmngr has been built with support for
127  * an alternative resolver.  */
128 void
129 enable_standard_resolver (int yes)
130 {
131   standard_resolver = yes;
132 }
133
134
135 /* Return true if the standard resolver is used.  */
136 int
137 standard_resolver_p (void)
138 {
139   return standard_resolver;
140 }
141
142
143 /* Sets the module in Tor mode.  Returns 0 is this is possible or an
144    error code.  */
145 gpg_error_t
146 enable_dns_tormode (int new_circuit)
147 {
148   /* XXX: dns.c doesn't support SOCKS credentials.  */
149
150   if (!*tor_credentials || new_circuit)
151     {
152       static unsigned int counter;
153
154       gpgrt_snprintf (tor_credentials, sizeof tor_credentials,
155                       "dirmngr-%lu:p%u",
156                       (unsigned long)getpid (), counter);
157       counter++;
158     }
159   tor_mode = 1;
160   return 0;
161 }
162
163
164 /* Change the default IP address of the nameserver to IPADDR.  The
165    address needs to be a numerical IP address and will be used for the
166    next DNS query.  Note that this is only used in Tor mode.  */
167 void
168 set_dns_nameserver (const char *ipaddr)
169 {
170   strncpy (tor_nameserver, ipaddr? ipaddr : DEFAULT_NAMESERVER,
171            sizeof tor_nameserver -1);
172   tor_nameserver[sizeof tor_nameserver -1] = 0;
173 }
174
175
176 /* Free an addressinfo linked list as returned by resolve_dns_name.  */
177 void
178 free_dns_addrinfo (dns_addrinfo_t ai)
179 {
180   while (ai)
181     {
182       dns_addrinfo_t next = ai->next;
183       xfree (ai);
184       ai = next;
185     }
186 }
187
188 /* Return H_ERRNO mapped to a gpg-error code.  Will never return 0. */
189 static gpg_error_t
190 get_h_errno_as_gpg_error (void)
191 {
192   gpg_err_code_t ec;
193
194   switch (h_errno)
195     {
196     case HOST_NOT_FOUND: ec = GPG_ERR_UNKNOWN_HOST; break;
197     case TRY_AGAIN:      ec = GPG_ERR_TRY_LATER; break;
198     case NO_RECOVERY:    ec = GPG_ERR_SERVER_FAILED; break;
199     case NO_DATA:        ec = GPG_ERR_NO_DATA; break;
200     default:             ec = GPG_ERR_UNKNOWN_ERRNO; break;
201     }
202   return gpg_error (ec);
203 }
204
205
206 static gpg_error_t
207 map_eai_to_gpg_error (int ec)
208 {
209   gpg_error_t err;
210
211   switch (ec)
212     {
213     case EAI_AGAIN:     err = gpg_error (GPG_ERR_EAGAIN); break;
214     case EAI_BADFLAGS:  err = gpg_error (GPG_ERR_INV_FLAG); break;
215     case EAI_FAIL:      err = gpg_error (GPG_ERR_SERVER_FAILED); break;
216     case EAI_MEMORY:    err = gpg_error (GPG_ERR_ENOMEM); break;
217 #ifdef EAI_NODATA
218     case EAI_NODATA:    err = gpg_error (GPG_ERR_NO_DATA); break;
219 #endif
220     case EAI_NONAME:    err = gpg_error (GPG_ERR_NO_NAME); break;
221     case EAI_SERVICE:   err = gpg_error (GPG_ERR_NOT_SUPPORTED); break;
222     case EAI_FAMILY:    err = gpg_error (GPG_ERR_EAFNOSUPPORT); break;
223     case EAI_SOCKTYPE:  err = gpg_error (GPG_ERR_ESOCKTNOSUPPORT); break;
224 #ifndef HAVE_W32_SYSTEM
225 # ifdef EAI_ADDRFAMILY
226     case EAI_ADDRFAMILY:err = gpg_error (GPG_ERR_EADDRNOTAVAIL); break;
227 # endif
228     case EAI_SYSTEM:    err = gpg_error_from_syserror (); break;
229 #endif
230     default:            err = gpg_error (GPG_ERR_UNKNOWN_ERRNO); break;
231     }
232   return err;
233 }
234
235
236 static gpg_error_t
237 libdns_error_to_gpg_error (int serr)
238 {
239   gpg_err_code_t ec;
240
241   switch (serr)
242     {
243     case 0: ec = 0; break;
244
245     case DNS_ENOBUFS:  ec = GPG_ERR_BUFFER_TOO_SHORT; break;
246     case DNS_EILLEGAL: ec = GPG_ERR_INV_OBJ; break;
247     case DNS_EORDER:   ec = GPG_ERR_INV_ORDER; break;
248     case DNS_ESECTION: ec = GPG_ERR_DNS_SECTION; break;
249     case DNS_EUNKNOWN: ec = GPG_ERR_DNS_UNKNOWN; break;
250     case DNS_EADDRESS: ec = GPG_ERR_DNS_ADDRESS; break;
251     case DNS_ENOQUERY: ec = GPG_ERR_DNS_NO_QUERY; break;
252     case DNS_ENOANSWER:ec = GPG_ERR_DNS_NO_ANSWER; break;
253     case DNS_EFETCHED: ec = GPG_ERR_ALREADY_FETCHED; break;
254     case DNS_ESERVICE: ec = GPG_ERR_NOT_SUPPORTED; break;
255     case DNS_ENONAME:  ec = GPG_ERR_NO_NAME; break;
256     case DNS_EFAIL:    ec = GPG_ERR_SERVER_FAILED; break;
257     case DNS_ECONNFIN: ec = GPG_ERR_DNS_CLOSED; break;
258     case DNS_EVERIFY:  ec = GPG_ERR_DNS_VERIFY; break;
259
260     default:
261       if (serr >= 0)
262         ec = gpg_err_code_from_errno (serr);
263       else
264         ec = GPG_ERR_DNS_UNKNOWN;
265       break;
266     }
267   return gpg_error (ec);
268 }
269
270
271 static gpg_error_t
272 libdns_init (void)
273 {
274   int error;
275
276   libdns.resolv_conf = dns_resconf_open (&error);
277   if (! libdns.resolv_conf)
278     goto leave;
279
280 #if 0
281   error = dns_resconf_pton (&libdns.resolv_conf->nameserver[0],
282                             "[127.0.0.1]:53");
283   if (error)
284     goto leave;
285 #else
286   error = dns_resconf_loadpath (libdns.resolv_conf, "/etc/resolv.conf");
287   if (error)
288     goto leave;
289
290   error = dns_nssconf_loadpath (libdns.resolv_conf, "/etc/nsswitch.conf");
291   if (error)
292     goto leave;
293 #endif
294
295   libdns.hosts = dns_hosts_open (&error);
296   if (! libdns.hosts)
297     goto leave;
298
299   /* dns_hints_local for stub mode, dns_hints_root for recursive.  */
300   libdns.hints = dns_hints_local (libdns.resolv_conf, &error);
301   if (! libdns.hints)
302     goto leave;
303
304   /* XXX */
305  leave:
306   return libdns_error_to_gpg_error (error);
307 }
308
309
310 static gpg_error_t
311 resolve_name_libdns (const char *name, unsigned short port,
312                      int want_family, int want_socktype,
313                      dns_addrinfo_t *r_dai, char **r_canonname)
314 {
315   gpg_error_t err;
316   dns_addrinfo_t daihead = NULL;
317   dns_addrinfo_t dai;
318   struct dns_resolver *res = NULL;
319   struct dns_addrinfo *ai = NULL;
320   struct addrinfo hints;
321   struct addrinfo *ent;
322   char portstr_[21];
323   char *portstr = NULL;
324   int derr;
325
326   *r_dai = NULL;
327   if (r_canonname)
328     *r_canonname = NULL;
329
330   err = libdns_init ();
331   if (err)
332     goto leave;
333
334   memset (&hints, 0, sizeof hints);
335   hints.ai_family = want_family;
336   hints.ai_socktype = want_socktype;
337   hints.ai_flags = AI_ADDRCONFIG;
338   if (r_canonname)
339     hints.ai_flags |= AI_CANONNAME;
340
341   if (port)
342     {
343       snprintf (portstr_, sizeof portstr_, "%hu", port);
344       portstr = portstr_;
345     }
346
347   res = dns_res_open (libdns.resolv_conf, libdns.hosts, libdns.hints, NULL,
348                       dns_opts (/*.socks_host=&libdns.socks_host*/), &derr);
349   if (!res)
350     {
351       err = libdns_error_to_gpg_error (derr);
352       goto leave;
353     }
354
355   ai = dns_ai_open (name, portstr, 0, &hints, res, &derr);
356   if (!ai)
357     {
358       err = libdns_error_to_gpg_error (derr);
359       goto leave;
360     }
361
362   /* Loop over all records.  */
363   for (;;)
364     {
365       err = libdns_error_to_gpg_error (dns_ai_nextent (&ent, ai));
366       if (gpg_err_code (err) == GPG_ERR_ENOENT)
367         {
368           if (daihead)
369             err = 0; /* We got some results, we're good.  */
370           break; /* Ready.  */
371         }
372       if (gpg_err_code (err) == GPG_ERR_EAGAIN)
373         {
374           if (dns_ai_elapsed (ai) > 30)
375             {
376               err = gpg_error (GPG_ERR_DNS_TIMEOUT);
377               goto leave;
378             }
379
380           my_unprotect ();
381           dns_ai_poll (ai, 1);
382           my_protect ();
383           continue;
384         }
385       if (err)
386         goto leave;
387
388       if (r_canonname && ! *r_canonname && ent && ent->ai_canonname)
389         {
390           *r_canonname = xtrystrdup (ent->ai_canonname);
391           if (!*r_canonname)
392             {
393               err = gpg_error_from_syserror ();
394               goto leave;
395             }
396         }
397
398       dai = xtrymalloc (sizeof *dai + ent->ai_addrlen -1);
399       if (dai == NULL)
400         {
401           err = gpg_error_from_syserror ();
402           goto leave;
403         }
404
405       dai->family = ent->ai_family;
406       dai->socktype = ent->ai_socktype;
407       dai->protocol = ent->ai_protocol;
408       dai->addrlen = ent->ai_addrlen;
409       memcpy (dai->addr, ent->ai_addr, ent->ai_addrlen);
410       dai->next = daihead;
411       daihead = dai;
412
413       xfree (ent);
414   }
415
416  leave:
417   dns_ai_close (ai);
418   dns_res_close (res);
419
420   if (err)
421     {
422       if (r_canonname)
423         {
424           xfree (*r_canonname);
425           *r_canonname = NULL;
426         }
427       free_dns_addrinfo (daihead);
428     }
429   else
430     *r_dai = daihead;
431
432   return err;
433 }
434
435
436 /* Resolve a name using the standard system function.  */
437 static gpg_error_t
438 resolve_name_standard (const char *name, unsigned short port,
439                        int want_family, int want_socktype,
440                        dns_addrinfo_t *r_dai, char **r_canonname)
441 {
442   gpg_error_t err = 0;
443   dns_addrinfo_t daihead = NULL;
444   dns_addrinfo_t dai;
445   struct addrinfo *aibuf = NULL;
446   struct addrinfo hints, *ai;
447   char portstr[21];
448   int ret;
449
450   *r_dai = NULL;
451   if (r_canonname)
452     *r_canonname = NULL;
453
454   memset (&hints, 0, sizeof hints);
455   hints.ai_family = want_family;
456   hints.ai_socktype = want_socktype;
457   hints.ai_flags = AI_ADDRCONFIG;
458   if (r_canonname)
459     hints.ai_flags |= AI_CANONNAME;
460
461   if (port)
462     snprintf (portstr, sizeof portstr, "%hu", port);
463   else
464     *portstr = 0;
465
466   /* We can't use the the AI_IDN flag because that does the conversion
467      using the current locale.  However, GnuPG always used UTF-8.  To
468      support IDN we would need to make use of the libidn API.  */
469   ret = getaddrinfo (name, *portstr? portstr : NULL, &hints, &aibuf);
470   if (ret)
471     {
472       aibuf = NULL;
473       err = map_eai_to_gpg_error (ret);
474       if (gpg_err_code (err) == GPG_ERR_NO_NAME)
475         {
476           /* There seems to be a bug in the glibc getaddrinfo function
477              if the CNAME points to a long list of A and AAAA records
478              in which case the function return NO_NAME.  Let's do the
479              CNAME redirection again.  */
480           char *cname;
481
482           if (get_dns_cname (name, &cname))
483             goto leave; /* Still no success.  */
484
485           ret = getaddrinfo (cname, *portstr? portstr : NULL, &hints, &aibuf);
486           xfree (cname);
487           if (ret)
488             {
489               aibuf = NULL;
490               err = map_eai_to_gpg_error (ret);
491               goto leave;
492             }
493           err = 0; /* Yep, now it worked.  */
494         }
495       else
496         goto leave;
497     }
498
499   if (r_canonname && aibuf && aibuf->ai_canonname)
500     {
501       *r_canonname = xtrystrdup (aibuf->ai_canonname);
502       if (!*r_canonname)
503         {
504           err = gpg_error_from_syserror ();
505           goto leave;
506         }
507     }
508
509   for (ai = aibuf; ai; ai = ai->ai_next)
510     {
511       if (ai->ai_family != AF_INET6 && ai->ai_family != AF_INET)
512         continue;
513
514       dai = xtrymalloc (sizeof *dai + ai->ai_addrlen - 1);
515       dai->family = ai->ai_family;
516       dai->socktype = ai->ai_socktype;
517       dai->protocol = ai->ai_protocol;
518       dai->addrlen = ai->ai_addrlen;
519       memcpy (dai->addr, ai->ai_addr, ai->ai_addrlen);
520       dai->next = daihead;
521       daihead = dai;
522     }
523
524  leave:
525   if (aibuf)
526     freeaddrinfo (aibuf);
527   if (err)
528     {
529       if (r_canonname)
530         {
531           xfree (*r_canonname);
532           *r_canonname = NULL;
533         }
534       free_dns_addrinfo (daihead);
535     }
536   else
537     *r_dai = daihead;
538   return err;
539 }
540
541
542 /* Resolve an address using the standard system function.  */
543 static gpg_error_t
544 resolve_addr_standard (const struct sockaddr *addr, int addrlen,
545                        unsigned int flags, char **r_name)
546 {
547   gpg_error_t err;
548   int ec;
549   char *buffer, *p;
550   int buflen;
551
552   *r_name = NULL;
553
554   buflen = NI_MAXHOST;
555   buffer = xtrymalloc (buflen + 2 + 1);
556   if (!buffer)
557     return gpg_error_from_syserror ();
558
559   if ((flags & DNS_NUMERICHOST) || tor_mode)
560     ec = EAI_NONAME;
561   else
562     ec = getnameinfo (addr, addrlen, buffer, buflen, NULL, 0, NI_NAMEREQD);
563
564   if (!ec && *buffer == '[')
565     ec = EAI_FAIL;  /* A name may never start with a bracket.  */
566   else if (ec == EAI_NONAME)
567     {
568       p = buffer;
569       if (addr->sa_family == AF_INET6 && (flags & DNS_WITHBRACKET))
570         {
571           *p++ = '[';
572           buflen -= 2;
573         }
574       ec = getnameinfo (addr, addrlen, p, buflen, NULL, 0, NI_NUMERICHOST);
575       if (!ec && addr->sa_family == AF_INET6 && (flags & DNS_WITHBRACKET))
576         strcat (buffer, "]");
577     }
578
579   if (ec)
580     err = map_eai_to_gpg_error (ec);
581   else
582     {
583       p = xtryrealloc (buffer, strlen (buffer)+1);
584       if (!p)
585         err = gpg_error_from_syserror ();
586       else
587         {
588           buffer = p;
589           err = 0;
590         }
591     }
592
593   if (err)
594     xfree (buffer);
595   else
596     *r_name = buffer;
597
598   return err;
599 }
600
601
602 /* This a wrapper around getaddrinfo with slightly different semantics.
603    NAME is the name to resolve.
604    PORT is the requested port or 0.
605    WANT_FAMILY is either 0 (AF_UNSPEC), AF_INET6, or AF_INET4.
606    WANT_SOCKETTYPE is either SOCK_STREAM or SOCK_DGRAM.
607
608    On success the result is stored in a linked list with the head
609    stored at the address R_AI; the caller must call gpg_addrinfo_free
610    on this.  If R_CANONNAME is not NULL the official name of the host
611    is stored there as a malloced string; if that name is not available
612    NULL is stored.  */
613 gpg_error_t
614 resolve_dns_name (const char *name, unsigned short port,
615                   int want_family, int want_socktype,
616                   dns_addrinfo_t *r_ai, char **r_canonname)
617 {
618   if (!standard_resolver)
619     return resolve_name_libdns (name, port, want_family, want_socktype,
620                                 r_ai, r_canonname);
621
622   return resolve_name_standard (name, port, want_family, want_socktype,
623                                 r_ai, r_canonname);
624 }
625
626
627 gpg_error_t
628 resolve_dns_addr (const struct sockaddr *addr, int addrlen,
629                   unsigned int flags, char **r_name)
630 {
631   return resolve_addr_standard (addr, addrlen, flags, r_name);
632 }
633
634
635 /* Check whether NAME is an IP address.  Returns true if it is either
636    an IPv6 or IPv4 numerical address.  */
637 int
638 is_ip_address (const char *name)
639 {
640   const char *s;
641   int ndots, dblcol, n;
642
643   if (*name == '[')
644     return 1; /* yes: A legal DNS name may not contain this character;
645                  this mut be bracketed v6 address.  */
646   if (*name == '.')
647     return 0; /* No.  A leading dot is not a valid IP address.  */
648
649   /* Check whether this is a v6 address.  */
650   ndots = n = dblcol = 0;
651   for (s=name; *s; s++)
652     {
653       if (*s == ':')
654         {
655           ndots++;
656           if (s[1] == ':')
657             {
658               ndots++;
659               if (dblcol)
660                 return 0; /* No: Only one "::" allowed.  */
661               dblcol++;
662               if (s[1])
663                 s++;
664             }
665           n = 0;
666         }
667       else if (*s == '.')
668         goto legacy;
669       else if (!strchr ("0123456789abcdefABCDEF", *s))
670         return 0; /* No: Not a hex digit.  */
671       else if (++n > 4)
672         return 0; /* To many digits in a group.  */
673     }
674   if (ndots > 7)
675     return 0; /* No: Too many colons.  */
676   else if (ndots > 1)
677     return 1; /* Yes: At least 2 colons indicate an v6 address.  */
678
679  legacy:
680   /* Check whether it is legacy IP address.  */
681   ndots = n = 0;
682   for (s=name; *s; s++)
683     {
684       if (*s == '.')
685         {
686           if (s[1] == '.')
687             return 0; /* No:  Douple dot. */
688           if (atoi (s+1) > 255)
689             return 0; /* No:  Ipv4 byte value too large.  */
690           ndots++;
691           n = 0;
692         }
693       else if (!strchr ("0123456789", *s))
694         return 0; /* No: Not a digit.  */
695       else if (++n > 3)
696         return 0; /* No: More than 3 digits.  */
697     }
698   return !!(ndots == 3);
699 }
700
701
702 /* Return true if NAME is an onion address.  */
703 int
704 is_onion_address (const char *name)
705 {
706   size_t len;
707
708   len = name? strlen (name) : 0;
709   if (len < 8 || strcmp (name + len - 6, ".onion"))
710     return 0;
711   /* Note that we require at least 2 characters before the suffix.  */
712   return 1;  /* Yes.  */
713 }
714
715
716 /* libdns version of get_dns_cert.  */
717 static gpg_error_t
718 get_dns_cert_libdns (const char *name, int want_certtype,
719                      void **r_key, size_t *r_keylen,
720                      unsigned char **r_fpr, size_t *r_fprlen, char **r_url)
721 {
722   gpg_error_t err;
723   struct dns_resolver *res = NULL;
724   struct dns_packet *ans = NULL;
725   struct dns_rr rr;
726   struct dns_rr_i rri;
727   char host[DNS_D_MAXNAME + 1];
728   int derr;
729   int srvcount = 0;
730   int qtype;
731
732   /* Gte the query type from WANT_CERTTYPE (which in general indicates
733    * the subtype we want). */
734   qtype = (want_certtype < DNS_CERTTYPE_RRBASE
735            ? T_CERT
736            : (want_certtype - DNS_CERTTYPE_RRBASE));
737
738
739   err = libdns_init ();
740   if (err)
741     goto leave;
742
743   res = dns_res_open (libdns.resolv_conf, libdns.hosts, libdns.hints, NULL,
744                       dns_opts (/*.socks_host=&libdns.socks_host*/), &derr);
745   if (!res)
746     {
747       err = libdns_error_to_gpg_error (derr);
748       goto leave;
749     }
750
751   if (dns_d_anchor (host, sizeof host, name, strlen (name)) >= sizeof host)
752     {
753       err = gpg_error (GPG_ERR_ENAMETOOLONG);
754       goto leave;
755     }
756
757   err = libdns_error_to_gpg_error (dns_res_submit (res, name, qtype, DNS_C_IN));
758   if (err)
759     goto leave;
760
761   /* Loop until we found a record.  */
762   while ((err = libdns_error_to_gpg_error (dns_res_check (res))))
763     {
764       if (gpg_err_code (err) == GPG_ERR_EAGAIN)
765         {
766           if (dns_res_elapsed (res) > 30)
767             {
768               err = gpg_error (GPG_ERR_DNS_TIMEOUT);
769               goto leave;
770             }
771
772           my_unprotect ();
773           dns_res_poll (res, 1);
774           my_protect ();
775         }
776       else if (err)
777         goto leave;
778     }
779   ans = dns_res_fetch (res, &derr);
780   if (!ans)
781     {
782       err = libdns_error_to_gpg_error (derr);
783       goto leave;
784     }
785
786   /* Check the rcode.  */
787   switch (dns_p_rcode (ans))
788     {
789     case DNS_RC_NOERROR: break;
790     case DNS_RC_NXDOMAIN: err = gpg_error (GPG_ERR_NO_NAME); break;
791     default: err = GPG_ERR_SERVER_FAILED; break;
792     }
793   if (err)
794     goto leave;
795
796   memset (&rri, 0, sizeof rri);
797   dns_rr_i_init (&rri, ans);
798   rri.section = DNS_S_ALL & ~DNS_S_QD;
799   rri.name    = host;
800   rri.type    = qtype;
801
802   err = gpg_error (GPG_ERR_NOT_FOUND);
803   while (dns_rr_grep (&rr, 1, &rri, ans, &derr))
804     {
805       unsigned char *rp  = ans->data + rr.rd.p;
806       unsigned short len = rr.rd.len;
807       u16 subtype;
808
809        if (!len)
810         {
811           /* Definitely too short - skip.  */
812         }
813       else if (want_certtype >= DNS_CERTTYPE_RRBASE
814           && rr.type == (want_certtype - DNS_CERTTYPE_RRBASE)
815           && r_key)
816         {
817           *r_key = xtrymalloc (len);
818           if (!*r_key)
819             err = gpg_error_from_syserror ();
820           else
821             {
822               memcpy (*r_key, rp, len);
823               *r_keylen = len;
824               err = 0;
825             }
826           goto leave;
827         }
828       else if (want_certtype >= DNS_CERTTYPE_RRBASE)
829         {
830           /* We did not found the requested RR - skip. */
831         }
832       else if (rr.type == T_CERT && len > 5)
833         {
834           /* We got a CERT type.   */
835           subtype = buf16_to_u16 (rp);
836           rp += 2; len -= 2;
837
838           /* Skip the CERT key tag and algo which we don't need.  */
839           rp += 3; len -= 3;
840
841           if (want_certtype && want_certtype != subtype)
842             ; /* Not the requested subtype - skip.  */
843           else if (subtype == DNS_CERTTYPE_PGP && len && r_key && r_keylen)
844             {
845               /* PGP subtype */
846               *r_key = xtrymalloc (len);
847               if (!*r_key)
848                 err = gpg_error_from_syserror ();
849               else
850                 {
851                   memcpy (*r_key, rp, len);
852                   *r_keylen = len;
853                   err = 0;
854                 }
855               goto leave;
856             }
857           else if (subtype == DNS_CERTTYPE_IPGP
858                    && len && len < 1023 && len >= rp[0] + 1)
859             {
860               /* IPGP type */
861               *r_fprlen = rp[0];
862               if (*r_fprlen)
863                 {
864                   *r_fpr = xtrymalloc (*r_fprlen);
865                   if (!*r_fpr)
866                     {
867                       err = gpg_error_from_syserror ();
868                       goto leave;
869                     }
870                   memcpy (*r_fpr, rp+1, *r_fprlen);
871                 }
872               else
873                 *r_fpr = NULL;
874
875               if (len > *r_fprlen + 1)
876                 {
877                   *r_url = xtrymalloc (len - (*r_fprlen + 1) + 1);
878                   if (!*r_url)
879                     {
880                       err = gpg_error_from_syserror ();
881                       xfree (*r_fpr);
882                       *r_fpr = NULL;
883                       goto leave;
884                     }
885                   memcpy (*r_url, rp + *r_fprlen + 1, len - (*r_fprlen + 1));
886                   (*r_url)[len - (*r_fprlen + 1)] = 0;
887                 }
888               else
889                 *r_url = NULL;
890
891               err = 0;
892               goto leave;
893             }
894           else
895             {
896               /* Unknown subtype or record too short - skip.  */
897             }
898         }
899       else
900         {
901           /* Not a requested type - skip.  */
902         }
903     }
904
905  leave:
906   dns_free (ans);
907   dns_res_close (res);
908   return err;
909 }
910
911
912 /* Standard resolver version of get_dns_cert.  */
913 static gpg_error_t
914 get_dns_cert_standard (const char *name, int want_certtype,
915                        void **r_key, size_t *r_keylen,
916                        unsigned char **r_fpr, size_t *r_fprlen, char **r_url)
917 {
918 #ifdef HAVE_SYSTEM_RESOLVER
919   gpg_error_t err;
920   unsigned char *answer;
921   int r;
922   u16 count;
923
924   /* Allocate a 64k buffer which is the limit for an DNS response.  */
925   answer = xtrymalloc (65536);
926   if (!answer)
927     return gpg_error_from_syserror ();
928
929   err = gpg_error (GPG_ERR_NOT_FOUND);
930   r = res_query (name, C_IN,
931                  (want_certtype < DNS_CERTTYPE_RRBASE
932                   ? T_CERT
933                   : (want_certtype - DNS_CERTTYPE_RRBASE)),
934                  answer, 65536);
935   /* Not too big, not too small, no errors and at least 1 answer. */
936   if (r >= sizeof (HEADER) && r <= 65536
937       && (((HEADER *)(void *) answer)->rcode) == NOERROR
938       && (count = ntohs (((HEADER *)(void *) answer)->ancount)))
939     {
940       int rc;
941       unsigned char *pt, *emsg;
942
943       emsg = &answer[r];
944
945       pt = &answer[sizeof (HEADER)];
946
947       /* Skip over the query */
948
949       rc = dn_skipname (pt, emsg);
950       if (rc == -1)
951         {
952           err = gpg_error (GPG_ERR_INV_OBJ);
953           goto leave;
954         }
955       pt += rc + QFIXEDSZ;
956
957       /* There are several possible response types for a CERT request.
958          We're interested in the PGP (a key) and IPGP (a URI) types.
959          Skip all others.  TODO: A key is better than a URI since
960          we've gone through all this bother to fetch it, so favor that
961          if we have both PGP and IPGP? */
962
963       while (count-- > 0 && pt < emsg)
964         {
965           u16 type, class, dlen, ctype;
966
967           rc = dn_skipname (pt, emsg);  /* the name we just queried for */
968           if (rc == -1)
969             {
970               err = gpg_error (GPG_ERR_INV_OBJ);
971               goto leave;
972             }
973
974           pt += rc;
975
976           /* Truncated message? 15 bytes takes us to the point where
977              we start looking at the ctype. */
978           if ((emsg - pt) < 15)
979             break;
980
981           type = buf16_to_u16 (pt);
982           pt += 2;
983
984           class = buf16_to_u16 (pt);
985           pt += 2;
986
987           if (class != C_IN)
988             break;
989
990           /* ttl */
991           pt += 4;
992
993           /* data length */
994           dlen = buf16_to_u16 (pt);
995           pt += 2;
996
997           /* Check the type and parse.  */
998           if (want_certtype >= DNS_CERTTYPE_RRBASE
999               && type == (want_certtype - DNS_CERTTYPE_RRBASE)
1000               && r_key)
1001             {
1002               *r_key = xtrymalloc (dlen);
1003               if (!*r_key)
1004                 err = gpg_error_from_syserror ();
1005               else
1006                 {
1007                   memcpy (*r_key, pt, dlen);
1008                   *r_keylen = dlen;
1009                   err = 0;
1010                 }
1011               goto leave;
1012             }
1013           else if (want_certtype >= DNS_CERTTYPE_RRBASE)
1014             {
1015               /* We did not found the requested RR.  */
1016               pt += dlen;
1017             }
1018           else if (type == T_CERT)
1019             {
1020               /* We got a CERT type.   */
1021               ctype = buf16_to_u16 (pt);
1022               pt += 2;
1023
1024               /* Skip the CERT key tag and algo which we don't need. */
1025               pt += 3;
1026
1027               dlen -= 5;
1028
1029               /* 15 bytes takes us to here */
1030               if (want_certtype && want_certtype != ctype)
1031                 ; /* Not of the requested certtype.  */
1032               else if (ctype == DNS_CERTTYPE_PGP && dlen && r_key && r_keylen)
1033                 {
1034                   /* PGP type */
1035                   *r_key = xtrymalloc (dlen);
1036                   if (!*r_key)
1037                     err = gpg_error_from_syserror ();
1038                   else
1039                     {
1040                       memcpy (*r_key, pt, dlen);
1041                       *r_keylen = dlen;
1042                       err = 0;
1043                     }
1044                   goto leave;
1045                 }
1046               else if (ctype == DNS_CERTTYPE_IPGP
1047                        && dlen && dlen < 1023 && dlen >= pt[0] + 1)
1048                 {
1049                   /* IPGP type */
1050                   *r_fprlen = pt[0];
1051                   if (*r_fprlen)
1052                     {
1053                       *r_fpr = xtrymalloc (*r_fprlen);
1054                       if (!*r_fpr)
1055                         {
1056                           err = gpg_error_from_syserror ();
1057                           goto leave;
1058                         }
1059                       memcpy (*r_fpr, &pt[1], *r_fprlen);
1060                     }
1061                   else
1062                     *r_fpr = NULL;
1063
1064                   if (dlen > *r_fprlen + 1)
1065                     {
1066                       *r_url = xtrymalloc (dlen - (*r_fprlen + 1) + 1);
1067                       if (!*r_url)
1068                         {
1069                           err = gpg_error_from_syserror ();
1070                           xfree (*r_fpr);
1071                           *r_fpr = NULL;
1072                           goto leave;
1073                         }
1074                       memcpy (*r_url, &pt[*r_fprlen + 1],
1075                               dlen - (*r_fprlen + 1));
1076                       (*r_url)[dlen - (*r_fprlen + 1)] = '\0';
1077                     }
1078                   else
1079                     *r_url = NULL;
1080
1081                   err = 0;
1082                   goto leave;
1083                 }
1084
1085               /* No subtype matches, so continue with the next answer. */
1086               pt += dlen;
1087             }
1088           else
1089             {
1090               /* Not a requested type - might be a CNAME. Try next item.  */
1091               pt += dlen;
1092             }
1093         }
1094     }
1095
1096  leave:
1097   xfree (answer);
1098   return err;
1099
1100 #else /*!HAVE_SYSTEM_RESOLVER*/
1101
1102   (void)name;
1103   (void)want_certtype;
1104   (void)r_key;
1105   (void)r_keylen;
1106   (void)r_fpr;
1107   (void)r_fprlen;
1108   (void)r_url;
1109   return gpg_error (GPG_ERR_NOT_SUPPORTED);
1110
1111 #endif /*!HAVE_SYSTEM_RESOLVER*/
1112 }
1113
1114
1115 /* Returns 0 on success or an error code.  If a PGP CERT record was
1116    found, the malloced data is returned at (R_KEY, R_KEYLEN) and
1117    the other return parameters are set to NULL/0.  If an IPGP CERT
1118    record was found the fingerprint is stored as an allocated block at
1119    R_FPR and its length at R_FPRLEN; an URL is is allocated as a
1120    string and returned at R_URL.  If WANT_CERTTYPE is 0 this function
1121    returns the first CERT found with a supported type; it is expected
1122    that only one CERT record is used.  If WANT_CERTTYPE is one of the
1123    supported certtypes only records with this certtype are considered
1124    and the first found is returned.  (R_KEY,R_KEYLEN) are optional. */
1125 gpg_error_t
1126 get_dns_cert (const char *name, int want_certtype,
1127               void **r_key, size_t *r_keylen,
1128               unsigned char **r_fpr, size_t *r_fprlen, char **r_url)
1129 {
1130   if (r_key)
1131     *r_key = NULL;
1132   if (r_keylen)
1133     *r_keylen = 0;
1134   *r_fpr = NULL;
1135   *r_fprlen = 0;
1136   *r_url = NULL;
1137
1138   if (!standard_resolver)
1139     return get_dns_cert_libdns (name, want_certtype, r_key, r_keylen,
1140                                 r_fpr, r_fprlen, r_url);
1141
1142   return get_dns_cert_standard (name, want_certtype, r_key, r_keylen,
1143                                 r_fpr, r_fprlen, r_url);
1144 }
1145
1146
1147 static int
1148 priosort(const void *a,const void *b)
1149 {
1150   const struct srventry *sa=a,*sb=b;
1151   if(sa->priority>sb->priority)
1152     return 1;
1153   else if(sa->priority<sb->priority)
1154     return -1;
1155   else
1156     return 0;
1157 }
1158
1159
1160 /* Libdns based helper for getsrv.  Note that it is expected that NULL
1161  * is stored at the address of LIST and 0 is stored at the address of
1162  * R_COUNT.  */
1163 static gpg_error_t
1164 getsrv_libdns (const char *name, struct srventry **list, int *r_count)
1165 {
1166   gpg_error_t err;
1167   struct dns_resolver *res = NULL;
1168   struct dns_packet *ans = NULL;
1169   struct dns_rr rr;
1170   struct dns_rr_i rri;
1171   char host[DNS_D_MAXNAME + 1];
1172   int derr;
1173   int srvcount=0;
1174
1175   err = libdns_init ();
1176   if (err)
1177     goto leave;
1178
1179   res = dns_res_open (libdns.resolv_conf, libdns.hosts, libdns.hints, NULL,
1180                       dns_opts (/*.socks_host=&libdns.socks_host*/), &derr);
1181   if (!res)
1182     {
1183       err = libdns_error_to_gpg_error (derr);
1184       goto leave;
1185     }
1186
1187   if (dns_d_anchor (host, sizeof host, name, strlen (name)) >= sizeof host)
1188     {
1189       err = gpg_error (GPG_ERR_ENAMETOOLONG);
1190       goto leave;
1191     }
1192
1193   err = libdns_error_to_gpg_error
1194     (dns_res_submit (res, name, DNS_T_SRV, DNS_C_IN));
1195   if (err)
1196     goto leave;
1197
1198   /* Loop until we found a record.  */
1199   while ((err = libdns_error_to_gpg_error (dns_res_check (res))))
1200     {
1201       if (gpg_err_code (err) == GPG_ERR_EAGAIN)
1202         {
1203           if (dns_res_elapsed (res) > 30)
1204             {
1205               err = gpg_error (GPG_ERR_DNS_TIMEOUT);
1206               goto leave;
1207             }
1208
1209           my_unprotect ();
1210           dns_res_poll (res, 1);
1211           my_protect ();
1212         }
1213       else if (err)
1214         goto leave;
1215     }
1216   ans = dns_res_fetch (res, &derr);
1217   if (!ans)
1218     {
1219       err = libdns_error_to_gpg_error (derr);
1220       goto leave;
1221     }
1222
1223   /* Check the rcode.  */
1224   switch (dns_p_rcode (ans))
1225     {
1226     case DNS_RC_NOERROR: break;
1227     case DNS_RC_NXDOMAIN: err = gpg_error (GPG_ERR_NO_NAME); break;
1228     default: err = GPG_ERR_SERVER_FAILED; break;
1229     }
1230   if (err)
1231     goto leave;
1232
1233   memset (&rri, 0, sizeof rri);
1234   dns_rr_i_init (&rri, ans);
1235   rri.section = DNS_S_ALL & ~DNS_S_QD;
1236   rri.name        = host;
1237   rri.type        = DNS_T_SRV;
1238
1239   while (dns_rr_grep (&rr, 1, &rri, ans, &derr))
1240     {
1241       struct dns_srv dsrv;
1242       struct srventry *srv;
1243       struct srventry *newlist;
1244
1245       err = libdns_error_to_gpg_error (dns_srv_parse(&dsrv, &rr, ans));
1246       if (err)
1247         goto leave;
1248
1249       newlist = xtryrealloc (*list, (srvcount+1)*sizeof(struct srventry));
1250       if (!newlist)
1251         {
1252           err = gpg_error_from_syserror ();
1253           goto leave;
1254         }
1255       *list = newlist;
1256       memset (&(*list)[srvcount], 0, sizeof(struct srventry));
1257       srv = &(*list)[srvcount];
1258       srvcount++;
1259       srv->priority = dsrv.priority;
1260       srv->weight   = dsrv.weight;
1261       srv->port     = dsrv.port;
1262       mem2str (srv->target, dsrv.target, sizeof srv->target);
1263     }
1264
1265   *r_count = srvcount;
1266
1267  leave:
1268   if (err)
1269     {
1270       xfree (*list);
1271       *list = NULL;
1272     }
1273   dns_free (ans);
1274   dns_res_close (res);
1275   return err;
1276 }
1277
1278
1279 /* Standard resolver based helper for getsrv.  Note that it is
1280  * expected that NULL is stored at the address of LIST and 0 is stored
1281  * at the address of R_COUNT.  */
1282 static gpg_error_t
1283 getsrv_standard (const char *name, struct srventry **list, int *r_count)
1284 {
1285 #ifdef HAVE_SYSTEM_RESOLVER
1286   union {
1287     unsigned char ans[2048];
1288     HEADER header[1];
1289   } res;
1290   unsigned char *answer = res.ans;
1291   HEADER *header = res.header;
1292   unsigned char *pt, *emsg;
1293   int r, rc;
1294   u16 dlen;
1295   int srvcount=0;
1296   u16 count;
1297
1298   /* Do not allow a query using the standard resolver in Tor mode.  */
1299   if (tor_mode)
1300     return gpg_error (GPG_ERR_NOT_ENABLED);
1301
1302   my_unprotect ();
1303   r = res_query (name, C_IN, T_SRV, answer, sizeof res.ans);
1304   my_protect ();
1305   if (r < 0)
1306     return get_h_errno_as_gpg_error ();
1307   if (r < sizeof (HEADER))
1308     return gpg_error (GPG_ERR_SERVER_FAILED);
1309   if (r > sizeof res.ans)
1310     return gpg_error (GPG_ERR_SYSTEM_BUG);
1311   if (header->rcode != NOERROR || !(count=ntohs (header->ancount)))
1312     return gpg_error (GPG_ERR_NO_NAME); /* Error or no record found.  */
1313
1314   emsg = &answer[r];
1315   pt = &answer[sizeof(HEADER)];
1316
1317   /* Skip over the query */
1318   rc = dn_skipname (pt, emsg);
1319   if (rc == -1)
1320     goto fail;
1321
1322   pt += rc + QFIXEDSZ;
1323
1324   while (count-- > 0 && pt < emsg)
1325     {
1326       struct srventry *srv;
1327       u16 type, class;
1328       struct srventry *newlist;
1329
1330       newlist = xtryrealloc (*list, (srvcount+1)*sizeof(struct srventry));
1331       if (!newlist)
1332         goto fail;
1333       *list = newlist;
1334       memset (&(*list)[srvcount], 0, sizeof(struct srventry));
1335       srv = &(*list)[srvcount];
1336       srvcount++;
1337
1338       rc = dn_skipname (pt, emsg); /* The name we just queried for.  */
1339       if (rc == -1)
1340         goto fail;
1341       pt += rc;
1342
1343       /* Truncated message? */
1344       if ((emsg-pt) < 16)
1345         goto fail;
1346
1347       type = buf16_to_u16 (pt);
1348       pt += 2;
1349       /* We asked for SRV and got something else !? */
1350       if (type != T_SRV)
1351         goto fail;
1352
1353       class = buf16_to_u16 (pt);
1354       pt += 2;
1355       /* We asked for IN and got something else !? */
1356       if (class != C_IN)
1357         goto fail;
1358
1359       pt += 4; /* ttl */
1360       dlen = buf16_to_u16 (pt);
1361       pt += 2;
1362
1363       srv->priority = buf16_to_ushort (pt);
1364       pt += 2;
1365       srv->weight = buf16_to_ushort (pt);
1366       pt += 2;
1367       srv->port = buf16_to_ushort (pt);
1368       pt += 2;
1369
1370       /* Get the name.  2782 doesn't allow name compression, but
1371        * dn_expand still works to pull the name out of the packet. */
1372       rc = dn_expand (answer, emsg, pt, srv->target, sizeof srv->target);
1373       if (rc == 1 && srv->target[0] == 0) /* "." */
1374         {
1375           xfree(*list);
1376           *list = NULL;
1377           return 0;
1378         }
1379       if (rc == -1)
1380         goto fail;
1381       pt += rc;
1382       /* Corrupt packet? */
1383       if (dlen != rc+6)
1384         goto fail;
1385     }
1386
1387   *r_count = srvcount;
1388   return 0;
1389
1390  fail:
1391   xfree (*list);
1392   *list = NULL;
1393   return gpg_error (GPG_ERR_GENERAL);
1394
1395 #else /*!HAVE_SYSTEM_RESOLVER*/
1396
1397   (void)name;
1398   (void)list;
1399   (void)r_count;
1400   return gpg_error (GPG_ERR_NOT_SUPPORTED);
1401
1402 #endif /*!HAVE_SYSTEM_RESOLVER*/
1403 }
1404
1405
1406 int
1407 getsrv (const char *name, struct srventry **list)
1408 {
1409   gpg_error_t err;
1410   int srvcount;
1411   int i;
1412
1413   *list = NULL;
1414   srvcount = 0;
1415   if (!standard_resolver)
1416     err = getsrv_libdns (name, list, &srvcount);
1417   else
1418     err = getsrv_standard (name, list, &srvcount);
1419
1420   if (err)
1421     return -1;  /* Ugly.  FIXME: Return an error code. */
1422
1423   /* Now we have an array of all the srv records. */
1424
1425   /* Order by priority */
1426   qsort(*list,srvcount,sizeof(struct srventry),priosort);
1427
1428   /* For each priority, move the zero-weighted items first. */
1429   for (i=0; i < srvcount; i++)
1430     {
1431       int j;
1432
1433       for (j=i;j < srvcount && (*list)[i].priority == (*list)[j].priority; j++)
1434         {
1435           if((*list)[j].weight==0)
1436             {
1437               /* Swap j with i */
1438               if(j!=i)
1439                 {
1440                   struct srventry temp;
1441
1442                   memcpy (&temp,&(*list)[j],sizeof(struct srventry));
1443                   memcpy (&(*list)[j],&(*list)[i],sizeof(struct srventry));
1444                   memcpy (&(*list)[i],&temp,sizeof(struct srventry));
1445                 }
1446
1447               break;
1448             }
1449         }
1450     }
1451
1452   /* Run the RFC-2782 weighting algorithm.  We don't need very high
1453      quality randomness for this, so regular libc srand/rand is
1454      sufficient.  */
1455
1456   {
1457     static int done;
1458     if (!done)
1459       {
1460         done = 1;
1461         srand (time (NULL)*getpid());
1462       }
1463   }
1464
1465   for (i=0; i < srvcount; i++)
1466     {
1467       int j;
1468       float prio_count=0,chose;
1469
1470       for (j=i; j < srvcount && (*list)[i].priority == (*list)[j].priority; j++)
1471         {
1472           prio_count+=(*list)[j].weight;
1473           (*list)[j].run_count=prio_count;
1474         }
1475
1476       chose=prio_count*rand()/RAND_MAX;
1477
1478       for (j=i;j<srvcount && (*list)[i].priority==(*list)[j].priority;j++)
1479         {
1480           if (chose<=(*list)[j].run_count)
1481             {
1482               /* Swap j with i */
1483               if(j!=i)
1484                 {
1485                   struct srventry temp;
1486
1487                   memcpy(&temp,&(*list)[j],sizeof(struct srventry));
1488                   memcpy(&(*list)[j],&(*list)[i],sizeof(struct srventry));
1489                   memcpy(&(*list)[i],&temp,sizeof(struct srventry));
1490                 }
1491               break;
1492             }
1493         }
1494     }
1495
1496   return srvcount;
1497 }
1498
1499
1500 \f
1501 /* libdns version of get_dns_cname.  */
1502 gpg_error_t
1503 get_dns_cname_libdns (const char *name, char **r_cname)
1504 {
1505   gpg_error_t err;
1506   struct dns_resolver *res = NULL;
1507   struct dns_packet *ans = NULL;
1508   struct dns_rr rr;
1509   struct dns_cname cname;
1510   int derr;
1511
1512   err = libdns_init ();
1513   if (err)
1514     goto leave;
1515
1516   res = dns_res_open (libdns.resolv_conf, libdns.hosts, libdns.hints, NULL,
1517                       dns_opts (/*.socks_host=&libdns.socks_host*/), &derr);
1518   if (!res)
1519     {
1520       err = libdns_error_to_gpg_error (derr);
1521       goto leave;
1522     }
1523
1524   err = libdns_error_to_gpg_error
1525     (dns_res_submit (res, name, DNS_T_CNAME, DNS_C_IN));
1526   if (err)
1527     goto leave;
1528
1529   /* Loop until we found a record.  */
1530   while ((err = libdns_error_to_gpg_error (dns_res_check (res))))
1531     {
1532       if (gpg_err_code (err) == GPG_ERR_EAGAIN)
1533         {
1534           if (dns_res_elapsed (res) > 30)
1535             {
1536               err = gpg_error (GPG_ERR_DNS_TIMEOUT);
1537               goto leave;
1538             }
1539
1540           my_unprotect ();
1541           dns_res_poll (res, 1);
1542           my_protect ();
1543         }
1544       else if (err)
1545         goto leave;
1546     }
1547   ans = dns_res_fetch (res, &derr);
1548   if (!ans)
1549     {
1550       err = libdns_error_to_gpg_error (derr);
1551       goto leave;
1552     }
1553
1554   /* Check the rcode.  */
1555   switch (dns_p_rcode (ans))
1556     {
1557     case DNS_RC_NOERROR: break;
1558     case DNS_RC_NXDOMAIN: err = gpg_error (GPG_ERR_NO_NAME); break;
1559     default: err = GPG_ERR_SERVER_FAILED; break;
1560     }
1561   if (err)
1562     goto leave;
1563
1564   /* Parse the result into CNAME.  */
1565   err = libdns_error_to_gpg_error (dns_p_study (ans));
1566   if (err)
1567     goto leave;
1568
1569   if (!dns_d_cname (&cname, sizeof cname, name, strlen (name), ans, &derr))
1570     {
1571       err = libdns_error_to_gpg_error (derr);
1572       goto leave;
1573     }
1574
1575   /* Copy result.  */
1576   *r_cname = xtrystrdup (cname.host);
1577   if (!*r_cname)
1578     err = gpg_error_from_syserror ();
1579
1580  leave:
1581   dns_free (ans);
1582   dns_res_close (res);
1583   return err;
1584 }
1585
1586
1587 /* Standard resolver version of get_dns_cname.  */
1588 gpg_error_t
1589 get_dns_cname_standard (const char *name, char **r_cname)
1590 {
1591 #ifdef HAVE_SYSTEM_RESOLVER
1592   gpg_error_t err;
1593   int rc;
1594   union {
1595     unsigned char ans[2048];
1596     HEADER header[1];
1597   } res;
1598   unsigned char *answer = res.ans;
1599   HEADER *header = res.header;
1600   unsigned char *pt, *emsg;
1601   int r;
1602   char *cname;
1603   int cnamesize = 1025;
1604   u16 count;
1605
1606   /* Do not allow a query using the standard resolver in Tor mode.  */
1607   if (tor_mode)
1608     return -1;
1609
1610   my_unprotect ();
1611   r = res_query (name, C_IN, T_CERT, answer, sizeof res.ans);
1612   my_protect ();
1613   if (r < 0)
1614     return get_h_errno_as_gpg_error ();
1615   if (r < sizeof (HEADER))
1616     return gpg_error (GPG_ERR_SERVER_FAILED);
1617   if (r > sizeof res.ans)
1618     return gpg_error (GPG_ERR_SYSTEM_BUG);
1619   if (header->rcode != NOERROR || !(count=ntohs (header->ancount)))
1620     return gpg_error (GPG_ERR_NO_NAME); /* Error or no record found.  */
1621   if (count != 1)
1622     return gpg_error (GPG_ERR_SERVER_FAILED);
1623
1624   emsg = &answer[r];
1625   pt = &answer[sizeof(HEADER)];
1626   rc = dn_skipname (pt, emsg);
1627   if (rc == -1)
1628     return gpg_error (GPG_ERR_SERVER_FAILED);
1629
1630   pt += rc + QFIXEDSZ;
1631   if (pt >= emsg)
1632     return gpg_error (GPG_ERR_SERVER_FAILED);
1633
1634   rc = dn_skipname (pt, emsg);
1635   if (rc == -1)
1636     return gpg_error (GPG_ERR_SERVER_FAILED);
1637   pt += rc + 2 + 2 + 4;
1638   if (pt+2 >= emsg)
1639     return gpg_error (GPG_ERR_SERVER_FAILED);
1640   pt += 2;  /* Skip rdlen */
1641
1642   cname = xtrymalloc (cnamesize);
1643   if (!cname)
1644     return gpg_error_from_syserror ();
1645
1646   rc = dn_expand (answer, emsg, pt, cname, cnamesize -1);
1647   if (rc == -1)
1648     {
1649       xfree (cname);
1650       return gpg_error (GPG_ERR_SERVER_FAILED);
1651     }
1652   *r_cname = xtryrealloc (cname, strlen (cname)+1);
1653   if (!*r_cname)
1654     {
1655       err = gpg_error_from_syserror ();
1656       xfree (cname);
1657       return err;
1658     }
1659   return 0;
1660
1661 #else /*!HAVE_SYSTEM_RESOLVER*/
1662
1663   (void)name;
1664   (void)r_cname;
1665   return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1666
1667 #endif /*!HAVE_SYSTEM_RESOLVER*/
1668 }
1669
1670
1671 gpg_error_t
1672 get_dns_cname (const char *name, char **r_cname)
1673 {
1674   *r_cname = NULL;
1675
1676   if (!standard_resolver)
1677     return get_dns_cname_libdns (name, r_cname);
1678
1679   return get_dns_cname_standard (name, r_cname);
1680 }