LCOV - code coverage report
Current view: top level - resolve - resolved-dns-question.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 1 243 0.4 %
Date: 2019-08-22 15:41:25 Functions: 1 16 6.2 %

          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        1258 : 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