LCOV - code coverage report
Current view: top level - resolve - resolved-dns-question.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 1 243 0.4 %
Date: 2019-08-23 13:36:53 Functions: 1 16 6.2 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 1 234 0.4 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : 
       3                 :            : #include "alloc-util.h"
       4                 :            : #include "dns-domain.h"
       5                 :            : #include "dns-type.h"
       6                 :            : #include "resolved-dns-question.h"
       7                 :            : 
       8                 :          0 : DnsQuestion *dns_question_new(size_t n) {
       9                 :            :         DnsQuestion *q;
      10                 :            : 
      11         [ #  # ]:          0 :         assert(n > 0);
      12                 :            : 
      13                 :          0 :         q = malloc0(offsetof(DnsQuestion, keys) + sizeof(DnsResourceKey*) * n);
      14         [ #  # ]:          0 :         if (!q)
      15                 :          0 :                 return NULL;
      16                 :            : 
      17                 :          0 :         q->n_ref = 1;
      18                 :          0 :         q->n_allocated = n;
      19                 :            : 
      20                 :          0 :         return q;
      21                 :            : }
      22                 :            : 
      23                 :          0 : static DnsQuestion *dns_question_free(DnsQuestion *q) {
      24                 :            :         size_t i;
      25                 :            : 
      26         [ #  # ]:          0 :         assert(q);
      27                 :            : 
      28         [ #  # ]:          0 :         for (i = 0; i < q->n_keys; i++)
      29                 :          0 :                 dns_resource_key_unref(q->keys[i]);
      30                 :          0 :         return mfree(q);
      31                 :            : }
      32                 :            : 
      33   [ +  -  #  #  :       5032 : DEFINE_TRIVIAL_REF_UNREF_FUNC(DnsQuestion, dns_question, dns_question_free);
                   #  # ]
      34                 :            : 
      35                 :          0 : int dns_question_add_raw(DnsQuestion *q, DnsResourceKey *key) {
      36                 :            :         /* Insert without checking for duplicates. */
      37                 :            : 
      38         [ #  # ]:          0 :         assert(key);
      39         [ #  # ]:          0 :         assert(q);
      40                 :            : 
      41         [ #  # ]:          0 :         if (q->n_keys >= q->n_allocated)
      42                 :          0 :                 return -ENOSPC;
      43                 :            : 
      44                 :          0 :         q->keys[q->n_keys++] = dns_resource_key_ref(key);
      45                 :          0 :         return 0;
      46                 :            : }
      47                 :            : 
      48                 :          0 : int dns_question_add(DnsQuestion *q, DnsResourceKey *key) {
      49                 :            :         int r;
      50                 :            : 
      51         [ #  # ]:          0 :         assert(key);
      52                 :            : 
      53         [ #  # ]:          0 :         if (!q)
      54                 :          0 :                 return -ENOSPC;
      55                 :            : 
      56         [ #  # ]:          0 :         for (size_t i = 0; i < q->n_keys; i++) {
      57                 :          0 :                 r = dns_resource_key_equal(q->keys[i], key);
      58         [ #  # ]:          0 :                 if (r < 0)
      59                 :          0 :                         return r;
      60         [ #  # ]:          0 :                 if (r > 0)
      61                 :          0 :                         return 0;
      62                 :            :         }
      63                 :            : 
      64                 :          0 :         return dns_question_add_raw(q, key);
      65                 :            : }
      66                 :            : 
      67                 :          0 : int dns_question_matches_rr(DnsQuestion *q, DnsResourceRecord *rr, const char *search_domain) {
      68                 :            :         size_t i;
      69                 :            :         int r;
      70                 :            : 
      71         [ #  # ]:          0 :         assert(rr);
      72                 :            : 
      73         [ #  # ]:          0 :         if (!q)
      74                 :          0 :                 return 0;
      75                 :            : 
      76         [ #  # ]:          0 :         for (i = 0; i < q->n_keys; i++) {
      77                 :          0 :                 r = dns_resource_key_match_rr(q->keys[i], rr, search_domain);
      78         [ #  # ]:          0 :                 if (r != 0)
      79                 :          0 :                         return r;
      80                 :            :         }
      81                 :            : 
      82                 :          0 :         return 0;
      83                 :            : }
      84                 :            : 
      85                 :          0 : int dns_question_matches_cname_or_dname(DnsQuestion *q, DnsResourceRecord *rr, const char *search_domain) {
      86                 :            :         size_t i;
      87                 :            :         int r;
      88                 :            : 
      89         [ #  # ]:          0 :         assert(rr);
      90                 :            : 
      91         [ #  # ]:          0 :         if (!q)
      92                 :          0 :                 return 0;
      93                 :            : 
      94   [ #  #  #  # ]:          0 :         if (!IN_SET(rr->key->type, DNS_TYPE_CNAME, DNS_TYPE_DNAME))
      95                 :          0 :                 return 0;
      96                 :            : 
      97         [ #  # ]:          0 :         for (i = 0; i < q->n_keys; i++) {
      98                 :            :                 /* For a {C,D}NAME record we can never find a matching {C,D}NAME record */
      99         [ #  # ]:          0 :                 if (!dns_type_may_redirect(q->keys[i]->type))
     100                 :          0 :                         return 0;
     101                 :            : 
     102                 :          0 :                 r = dns_resource_key_match_cname_or_dname(q->keys[i], rr->key, search_domain);
     103         [ #  # ]:          0 :                 if (r != 0)
     104                 :          0 :                         return r;
     105                 :            :         }
     106                 :            : 
     107                 :          0 :         return 0;
     108                 :            : }
     109                 :            : 
     110                 :          0 : int dns_question_is_valid_for_query(DnsQuestion *q) {
     111                 :            :         const char *name;
     112                 :            :         size_t i;
     113                 :            :         int r;
     114                 :            : 
     115         [ #  # ]:          0 :         if (!q)
     116                 :          0 :                 return 0;
     117                 :            : 
     118         [ #  # ]:          0 :         if (q->n_keys <= 0)
     119                 :          0 :                 return 0;
     120                 :            : 
     121         [ #  # ]:          0 :         if (q->n_keys > 65535)
     122                 :          0 :                 return 0;
     123                 :            : 
     124                 :          0 :         name = dns_resource_key_name(q->keys[0]);
     125         [ #  # ]:          0 :         if (!name)
     126                 :          0 :                 return 0;
     127                 :            : 
     128                 :            :         /* Check that all keys in this question bear the same name */
     129         [ #  # ]:          0 :         for (i = 0; i < q->n_keys; i++) {
     130         [ #  # ]:          0 :                 assert(q->keys[i]);
     131                 :            : 
     132         [ #  # ]:          0 :                 if (i > 0) {
     133                 :          0 :                         r = dns_name_equal(dns_resource_key_name(q->keys[i]), name);
     134         [ #  # ]:          0 :                         if (r <= 0)
     135                 :          0 :                                 return r;
     136                 :            :                 }
     137                 :            : 
     138         [ #  # ]:          0 :                 if (!dns_type_is_valid_query(q->keys[i]->type))
     139                 :          0 :                         return 0;
     140                 :            :         }
     141                 :            : 
     142                 :          0 :         return 1;
     143                 :            : }
     144                 :            : 
     145                 :          0 : int dns_question_contains(DnsQuestion *a, const DnsResourceKey *k) {
     146                 :            :         size_t j;
     147                 :            :         int r;
     148                 :            : 
     149         [ #  # ]:          0 :         assert(k);
     150                 :            : 
     151         [ #  # ]:          0 :         if (!a)
     152                 :          0 :                 return 0;
     153                 :            : 
     154         [ #  # ]:          0 :         for (j = 0; j < a->n_keys; j++) {
     155                 :          0 :                 r = dns_resource_key_equal(a->keys[j], k);
     156         [ #  # ]:          0 :                 if (r != 0)
     157                 :          0 :                         return r;
     158                 :            :         }
     159                 :            : 
     160                 :          0 :         return 0;
     161                 :            : }
     162                 :            : 
     163                 :          0 : int dns_question_is_equal(DnsQuestion *a, DnsQuestion *b) {
     164                 :            :         size_t j;
     165                 :            :         int r;
     166                 :            : 
     167         [ #  # ]:          0 :         if (a == b)
     168                 :          0 :                 return 1;
     169                 :            : 
     170         [ #  # ]:          0 :         if (!a)
     171   [ #  #  #  # ]:          0 :                 return !b || b->n_keys == 0;
     172         [ #  # ]:          0 :         if (!b)
     173                 :          0 :                 return a->n_keys == 0;
     174                 :            : 
     175                 :            :         /* Checks if all keys in a are also contained b, and vice versa */
     176                 :            : 
     177         [ #  # ]:          0 :         for (j = 0; j < a->n_keys; j++) {
     178                 :          0 :                 r = dns_question_contains(b, a->keys[j]);
     179         [ #  # ]:          0 :                 if (r <= 0)
     180                 :          0 :                         return r;
     181                 :            :         }
     182                 :            : 
     183         [ #  # ]:          0 :         for (j = 0; j < b->n_keys; j++) {
     184                 :          0 :                 r = dns_question_contains(a, b->keys[j]);
     185         [ #  # ]:          0 :                 if (r <= 0)
     186                 :          0 :                         return r;
     187                 :            :         }
     188                 :            : 
     189                 :          0 :         return 1;
     190                 :            : }
     191                 :            : 
     192                 :          0 : int dns_question_cname_redirect(DnsQuestion *q, const DnsResourceRecord *cname, DnsQuestion **ret) {
     193                 :          0 :         _cleanup_(dns_question_unrefp) DnsQuestion *n = NULL;
     194                 :            :         DnsResourceKey *key;
     195                 :          0 :         bool same = true;
     196                 :            :         int r;
     197                 :            : 
     198         [ #  # ]:          0 :         assert(cname);
     199         [ #  # ]:          0 :         assert(ret);
     200   [ #  #  #  # ]:          0 :         assert(IN_SET(cname->key->type, DNS_TYPE_CNAME, DNS_TYPE_DNAME));
     201                 :            : 
     202         [ #  # ]:          0 :         if (dns_question_size(q) <= 0) {
     203                 :          0 :                 *ret = NULL;
     204                 :          0 :                 return 0;
     205                 :            :         }
     206                 :            : 
     207   [ #  #  #  #  :          0 :         DNS_QUESTION_FOREACH(key, q) {
          #  #  #  #  #  
                      # ]
     208   [ #  #  #  # ]:          0 :                 _cleanup_free_ char *destination = NULL;
     209                 :            :                 const char *d;
     210                 :            : 
     211         [ #  # ]:          0 :                 if (cname->key->type == DNS_TYPE_CNAME)
     212                 :          0 :                         d = cname->cname.name;
     213                 :            :                 else {
     214                 :          0 :                         r = dns_name_change_suffix(dns_resource_key_name(key), dns_resource_key_name(cname->key), cname->dname.name, &destination);
     215         [ #  # ]:          0 :                         if (r < 0)
     216                 :          0 :                                 return r;
     217         [ #  # ]:          0 :                         if (r == 0)
     218                 :          0 :                                 continue;
     219                 :            : 
     220                 :          0 :                         d = destination;
     221                 :            :                 }
     222                 :            : 
     223                 :          0 :                 r = dns_name_equal(dns_resource_key_name(key), d);
     224         [ #  # ]:          0 :                 if (r < 0)
     225                 :          0 :                         return r;
     226                 :            : 
     227         [ #  # ]:          0 :                 if (r == 0) {
     228                 :          0 :                         same = false;
     229                 :          0 :                         break;
     230                 :            :                 }
     231                 :            :         }
     232                 :            : 
     233                 :            :         /* Fully the same, indicate we didn't do a thing */
     234         [ #  # ]:          0 :         if (same) {
     235                 :          0 :                 *ret = NULL;
     236                 :          0 :                 return 0;
     237                 :            :         }
     238                 :            : 
     239                 :          0 :         n = dns_question_new(q->n_keys);
     240         [ #  # ]:          0 :         if (!n)
     241                 :          0 :                 return -ENOMEM;
     242                 :            : 
     243                 :            :         /* Create a new question, and patch in the new name */
     244   [ #  #  #  #  :          0 :         DNS_QUESTION_FOREACH(key, q) {
          #  #  #  #  #  
                      # ]
     245         [ #  # ]:          0 :                 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *k = NULL;
     246                 :            : 
     247                 :          0 :                 k = dns_resource_key_new_redirect(key, cname);
     248         [ #  # ]:          0 :                 if (!k)
     249                 :          0 :                         return -ENOMEM;
     250                 :            : 
     251                 :          0 :                 r = dns_question_add(n, k);
     252         [ #  # ]:          0 :                 if (r < 0)
     253                 :          0 :                         return r;
     254                 :            :         }
     255                 :            : 
     256                 :          0 :         *ret = TAKE_PTR(n);
     257                 :            : 
     258                 :          0 :         return 1;
     259                 :            : }
     260                 :            : 
     261                 :          0 : const char *dns_question_first_name(DnsQuestion *q) {
     262                 :            : 
     263         [ #  # ]:          0 :         if (!q)
     264                 :          0 :                 return NULL;
     265                 :            : 
     266         [ #  # ]:          0 :         if (q->n_keys < 1)
     267                 :          0 :                 return NULL;
     268                 :            : 
     269                 :          0 :         return dns_resource_key_name(q->keys[0]);
     270                 :            : }
     271                 :            : 
     272                 :          0 : int dns_question_new_address(DnsQuestion **ret, int family, const char *name, bool convert_idna) {
     273                 :          0 :         _cleanup_(dns_question_unrefp) DnsQuestion *q = NULL;
     274                 :          0 :         _cleanup_free_ char *buf = NULL;
     275                 :            :         int r;
     276                 :            : 
     277         [ #  # ]:          0 :         assert(ret);
     278         [ #  # ]:          0 :         assert(name);
     279                 :            : 
     280   [ #  #  #  # ]:          0 :         if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
     281                 :          0 :                 return -EAFNOSUPPORT;
     282                 :            : 
     283         [ #  # ]:          0 :         if (convert_idna) {
     284                 :          0 :                 r = dns_name_apply_idna(name, &buf);
     285         [ #  # ]:          0 :                 if (r < 0)
     286                 :          0 :                         return r;
     287   [ #  #  #  # ]:          0 :                 if (r > 0 && !streq(name, buf))
     288                 :          0 :                         name = buf;
     289                 :            :                 else
     290                 :            :                         /* We did not manage to create convert the idna name, or it's
     291                 :            :                          * the same as the original name. We assume the caller already
     292                 :            :                          * created an unconverted question, so let's not repeat work
     293                 :            :                          * unnecessarily. */
     294                 :          0 :                         return -EALREADY;
     295                 :            :         }
     296                 :            : 
     297         [ #  # ]:          0 :         q = dns_question_new(family == AF_UNSPEC ? 2 : 1);
     298         [ #  # ]:          0 :         if (!q)
     299                 :          0 :                 return -ENOMEM;
     300                 :            : 
     301         [ #  # ]:          0 :         if (family != AF_INET6) {
     302         [ #  # ]:          0 :                 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
     303                 :            : 
     304                 :          0 :                 key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, name);
     305         [ #  # ]:          0 :                 if (!key)
     306                 :          0 :                         return -ENOMEM;
     307                 :            : 
     308                 :          0 :                 r = dns_question_add(q, key);
     309         [ #  # ]:          0 :                 if (r < 0)
     310                 :          0 :                         return r;
     311                 :            :         }
     312                 :            : 
     313         [ #  # ]:          0 :         if (family != AF_INET) {
     314         [ #  # ]:          0 :                 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
     315                 :            : 
     316                 :          0 :                 key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, name);
     317         [ #  # ]:          0 :                 if (!key)
     318                 :          0 :                         return -ENOMEM;
     319                 :            : 
     320                 :          0 :                 r = dns_question_add(q, key);
     321         [ #  # ]:          0 :                 if (r < 0)
     322                 :          0 :                         return r;
     323                 :            :         }
     324                 :            : 
     325                 :          0 :         *ret = TAKE_PTR(q);
     326                 :            : 
     327                 :          0 :         return 0;
     328                 :            : }
     329                 :            : 
     330                 :          0 : int dns_question_new_reverse(DnsQuestion **ret, int family, const union in_addr_union *a) {
     331                 :          0 :         _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
     332                 :          0 :         _cleanup_(dns_question_unrefp) DnsQuestion *q = NULL;
     333                 :          0 :         _cleanup_free_ char *reverse = NULL;
     334                 :            :         int r;
     335                 :            : 
     336         [ #  # ]:          0 :         assert(ret);
     337         [ #  # ]:          0 :         assert(a);
     338                 :            : 
     339   [ #  #  #  # ]:          0 :         if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
     340                 :          0 :                 return -EAFNOSUPPORT;
     341                 :            : 
     342                 :          0 :         r = dns_name_reverse(family, a, &reverse);
     343         [ #  # ]:          0 :         if (r < 0)
     344                 :          0 :                 return r;
     345                 :            : 
     346                 :          0 :         q = dns_question_new(1);
     347         [ #  # ]:          0 :         if (!q)
     348                 :          0 :                 return -ENOMEM;
     349                 :            : 
     350                 :          0 :         key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, reverse);
     351         [ #  # ]:          0 :         if (!key)
     352                 :          0 :                 return -ENOMEM;
     353                 :            : 
     354                 :          0 :         reverse = NULL;
     355                 :            : 
     356                 :          0 :         r = dns_question_add(q, key);
     357         [ #  # ]:          0 :         if (r < 0)
     358                 :          0 :                 return r;
     359                 :            : 
     360                 :          0 :         *ret = TAKE_PTR(q);
     361                 :            : 
     362                 :          0 :         return 0;
     363                 :            : }
     364                 :            : 
     365                 :          0 : int dns_question_new_service(
     366                 :            :                 DnsQuestion **ret,
     367                 :            :                 const char *service,
     368                 :            :                 const char *type,
     369                 :            :                 const char *domain,
     370                 :            :                 bool with_txt,
     371                 :            :                 bool convert_idna) {
     372                 :            : 
     373                 :          0 :         _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
     374                 :          0 :         _cleanup_(dns_question_unrefp) DnsQuestion *q = NULL;
     375                 :          0 :         _cleanup_free_ char *buf = NULL, *joined = NULL;
     376                 :            :         const char *name;
     377                 :            :         int r;
     378                 :            : 
     379         [ #  # ]:          0 :         assert(ret);
     380                 :            : 
     381                 :            :         /* We support three modes of invocation:
     382                 :            :          *
     383                 :            :          * 1. Only a domain is specified, in which case we assume a properly encoded SRV RR name, including service
     384                 :            :          *    type and possibly a service name. If specified in this way we assume it's already IDNA converted if
     385                 :            :          *    that's necessary.
     386                 :            :          *
     387                 :            :          * 2. Both service type and a domain specified, in which case a normal SRV RR is assumed, without a DNS-SD
     388                 :            :          *    style prefix. In this case we'll IDNA convert the domain, if that's requested.
     389                 :            :          *
     390                 :            :          * 3. All three of service name, type and domain are specified, in which case a DNS-SD service is put
     391                 :            :          *    together. The service name is never IDNA converted, and the domain is if requested.
     392                 :            :          *
     393                 :            :          * It's not supported to specify a service name without a type, or no domain name.
     394                 :            :          */
     395                 :            : 
     396         [ #  # ]:          0 :         if (!domain)
     397                 :          0 :                 return -EINVAL;
     398                 :            : 
     399         [ #  # ]:          0 :         if (type) {
     400         [ #  # ]:          0 :                 if (convert_idna) {
     401                 :          0 :                         r = dns_name_apply_idna(domain, &buf);
     402         [ #  # ]:          0 :                         if (r < 0)
     403                 :          0 :                                 return r;
     404         [ #  # ]:          0 :                         if (r > 0)
     405                 :          0 :                                 domain = buf;
     406                 :            :                 }
     407                 :            : 
     408                 :          0 :                 r = dns_service_join(service, type, domain, &joined);
     409         [ #  # ]:          0 :                 if (r < 0)
     410                 :          0 :                         return r;
     411                 :            : 
     412                 :          0 :                 name = joined;
     413                 :            :         } else {
     414         [ #  # ]:          0 :                 if (service)
     415                 :          0 :                         return -EINVAL;
     416                 :            : 
     417                 :          0 :                 name = domain;
     418                 :            :         }
     419                 :            : 
     420                 :          0 :         q = dns_question_new(1 + with_txt);
     421         [ #  # ]:          0 :         if (!q)
     422                 :          0 :                 return -ENOMEM;
     423                 :            : 
     424                 :          0 :         key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_SRV, name);
     425         [ #  # ]:          0 :         if (!key)
     426                 :          0 :                 return -ENOMEM;
     427                 :            : 
     428                 :          0 :         r = dns_question_add(q, key);
     429         [ #  # ]:          0 :         if (r < 0)
     430                 :          0 :                 return r;
     431                 :            : 
     432         [ #  # ]:          0 :         if (with_txt) {
     433                 :          0 :                 dns_resource_key_unref(key);
     434                 :          0 :                 key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_TXT, name);
     435         [ #  # ]:          0 :                 if (!key)
     436                 :          0 :                         return -ENOMEM;
     437                 :            : 
     438                 :          0 :                 r = dns_question_add(q, key);
     439         [ #  # ]:          0 :                 if (r < 0)
     440                 :          0 :                         return r;
     441                 :            :         }
     442                 :            : 
     443                 :          0 :         *ret = TAKE_PTR(q);
     444                 :            : 
     445                 :          0 :         return 0;
     446                 :            : }

Generated by: LCOV version 1.14