Move SRV RR code from common/ to dirmngr/.
[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 /* Returns 0 on success or an error code.  If a PGP CERT record was
223    found, the malloced data is returned at (R_KEY, R_KEYLEN) and
224    the other return parameters are set to NULL/0.  If an IPGP CERT
225    record was found the fingerprint is stored as an allocated block at
226    R_FPR and its length at R_FPRLEN; an URL is is allocated as a
227    string and returned at R_URL.  If WANT_CERTTYPE is 0 this function
228    returns the first CERT found with a supported type; it is expected
229    that only one CERT record is used.  If WANT_CERTTYPE is one of the
230    supported certtypes only records with this certtype are considered
231    and the first found is returned.  (R_KEY,R_KEYLEN) are optional. */
232 gpg_error_t
233 get_dns_cert (const char *name, int want_certtype,
234               void **r_key, size_t *r_keylen,
235               unsigned char **r_fpr, size_t *r_fprlen, char **r_url)
236 {
237 #ifdef USE_DNS_CERT
238 #ifdef USE_ADNS
239   gpg_error_t err;
240   adns_state state;
241   adns_answer *answer = NULL;
242   unsigned int ctype;
243   int count;
244
245   if (r_key)
246     *r_key = NULL;
247   if (r_keylen)
248     *r_keylen = 0;
249   *r_fpr = NULL;
250   *r_fprlen = 0;
251   *r_url = NULL;
252
253   if (tor_mode? adns_init_strcfg (&state, adns_if_noerrprint|adns_if_tormode,
254                                   NULL, "nameserver 8.8.8.8")
255       /*    */: adns_init (&state, adns_if_noerrprint, NULL))
256     {
257       err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
258       log_error ("error initializing adns: %s\n", strerror (errno));
259       return err;
260     }
261
262   if (adns_synchronous (state, name,
263                         (adns_r_unknown
264                          | (want_certtype < DNS_CERTTYPE_RRBASE
265                             ? my_adns_r_cert
266                             : (want_certtype - DNS_CERTTYPE_RRBASE))),
267                         adns_qf_quoteok_query, &answer))
268     {
269       err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
270       /* log_error ("DNS query failed: %s\n", strerror (errno)); */
271       adns_finish (state);
272       return err;
273     }
274   if (answer->status != adns_s_ok)
275     {
276       /* log_error ("DNS query returned an error: %s (%s)\n", */
277       /*            adns_strerror (answer->status), */
278       /*            adns_errabbrev (answer->status)); */
279       err = gpg_err_make (default_errsource, GPG_ERR_NOT_FOUND);
280       goto leave;
281     }
282
283   err = gpg_err_make (default_errsource, GPG_ERR_NOT_FOUND);
284   for (count = 0; count < answer->nrrs; count++)
285     {
286       int datalen = answer->rrs.byteblock[count].len;
287       const unsigned char *data = answer->rrs.byteblock[count].data;
288
289       /* First check for our generic RR hack.  */
290       if (datalen
291           && want_certtype >= DNS_CERTTYPE_RRBASE
292           && ((want_certtype - DNS_CERTTYPE_RRBASE)
293               == (answer->type & ~adns_r_unknown)))
294         {
295           /* Found the requested record - return it.  */
296           *r_key = xtrymalloc (datalen);
297           if (!*r_key)
298             err = gpg_err_make (default_errsource,
299                                 gpg_err_code_from_syserror ());
300           else
301             {
302               memcpy (*r_key, data, datalen);
303               *r_keylen = datalen;
304               err = 0;
305             }
306           goto leave;
307         }
308
309       if (datalen < 5)
310         continue;  /* Truncated CERT record - skip.  */
311
312       ctype = buf16_to_uint (data);
313       /* (key tag and algorithm fields are not required.) */
314       data += 5;
315       datalen -= 5;
316
317       if (want_certtype && want_certtype != ctype)
318         ; /* Not of the requested certtype.  */
319       else if (ctype == DNS_CERTTYPE_PGP && datalen >= 11 && r_key && r_keylen)
320         {
321           /* CERT type is PGP.  Gpg checks for a minimum length of 11,
322              thus we do the same.  */
323           *r_key = xtrymalloc (datalen);
324           if (!*r_key)
325             err = gpg_err_make (default_errsource,
326                                 gpg_err_code_from_syserror ());
327           else
328             {
329               memcpy (*r_key, data, datalen);
330               *r_keylen = datalen;
331               err = 0;
332             }
333           goto leave;
334         }
335       else if (ctype == DNS_CERTTYPE_IPGP && datalen && datalen < 1023
336                && datalen >= data[0] + 1 && r_fpr && r_fprlen && r_url)
337         {
338           /* CERT type is IPGP.  We made sure that the data is
339              plausible and that the caller requested this
340              information.  */
341           *r_fprlen = data[0];
342           if (*r_fprlen)
343             {
344               *r_fpr = xtrymalloc (*r_fprlen);
345               if (!*r_fpr)
346                 {
347                   err = gpg_err_make (default_errsource,
348                                       gpg_err_code_from_syserror ());
349                   goto leave;
350                 }
351               memcpy (*r_fpr, data + 1, *r_fprlen);
352             }
353           else
354             *r_fpr = NULL;
355
356           if (datalen > *r_fprlen + 1)
357             {
358               *r_url = xtrymalloc (datalen - (*r_fprlen + 1) + 1);
359               if (!*r_url)
360                 {
361                   err = gpg_err_make (default_errsource,
362                                       gpg_err_code_from_syserror ());
363                   xfree (*r_fpr);
364                   *r_fpr = NULL;
365                   goto leave;
366                 }
367               memcpy (*r_url,
368                       data + (*r_fprlen + 1), datalen - (*r_fprlen + 1));
369               (*r_url)[datalen - (*r_fprlen + 1)] = '\0';
370             }
371           else
372             *r_url = NULL;
373
374           err = 0;
375           goto leave;
376         }
377     }
378
379  leave:
380   adns_free (answer);
381   adns_finish (state);
382   return err;
383
384 #else /*!USE_ADNS*/
385
386   gpg_error_t err;
387   unsigned char *answer;
388   int r;
389   u16 count;
390
391   if (r_key)
392     *r_key = NULL;
393   if (r_keylen)
394     *r_keylen = 0;
395   *r_fpr = NULL;
396   *r_fprlen = 0;
397   *r_url = NULL;
398
399   /* Allocate a 64k buffer which is the limit for an DNS response.  */
400   answer = xtrymalloc (65536);
401   if (!answer)
402     return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
403
404   err = gpg_err_make (default_errsource, GPG_ERR_NOT_FOUND);
405
406   r = res_query (name, C_IN,
407                  (want_certtype < DNS_CERTTYPE_RRBASE
408                   ? T_CERT
409                   : (want_certtype - DNS_CERTTYPE_RRBASE)),
410                  answer, 65536);
411   /* Not too big, not too small, no errors and at least 1 answer. */
412   if (r >= sizeof (HEADER) && r <= 65536
413       && (((HEADER *) answer)->rcode) == NOERROR
414       && (count = ntohs (((HEADER *) answer)->ancount)))
415     {
416       int rc;
417       unsigned char *pt, *emsg;
418
419       emsg = &answer[r];
420
421       pt = &answer[sizeof (HEADER)];
422
423       /* Skip over the query */
424
425       rc = dn_skipname (pt, emsg);
426       if (rc == -1)
427         {
428           err = gpg_err_make (default_errsource, GPG_ERR_INV_OBJ);
429           goto leave;
430         }
431       pt += rc + QFIXEDSZ;
432
433       /* There are several possible response types for a CERT request.
434          We're interested in the PGP (a key) and IPGP (a URI) types.
435          Skip all others.  TODO: A key is better than a URI since
436          we've gone through all this bother to fetch it, so favor that
437          if we have both PGP and IPGP? */
438
439       while (count-- > 0 && pt < emsg)
440         {
441           u16 type, class, dlen, ctype;
442
443           rc = dn_skipname (pt, emsg);  /* the name we just queried for */
444           if (rc == -1)
445             {
446               err = gpg_err_make (default_errsource, GPG_ERR_INV_OBJ);
447               goto leave;
448             }
449
450           pt += rc;
451
452           /* Truncated message? 15 bytes takes us to the point where
453              we start looking at the ctype. */
454           if ((emsg - pt) < 15)
455             break;
456
457           type = buf16_to_u16 (pt);
458           pt += 2;
459
460           class = buf16_to_u16 (pt);
461           pt += 2;
462
463           if (class != C_IN)
464             break;
465
466           /* ttl */
467           pt += 4;
468
469           /* data length */
470           dlen = buf16_to_u16 (pt);
471           pt += 2;
472
473           /* Check the type and parse.  */
474           if (want_certtype >= DNS_CERTTYPE_RRBASE
475               && type == (want_certtype - DNS_CERTTYPE_RRBASE)
476               && r_key)
477             {
478               *r_key = xtrymalloc (dlen);
479               if (!*r_key)
480                 err = gpg_err_make (default_errsource,
481                                     gpg_err_code_from_syserror ());
482               else
483                 {
484                   memcpy (*r_key, pt, dlen);
485                   *r_keylen = dlen;
486                   err = 0;
487                 }
488               goto leave;
489             }
490           else if (want_certtype >= DNS_CERTTYPE_RRBASE)
491             {
492               /* We did not found the requested RR.  */
493               pt += dlen;
494             }
495           else if (type == T_CERT)
496             {
497               /* We got a CERT type.   */
498               ctype = buf16_to_u16 (pt);
499               pt += 2;
500
501               /* Skip the CERT key tag and algo which we don't need. */
502               pt += 3;
503
504               dlen -= 5;
505
506               /* 15 bytes takes us to here */
507               if (want_certtype && want_certtype != ctype)
508                 ; /* Not of the requested certtype.  */
509               else if (ctype == DNS_CERTTYPE_PGP && dlen && r_key && r_keylen)
510                 {
511                   /* PGP type */
512                   *r_key = xtrymalloc (dlen);
513                   if (!*r_key)
514                     err = gpg_err_make (default_errsource,
515                                         gpg_err_code_from_syserror ());
516                   else
517                     {
518                       memcpy (*r_key, pt, dlen);
519                       *r_keylen = dlen;
520                       err = 0;
521                     }
522                   goto leave;
523                 }
524               else if (ctype == DNS_CERTTYPE_IPGP
525                        && dlen && dlen < 1023 && dlen >= pt[0] + 1)
526                 {
527                   /* IPGP type */
528                   *r_fprlen = pt[0];
529                   if (*r_fprlen)
530                     {
531                       *r_fpr = xtrymalloc (*r_fprlen);
532                       if (!*r_fpr)
533                         {
534                           err = gpg_err_make (default_errsource,
535                                               gpg_err_code_from_syserror ());
536                           goto leave;
537                         }
538                       memcpy (*r_fpr, &pt[1], *r_fprlen);
539                     }
540                   else
541                     *r_fpr = NULL;
542
543                   if (dlen > *r_fprlen + 1)
544                     {
545                       *r_url = xtrymalloc (dlen - (*r_fprlen + 1) + 1);
546                       if (!*r_fpr)
547                         {
548                           err = gpg_err_make (default_errsource,
549                                               gpg_err_code_from_syserror ());
550                           xfree (*r_fpr);
551                           *r_fpr = NULL;
552                           goto leave;
553                         }
554                       memcpy (*r_url, &pt[*r_fprlen + 1],
555                               dlen - (*r_fprlen + 1));
556                       (*r_url)[dlen - (*r_fprlen + 1)] = '\0';
557                     }
558                   else
559                     *r_url = NULL;
560
561                   err = 0;
562                   goto leave;
563                 }
564
565               /* No subtype matches, so continue with the next answer. */
566               pt += dlen;
567             }
568           else
569             {
570               /* Not a requested type - might be a CNAME. Try next item.  */
571               pt += dlen;
572             }
573         }
574     }
575
576  leave:
577   xfree (answer);
578   return err;
579
580 #endif /*!USE_ADNS */
581 #else /* !USE_DNS_CERT */
582   (void)name;
583   if (r_key)
584     *r_key = NULL;
585   if (r_keylen)
586     *r_keylen = NULL;
587   *r_fpr = NULL;
588   *r_fprlen = 0;
589   *r_url = NULL;
590
591   return gpg_err_make (default_errsource, GPG_ERR_NOT_SUPPORTED);
592 #endif
593 }
594
595 #ifdef USE_DNS_SRV
596 static int
597 priosort(const void *a,const void *b)
598 {
599   const struct srventry *sa=a,*sb=b;
600   if(sa->priority>sb->priority)
601     return 1;
602   else if(sa->priority<sb->priority)
603     return -1;
604   else
605     return 0;
606 }
607
608
609 int
610 getsrv (const char *name,struct srventry **list)
611 {
612   int srvcount=0;
613   u16 count;
614   int i, rc;
615
616   *list = NULL;
617
618 #ifdef USE_ADNS
619   {
620     adns_state state;
621     adns_answer *answer = NULL;
622
623     rc = adns_init (&state, adns_if_noerrprint, NULL);
624     if (rc)
625       {
626         log_error ("error initializing adns: %s\n", strerror (errno));
627         return -1;
628       }
629
630     rc = adns_synchronous (state, name, adns_r_srv, adns_qf_quoteok_query,
631                            &answer);
632     if (rc)
633       {
634         log_error ("DNS query failed: %s\n", strerror (errno));
635         adns_finish (state);
636         return -1;
637       }
638     if (answer->status != adns_s_ok
639         || answer->type != adns_r_srv || !answer->nrrs)
640       {
641         log_error ("DNS query returned an error or no records: %s (%s)\n",
642                    adns_strerror (answer->status),
643                    adns_errabbrev (answer->status));
644         adns_free (answer);
645         adns_finish (state);
646         return 0;
647       }
648
649     for (count = 0; count < answer->nrrs; count++)
650       {
651         struct srventry *srv = NULL;
652         struct srventry *newlist;
653
654         if (strlen (answer->rrs.srvha[count].ha.host) >= MAXDNAME)
655           {
656             log_info ("hostname in SRV record too long - skipped\n");
657             continue;
658           }
659
660         newlist = xtryrealloc (*list, (srvcount+1)*sizeof(struct srventry));
661         if (!newlist)
662           goto fail;
663         *list = newlist;
664         memset (&(*list)[srvcount], 0, sizeof(struct srventry));
665         srv = &(*list)[srvcount];
666         srvcount++;
667
668         srv->priority = answer->rrs.srvha[count].priority;
669         srv->weight   = answer->rrs.srvha[count].weight;
670         srv->port     = answer->rrs.srvha[count].port;
671         strcpy (srv->target, answer->rrs.srvha[count].ha.host);
672       }
673
674     adns_free (answer);
675     adns_finish (state);
676   }
677 #else /*!USE_ADNS*/
678   {
679     unsigned char answer[2048];
680     HEADER *header = (HEADER *)answer;
681     unsigned char *pt, *emsg;
682     int r;
683     u16 dlen;
684
685     r = res_query (name, C_IN, T_SRV, answer, sizeof answer);
686     if (r < sizeof (HEADER) || r > sizeof answer)
687       return -1;
688     if (header->rcode != NOERROR || !(count=ntohs (header->ancount)))
689       return 0; /* Error or no record found.  */
690
691     emsg = &answer[r];
692     pt = &answer[sizeof(HEADER)];
693
694     /* Skip over the query */
695     rc = dn_skipname (pt, emsg);
696     if (rc == -1)
697       goto fail;
698
699     pt += rc + QFIXEDSZ;
700
701     while (count-- > 0 && pt < emsg)
702       {
703         struct srventry *srv=NULL;
704         u16 type,class;
705         struct srventry *newlist;
706
707         newlist = xtryrealloc (*list, (srvcount+1)*sizeof(struct srventry));
708         if (!newlist)
709           goto fail;
710         *list = newlist;
711         memset(&(*list)[srvcount],0,sizeof(struct srventry));
712         srv=&(*list)[srvcount];
713         srvcount++;
714
715         rc = dn_skipname(pt,emsg); /* the name we just queried for */
716         if (rc == -1)
717           goto fail;
718         pt+=rc;
719
720         /* Truncated message? */
721         if((emsg-pt)<16)
722           goto fail;
723
724         type = buf16_to_u16 (pt);
725         pt += 2;
726         /* We asked for SRV and got something else !? */
727         if(type!=T_SRV)
728           goto fail;
729
730         class = buf16_to_u16 (pt);
731         pt += 2;
732         /* We asked for IN and got something else !? */
733         if(class!=C_IN)
734           goto fail;
735
736         pt += 4; /* ttl */
737         dlen = buf16_to_u16 (pt);
738         pt += 2;
739
740         srv->priority = buf16_to_ushort (pt);
741         pt += 2;
742         srv->weight = buf16_to_ushort (pt);
743         pt += 2;
744         srv->port = buf16_to_ushort (pt);
745         pt += 2;
746
747         /* Get the name.  2782 doesn't allow name compression, but
748            dn_expand still works to pull the name out of the
749            packet. */
750         rc = dn_expand(answer,emsg,pt,srv->target,MAXDNAME);
751         if (rc == 1 && srv->target[0] == 0) /* "." */
752           {
753             xfree(*list);
754             *list = NULL;
755             return 0;
756           }
757         if (rc == -1)
758           goto fail;
759         pt += rc;
760         /* Corrupt packet? */
761         if (dlen != rc+6)
762           goto fail;
763       }
764   }
765 #endif /*!USE_ADNS*/
766
767   /* Now we have an array of all the srv records. */
768
769   /* Order by priority */
770   qsort(*list,srvcount,sizeof(struct srventry),priosort);
771
772   /* For each priority, move the zero-weighted items first. */
773   for (i=0; i < srvcount; i++)
774     {
775       int j;
776
777       for (j=i;j < srvcount && (*list)[i].priority == (*list)[j].priority; j++)
778         {
779           if((*list)[j].weight==0)
780             {
781               /* Swap j with i */
782               if(j!=i)
783                 {
784                   struct srventry temp;
785
786                   memcpy (&temp,&(*list)[j],sizeof(struct srventry));
787                   memcpy (&(*list)[j],&(*list)[i],sizeof(struct srventry));
788                   memcpy (&(*list)[i],&temp,sizeof(struct srventry));
789                 }
790
791               break;
792             }
793         }
794     }
795
796   /* Run the RFC-2782 weighting algorithm.  We don't need very high
797      quality randomness for this, so regular libc srand/rand is
798      sufficient.  Fixme: It is a bit questionaly to reinitalize srand
799      - better use a gnupg fucntion for this.  */
800   srand(time(NULL)*getpid());
801
802   for (i=0; i < srvcount; i++)
803     {
804       int j;
805       float prio_count=0,chose;
806
807       for (j=i; j < srvcount && (*list)[i].priority == (*list)[j].priority; j++)
808         {
809           prio_count+=(*list)[j].weight;
810           (*list)[j].run_count=prio_count;
811         }
812
813       chose=prio_count*rand()/RAND_MAX;
814
815       for (j=i;j<srvcount && (*list)[i].priority==(*list)[j].priority;j++)
816         {
817           if (chose<=(*list)[j].run_count)
818             {
819               /* Swap j with i */
820               if(j!=i)
821                 {
822                   struct srventry temp;
823
824                   memcpy(&temp,&(*list)[j],sizeof(struct srventry));
825                   memcpy(&(*list)[j],&(*list)[i],sizeof(struct srventry));
826                   memcpy(&(*list)[i],&temp,sizeof(struct srventry));
827                 }
828               break;
829             }
830         }
831     }
832
833   return srvcount;
834
835  fail:
836   xfree(*list);
837   *list=NULL;
838   return -1;
839 }
840 #endif /*USE_DNS_SRV*/