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