LCOV - code coverage report
Current view: top level - libpkg - dns_utils.c (source / functions) Hit Total Coverage
Test: rapport Lines: 31 140 22.1 %
Date: 2021-12-10 16:22:55 Functions: 2 5 40.0 %
Branches: 11 65 16.9 %

           Branch data     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                 :            : #ifndef NS_QFIXEDSZ
      44                 :            : #define NS_QFIXEDSZ     4       /*%< #/bytes of fixed data in query */
      45                 :            : #endif
      46                 :            : 
      47                 :            : #ifndef NS_INT16SZ
      48                 :            : #define NS_INT16SZ      2       /*%< #/bytes of data in a u_int16_t */
      49                 :            : #endif
      50                 :            : 
      51                 :            : #ifndef NS_INT32SZ
      52                 :            : #define NS_INT32SZ      4       /*%< #/bytes of data in a u_int32_t */
      53                 :            : #endif
      54                 :            : 
      55                 :            : /*%
      56                 :            :  * Inline versions of get/put short/long.  Pointer is advanced.
      57                 :            :  */
      58                 :            : #ifndef NS_GET16
      59                 :            : #define NS_GET16(s, cp) do { \
      60                 :            :         register const u_char *t_cp = (const u_char *)(cp); \
      61                 :            :         (s) = ((u_int16_t)t_cp[0] << 8) \
      62                 :            :             | ((u_int16_t)t_cp[1]) \
      63                 :            :             ; \
      64                 :            :         (cp) += NS_INT16SZ; \
      65                 :            : } while (0)
      66                 :            : #endif
      67                 :            : 
      68                 :            : #ifndef NS_GET32
      69                 :            : #define NS_GET32(l, cp) do { \
      70                 :            :         register const u_char *t_cp = (const u_char *)(cp); \
      71                 :            :         (l) = ((u_int32_t)t_cp[0] << 24) \
      72                 :            :             | ((u_int32_t)t_cp[1] << 16) \
      73                 :            :             | ((u_int32_t)t_cp[2] << 8) \
      74                 :            :             | ((u_int32_t)t_cp[3]) \
      75                 :            :             ; \
      76                 :            :         (cp) += NS_INT32SZ; \
      77                 :            : } while (0)
      78                 :            : #endif
      79                 :            : 
      80                 :            : #include <bsd_compat.h>
      81                 :            : #include "private/utils.h"
      82                 :            : #include "xmalloc.h"
      83                 :            : #include "pkg.h"
      84                 :            : 
      85                 :            : #ifndef HAVE_LDNS
      86                 :            : typedef union {
      87                 :            :         HEADER hdr;
      88                 :            :         unsigned char buf[1024];
      89                 :            : } query_t;
      90                 :            : #endif
      91                 :            : 
      92                 :            : static int
      93                 :          0 : srv_priority_cmp(const void *a, const void *b)
      94                 :            : {
      95                 :            :         const struct dns_srvinfo *da, *db;
      96                 :            : #ifdef HAVE_LDNS
      97                 :            :         da = (const struct dns_srvinfo *)a;
      98                 :            :         db = (const struct dns_srvinfo *)b;
      99                 :            : #else
     100                 :          0 :         da = *(struct dns_srvinfo * const *)a;
     101                 :          0 :         db = *(struct dns_srvinfo * const *)b;
     102                 :            : #endif
     103                 :            : 
     104                 :          0 :         return ((da->priority > db->priority) - (da->priority < db->priority));
     105                 :            : }
     106                 :            : 
     107                 :            : static int
     108                 :          0 : srv_final_cmp(const void *a, const void *b)
     109                 :            : {
     110                 :            :         const struct dns_srvinfo *da, *db;
     111                 :            :         int res;
     112                 :            : #ifdef HAVE_LDNS
     113                 :            :         da = (const struct dns_srvinfo *)a;
     114                 :            :         db = (const struct dns_srvinfo *)b;
     115                 :            : #else
     116                 :          0 :         da = *(struct dns_srvinfo * const *)a;
     117                 :          0 :         db = *(struct dns_srvinfo * const *)b;
     118                 :            : #endif
     119                 :            : 
     120                 :          0 :         res = ((da->priority > db->priority) - (da->priority < db->priority));
     121         [ #  # ]:          0 :         if (res == 0)
     122                 :          0 :                 res = ((db->finalweight > da->finalweight) - (db->finalweight < da->finalweight));
     123                 :            : 
     124                 :          0 :         return (res);
     125                 :            : }
     126                 :            : 
     127                 :            : #ifndef HAVE_LDNS
     128                 :            : static void
     129                 :          0 : compute_weight(struct dns_srvinfo **d, int first, int last)
     130                 :            : {
     131                 :            :         int i, j;
     132                 :          0 :         int totalweight = 0;
     133                 :            :         int *chosen;
     134                 :            : 
     135         [ #  # ]:          0 :         for (i = 0; i <= last; i++)
     136                 :          0 :                 totalweight += d[i]->weight;
     137                 :            : 
     138         [ #  # ]:          0 :         if (totalweight == 0)
     139                 :          0 :                 return;
     140                 :            : 
     141                 :          0 :         chosen = xmalloc(sizeof(int) * (last - first + 1));
     142                 :            : 
     143         [ #  # ]:          0 :         for (i = 0; i <= last; i++) {
     144                 :          0 :                 for (;;) {
     145                 :          0 :                         chosen[i] = random() % (d[i]->weight * 100 / totalweight);
     146         [ #  # ]:          0 :                         for (j = 0; j < i; j++) {
     147         [ #  # ]:          0 :                                 if (chosen[i] == chosen[j])
     148                 :          0 :                                         break;
     149                 :          0 :                         }
     150         [ #  # ]:          0 :                         if (j == i) {
     151                 :          0 :                                 d[i]->finalweight = chosen[i];
     152                 :          0 :                                 break;
     153                 :            :                         }
     154                 :            :                 }
     155                 :          0 :         }
     156                 :            : 
     157                 :          0 :         free(chosen);
     158                 :          0 : }
     159                 :            : 
     160                 :            : struct dns_srvinfo *
     161                 :          4 : dns_getsrvinfo(const char *zone)
     162                 :            : {
     163                 :            :         char host[MAXHOSTNAMELEN];
     164                 :            :         query_t q;
     165                 :            :         int len, qdcount, ancount, n, i;
     166                 :            :         struct dns_srvinfo **res, *first;
     167                 :            :         unsigned char *end, *p;
     168                 :            :         unsigned int type, class, ttl, priority, weight, port;
     169                 :            :         int f, l;
     170                 :            : 
     171   [ -  +  #  # ]:          4 :         if ((len = res_query(zone, C_IN, T_SRV, q.buf, sizeof(q.buf))) == -1 ||
     172                 :          0 :             len < (int)sizeof(HEADER))
     173                 :          4 :                 return (NULL);
     174                 :            : 
     175                 :          0 :         qdcount = ntohs(q.hdr.qdcount);
     176                 :          0 :         ancount = ntohs(q.hdr.ancount);
     177                 :            : 
     178                 :          0 :         end = q.buf + len;
     179                 :          0 :         p = q.buf + sizeof(HEADER);
     180                 :            : 
     181   [ #  #  #  # ]:          0 :         while(qdcount > 0 && p < end) {
     182                 :          0 :                 qdcount--;
     183         [ #  # ]:          0 :                 if((len = dn_expand(q.buf, end, p, host, sizeof(host))) < 0)
     184                 :          0 :                         return (NULL);
     185                 :          0 :                 p += len + NS_QFIXEDSZ;
     186                 :            :         }
     187                 :            : 
     188                 :          0 :         res = xcalloc(ancount, sizeof(struct dns_srvinfo *));
     189                 :          0 :         n = 0;
     190   [ #  #  #  # ]:          0 :         while (ancount > 0 && p < end) {
     191                 :          0 :                 ancount--;
     192                 :          0 :                 len = dn_expand(q.buf, end, p, host, sizeof(host));
     193         [ #  # ]:          0 :                 if (len < 0) {
     194         [ #  # ]:          0 :                         for (i = 0; i < n; i++)
     195                 :          0 :                                 free(res[i]);
     196                 :          0 :                         free(res);
     197                 :          0 :                         return NULL;
     198                 :            :                 }
     199                 :            : 
     200                 :          0 :                 p += len;
     201                 :            : 
     202                 :          0 :                 NS_GET16(type, p);
     203                 :          0 :                 NS_GET16(class, p);
     204                 :          0 :                 NS_GET32(ttl, p);
     205                 :          0 :                 NS_GET16(len, p);
     206                 :            : 
     207         [ #  # ]:          0 :                 if (type != T_SRV) {
     208                 :          0 :                         p += len;
     209                 :          0 :                         continue;
     210                 :            :                 }
     211                 :            : 
     212                 :          0 :                 NS_GET16(priority, p);
     213                 :          0 :                 NS_GET16(weight, p);
     214                 :          0 :                 NS_GET16(port, p);
     215                 :            : 
     216                 :          0 :                 len = dn_expand(q.buf, end, p, host, sizeof(host));
     217         [ #  # ]:          0 :                 if (len < 0) {
     218         [ #  # ]:          0 :                         for (i = 0; i < n; i++)
     219                 :          0 :                                 free(res[i]);
     220                 :          0 :                         free(res);
     221                 :          0 :                         return NULL;
     222                 :            :                 }
     223                 :            : 
     224                 :          0 :                 res[n] = xmalloc(sizeof(struct dns_srvinfo));
     225         [ #  # ]:          0 :                 if (res[n] == NULL) {
     226         [ #  # ]:          0 :                         for (i = 0; i < n; i++)
     227                 :          0 :                                 free(res[i]);
     228                 :          0 :                         free(res);
     229                 :          0 :                         return NULL;
     230                 :            :                 }
     231                 :          0 :                 res[n]->type = type;
     232                 :          0 :                 res[n]->class = class;
     233                 :          0 :                 res[n]->ttl = ttl;
     234                 :          0 :                 res[n]->priority = priority;
     235                 :          0 :                 res[n]->weight = weight;
     236                 :          0 :                 res[n]->port = port;
     237                 :          0 :                 res[n]->next = NULL;
     238                 :          0 :                 res[n]->finalweight = 0;
     239                 :          0 :                 strlcpy(res[n]->host, host, sizeof(res[n]->host));
     240                 :            : 
     241                 :          0 :                 p += len;
     242                 :          0 :                 n++;
     243                 :            :         }
     244                 :            : 
     245                 :            :         /* order by priority */
     246                 :          0 :         qsort(res, n, sizeof(res[0]), srv_priority_cmp);
     247                 :            : 
     248                 :          0 :         priority = 0;
     249                 :          0 :         f = 0;
     250                 :          0 :         l = 0;
     251         [ #  # ]:          0 :         for (i = 0; i < n; i++) {
     252         [ #  # ]:          0 :                 if (res[i]->priority != priority) {
     253         [ #  # ]:          0 :                         if (f != l)
     254                 :          0 :                                 compute_weight(res, f, l);
     255                 :          0 :                         f = i;
     256                 :          0 :                         priority = res[i]->priority;
     257                 :          0 :                 }
     258                 :          0 :                 l = i;
     259                 :          0 :         }
     260                 :            : 
     261                 :          0 :         qsort(res, n, sizeof(res[0]), srv_final_cmp);
     262                 :            : 
     263         [ #  # ]:          0 :         for (i = 0; i < n - 1; i++)
     264                 :          0 :                 res[i]->next = res[i + 1];
     265                 :            : 
     266                 :            :         /* Sort against priority then weight */
     267                 :            : 
     268                 :          0 :         first = res[0];
     269                 :          0 :         free(res);
     270                 :            : 
     271                 :          0 :         return (first);
     272                 :          4 : }
     273                 :            : 
     274                 :            : int
     275                 :         16 : set_nameserver(const char *nsname) {
     276                 :            : #ifndef HAVE___RES_SETSERVERS
     277                 :            :         return (-1);
     278                 :            : #else
     279                 :            :         struct __res_state res;
     280                 :            :         union res_sockaddr_union u[MAXNS];
     281                 :         16 :         struct addrinfo *answer = NULL;
     282                 :         16 :         struct addrinfo *cur = NULL;
     283                 :            :         struct addrinfo hint;
     284                 :         16 :         int nscount = 0;
     285                 :            : 
     286                 :         16 :         memset(u, 0, sizeof(u));
     287                 :         16 :         memset(&hint, 0, sizeof(hint));
     288                 :         16 :         memset(&res, 0, sizeof(res));
     289                 :         16 :         hint.ai_socktype = SOCK_DGRAM;
     290                 :         16 :         hint.ai_flags = AI_NUMERICHOST;
     291                 :            : 
     292         [ -  + ]:         16 :         if (res_ninit(&res) == -1)
     293                 :          0 :                 return (-1);
     294                 :            : 
     295         [ +  + ]:         16 :         if (getaddrinfo(nsname, NULL, &hint, &answer) == 0) {
     296         [ +  + ]:         16 :                 for (cur = answer; cur != NULL; cur = cur->ai_next) {
     297         [ -  + ]:          8 :                         if (nscount == MAXNS)
     298                 :          0 :                                 break;
     299      [ -  -  + ]:          8 :                         switch (cur->ai_addr->sa_family) {
     300                 :            :                         case AF_INET6:
     301                 :          0 :                                 u[nscount].sin6 = *(struct sockaddr_in6*)(void *)cur->ai_addr;
     302                 :          0 :                                 u[nscount++].sin6.sin6_port = htons(53);
     303                 :          0 :                                 break;
     304                 :            :                         case AF_INET:
     305                 :          8 :                                 u[nscount].sin = *(struct sockaddr_in*)(void *)cur->ai_addr;
     306                 :          8 :                                 u[nscount++].sin.sin_port = htons(53);
     307                 :          8 :                                 break;
     308                 :            :                         }
     309                 :          8 :                 }
     310         [ -  + ]:          8 :                 if (nscount != 0)
     311                 :          8 :                         res_setservers(&res, u, nscount);
     312                 :          8 :                 freeaddrinfo(answer);
     313                 :          8 :         }
     314         [ +  + ]:         16 :         if (nscount == 0)
     315                 :          8 :                 return (-1);
     316                 :            : 
     317                 :          8 :         _res = res;
     318                 :            : 
     319                 :          8 :         return (0);
     320                 :            : #endif
     321                 :         16 : }
     322                 :            : #else
     323                 :            : 
     324                 :            : static ldns_resolver *lres = NULL;
     325                 :            : 
     326                 :            : static void
     327                 :            : compute_weight(struct dns_srvinfo *d, int first, int last)
     328                 :            : {
     329                 :            :         int i, j;
     330                 :            :         int totalweight = 0;
     331                 :            :         int *chosen;
     332                 :            : 
     333                 :            :         for (i = 0; i <= last; i++)
     334                 :            :                 totalweight += d[i].weight;
     335                 :            : 
     336                 :            :         if (totalweight == 0)
     337                 :            :                 return;
     338                 :            : 
     339                 :            :         chosen = xmalloc(sizeof(int) * (last - first + 1));
     340                 :            : 
     341                 :            :         for (i = 0; i <= last; i++) {
     342                 :            :                 for (;;) {
     343                 :            :                         chosen[i] = random() % (d[i].weight * 100 / totalweight);
     344                 :            :                         for (j = 0; j < i; j++) {
     345                 :            :                                 if (chosen[i] == chosen[j])
     346                 :            :                                         break;
     347                 :            :                         }
     348                 :            :                         if (j == i) {
     349                 :            :                                 d[i].finalweight = chosen[i];
     350                 :            :                                 break;
     351                 :            :                         }
     352                 :            :                 }
     353                 :            :         }
     354                 :            : 
     355                 :            :         free(chosen);
     356                 :            : }
     357                 :            : 
     358                 :            : struct dns_srvinfo *
     359                 :            : dns_getsrvinfo(const char *zone)
     360                 :            : {
     361                 :            :         ldns_rdf *domain;
     362                 :            :         ldns_pkt *p;
     363                 :            :         ldns_rr_list *srv;
     364                 :            :         struct dns_srvinfo *res;
     365                 :            :         int ancount, i;
     366                 :            :         int f, l, priority;
     367                 :            : 
     368                 :            :         if (lres == NULL)
     369                 :            :                 if (ldns_resolver_new_frm_file(&lres, NULL) != LDNS_STATUS_OK)
     370                 :            :                         return (NULL);
     371                 :            : 
     372                 :            :         domain = ldns_dname_new_frm_str(zone);
     373                 :            :         if (domain == NULL)
     374                 :            :                 return (NULL);
     375                 :            : 
     376                 :            :         p = ldns_resolver_query(lres, domain,
     377                 :            :             LDNS_RR_TYPE_SRV,
     378                 :            :             LDNS_RR_CLASS_IN,
     379                 :            :             LDNS_RD);
     380                 :            : 
     381                 :            :         ldns_rdf_deep_free(domain);
     382                 :            : 
     383                 :            :         if (p == NULL)
     384                 :            :                 return (NULL);
     385                 :            : 
     386                 :            :         srv = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_SRV, LDNS_SECTION_ANSWER);
     387                 :            :         ldns_pkt_free(p);
     388                 :            : 
     389                 :            :         if (srv == NULL)
     390                 :            :                 return (NULL);
     391                 :            : 
     392                 :            :         ancount = ldns_rr_list_rr_count(srv);
     393                 :            :         res = xcalloc(ancount, sizeof(struct dns_srvinfo));
     394                 :            : 
     395                 :            :         for (i = 0; i < ancount; i ++) {
     396                 :            :                 ldns_rr *rr;
     397                 :            : 
     398                 :            :                 rr = ldns_rr_list_rr(srv, i);
     399                 :            :                 if (rr != NULL) {
     400                 :            :                         char *host;
     401                 :            :                         res[i].class = ldns_rr_get_class(rr);
     402                 :            :                         res[i].ttl = ldns_rr_ttl(rr);
     403                 :            :                         res[i].priority = ldns_rdf2native_int16(ldns_rr_rdf(rr, 0));
     404                 :            :                         res[i].weight = ldns_rdf2native_int16(ldns_rr_rdf(rr, 1));
     405                 :            :                         res[i].port = ldns_rdf2native_int16(ldns_rr_rdf(rr, 2));
     406                 :            :                         host = ldns_rdf2str(ldns_rr_rdf(rr, 3));
     407                 :            :                         strlcpy(res[i].host, host, sizeof(res[i].host));
     408                 :            :                         free(host);
     409                 :            :                 }
     410                 :            :         }
     411                 :            : 
     412                 :            :         ldns_rr_list_deep_free(srv);
     413                 :            : 
     414                 :            :         /* order by priority */
     415                 :            :         qsort(res, ancount, sizeof(res[0]), srv_priority_cmp);
     416                 :            : 
     417                 :            :         priority = 0;
     418                 :            :         f = 0;
     419                 :            :         l = 0;
     420                 :            :         for (i = 0; i < ancount; i++) {
     421                 :            :                 if (res[i].priority != priority) {
     422                 :            :                         if (f != l)
     423                 :            :                                 compute_weight(res, f, l);
     424                 :            :                         f = i;
     425                 :            :                         priority = res[i].priority;
     426                 :            :                 }
     427                 :            :                 l = i;
     428                 :            :         }
     429                 :            : 
     430                 :            :         /* Sort against priority then weight */
     431                 :            :         qsort(res, ancount, sizeof(res[0]), srv_final_cmp);
     432                 :            : 
     433                 :            :         for (i = 0; i < ancount - 1; i++)
     434                 :            :                 res[i].next = &res[i + 1];
     435                 :            : 
     436                 :            :         return (res);
     437                 :            : }
     438                 :            : 
     439                 :            : int
     440                 :            : set_nameserver(const char *nsname)
     441                 :            : {
     442                 :            :         /*
     443                 :            :          * XXX: can we use the system resolver to resolve this name ??
     444                 :            :          * The current code does this, but it is unlikely a good solution
     445                 :            :          * So here we allow IP addresses only
     446                 :            :          */
     447                 :            :         ldns_rdf *rdf;
     448                 :            : 
     449                 :            :         rdf = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_A, nsname);
     450                 :            :         if (rdf == NULL)
     451                 :            :                 rdf = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_AAAA, nsname);
     452                 :            : 
     453                 :            :         if (rdf == NULL)
     454                 :            :                 return (EPKG_FATAL);
     455                 :            : 
     456                 :            :         if (lres == NULL)
     457                 :            :                 if (ldns_resolver_new_frm_file(&lres, NULL) != LDNS_STATUS_OK)
     458                 :            :                         return (EPKG_FATAL);
     459                 :            : 
     460                 :            :         if (ldns_resolver_push_nameserver(lres, rdf) != LDNS_STATUS_OK)
     461                 :            :                 return (EPKG_FATAL);
     462                 :            : 
     463                 :            :         return (EPKG_OK);
     464                 :            : }
     465                 :            : #endif

Generated by: LCOV version 1.15