LCOV - code coverage report
Current view: top level - libpkg - dns_utils.c (source / functions) Hit Total Coverage
Test: cov.info Lines: 0 130 0.0 %
Date: 2015-08-15 Functions: 0 5 0.0 %

          Line data    Source code
       1             : /*-
       2             :  * Copyright (c) 2012-2014 Baptiste Daroussin <bapt@FreeBSD.org>
       3             :  * Copyright (c) 2014 Vsevolod Stakhov <vsevolod@FreeBSD.org>
       4             :  * All rights reserved.
       5             :  *
       6             :  * Redistribution and use in source and binary forms, with or without
       7             :  * modification, are permitted provided that the following conditions
       8             :  * are met:
       9             :  * 1. Redistributions of source code must retain the above copyright
      10             :  *    notice, this list of conditions and the following disclaimer,
      11             :  *    without modification, immediately at the beginning of the file.
      12             :  * 2. Redistributions in binary form must reproduce the above copyright
      13             :  *    notice, this list of conditions and the following disclaimer in the
      14             :  *    documentation and/or other materials provided with the distribution.
      15             :  *
      16             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
      17             :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      18             :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      19             :  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
      20             :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
      21             :  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      22             :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      23             :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      24             :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      25             :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      26             :  */
      27             : 
      28             : #include <pkg_config.h>
      29             : 
      30             : #include <sys/stat.h> /* for private.utils.h */
      31             : 
      32             : #include <string.h>
      33             : #include <netinet/in.h>
      34             : #ifdef HAVE_LDNS
      35             : #include <ldns/ldns.h>
      36             : #else
      37             : #define BIND_8_COMPAT
      38             : #include <arpa/nameser.h>
      39             : #include <resolv.h>
      40             : #endif
      41             : #include <netdb.h>
      42             : 
      43             : #include <bsd_compat.h>
      44             : #include "private/utils.h"
      45             : #include "pkg.h"
      46             : 
      47             : #ifndef HAVE_LDNS
      48             : typedef union {
      49             :         HEADER hdr;
      50             :         unsigned char buf[1024];
      51             : } query_t;
      52             : #endif
      53             : 
      54             : static int
      55           0 : srv_priority_cmp(const void *a, const void *b)
      56             : {
      57             :         const struct dns_srvinfo *da, *db;
      58             : #ifdef HAVE_LDNS
      59             :         da = (const struct dns_srvinfo *)a;
      60             :         db = (const struct dns_srvinfo *)b;
      61             : #else
      62           0 :         da = *(struct dns_srvinfo * const *)a;
      63           0 :         db = *(struct dns_srvinfo * const *)b;
      64             : #endif
      65             : 
      66           0 :         return ((da->priority > db->priority) - (da->priority < db->priority));
      67             : }
      68             : 
      69             : static int
      70           0 : srv_final_cmp(const void *a, const void *b)
      71             : {
      72             :         const struct dns_srvinfo *da, *db;
      73             :         int res;
      74             : #ifdef HAVE_LDNS
      75             :         da = (const struct dns_srvinfo *)a;
      76             :         db = (const struct dns_srvinfo *)b;
      77             : #else
      78           0 :         da = *(struct dns_srvinfo * const *)a;
      79           0 :         db = *(struct dns_srvinfo * const *)b;
      80             : #endif
      81             : 
      82           0 :         res = ((da->priority > db->priority) - (da->priority < db->priority));
      83           0 :         if (res == 0)
      84           0 :                 res = ((db->finalweight > da->finalweight) - (db->finalweight < da->finalweight));
      85             : 
      86           0 :         return (res);
      87             : }
      88             : 
      89             : #ifndef HAVE_LDNS
      90             : static void
      91           0 : compute_weight(struct dns_srvinfo **d, int first, int last)
      92             : {
      93             :         int i, j;
      94           0 :         int totalweight = 0;
      95             :         int *chosen;
      96             : 
      97           0 :         for (i = 0; i <= last; i++)
      98           0 :                 totalweight += d[i]->weight;
      99             : 
     100           0 :         if (totalweight == 0)
     101           0 :                 return;
     102             : 
     103           0 :         chosen = malloc(sizeof(int) * (last - first + 1));
     104             : 
     105           0 :         for (i = 0; i <= last; i++) {
     106             :                 for (;;) {
     107           0 :                         chosen[i] = random() % (d[i]->weight * 100 / totalweight);
     108           0 :                         for (j = 0; j < i; j++) {
     109           0 :                                 if (chosen[i] == chosen[j])
     110           0 :                                         break;
     111             :                         }
     112           0 :                         if (j == i) {
     113           0 :                                 d[i]->finalweight = chosen[i];
     114           0 :                                 break;
     115             :                         }
     116           0 :                 }
     117             :         }
     118             : 
     119           0 :         free(chosen);
     120             : }
     121             : 
     122             : struct dns_srvinfo *
     123           0 : dns_getsrvinfo(const char *zone)
     124             : {
     125             :         char host[MAXHOSTNAMELEN];
     126             :         query_t q;
     127             :         int len, qdcount, ancount, n, i;
     128             :         struct dns_srvinfo **res, *first;
     129             :         unsigned char *end, *p;
     130             :         unsigned int type, class, ttl, priority, weight, port;
     131             :         int f, l;
     132             : 
     133           0 :         if ((len = res_query(zone, C_IN, T_SRV, q.buf, sizeof(q.buf))) == -1 ||
     134             :             len < (int)sizeof(HEADER))
     135           0 :                 return (NULL);
     136             : 
     137           0 :         qdcount = ntohs(q.hdr.qdcount);
     138           0 :         ancount = ntohs(q.hdr.ancount);
     139             : 
     140           0 :         end = q.buf + len;
     141           0 :         p = q.buf + sizeof(HEADER);
     142             : 
     143           0 :         while(qdcount > 0 && p < end) {
     144           0 :                 qdcount--;
     145           0 :                 if((len = dn_expand(q.buf, end, p, host, sizeof(host))) < 0)
     146           0 :                         return (NULL);
     147           0 :                 p += len + NS_QFIXEDSZ;
     148             :         }
     149             : 
     150           0 :         res = calloc(ancount, sizeof(struct dns_srvinfo *));
     151           0 :         if (res == NULL)
     152           0 :                 return (NULL);
     153             : 
     154           0 :         n = 0;
     155           0 :         while (ancount > 0 && p < end) {
     156           0 :                 ancount--;
     157           0 :                 len = dn_expand(q.buf, end, p, host, sizeof(host));
     158           0 :                 if (len < 0) {
     159           0 :                         for (i = 0; i < n; i++)
     160           0 :                                 free(res[i]);
     161           0 :                         free(res);
     162           0 :                         return NULL;
     163             :                 }
     164             : 
     165           0 :                 p += len;
     166             : 
     167           0 :                 NS_GET16(type, p);
     168           0 :                 NS_GET16(class, p);
     169           0 :                 NS_GET32(ttl, p);
     170           0 :                 NS_GET16(len, p);
     171             : 
     172           0 :                 if (type != T_SRV) {
     173           0 :                         p += len;
     174           0 :                         continue;
     175             :                 }
     176             : 
     177           0 :                 NS_GET16(priority, p);
     178           0 :                 NS_GET16(weight, p);
     179           0 :                 NS_GET16(port, p);
     180             : 
     181           0 :                 len = dn_expand(q.buf, end, p, host, sizeof(host));
     182           0 :                 if (len < 0) {
     183           0 :                         for (i = 0; i < n; i++)
     184           0 :                                 free(res[i]);
     185           0 :                         free(res);
     186           0 :                         return NULL;
     187             :                 }
     188             : 
     189           0 :                 res[n] = malloc(sizeof(struct dns_srvinfo));
     190           0 :                 if (res[n] == NULL) {
     191           0 :                         for (i = 0; i < n; i++)
     192           0 :                                 free(res[i]);
     193           0 :                         free(res);
     194           0 :                         return NULL;
     195             :                 }
     196           0 :                 res[n]->type = type;
     197           0 :                 res[n]->class = class;
     198           0 :                 res[n]->ttl = ttl;
     199           0 :                 res[n]->priority = priority;
     200           0 :                 res[n]->weight = weight;
     201           0 :                 res[n]->port = port;
     202           0 :                 res[n]->next = NULL;
     203           0 :                 res[n]->finalweight = 0;
     204           0 :                 strlcpy(res[n]->host, host, sizeof(res[n]->host));
     205             : 
     206           0 :                 p += len;
     207           0 :                 n++;
     208             :         }
     209             : 
     210             :         /* order by priority */
     211           0 :         qsort(res, n, sizeof(res[0]), srv_priority_cmp);
     212             : 
     213           0 :         priority = 0;
     214           0 :         f = 0;
     215           0 :         l = 0;
     216           0 :         for (i = 0; i < n; i++) {
     217           0 :                 if (res[i]->priority != priority) {
     218           0 :                         if (f != l)
     219           0 :                                 compute_weight(res, f, l);
     220           0 :                         f = i;
     221           0 :                         priority = res[i]->priority;
     222             :                 }
     223           0 :                 l = i;
     224             :         }
     225             : 
     226           0 :         qsort(res, n, sizeof(res[0]), srv_final_cmp);
     227             : 
     228           0 :         for (i = 0; i < n - 1; i++)
     229           0 :                 res[i]->next = res[i + 1];
     230             : 
     231             :         /* Sort against priority then weight */
     232             : 
     233           0 :         first = res[0];
     234           0 :         free(res);
     235             : 
     236           0 :         return (first);
     237             : }
     238             : 
     239             : int
     240           0 : set_nameserver(const char *nsname) {
     241             :         struct __res_state res;
     242             :         union res_sockaddr_union u[MAXNS];
     243           0 :         struct addrinfo *answer = NULL;
     244           0 :         struct addrinfo *cur = NULL;
     245             :         struct addrinfo hint;
     246           0 :         int nscount = 0;
     247             : 
     248           0 :         memset(u, 0, sizeof(u));
     249           0 :         memset(&hint, 0, sizeof(hint));
     250           0 :         hint.ai_socktype = SOCK_DGRAM;
     251             : 
     252           0 :         if (res_ninit(&res) == -1)
     253           0 :                 return (-1);
     254             : 
     255           0 :         if (getaddrinfo(nsname, NULL, &hint, &answer) == 0) {
     256           0 :                 for (cur = answer; cur != NULL; cur = cur->ai_next) {
     257           0 :                         if (nscount == MAXNS)
     258           0 :                                 break;
     259           0 :                         switch (cur->ai_addr->sa_family) {
     260             :                         case AF_INET6:
     261           0 :                                 u[nscount].sin6 = *(struct sockaddr_in6*)(void *)cur->ai_addr;
     262           0 :                                 u[nscount++].sin6.sin6_port = htons(53);
     263           0 :                                 break;
     264             :                         case AF_INET:
     265           0 :                                 u[nscount].sin = *(struct sockaddr_in*)(void *)cur->ai_addr;
     266           0 :                                 u[nscount++].sin.sin_port = htons(53);
     267           0 :                                 break;
     268             :                         }
     269             :                 }
     270           0 :                 if (nscount != 0)
     271           0 :                         res_setservers(&res, u, nscount);
     272           0 :                 freeaddrinfo(answer);
     273             :         }
     274           0 :         if (nscount == 0)
     275           0 :                 return (-1);
     276             : 
     277           0 :         _res = res;
     278             : 
     279           0 :         return (0);
     280             : }
     281             : #else
     282             : 
     283             : static ldns_resolver *lres = NULL;
     284             : 
     285             : static void
     286             : compute_weight(struct dns_srvinfo *d, int first, int last)
     287             : {
     288             :         int i, j;
     289             :         int totalweight = 0;
     290             :         int *chosen;
     291             : 
     292             :         for (i = 0; i <= last; i++)
     293             :                 totalweight += d[i].weight;
     294             : 
     295             :         if (totalweight == 0)
     296             :                 return;
     297             : 
     298             :         chosen = malloc(sizeof(int) * (last - first + 1));
     299             : 
     300             :         for (i = 0; i <= last; i++) {
     301             :                 for (;;) {
     302             :                         chosen[i] = random() % (d[i].weight * 100 / totalweight);
     303             :                         for (j = 0; j < i; j++) {
     304             :                                 if (chosen[i] == chosen[j])
     305             :                                         break;
     306             :                         }
     307             :                         if (j == i) {
     308             :                                 d[i].finalweight = chosen[i];
     309             :                                 break;
     310             :                         }
     311             :                 }
     312             :         }
     313             : 
     314             :         free(chosen);
     315             : }
     316             : 
     317             : struct dns_srvinfo *
     318             : dns_getsrvinfo(const char *zone)
     319             : {
     320             :         ldns_rdf *domain;
     321             :         ldns_pkt *p;
     322             :         ldns_rr_list *srv;
     323             :         struct dns_srvinfo *res;
     324             :         int ancount, i;
     325             :         int f, l, priority;
     326             : 
     327             :         if (lres == NULL)
     328             :                 if (ldns_resolver_new_frm_file(&lres, NULL) != LDNS_STATUS_OK)
     329             :                         return (NULL);
     330             : 
     331             :         domain = ldns_dname_new_frm_str(zone);
     332             :         if (domain == NULL)
     333             :                 return (NULL);
     334             : 
     335             :         p = ldns_resolver_query(lres, domain,
     336             :             LDNS_RR_TYPE_SRV,
     337             :             LDNS_RR_CLASS_IN,
     338             :             LDNS_RD);
     339             : 
     340             :         ldns_rdf_deep_free(domain);
     341             : 
     342             :         if (p == NULL)
     343             :                 return (NULL);
     344             : 
     345             :         srv = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_SRV, LDNS_SECTION_ANSWER);
     346             :         ldns_pkt_free(p);
     347             : 
     348             :         if (srv == NULL)
     349             :                 return (NULL);
     350             : 
     351             :         ancount = ldns_rr_list_rr_count(srv);
     352             :         res = calloc(ancount, sizeof(struct dns_srvinfo));
     353             :         if (res == NULL)
     354             :                 return (NULL);
     355             : 
     356             :         for (i = 0; i < ancount; i ++) {
     357             :                 ldns_rr *rr;
     358             : 
     359             :                 rr = ldns_rr_list_rr(srv, i);
     360             :                 if (rr != NULL) {
     361             :                         char *host;
     362             :                         res[i].class = ldns_rr_get_class(rr);
     363             :                         res[i].ttl = ldns_rr_ttl(rr);
     364             :                         res[i].priority = ldns_rdf2native_int16(ldns_rr_rdf(rr, 0));
     365             :                         res[i].weight = ldns_rdf2native_int16(ldns_rr_rdf(rr, 1));
     366             :                         res[i].port = ldns_rdf2native_int16(ldns_rr_rdf(rr, 2));
     367             :                         host = ldns_rdf2str(ldns_rr_rdf(rr, 3));
     368             :                         strlcpy(res[i].host, host, sizeof(res[i].host));
     369             :                         free(host);
     370             :                 }
     371             :         }
     372             : 
     373             :         ldns_rr_list_deep_free(srv);
     374             : 
     375             :         /* order by priority */
     376             :         qsort(res, ancount, sizeof(res[0]), srv_priority_cmp);
     377             : 
     378             :         priority = 0;
     379             :         f = 0;
     380             :         l = 0;
     381             :         for (i = 0; i < ancount; i++) {
     382             :                 if (res[i].priority != priority) {
     383             :                         if (f != l)
     384             :                                 compute_weight(res, f, l);
     385             :                         f = i;
     386             :                         priority = res[i].priority;
     387             :                 }
     388             :                 l = i;
     389             :         }
     390             : 
     391             :         /* Sort against priority then weight */
     392             :         qsort(res, ancount, sizeof(res[0]), srv_final_cmp);
     393             : 
     394             :         for (i = 0; i < ancount - 1; i++)
     395             :                 res[i].next = &res[i + 1];
     396             : 
     397             :         return (res);
     398             : }
     399             : 
     400             : int
     401             : set_nameserver(const char *nsname)
     402             : {
     403             :         /*
     404             :          * XXX: can we use the system resolver to resolve this name ??
     405             :          * The current code does this, but it is unlikely a good solution
     406             :          * So here we allow IP addresses only
     407             :          */
     408             :         ldns_rdf *rdf;
     409             : 
     410             :         rdf = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_A, nsname);
     411             :         if (rdf == NULL)
     412             :                 rdf = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_AAAA, nsname);
     413             : 
     414             :         if (rdf == NULL)
     415             :                 return (EPKG_FATAL);
     416             : 
     417             :         if (lres == NULL)
     418             :                 if (ldns_resolver_new_frm_file(&lres, NULL) != LDNS_STATUS_OK)
     419             :                         return (EPKG_FATAL);
     420             : 
     421             :         if (ldns_resolver_push_nameserver(lres, rdf) != LDNS_STATUS_OK)
     422             :                 return (EPKG_FATAL);
     423             : 
     424             :         return (EPKG_OK);
     425             : }
     426             : #endif

Generated by: LCOV version 1.10