LCOV - code coverage report
Current view: top level - libpkg - dns_utils.c (source / functions) Hit Total Coverage
Test: plop Lines: 27 135 20.0 %
Date: 2024-12-28 18:40:32 Functions: 1 5 20.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 10 65 15.4 %

           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                 :          0 : 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   [ #  #  #  # ]:          0 :         if ((len = res_query(zone, C_IN, T_SRV, q.buf, sizeof(q.buf))) == -1 ||
     172                 :          0 :             len < (int)sizeof(HEADER))
     173                 :          0 :                 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 :                 res[n]->type = type;
     226                 :          0 :                 res[n]->class = class;
     227                 :          0 :                 res[n]->ttl = ttl;
     228                 :          0 :                 res[n]->priority = priority;
     229                 :          0 :                 res[n]->weight = weight;
     230                 :          0 :                 res[n]->port = port;
     231                 :          0 :                 res[n]->next = NULL;
     232                 :          0 :                 res[n]->finalweight = 0;
     233                 :          0 :                 strlcpy(res[n]->host, host, sizeof(res[n]->host));
     234                 :            : 
     235                 :          0 :                 p += len;
     236                 :          0 :                 n++;
     237                 :            :         }
     238                 :            : 
     239                 :            :         /* order by priority */
     240                 :          0 :         qsort(res, n, sizeof(res[0]), srv_priority_cmp);
     241                 :            : 
     242                 :          0 :         priority = 0;
     243                 :          0 :         f = 0;
     244                 :          0 :         l = 0;
     245         [ #  # ]:          0 :         for (i = 0; i < n; i++) {
     246         [ #  # ]:          0 :                 if (res[i]->priority != priority) {
     247         [ #  # ]:          0 :                         if (f != l)
     248                 :          0 :                                 compute_weight(res, f, l);
     249                 :          0 :                         f = i;
     250                 :          0 :                         priority = res[i]->priority;
     251                 :          0 :                 }
     252                 :          0 :                 l = i;
     253                 :          0 :         }
     254                 :            : 
     255                 :          0 :         qsort(res, n, sizeof(res[0]), srv_final_cmp);
     256                 :            : 
     257         [ #  # ]:          0 :         for (i = 0; i < n - 1; i++)
     258                 :          0 :                 res[i]->next = res[i + 1];
     259                 :            : 
     260                 :            :         /* Sort against priority then weight */
     261                 :            : 
     262                 :          0 :         first = res[0];
     263                 :          0 :         free(res);
     264                 :            : 
     265                 :          0 :         return (first);
     266                 :          0 : }
     267                 :            : 
     268                 :            : int
     269                 :          2 : set_nameserver(const char *nsname) {
     270                 :            : #ifndef HAVE___RES_SETSERVERS
     271                 :            :         return (-1);
     272                 :            : #else
     273                 :            :         struct __res_state res;
     274                 :            :         union res_sockaddr_union u[MAXNS];
     275                 :          2 :         struct addrinfo *answer = NULL;
     276                 :          2 :         struct addrinfo *cur = NULL;
     277                 :            :         struct addrinfo hint;
     278                 :          2 :         int nscount = 0;
     279                 :            : 
     280                 :          2 :         memset(u, 0, sizeof(u));
     281                 :          2 :         memset(&hint, 0, sizeof(hint));
     282                 :          2 :         memset(&res, 0, sizeof(res));
     283                 :          2 :         hint.ai_socktype = SOCK_DGRAM;
     284                 :          2 :         hint.ai_flags = AI_NUMERICHOST;
     285                 :            : 
     286         [ +  - ]:          2 :         if (res_ninit(&res) == -1)
     287                 :          0 :                 return (-1);
     288                 :            : 
     289         [ +  + ]:          2 :         if (getaddrinfo(nsname, NULL, &hint, &answer) == 0) {
     290         [ +  + ]:          2 :                 for (cur = answer; cur != NULL; cur = cur->ai_next) {
     291         [ -  + ]:          1 :                         if (nscount == MAXNS)
     292                 :          0 :                                 break;
     293      [ -  -  + ]:          1 :                         switch (cur->ai_addr->sa_family) {
     294                 :            :                         case AF_INET6:
     295                 :          0 :                                 u[nscount].sin6 = *(struct sockaddr_in6*)(void *)cur->ai_addr;
     296                 :          0 :                                 u[nscount++].sin6.sin6_port = htons(53);
     297                 :          0 :                                 break;
     298                 :            :                         case AF_INET:
     299                 :          1 :                                 u[nscount].sin = *(struct sockaddr_in*)(void *)cur->ai_addr;
     300                 :          1 :                                 u[nscount++].sin.sin_port = htons(53);
     301                 :          1 :                                 break;
     302                 :            :                         }
     303                 :          1 :                 }
     304         [ -  + ]:          1 :                 if (nscount != 0)
     305                 :          1 :                         res_setservers(&res, u, nscount);
     306                 :          1 :                 freeaddrinfo(answer);
     307                 :          1 :         }
     308         [ +  + ]:          2 :         if (nscount == 0)
     309                 :          1 :                 return (-1);
     310                 :            : 
     311                 :          1 :         _res = res;
     312                 :            : 
     313                 :          1 :         return (0);
     314                 :            : #endif
     315                 :          2 : }
     316                 :            : #else
     317                 :            : 
     318                 :            : static ldns_resolver *lres = NULL;
     319                 :            : 
     320                 :            : static void
     321                 :            : compute_weight(struct dns_srvinfo *d, int first, int last)
     322                 :            : {
     323                 :            :         int i, j;
     324                 :            :         int totalweight = 0;
     325                 :            :         int *chosen;
     326                 :            : 
     327                 :            :         for (i = 0; i <= last; i++)
     328                 :            :                 totalweight += d[i].weight;
     329                 :            : 
     330                 :            :         if (totalweight == 0)
     331                 :            :                 return;
     332                 :            : 
     333                 :            :         chosen = xmalloc(sizeof(int) * (last - first + 1));
     334                 :            : 
     335                 :            :         for (i = 0; i <= last; i++) {
     336                 :            :                 for (;;) {
     337                 :            :                         chosen[i] = random() % (d[i].weight * 100 / totalweight);
     338                 :            :                         for (j = 0; j < i; j++) {
     339                 :            :                                 if (chosen[i] == chosen[j])
     340                 :            :                                         break;
     341                 :            :                         }
     342                 :            :                         if (j == i) {
     343                 :            :                                 d[i].finalweight = chosen[i];
     344                 :            :                                 break;
     345                 :            :                         }
     346                 :            :                 }
     347                 :            :         }
     348                 :            : 
     349                 :            :         free(chosen);
     350                 :            : }
     351                 :            : 
     352                 :            : struct dns_srvinfo *
     353                 :            : dns_getsrvinfo(const char *zone)
     354                 :            : {
     355                 :            :         ldns_rdf *domain;
     356                 :            :         ldns_pkt *p;
     357                 :            :         ldns_rr_list *srv;
     358                 :            :         struct dns_srvinfo *res;
     359                 :            :         int ancount, i;
     360                 :            :         int f, l, priority;
     361                 :            : 
     362                 :            :         if (lres == NULL)
     363                 :            :                 if (ldns_resolver_new_frm_file(&lres, NULL) != LDNS_STATUS_OK)
     364                 :            :                         return (NULL);
     365                 :            : 
     366                 :            :         domain = ldns_dname_new_frm_str(zone);
     367                 :            :         if (domain == NULL)
     368                 :            :                 return (NULL);
     369                 :            : 
     370                 :            :         p = ldns_resolver_query(lres, domain,
     371                 :            :             LDNS_RR_TYPE_SRV,
     372                 :            :             LDNS_RR_CLASS_IN,
     373                 :            :             LDNS_RD);
     374                 :            : 
     375                 :            :         ldns_rdf_deep_free(domain);
     376                 :            : 
     377                 :            :         if (p == NULL)
     378                 :            :                 return (NULL);
     379                 :            : 
     380                 :            :         srv = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_SRV, LDNS_SECTION_ANSWER);
     381                 :            :         ldns_pkt_free(p);
     382                 :            : 
     383                 :            :         if (srv == NULL)
     384                 :            :                 return (NULL);
     385                 :            : 
     386                 :            :         ancount = ldns_rr_list_rr_count(srv);
     387                 :            :         res = xcalloc(ancount, sizeof(struct dns_srvinfo));
     388                 :            : 
     389                 :            :         for (i = 0; i < ancount; i ++) {
     390                 :            :                 ldns_rr *rr;
     391                 :            : 
     392                 :            :                 rr = ldns_rr_list_rr(srv, i);
     393                 :            :                 if (rr != NULL) {
     394                 :            :                         char *host;
     395                 :            :                         res[i].class = ldns_rr_get_class(rr);
     396                 :            :                         res[i].ttl = ldns_rr_ttl(rr);
     397                 :            :                         res[i].priority = ldns_rdf2native_int16(ldns_rr_rdf(rr, 0));
     398                 :            :                         res[i].weight = ldns_rdf2native_int16(ldns_rr_rdf(rr, 1));
     399                 :            :                         res[i].port = ldns_rdf2native_int16(ldns_rr_rdf(rr, 2));
     400                 :            :                         host = ldns_rdf2str(ldns_rr_rdf(rr, 3));
     401                 :            :                         strlcpy(res[i].host, host, sizeof(res[i].host));
     402                 :            :                         free(host);
     403                 :            :                 }
     404                 :            :         }
     405                 :            : 
     406                 :            :         ldns_rr_list_deep_free(srv);
     407                 :            : 
     408                 :            :         /* order by priority */
     409                 :            :         qsort(res, ancount, sizeof(res[0]), srv_priority_cmp);
     410                 :            : 
     411                 :            :         priority = 0;
     412                 :            :         f = 0;
     413                 :            :         l = 0;
     414                 :            :         for (i = 0; i < ancount; i++) {
     415                 :            :                 if (res[i].priority != priority) {
     416                 :            :                         if (f != l)
     417                 :            :                                 compute_weight(res, f, l);
     418                 :            :                         f = i;
     419                 :            :                         priority = res[i].priority;
     420                 :            :                 }
     421                 :            :                 l = i;
     422                 :            :         }
     423                 :            : 
     424                 :            :         /* Sort against priority then weight */
     425                 :            :         qsort(res, ancount, sizeof(res[0]), srv_final_cmp);
     426                 :            : 
     427                 :            :         for (i = 0; i < ancount - 1; i++)
     428                 :            :                 res[i].next = &res[i + 1];
     429                 :            : 
     430                 :            :         return (res);
     431                 :            : }
     432                 :            : 
     433                 :            : int
     434                 :            : set_nameserver(const char *nsname)
     435                 :            : {
     436                 :            :         /*
     437                 :            :          * XXX: can we use the system resolver to resolve this name ??
     438                 :            :          * The current code does this, but it is unlikely a good solution
     439                 :            :          * So here we allow IP addresses only
     440                 :            :          */
     441                 :            :         ldns_rdf *rdf;
     442                 :            : 
     443                 :            :         rdf = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_A, nsname);
     444                 :            :         if (rdf == NULL)
     445                 :            :                 rdf = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_AAAA, nsname);
     446                 :            : 
     447                 :            :         if (rdf == NULL)
     448                 :            :                 return (EPKG_FATAL);
     449                 :            : 
     450                 :            :         if (lres == NULL)
     451                 :            :                 if (ldns_resolver_new_frm_file(&lres, NULL) != LDNS_STATUS_OK)
     452                 :            :                         return (EPKG_FATAL);
     453                 :            : 
     454                 :            :         if (ldns_resolver_push_nameserver(lres, rdf) != LDNS_STATUS_OK)
     455                 :            :                 return (EPKG_FATAL);
     456                 :            : 
     457                 :            :         return (EPKG_OK);
     458                 :            : }
     459                 :            : #endif

Generated by: LCOV version 1.15