dirmngr: Implement a getnameinfo wrapper.
[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 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 <http://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 # include <netinet/in.h>
40 # include <arpa/nameser.h>
41 # include <resolv.h>
42 # include <netdb.h>
43 #endif
44 #include <string.h>
45 #ifdef USE_ADNS
46 # include <adns.h>
47 #endif
48
49 #if !defined(HAVE_GETADDRINFO) && !defined(USE_ADNS)
50 # error Either getaddrinfo or the ADNS libary is required.
51 #endif
52
53 #include "util.h"
54 #include "host2net.h"
55 #include "dns-stuff.h"
56
57
58 #if AF_UNSPEC != 0
59 # error AF_UNSPEC does not have the value 0
60 #endif
61
62 /* Not every installation has gotten around to supporting SRVs or
63    CERTs yet... */
64 #ifndef T_SRV
65 #define T_SRV 33
66 #endif
67 #ifndef T_CERT
68 # define T_CERT 37
69 #endif
70
71 /* ADNS has no support for CERT yet. */
72 #define my_adns_r_cert 37
73
74 /* If set Tor mode shall be used.  */
75 static int tor_mode;
76
77 /* Sets the module in Tor mode.  Returns 0 is this is possible or an
78    error code.  */
79 gpg_error_t
80 enable_dns_tormode (void)
81 {
82 #if defined(USE_DNS_CERT) && defined(USE_ADNS)
83 # if HAVE_ADNS_IF_TORMODE
84    tor_mode = 1;
85    return 0;
86 # endif
87 #endif
88   return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
89 }
90
91 /* Free an addressinfo linked list as returned by resolve_dns_name.  */
92 void
93 free_dns_addrinfo (dns_addrinfo_t ai)
94 {
95   while (ai)
96     {
97       dns_addrinfo_t next = ai->next;
98       xfree (ai);
99       ai = next;
100     }
101 }
102
103
104 static gpg_error_t
105 map_eai_to_gpg_error (int ec)
106 {
107   gpg_error_t err;
108
109   switch (ec)
110     {
111     case EAI_AGAIN:     err = gpg_error (GPG_ERR_EAGAIN); break;
112     case EAI_BADFLAGS:  err = gpg_error (GPG_ERR_INV_FLAG); break;
113     case EAI_FAIL:      err = gpg_error (GPG_ERR_SERVER_FAILED); break;
114     case EAI_MEMORY:    err = gpg_error (GPG_ERR_ENOMEM); break;
115     case EAI_NODATA:    err = gpg_error (GPG_ERR_NO_DATA); break;
116     case EAI_NONAME:    err = gpg_error (GPG_ERR_NO_NAME); break;
117     case EAI_SERVICE:   err = gpg_error (GPG_ERR_NOT_SUPPORTED); break;
118     case EAI_ADDRFAMILY:err = gpg_error (GPG_ERR_EADDRNOTAVAIL); break;
119     case EAI_FAMILY:    err = gpg_error (GPG_ERR_EAFNOSUPPORT); break;
120     case EAI_SOCKTYPE:  err = gpg_error (GPG_ERR_ESOCKTNOSUPPORT); break;
121     case EAI_SYSTEM:    err = gpg_error_from_syserror (); break;
122     default:            err = gpg_error (GPG_ERR_UNKNOWN_ERRNO); break;
123     }
124   return err;
125 }
126
127
128 /* Resolve a name using the standard system function.  */
129 static gpg_error_t
130 resolve_name_standard (const char *name, unsigned short port,
131                        int want_family, int want_socktype,
132                        dns_addrinfo_t *r_dai, char **r_canonname)
133 {
134   gpg_error_t err = 0;
135   dns_addrinfo_t daihead = NULL;
136   dns_addrinfo_t dai;
137   struct addrinfo *aibuf = NULL;
138   struct addrinfo hints, *ai;
139   char portstr[21];
140   int ret;
141
142   *r_dai = NULL;
143   if (r_canonname)
144     *r_canonname = NULL;
145
146   memset (&hints, 0, sizeof hints);
147   hints.ai_family = want_family;
148   hints.ai_socktype = want_socktype;
149   if (r_canonname)
150     hints.ai_flags = AI_CANONNAME;
151
152   if (port)
153     snprintf (portstr, sizeof portstr, "%hu", port);
154   else
155     *portstr = 0;
156
157   /* We can't use the the AI_IDN flag because that does the conversion
158      using the current locale.  However, GnuPG always used UTF-8.  To
159      support IDN we would need to make use of the libidn API.  */
160   ret = getaddrinfo (name, *portstr? portstr : NULL, &hints, &aibuf);
161   if (ret)
162     {
163       aibuf = NULL;
164       err = map_eai_to_gpg_error (ret);
165       goto leave;
166     }
167
168   if (r_canonname && aibuf && aibuf->ai_canonname)
169     {
170       *r_canonname = xtrystrdup (aibuf->ai_canonname);
171       if (!*r_canonname)
172         {
173           err = gpg_error_from_syserror ();
174           goto leave;
175         }
176     }
177
178   for (ai = aibuf; ai; ai = ai->ai_next)
179     {
180       if (ai->ai_family != AF_INET6 && ai->ai_family != AF_INET)
181         continue;
182
183       dai = xtrymalloc (sizeof *dai + ai->ai_addrlen - 1);
184       dai->family = ai->ai_family;
185       dai->socktype = ai->ai_socktype;
186       dai->protocol = ai->ai_protocol;
187       dai->addrlen = ai->ai_addrlen;
188       memcpy (dai->addr, ai->ai_addr, ai->ai_addrlen);
189       dai->next = daihead;
190       daihead = dai;
191     }
192
193  leave:
194   if (aibuf)
195     freeaddrinfo (aibuf);
196   if (err)
197     {
198       if (r_canonname)
199         {
200           xfree (*r_canonname);
201           *r_canonname = NULL;
202         }
203       free_dns_addrinfo (daihead);
204     }
205   else
206     *r_dai = daihead;
207   return err;
208 }
209
210
211 /* Resolve an address using the standard system function.  */
212 static gpg_error_t
213 resolve_addr_standard (const struct sockaddr *addr, int addrlen,
214                        unsigned int flags, char **r_name)
215 {
216   gpg_error_t err;
217   int ec;
218   char *buffer, *p;
219   int buflen;
220
221   *r_name = NULL;
222
223   buflen = NI_MAXHOST;
224   buffer = xtrymalloc (buflen + 2 + 1);
225   if (!buffer)
226     return gpg_error_from_syserror ();
227
228   if ((flags & DNS_NUMERICHOST) || tor_mode)
229     ec = EAI_NONAME;
230   else
231     ec = getnameinfo (addr, addrlen, buffer, buflen, NULL, 0, NI_NAMEREQD);
232
233   if (!ec && *buffer == '[')
234     ec = EAI_FAIL;  /* A name may never start with a bracket.  */
235   else if (ec == EAI_NONAME)
236     {
237       p = buffer;
238       if (addr->sa_family == AF_INET6 && (flags & DNS_WITHBRACKET))
239         {
240           *p++ = '[';
241           buflen -= 2;
242         }
243       ec = getnameinfo (addr, addrlen, p, buflen, NULL, 0, NI_NUMERICHOST);
244       if (!ec && addr->sa_family == AF_INET6 && (flags & DNS_WITHBRACKET))
245         strcat (buffer, "]");
246     }
247
248   if (ec)
249     err = map_eai_to_gpg_error (ec);
250   else
251     {
252       p = xtryrealloc (buffer, strlen (buffer)+1);
253       if (!p)
254         err = gpg_error_from_syserror ();
255       else
256         {
257           buffer = p;
258           err = 0;
259         }
260     }
261
262   if (err)
263     xfree (buffer);
264   else
265     *r_name = buffer;
266
267   return err;
268 }
269
270
271 /* This a wrapper around getaddrinfo with slighly different semantics.
272    NAME is the name to resolve.
273    PORT is the requested port or 0.
274    WANT_FAMILY is either 0 (AF_UNSPEC), AF_INET6, or AF_INET4.
275    WANT_SOCKETTYPE is either SOCK_STREAM or SOCK_DGRAM.
276
277    On success the result is stored in a linked list with the head
278    stored at the address R_AI; the caller must call gpg_addrinfo_free
279    on this.  If R_CANONNAME is not NULL the official name of the host
280    is stored there as a malloced string; if that name is not available
281    NULL is stored.  */
282 gpg_error_t
283 resolve_dns_name (const char *name, unsigned short port,
284                   int want_family, int want_socktype,
285                   dns_addrinfo_t *r_ai, char **r_canonname)
286 {
287 #ifdef USE_ADNS_disabled_for_now
288   return resolve_name_adns (name, port, want_family, want_socktype,
289                             r_ai, r_canonname);
290 #else
291   return resolve_name_standard (name, port, want_family, want_socktype,
292                                 r_ai, r_canonname);
293 #endif
294 }
295
296
297 gpg_error_t
298 resolve_dns_addr (const struct sockaddr *addr, int addrlen,
299                   unsigned int flags, char **r_name)
300 {
301 #ifdef USE_ADNS_disabled_for_now
302   return resolve_addr_adns (addr, addrlen, flags, r_name);
303 #else
304   return resolve_addr_standard (addr, addrlen, flags, r_name);
305 #endif
306 }
307
308
309 /* Check whether NAME is an IP address.  Returns true if it is either
310    an IPv6 or IPv4 numerical address.  */
311 int
312 is_ip_address (const char *name)
313 {
314   const char *s;
315   int ndots, dblcol, n;
316
317   if (*name == '[')
318     return 1; /* yes: A legal DNS name may not contain this character;
319                  this mut be bracketed v6 address.  */
320   if (*name == '.')
321     return 0; /* No.  A leading dot is not a valid IP address.  */
322
323   /* Check whether this is a v6 address.  */
324   ndots = n = dblcol = 0;
325   for (s=name; *s; s++)
326     {
327       if (*s == ':')
328         {
329           ndots++;
330           if (s[1] == ':')
331             {
332               ndots++;
333               if (dblcol)
334                 return 0; /* No: Only one "::" allowed.  */
335               dblcol++;
336               if (s[1])
337                 s++;
338             }
339           n = 0;
340         }
341       else if (*s == '.')
342         goto legacy;
343       else if (!strchr ("0123456789abcdefABCDEF", *s))
344         return 0; /* No: Not a hex digit.  */
345       else if (++n > 4)
346         return 0; /* To many digits in a group.  */
347     }
348   if (ndots > 7)
349     return 0; /* No: Too many colons.  */
350   else if (ndots > 1)
351     return 1; /* Yes: At least 2 colons indicate an v6 address.  */
352
353  legacy:
354   /* Check whether it is legacy IP address.  */
355   ndots = n = 0;
356   for (s=name; *s; s++)
357     {
358       if (*s == '.')
359         {
360           if (s[1] == '.')
361             return 0; /* No:  Douple dot. */
362           if (atoi (s+1) > 255)
363             return 0; /* No:  Ipv4 byte value too large.  */
364           ndots++;
365           n = 0;
366         }
367       else if (!strchr ("0123456789", *s))
368         return 0; /* No: Not a digit.  */
369       else if (++n > 3)
370         return 0; /* No: More than 3 digits.  */
371     }
372   return !!(ndots == 3);
373 }
374
375
376 #ifdef USE_ADNS
377 /* Init ADNS and store the new state at R_STATE.  Returns 0 on
378    success; prints an error message and returns an error code on
379    failure.  */
380 static gpg_error_t
381 my_adns_init (adns_state *r_state)
382 {
383   gpg_error_t err;
384
385   if (tor_mode? adns_init_strcfg (r_state,
386                                   adns_if_noerrprint|adns_if_tormode,
387                                   NULL, "nameserver 8.8.8.8")
388       /*    */: adns_init (r_state, adns_if_noerrprint, NULL))
389     {
390       err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
391       log_error ("error initializing adns: %s\n", gpg_strerror (err));
392       return err;
393     }
394   return 0;
395 }
396 #endif /*USE_ADNS*/
397
398
399 /* Returns 0 on success or an error code.  If a PGP CERT record was
400    found, the malloced data is returned at (R_KEY, R_KEYLEN) and
401    the other return parameters are set to NULL/0.  If an IPGP CERT
402    record was found the fingerprint is stored as an allocated block at
403    R_FPR and its length at R_FPRLEN; an URL is is allocated as a
404    string and returned at R_URL.  If WANT_CERTTYPE is 0 this function
405    returns the first CERT found with a supported type; it is expected
406    that only one CERT record is used.  If WANT_CERTTYPE is one of the
407    supported certtypes only records with this certtype are considered
408    and the first found is returned.  (R_KEY,R_KEYLEN) are optional. */
409 gpg_error_t
410 get_dns_cert (const char *name, int want_certtype,
411               void **r_key, size_t *r_keylen,
412               unsigned char **r_fpr, size_t *r_fprlen, char **r_url)
413 {
414 #ifdef USE_DNS_CERT
415 #ifdef USE_ADNS
416   gpg_error_t err;
417   adns_state state;
418   adns_answer *answer = NULL;
419   unsigned int ctype;
420   int count;
421
422   if (r_key)
423     *r_key = NULL;
424   if (r_keylen)
425     *r_keylen = 0;
426   *r_fpr = NULL;
427   *r_fprlen = 0;
428   *r_url = NULL;
429
430   err = my_adns_init (&state);
431   if (err)
432     return err;
433
434   if (adns_synchronous (state, name,
435                         (adns_r_unknown
436                          | (want_certtype < DNS_CERTTYPE_RRBASE
437                             ? my_adns_r_cert
438                             : (want_certtype - DNS_CERTTYPE_RRBASE))),
439                         adns_qf_quoteok_query, &answer))
440     {
441       err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
442       /* log_error ("DNS query failed: %s\n", strerror (errno)); */
443       adns_finish (state);
444       return err;
445     }
446   if (answer->status != adns_s_ok)
447     {
448       /* log_error ("DNS query returned an error: %s (%s)\n", */
449       /*            adns_strerror (answer->status), */
450       /*            adns_errabbrev (answer->status)); */
451       err = gpg_err_make (default_errsource, GPG_ERR_NOT_FOUND);
452       goto leave;
453     }
454
455   err = gpg_err_make (default_errsource, GPG_ERR_NOT_FOUND);
456   for (count = 0; count < answer->nrrs; count++)
457     {
458       int datalen = answer->rrs.byteblock[count].len;
459       const unsigned char *data = answer->rrs.byteblock[count].data;
460
461       /* First check for our generic RR hack.  */
462       if (datalen
463           && want_certtype >= DNS_CERTTYPE_RRBASE
464           && ((want_certtype - DNS_CERTTYPE_RRBASE)
465               == (answer->type & ~adns_r_unknown)))
466         {
467           /* Found the requested record - return it.  */
468           *r_key = xtrymalloc (datalen);
469           if (!*r_key)
470             err = gpg_err_make (default_errsource,
471                                 gpg_err_code_from_syserror ());
472           else
473             {
474               memcpy (*r_key, data, datalen);
475               *r_keylen = datalen;
476               err = 0;
477             }
478           goto leave;
479         }
480
481       if (datalen < 5)
482         continue;  /* Truncated CERT record - skip.  */
483
484       ctype = buf16_to_uint (data);
485       /* (key tag and algorithm fields are not required.) */
486       data += 5;
487       datalen -= 5;
488
489       if (want_certtype && want_certtype != ctype)
490         ; /* Not of the requested certtype.  */
491       else if (ctype == DNS_CERTTYPE_PGP && datalen >= 11 && r_key && r_keylen)
492         {
493           /* CERT type is PGP.  Gpg checks for a minimum length of 11,
494              thus we do the same.  */
495           *r_key = xtrymalloc (datalen);
496           if (!*r_key)
497             err = gpg_err_make (default_errsource,
498                                 gpg_err_code_from_syserror ());
499           else
500             {
501               memcpy (*r_key, data, datalen);
502               *r_keylen = datalen;
503               err = 0;
504             }
505           goto leave;
506         }
507       else if (ctype == DNS_CERTTYPE_IPGP && datalen && datalen < 1023
508                && datalen >= data[0] + 1 && r_fpr && r_fprlen && r_url)
509         {
510           /* CERT type is IPGP.  We made sure that the data is
511              plausible and that the caller requested this
512              information.  */
513           *r_fprlen = data[0];
514           if (*r_fprlen)
515             {
516               *r_fpr = xtrymalloc (*r_fprlen);
517               if (!*r_fpr)
518                 {
519                   err = gpg_err_make (default_errsource,
520                                       gpg_err_code_from_syserror ());
521                   goto leave;
522                 }
523               memcpy (*r_fpr, data + 1, *r_fprlen);
524             }
525           else
526             *r_fpr = NULL;
527
528           if (datalen > *r_fprlen + 1)
529             {
530               *r_url = xtrymalloc (datalen - (*r_fprlen + 1) + 1);
531               if (!*r_url)
532                 {
533                   err = gpg_err_make (default_errsource,
534                                       gpg_err_code_from_syserror ());
535                   xfree (*r_fpr);
536                   *r_fpr = NULL;
537                   goto leave;
538                 }
539               memcpy (*r_url,
540                       data + (*r_fprlen + 1), datalen - (*r_fprlen + 1));
541               (*r_url)[datalen - (*r_fprlen + 1)] = '\0';
542             }
543           else
544             *r_url = NULL;
545
546           err = 0;
547           goto leave;
548         }
549     }
550
551  leave:
552   adns_free (answer);
553   adns_finish (state);
554   return err;
555
556 #else /*!USE_ADNS*/
557
558   gpg_error_t err;
559   unsigned char *answer;
560   int r;
561   u16 count;
562
563   if (r_key)
564     *r_key = NULL;
565   if (r_keylen)
566     *r_keylen = 0;
567   *r_fpr = NULL;
568   *r_fprlen = 0;
569   *r_url = NULL;
570
571   /* Allocate a 64k buffer which is the limit for an DNS response.  */
572   answer = xtrymalloc (65536);
573   if (!answer)
574     return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
575
576   err = gpg_err_make (default_errsource, GPG_ERR_NOT_FOUND);
577
578   r = res_query (name, C_IN,
579                  (want_certtype < DNS_CERTTYPE_RRBASE
580                   ? T_CERT
581                   : (want_certtype - DNS_CERTTYPE_RRBASE)),
582                  answer, 65536);
583   /* Not too big, not too small, no errors and at least 1 answer. */
584   if (r >= sizeof (HEADER) && r <= 65536
585       && (((HEADER *) answer)->rcode) == NOERROR
586       && (count = ntohs (((HEADER *) answer)->ancount)))
587     {
588       int rc;
589       unsigned char *pt, *emsg;
590
591       emsg = &answer[r];
592
593       pt = &answer[sizeof (HEADER)];
594
595       /* Skip over the query */
596
597       rc = dn_skipname (pt, emsg);
598       if (rc == -1)
599         {
600           err = gpg_err_make (default_errsource, GPG_ERR_INV_OBJ);
601           goto leave;
602         }
603       pt += rc + QFIXEDSZ;
604
605       /* There are several possible response types for a CERT request.
606          We're interested in the PGP (a key) and IPGP (a URI) types.
607          Skip all others.  TODO: A key is better than a URI since
608          we've gone through all this bother to fetch it, so favor that
609          if we have both PGP and IPGP? */
610
611       while (count-- > 0 && pt < emsg)
612         {
613           u16 type, class, dlen, ctype;
614
615           rc = dn_skipname (pt, emsg);  /* the name we just queried for */
616           if (rc == -1)
617             {
618               err = gpg_err_make (default_errsource, GPG_ERR_INV_OBJ);
619               goto leave;
620             }
621
622           pt += rc;
623
624           /* Truncated message? 15 bytes takes us to the point where
625              we start looking at the ctype. */
626           if ((emsg - pt) < 15)
627             break;
628
629           type = buf16_to_u16 (pt);
630           pt += 2;
631
632           class = buf16_to_u16 (pt);
633           pt += 2;
634
635           if (class != C_IN)
636             break;
637
638           /* ttl */
639           pt += 4;
640
641           /* data length */
642           dlen = buf16_to_u16 (pt);
643           pt += 2;
644
645           /* Check the type and parse.  */
646           if (want_certtype >= DNS_CERTTYPE_RRBASE
647               && type == (want_certtype - DNS_CERTTYPE_RRBASE)
648               && r_key)
649             {
650               *r_key = xtrymalloc (dlen);
651               if (!*r_key)
652                 err = gpg_err_make (default_errsource,
653                                     gpg_err_code_from_syserror ());
654               else
655                 {
656                   memcpy (*r_key, pt, dlen);
657                   *r_keylen = dlen;
658                   err = 0;
659                 }
660               goto leave;
661             }
662           else if (want_certtype >= DNS_CERTTYPE_RRBASE)
663             {
664               /* We did not found the requested RR.  */
665               pt += dlen;
666             }
667           else if (type == T_CERT)
668             {
669               /* We got a CERT type.   */
670               ctype = buf16_to_u16 (pt);
671               pt += 2;
672
673               /* Skip the CERT key tag and algo which we don't need. */
674               pt += 3;
675
676               dlen -= 5;
677
678               /* 15 bytes takes us to here */
679               if (want_certtype && want_certtype != ctype)
680                 ; /* Not of the requested certtype.  */
681               else if (ctype == DNS_CERTTYPE_PGP && dlen && r_key && r_keylen)
682                 {
683                   /* PGP type */
684                   *r_key = xtrymalloc (dlen);
685                   if (!*r_key)
686                     err = gpg_err_make (default_errsource,
687                                         gpg_err_code_from_syserror ());
688                   else
689                     {
690                       memcpy (*r_key, pt, dlen);
691                       *r_keylen = dlen;
692                       err = 0;
693                     }
694                   goto leave;
695                 }
696               else if (ctype == DNS_CERTTYPE_IPGP
697                        && dlen && dlen < 1023 && dlen >= pt[0] + 1)
698                 {
699                   /* IPGP type */
700                   *r_fprlen = pt[0];
701                   if (*r_fprlen)
702                     {
703                       *r_fpr = xtrymalloc (*r_fprlen);
704                       if (!*r_fpr)
705                         {
706                           err = gpg_err_make (default_errsource,
707                                               gpg_err_code_from_syserror ());
708                           goto leave;
709                         }
710                       memcpy (*r_fpr, &pt[1], *r_fprlen);
711                     }
712                   else
713                     *r_fpr = NULL;
714
715                   if (dlen > *r_fprlen + 1)
716                     {
717                       *r_url = xtrymalloc (dlen - (*r_fprlen + 1) + 1);
718                       if (!*r_fpr)
719                         {
720                           err = gpg_err_make (default_errsource,
721                                               gpg_err_code_from_syserror ());
722                           xfree (*r_fpr);
723                           *r_fpr = NULL;
724                           goto leave;
725                         }
726                       memcpy (*r_url, &pt[*r_fprlen + 1],
727                               dlen - (*r_fprlen + 1));
728                       (*r_url)[dlen - (*r_fprlen + 1)] = '\0';
729                     }
730                   else
731                     *r_url = NULL;
732
733                   err = 0;
734                   goto leave;
735                 }
736
737               /* No subtype matches, so continue with the next answer. */
738               pt += dlen;
739             }
740           else
741             {
742               /* Not a requested type - might be a CNAME. Try next item.  */
743               pt += dlen;
744             }
745         }
746     }
747
748  leave:
749   xfree (answer);
750   return err;
751
752 #endif /*!USE_ADNS */
753 #else /* !USE_DNS_CERT */
754   (void)name;
755   if (r_key)
756     *r_key = NULL;
757   if (r_keylen)
758     *r_keylen = NULL;
759   *r_fpr = NULL;
760   *r_fprlen = 0;
761   *r_url = NULL;
762
763   return gpg_err_make (default_errsource, GPG_ERR_NOT_SUPPORTED);
764 #endif
765 }
766
767 #ifdef USE_DNS_SRV
768 static int
769 priosort(const void *a,const void *b)
770 {
771   const struct srventry *sa=a,*sb=b;
772   if(sa->priority>sb->priority)
773     return 1;
774   else if(sa->priority<sb->priority)
775     return -1;
776   else
777     return 0;
778 }
779
780
781 int
782 getsrv (const char *name,struct srventry **list)
783 {
784   int srvcount=0;
785   u16 count;
786   int i, rc;
787
788   *list = NULL;
789
790 #ifdef USE_ADNS
791   {
792     adns_state state;
793     adns_answer *answer = NULL;
794
795     if (my_adns_init (&state))
796       return -1;
797
798     rc = adns_synchronous (state, name, adns_r_srv, adns_qf_quoteok_query,
799                            &answer);
800     if (rc)
801       {
802         log_error ("DNS query failed: %s\n", strerror (errno));
803         adns_finish (state);
804         return -1;
805       }
806     if (answer->status != adns_s_ok
807         || answer->type != adns_r_srv || !answer->nrrs)
808       {
809         log_error ("DNS query returned an error or no records: %s (%s)\n",
810                    adns_strerror (answer->status),
811                    adns_errabbrev (answer->status));
812         adns_free (answer);
813         adns_finish (state);
814         return 0;
815       }
816
817     for (count = 0; count < answer->nrrs; count++)
818       {
819         struct srventry *srv = NULL;
820         struct srventry *newlist;
821
822         if (strlen (answer->rrs.srvha[count].ha.host) >= sizeof srv->target)
823           {
824             log_info ("hostname in SRV record too long - skipped\n");
825             continue;
826           }
827
828         newlist = xtryrealloc (*list, (srvcount+1)*sizeof(struct srventry));
829         if (!newlist)
830           goto fail;
831         *list = newlist;
832         memset (&(*list)[srvcount], 0, sizeof(struct srventry));
833         srv = &(*list)[srvcount];
834         srvcount++;
835
836         srv->priority = answer->rrs.srvha[count].priority;
837         srv->weight   = answer->rrs.srvha[count].weight;
838         srv->port     = answer->rrs.srvha[count].port;
839         strcpy (srv->target, answer->rrs.srvha[count].ha.host);
840       }
841
842     adns_free (answer);
843     adns_finish (state);
844   }
845 #else /*!USE_ADNS*/
846   {
847     unsigned char answer[2048];
848     HEADER *header = (HEADER *)answer;
849     unsigned char *pt, *emsg;
850     int r;
851     u16 dlen;
852
853     /* Do not allow a query using the standard resolver in Tor mode.  */
854     if (tor_mode)
855       return -1;
856
857     r = res_query (name, C_IN, T_SRV, answer, sizeof answer);
858     if (r < sizeof (HEADER) || r > sizeof answer)
859       return -1;
860     if (header->rcode != NOERROR || !(count=ntohs (header->ancount)))
861       return 0; /* Error or no record found.  */
862
863     emsg = &answer[r];
864     pt = &answer[sizeof(HEADER)];
865
866     /* Skip over the query */
867     rc = dn_skipname (pt, emsg);
868     if (rc == -1)
869       goto fail;
870
871     pt += rc + QFIXEDSZ;
872
873     while (count-- > 0 && pt < emsg)
874       {
875         struct srventry *srv=NULL;
876         u16 type,class;
877         struct srventry *newlist;
878
879         newlist = xtryrealloc (*list, (srvcount+1)*sizeof(struct srventry));
880         if (!newlist)
881           goto fail;
882         *list = newlist;
883         memset(&(*list)[srvcount],0,sizeof(struct srventry));
884         srv=&(*list)[srvcount];
885         srvcount++;
886
887         rc = dn_skipname(pt,emsg); /* the name we just queried for */
888         if (rc == -1)
889           goto fail;
890         pt+=rc;
891
892         /* Truncated message? */
893         if((emsg-pt)<16)
894           goto fail;
895
896         type = buf16_to_u16 (pt);
897         pt += 2;
898         /* We asked for SRV and got something else !? */
899         if(type!=T_SRV)
900           goto fail;
901
902         class = buf16_to_u16 (pt);
903         pt += 2;
904         /* We asked for IN and got something else !? */
905         if(class!=C_IN)
906           goto fail;
907
908         pt += 4; /* ttl */
909         dlen = buf16_to_u16 (pt);
910         pt += 2;
911
912         srv->priority = buf16_to_ushort (pt);
913         pt += 2;
914         srv->weight = buf16_to_ushort (pt);
915         pt += 2;
916         srv->port = buf16_to_ushort (pt);
917         pt += 2;
918
919         /* Get the name.  2782 doesn't allow name compression, but
920            dn_expand still works to pull the name out of the
921            packet. */
922         rc = dn_expand(answer,emsg,pt,srv->target, sizeof srv->target);
923         if (rc == 1 && srv->target[0] == 0) /* "." */
924           {
925             xfree(*list);
926             *list = NULL;
927             return 0;
928           }
929         if (rc == -1)
930           goto fail;
931         pt += rc;
932         /* Corrupt packet? */
933         if (dlen != rc+6)
934           goto fail;
935       }
936   }
937 #endif /*!USE_ADNS*/
938
939   /* Now we have an array of all the srv records. */
940
941   /* Order by priority */
942   qsort(*list,srvcount,sizeof(struct srventry),priosort);
943
944   /* For each priority, move the zero-weighted items first. */
945   for (i=0; i < srvcount; i++)
946     {
947       int j;
948
949       for (j=i;j < srvcount && (*list)[i].priority == (*list)[j].priority; j++)
950         {
951           if((*list)[j].weight==0)
952             {
953               /* Swap j with i */
954               if(j!=i)
955                 {
956                   struct srventry temp;
957
958                   memcpy (&temp,&(*list)[j],sizeof(struct srventry));
959                   memcpy (&(*list)[j],&(*list)[i],sizeof(struct srventry));
960                   memcpy (&(*list)[i],&temp,sizeof(struct srventry));
961                 }
962
963               break;
964             }
965         }
966     }
967
968   /* Run the RFC-2782 weighting algorithm.  We don't need very high
969      quality randomness for this, so regular libc srand/rand is
970      sufficient.  Fixme: It is a bit questionaly to reinitalize srand
971      - better use a gnupg fucntion for this.  */
972   srand(time(NULL)*getpid());
973
974   for (i=0; i < srvcount; i++)
975     {
976       int j;
977       float prio_count=0,chose;
978
979       for (j=i; j < srvcount && (*list)[i].priority == (*list)[j].priority; j++)
980         {
981           prio_count+=(*list)[j].weight;
982           (*list)[j].run_count=prio_count;
983         }
984
985       chose=prio_count*rand()/RAND_MAX;
986
987       for (j=i;j<srvcount && (*list)[i].priority==(*list)[j].priority;j++)
988         {
989           if (chose<=(*list)[j].run_count)
990             {
991               /* Swap j with i */
992               if(j!=i)
993                 {
994                   struct srventry temp;
995
996                   memcpy(&temp,&(*list)[j],sizeof(struct srventry));
997                   memcpy(&(*list)[j],&(*list)[i],sizeof(struct srventry));
998                   memcpy(&(*list)[i],&temp,sizeof(struct srventry));
999                 }
1000               break;
1001             }
1002         }
1003     }
1004
1005   return srvcount;
1006
1007  fail:
1008   xfree(*list);
1009   *list=NULL;
1010   return -1;
1011 }
1012 #endif /*USE_DNS_SRV*/