LCOV - code coverage report
Current view: top level - resolve - resolved-dns-answer.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 29 414 7.0 %
Date: 2019-08-22 15:41:25 Functions: 6 27 22.2 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <stdio.h>
       4             : 
       5             : #include "alloc-util.h"
       6             : #include "dns-domain.h"
       7             : #include "resolved-dns-answer.h"
       8             : #include "resolved-dns-dnssec.h"
       9             : #include "string-util.h"
      10             : 
      11           4 : DnsAnswer *dns_answer_new(size_t n) {
      12             :         DnsAnswer *a;
      13             : 
      14           4 :         a = malloc0(offsetof(DnsAnswer, items) + sizeof(DnsAnswerItem) * n);
      15           4 :         if (!a)
      16           0 :                 return NULL;
      17             : 
      18           4 :         a->n_ref = 1;
      19           4 :         a->n_allocated = n;
      20             : 
      21           4 :         return a;
      22             : }
      23             : 
      24           4 : static void dns_answer_flush(DnsAnswer *a) {
      25             :         DnsResourceRecord *rr;
      26             : 
      27           4 :         if (!a)
      28           0 :                 return;
      29             : 
      30           8 :         DNS_ANSWER_FOREACH(rr, a)
      31           4 :                 dns_resource_record_unref(rr);
      32             : 
      33           4 :         a->n_rrs = 0;
      34             : }
      35             : 
      36           4 : static DnsAnswer *dns_answer_free(DnsAnswer *a) {
      37           4 :         assert(a);
      38             : 
      39           4 :         dns_answer_flush(a);
      40           4 :         return mfree(a);
      41             : }
      42             : 
      43        1262 : DEFINE_TRIVIAL_REF_UNREF_FUNC(DnsAnswer, dns_answer, dns_answer_free);
      44             : 
      45           4 : static int dns_answer_add_raw(DnsAnswer *a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags) {
      46           4 :         assert(rr);
      47             : 
      48           4 :         if (!a)
      49           0 :                 return -ENOSPC;
      50             : 
      51           4 :         if (a->n_rrs >= a->n_allocated)
      52           0 :                 return -ENOSPC;
      53             : 
      54           8 :         a->items[a->n_rrs++] = (DnsAnswerItem) {
      55           4 :                 .rr = dns_resource_record_ref(rr),
      56             :                 .ifindex = ifindex,
      57             :                 .flags = flags,
      58             :         };
      59             : 
      60           4 :         return 1;
      61             : }
      62             : 
      63           0 : static int dns_answer_add_raw_all(DnsAnswer *a, DnsAnswer *source) {
      64             :         DnsResourceRecord *rr;
      65             :         DnsAnswerFlags flags;
      66             :         int ifindex, r;
      67             : 
      68           0 :         DNS_ANSWER_FOREACH_FULL(rr, ifindex, flags, source) {
      69           0 :                 r = dns_answer_add_raw(a, rr, ifindex, flags);
      70           0 :                 if (r < 0)
      71           0 :                         return r;
      72             :         }
      73             : 
      74           0 :         return 0;
      75             : }
      76             : 
      77           4 : int dns_answer_add(DnsAnswer *a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags) {
      78             :         size_t i;
      79             :         int r;
      80             : 
      81           4 :         assert(rr);
      82             : 
      83           4 :         if (!a)
      84           0 :                 return -ENOSPC;
      85           4 :         if (a->n_ref > 1)
      86           0 :                 return -EBUSY;
      87             : 
      88           4 :         for (i = 0; i < a->n_rrs; i++) {
      89           0 :                 if (a->items[i].ifindex != ifindex)
      90           0 :                         continue;
      91             : 
      92           0 :                 r = dns_resource_key_equal(a->items[i].rr->key, rr->key);
      93           0 :                 if (r < 0)
      94           0 :                         return r;
      95           0 :                 if (r == 0)
      96           0 :                         continue;
      97             : 
      98             :                 /* There's already an RR of the same RRset in place! Let's see if the TTLs more or less
      99             :                  * match. We don't really care if they match precisely, but we do care whether one is 0 and
     100             :                  * the other is not. See RFC 2181, Section 5.2. */
     101           0 :                 if ((rr->ttl == 0) != (a->items[i].rr->ttl == 0))
     102           0 :                         return -EINVAL;
     103             : 
     104           0 :                 r = dns_resource_record_payload_equal(a->items[i].rr, rr);
     105           0 :                 if (r < 0)
     106           0 :                         return r;
     107           0 :                 if (r == 0)
     108           0 :                         continue;
     109             : 
     110             :                 /* Entry already exists, keep the entry with the higher RR. */
     111           0 :                 if (rr->ttl > a->items[i].rr->ttl) {
     112           0 :                         dns_resource_record_ref(rr);
     113           0 :                         dns_resource_record_unref(a->items[i].rr);
     114           0 :                         a->items[i].rr = rr;
     115             :                 }
     116             : 
     117           0 :                 a->items[i].flags |= flags;
     118           0 :                 return 0;
     119             :         }
     120             : 
     121           4 :         return dns_answer_add_raw(a, rr, ifindex, flags);
     122             : }
     123             : 
     124           0 : static int dns_answer_add_all(DnsAnswer *a, DnsAnswer *b) {
     125             :         DnsResourceRecord *rr;
     126             :         DnsAnswerFlags flags;
     127             :         int ifindex, r;
     128             : 
     129           0 :         DNS_ANSWER_FOREACH_FULL(rr, ifindex, flags, b) {
     130           0 :                 r = dns_answer_add(a, rr, ifindex, flags);
     131           0 :                 if (r < 0)
     132           0 :                         return r;
     133             :         }
     134             : 
     135           0 :         return 0;
     136             : }
     137             : 
     138           0 : int dns_answer_add_extend(DnsAnswer **a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags) {
     139             :         int r;
     140             : 
     141           0 :         assert(a);
     142           0 :         assert(rr);
     143             : 
     144           0 :         r = dns_answer_reserve_or_clone(a, 1);
     145           0 :         if (r < 0)
     146           0 :                 return r;
     147             : 
     148           0 :         return dns_answer_add(*a, rr, ifindex, flags);
     149             : }
     150             : 
     151           0 : int dns_answer_add_soa(DnsAnswer *a, const char *name, uint32_t ttl, int ifindex) {
     152           0 :         _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *soa = NULL;
     153             : 
     154           0 :         soa = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_SOA, name);
     155           0 :         if (!soa)
     156           0 :                 return -ENOMEM;
     157             : 
     158           0 :         soa->ttl = ttl;
     159             : 
     160           0 :         soa->soa.mname = strdup(name);
     161           0 :         if (!soa->soa.mname)
     162           0 :                 return -ENOMEM;
     163             : 
     164           0 :         soa->soa.rname = strjoin("root.", name);
     165           0 :         if (!soa->soa.rname)
     166           0 :                 return -ENOMEM;
     167             : 
     168           0 :         soa->soa.serial = 1;
     169           0 :         soa->soa.refresh = 1;
     170           0 :         soa->soa.retry = 1;
     171           0 :         soa->soa.expire = 1;
     172           0 :         soa->soa.minimum = ttl;
     173             : 
     174           0 :         return dns_answer_add(a, soa, ifindex, DNS_ANSWER_AUTHENTICATED);
     175             : }
     176             : 
     177           0 : int dns_answer_match_key(DnsAnswer *a, const DnsResourceKey *key, DnsAnswerFlags *ret_flags) {
     178           0 :         DnsAnswerFlags flags = 0, i_flags;
     179             :         DnsResourceRecord *i;
     180           0 :         bool found = false;
     181             :         int r;
     182             : 
     183           0 :         assert(key);
     184             : 
     185           0 :         DNS_ANSWER_FOREACH_FLAGS(i, i_flags, a) {
     186           0 :                 r = dns_resource_key_match_rr(key, i, NULL);
     187           0 :                 if (r < 0)
     188           0 :                         return r;
     189           0 :                 if (r == 0)
     190           0 :                         continue;
     191             : 
     192           0 :                 if (!ret_flags)
     193           0 :                         return 1;
     194             : 
     195           0 :                 if (found)
     196           0 :                         flags &= i_flags;
     197             :                 else {
     198           0 :                         flags = i_flags;
     199           0 :                         found = true;
     200             :                 }
     201             :         }
     202             : 
     203           0 :         if (ret_flags)
     204           0 :                 *ret_flags = flags;
     205             : 
     206           0 :         return found;
     207             : }
     208             : 
     209           0 : int dns_answer_contains_nsec_or_nsec3(DnsAnswer *a) {
     210             :         DnsResourceRecord *i;
     211             : 
     212           0 :         DNS_ANSWER_FOREACH(i, a) {
     213           0 :                 if (IN_SET(i->key->type, DNS_TYPE_NSEC, DNS_TYPE_NSEC3))
     214           0 :                         return true;
     215             :         }
     216             : 
     217           0 :         return false;
     218             : }
     219             : 
     220           0 : int dns_answer_contains_zone_nsec3(DnsAnswer *answer, const char *zone) {
     221             :         DnsResourceRecord *rr;
     222             :         int r;
     223             : 
     224             :         /* Checks whether the specified answer contains at least one NSEC3 RR in the specified zone */
     225             : 
     226           0 :         DNS_ANSWER_FOREACH(rr, answer) {
     227             :                 const char *p;
     228             : 
     229           0 :                 if (rr->key->type != DNS_TYPE_NSEC3)
     230           0 :                         continue;
     231             : 
     232           0 :                 p = dns_resource_key_name(rr->key);
     233           0 :                 r = dns_name_parent(&p);
     234           0 :                 if (r < 0)
     235           0 :                         return r;
     236           0 :                 if (r == 0)
     237           0 :                         continue;
     238             : 
     239           0 :                 r = dns_name_equal(p, zone);
     240           0 :                 if (r != 0)
     241           0 :                         return r;
     242             :         }
     243             : 
     244           0 :         return false;
     245             : }
     246             : 
     247           0 : int dns_answer_find_soa(DnsAnswer *a, const DnsResourceKey *key, DnsResourceRecord **ret, DnsAnswerFlags *flags) {
     248           0 :         DnsResourceRecord *rr, *soa = NULL;
     249           0 :         DnsAnswerFlags rr_flags, soa_flags = 0;
     250             :         int r;
     251             : 
     252           0 :         assert(key);
     253             : 
     254             :         /* For a SOA record we can never find a matching SOA record */
     255           0 :         if (key->type == DNS_TYPE_SOA)
     256           0 :                 return 0;
     257             : 
     258           0 :         DNS_ANSWER_FOREACH_FLAGS(rr, rr_flags, a) {
     259           0 :                 r = dns_resource_key_match_soa(key, rr->key);
     260           0 :                 if (r < 0)
     261           0 :                         return r;
     262           0 :                 if (r > 0) {
     263             : 
     264           0 :                         if (soa) {
     265           0 :                                 r = dns_name_endswith(dns_resource_key_name(rr->key), dns_resource_key_name(soa->key));
     266           0 :                                 if (r < 0)
     267           0 :                                         return r;
     268           0 :                                 if (r > 0)
     269           0 :                                         continue;
     270             :                         }
     271             : 
     272           0 :                         soa = rr;
     273           0 :                         soa_flags = rr_flags;
     274             :                 }
     275             :         }
     276             : 
     277           0 :         if (!soa)
     278           0 :                 return 0;
     279             : 
     280           0 :         if (ret)
     281           0 :                 *ret = soa;
     282           0 :         if (flags)
     283           0 :                 *flags = soa_flags;
     284             : 
     285           0 :         return 1;
     286             : }
     287             : 
     288           0 : int dns_answer_find_cname_or_dname(DnsAnswer *a, const DnsResourceKey *key, DnsResourceRecord **ret, DnsAnswerFlags *flags) {
     289             :         DnsResourceRecord *rr;
     290             :         DnsAnswerFlags rr_flags;
     291             :         int r;
     292             : 
     293           0 :         assert(key);
     294             : 
     295             :         /* For a {C,D}NAME record we can never find a matching {C,D}NAME record */
     296           0 :         if (!dns_type_may_redirect(key->type))
     297           0 :                 return 0;
     298             : 
     299           0 :         DNS_ANSWER_FOREACH_FLAGS(rr, rr_flags, a) {
     300           0 :                 r = dns_resource_key_match_cname_or_dname(key, rr->key, NULL);
     301           0 :                 if (r < 0)
     302           0 :                         return r;
     303           0 :                 if (r > 0) {
     304           0 :                         if (ret)
     305           0 :                                 *ret = rr;
     306           0 :                         if (flags)
     307           0 :                                 *flags = rr_flags;
     308           0 :                         return 1;
     309             :                 }
     310             :         }
     311             : 
     312           0 :         return 0;
     313             : }
     314             : 
     315           0 : int dns_answer_merge(DnsAnswer *a, DnsAnswer *b, DnsAnswer **ret) {
     316           0 :         _cleanup_(dns_answer_unrefp) DnsAnswer *k = NULL;
     317             :         int r;
     318             : 
     319           0 :         assert(ret);
     320             : 
     321           0 :         if (dns_answer_size(a) <= 0) {
     322           0 :                 *ret = dns_answer_ref(b);
     323           0 :                 return 0;
     324             :         }
     325             : 
     326           0 :         if (dns_answer_size(b) <= 0) {
     327           0 :                 *ret = dns_answer_ref(a);
     328           0 :                 return 0;
     329             :         }
     330             : 
     331           0 :         k = dns_answer_new(a->n_rrs + b->n_rrs);
     332           0 :         if (!k)
     333           0 :                 return -ENOMEM;
     334             : 
     335           0 :         r = dns_answer_add_raw_all(k, a);
     336           0 :         if (r < 0)
     337           0 :                 return r;
     338             : 
     339           0 :         r = dns_answer_add_all(k, b);
     340           0 :         if (r < 0)
     341           0 :                 return r;
     342             : 
     343           0 :         *ret = TAKE_PTR(k);
     344             : 
     345           0 :         return 0;
     346             : }
     347             : 
     348           0 : int dns_answer_extend(DnsAnswer **a, DnsAnswer *b) {
     349             :         DnsAnswer *merged;
     350             :         int r;
     351             : 
     352           0 :         assert(a);
     353             : 
     354           0 :         r = dns_answer_merge(*a, b, &merged);
     355           0 :         if (r < 0)
     356           0 :                 return r;
     357             : 
     358           0 :         dns_answer_unref(*a);
     359           0 :         *a = merged;
     360             : 
     361           0 :         return 0;
     362             : }
     363             : 
     364           0 : int dns_answer_remove_by_key(DnsAnswer **a, const DnsResourceKey *key) {
     365           0 :         bool found = false, other = false;
     366             :         DnsResourceRecord *rr;
     367             :         size_t i;
     368             :         int r;
     369             : 
     370           0 :         assert(a);
     371           0 :         assert(key);
     372             : 
     373             :         /* Remove all entries matching the specified key from *a */
     374             : 
     375           0 :         DNS_ANSWER_FOREACH(rr, *a) {
     376           0 :                 r = dns_resource_key_equal(rr->key, key);
     377           0 :                 if (r < 0)
     378           0 :                         return r;
     379           0 :                 if (r > 0)
     380           0 :                         found = true;
     381             :                 else
     382           0 :                         other = true;
     383             : 
     384           0 :                 if (found && other)
     385           0 :                         break;
     386             :         }
     387             : 
     388           0 :         if (!found)
     389           0 :                 return 0;
     390             : 
     391           0 :         if (!other) {
     392           0 :                 *a = dns_answer_unref(*a); /* Return NULL for the empty answer */
     393           0 :                 return 1;
     394             :         }
     395             : 
     396           0 :         if ((*a)->n_ref > 1) {
     397           0 :                 _cleanup_(dns_answer_unrefp) DnsAnswer *copy = NULL;
     398             :                 DnsAnswerFlags flags;
     399             :                 int ifindex;
     400             : 
     401           0 :                 copy = dns_answer_new((*a)->n_rrs);
     402           0 :                 if (!copy)
     403           0 :                         return -ENOMEM;
     404             : 
     405           0 :                 DNS_ANSWER_FOREACH_FULL(rr, ifindex, flags, *a) {
     406           0 :                         r = dns_resource_key_equal(rr->key, key);
     407           0 :                         if (r < 0)
     408           0 :                                 return r;
     409           0 :                         if (r > 0)
     410           0 :                                 continue;
     411             : 
     412           0 :                         r = dns_answer_add_raw(copy, rr, ifindex, flags);
     413           0 :                         if (r < 0)
     414           0 :                                 return r;
     415             :                 }
     416             : 
     417           0 :                 dns_answer_unref(*a);
     418           0 :                 *a = TAKE_PTR(copy);
     419             : 
     420           0 :                 return 1;
     421             :         }
     422             : 
     423             :         /* Only a single reference, edit in-place */
     424             : 
     425           0 :         i = 0;
     426             :         for (;;) {
     427           0 :                 if (i >= (*a)->n_rrs)
     428           0 :                         break;
     429             : 
     430           0 :                 r = dns_resource_key_equal((*a)->items[i].rr->key, key);
     431           0 :                 if (r < 0)
     432           0 :                         return r;
     433           0 :                 if (r > 0) {
     434             :                         /* Kill this entry */
     435             : 
     436           0 :                         dns_resource_record_unref((*a)->items[i].rr);
     437           0 :                         memmove((*a)->items + i, (*a)->items + i + 1, sizeof(DnsAnswerItem) * ((*a)->n_rrs - i - 1));
     438           0 :                         (*a)->n_rrs--;
     439           0 :                         continue;
     440             : 
     441             :                 } else
     442             :                         /* Keep this entry */
     443           0 :                         i++;
     444             :         }
     445             : 
     446           0 :         return 1;
     447             : }
     448             : 
     449           0 : int dns_answer_remove_by_rr(DnsAnswer **a, DnsResourceRecord *rm) {
     450           0 :         bool found = false, other = false;
     451             :         DnsResourceRecord *rr;
     452             :         size_t i;
     453             :         int r;
     454             : 
     455           0 :         assert(a);
     456           0 :         assert(rm);
     457             : 
     458             :         /* Remove all entries matching the specified RR from *a */
     459             : 
     460           0 :         DNS_ANSWER_FOREACH(rr, *a) {
     461           0 :                 r = dns_resource_record_equal(rr, rm);
     462           0 :                 if (r < 0)
     463           0 :                         return r;
     464           0 :                 if (r > 0)
     465           0 :                         found = true;
     466             :                 else
     467           0 :                         other = true;
     468             : 
     469           0 :                 if (found && other)
     470           0 :                         break;
     471             :         }
     472             : 
     473           0 :         if (!found)
     474           0 :                 return 0;
     475             : 
     476           0 :         if (!other) {
     477           0 :                 *a = dns_answer_unref(*a); /* Return NULL for the empty answer */
     478           0 :                 return 1;
     479             :         }
     480             : 
     481           0 :         if ((*a)->n_ref > 1) {
     482           0 :                 _cleanup_(dns_answer_unrefp) DnsAnswer *copy = NULL;
     483             :                 DnsAnswerFlags flags;
     484             :                 int ifindex;
     485             : 
     486           0 :                 copy = dns_answer_new((*a)->n_rrs);
     487           0 :                 if (!copy)
     488           0 :                         return -ENOMEM;
     489             : 
     490           0 :                 DNS_ANSWER_FOREACH_FULL(rr, ifindex, flags, *a) {
     491           0 :                         r = dns_resource_record_equal(rr, rm);
     492           0 :                         if (r < 0)
     493           0 :                                 return r;
     494           0 :                         if (r > 0)
     495           0 :                                 continue;
     496             : 
     497           0 :                         r = dns_answer_add_raw(copy, rr, ifindex, flags);
     498           0 :                         if (r < 0)
     499           0 :                                 return r;
     500             :                 }
     501             : 
     502           0 :                 dns_answer_unref(*a);
     503           0 :                 *a = TAKE_PTR(copy);
     504             : 
     505           0 :                 return 1;
     506             :         }
     507             : 
     508             :         /* Only a single reference, edit in-place */
     509             : 
     510           0 :         i = 0;
     511             :         for (;;) {
     512           0 :                 if (i >= (*a)->n_rrs)
     513           0 :                         break;
     514             : 
     515           0 :                 r = dns_resource_record_equal((*a)->items[i].rr, rm);
     516           0 :                 if (r < 0)
     517           0 :                         return r;
     518           0 :                 if (r > 0) {
     519             :                         /* Kill this entry */
     520             : 
     521           0 :                         dns_resource_record_unref((*a)->items[i].rr);
     522           0 :                         memmove((*a)->items + i, (*a)->items + i + 1, sizeof(DnsAnswerItem) * ((*a)->n_rrs - i - 1));
     523           0 :                         (*a)->n_rrs--;
     524           0 :                         continue;
     525             : 
     526             :                 } else
     527             :                         /* Keep this entry */
     528           0 :                         i++;
     529             :         }
     530             : 
     531           0 :         return 1;
     532             : }
     533             : 
     534           0 : int dns_answer_copy_by_key(DnsAnswer **a, DnsAnswer *source, const DnsResourceKey *key, DnsAnswerFlags or_flags) {
     535             :         DnsResourceRecord *rr_source;
     536             :         int ifindex_source, r;
     537             :         DnsAnswerFlags flags_source;
     538             : 
     539           0 :         assert(a);
     540           0 :         assert(key);
     541             : 
     542             :         /* Copy all RRs matching the specified key from source into *a */
     543             : 
     544           0 :         DNS_ANSWER_FOREACH_FULL(rr_source, ifindex_source, flags_source, source) {
     545             : 
     546           0 :                 r = dns_resource_key_equal(rr_source->key, key);
     547           0 :                 if (r < 0)
     548           0 :                         return r;
     549           0 :                 if (r == 0)
     550           0 :                         continue;
     551             : 
     552             :                 /* Make space for at least one entry */
     553           0 :                 r = dns_answer_reserve_or_clone(a, 1);
     554           0 :                 if (r < 0)
     555           0 :                         return r;
     556             : 
     557           0 :                 r = dns_answer_add(*a, rr_source, ifindex_source, flags_source|or_flags);
     558           0 :                 if (r < 0)
     559           0 :                         return r;
     560             :         }
     561             : 
     562           0 :         return 0;
     563             : }
     564             : 
     565           0 : int dns_answer_move_by_key(DnsAnswer **to, DnsAnswer **from, const DnsResourceKey *key, DnsAnswerFlags or_flags) {
     566             :         int r;
     567             : 
     568           0 :         assert(to);
     569           0 :         assert(from);
     570           0 :         assert(key);
     571             : 
     572           0 :         r = dns_answer_copy_by_key(to, *from, key, or_flags);
     573           0 :         if (r < 0)
     574           0 :                 return r;
     575             : 
     576           0 :         return dns_answer_remove_by_key(from, key);
     577             : }
     578             : 
     579           0 : void dns_answer_order_by_scope(DnsAnswer *a, bool prefer_link_local) {
     580             :         DnsAnswerItem *items;
     581             :         size_t i, start, end;
     582             : 
     583           0 :         if (!a)
     584           0 :                 return;
     585             : 
     586           0 :         if (a->n_rrs <= 1)
     587           0 :                 return;
     588             : 
     589           0 :         start = 0;
     590           0 :         end = a->n_rrs-1;
     591             : 
     592             :         /* RFC 4795, Section 2.6 suggests we should order entries
     593             :          * depending on whether the sender is a link-local address. */
     594             : 
     595           0 :         items = newa(DnsAnswerItem, a->n_rrs);
     596           0 :         for (i = 0; i < a->n_rrs; i++) {
     597             : 
     598           0 :                 if (a->items[i].rr->key->class == DNS_CLASS_IN &&
     599           0 :                     ((a->items[i].rr->key->type == DNS_TYPE_A && in_addr_is_link_local(AF_INET, (union in_addr_union*) &a->items[i].rr->a.in_addr) != prefer_link_local) ||
     600           0 :                      (a->items[i].rr->key->type == DNS_TYPE_AAAA && in_addr_is_link_local(AF_INET6, (union in_addr_union*) &a->items[i].rr->aaaa.in6_addr) != prefer_link_local)))
     601             :                         /* Order address records that are not preferred to the end of the array */
     602           0 :                         items[end--] = a->items[i];
     603             :                 else
     604             :                         /* Order all other records to the beginning of the array */
     605           0 :                         items[start++] = a->items[i];
     606             :         }
     607             : 
     608           0 :         assert(start == end+1);
     609           0 :         memcpy(a->items, items, sizeof(DnsAnswerItem) * a->n_rrs);
     610             : }
     611             : 
     612           0 : int dns_answer_reserve(DnsAnswer **a, size_t n_free) {
     613             :         DnsAnswer *n;
     614             : 
     615           0 :         assert(a);
     616             : 
     617           0 :         if (n_free <= 0)
     618           0 :                 return 0;
     619             : 
     620           0 :         if (*a) {
     621             :                 size_t ns;
     622             : 
     623           0 :                 if ((*a)->n_ref > 1)
     624           0 :                         return -EBUSY;
     625             : 
     626           0 :                 ns = (*a)->n_rrs + n_free;
     627             : 
     628           0 :                 if ((*a)->n_allocated >= ns)
     629           0 :                         return 0;
     630             : 
     631             :                 /* Allocate more than we need */
     632           0 :                 ns *= 2;
     633             : 
     634           0 :                 n = realloc(*a, offsetof(DnsAnswer, items) + sizeof(DnsAnswerItem) * ns);
     635           0 :                 if (!n)
     636           0 :                         return -ENOMEM;
     637             : 
     638           0 :                 n->n_allocated = ns;
     639             :         } else {
     640           0 :                 n = dns_answer_new(n_free);
     641           0 :                 if (!n)
     642           0 :                         return -ENOMEM;
     643             :         }
     644             : 
     645           0 :         *a = n;
     646           0 :         return 0;
     647             : }
     648             : 
     649           0 : int dns_answer_reserve_or_clone(DnsAnswer **a, size_t n_free) {
     650           0 :         _cleanup_(dns_answer_unrefp) DnsAnswer *n = NULL;
     651             :         int r;
     652             : 
     653           0 :         assert(a);
     654             : 
     655             :         /* Tries to extend the DnsAnswer object. And if that's not
     656             :          * possible, since we are not the sole owner, then allocate a
     657             :          * new, appropriately sized one. Either way, after this call
     658             :          * the object will only have a single reference, and has room
     659             :          * for at least the specified number of RRs. */
     660             : 
     661           0 :         r = dns_answer_reserve(a, n_free);
     662           0 :         if (r != -EBUSY)
     663           0 :                 return r;
     664             : 
     665           0 :         assert(*a);
     666             : 
     667           0 :         n = dns_answer_new(((*a)->n_rrs + n_free) * 2);
     668           0 :         if (!n)
     669           0 :                 return -ENOMEM;
     670             : 
     671           0 :         r = dns_answer_add_raw_all(n, *a);
     672           0 :         if (r < 0)
     673           0 :                 return r;
     674             : 
     675           0 :         dns_answer_unref(*a);
     676           0 :         *a = TAKE_PTR(n);
     677             : 
     678           0 :         return 0;
     679             : }
     680             : 
     681           0 : void dns_answer_dump(DnsAnswer *answer, FILE *f) {
     682             :         DnsResourceRecord *rr;
     683             :         DnsAnswerFlags flags;
     684             :         int ifindex;
     685             : 
     686           0 :         if (!f)
     687           0 :                 f = stdout;
     688             : 
     689           0 :         DNS_ANSWER_FOREACH_FULL(rr, ifindex, flags, answer) {
     690             :                 const char *t;
     691             : 
     692           0 :                 fputc('\t', f);
     693             : 
     694           0 :                 t = dns_resource_record_to_string(rr);
     695           0 :                 if (!t) {
     696           0 :                         log_oom();
     697           0 :                         continue;
     698             :                 }
     699             : 
     700           0 :                 fputs(t, f);
     701             : 
     702           0 :                 if (ifindex != 0 || flags & (DNS_ANSWER_AUTHENTICATED|DNS_ANSWER_CACHEABLE|DNS_ANSWER_SHARED_OWNER))
     703           0 :                         fputs("\t;", f);
     704             : 
     705           0 :                 if (ifindex != 0)
     706           0 :                         printf(" ifindex=%i", ifindex);
     707           0 :                 if (flags & DNS_ANSWER_AUTHENTICATED)
     708           0 :                         fputs(" authenticated", f);
     709           0 :                 if (flags & DNS_ANSWER_CACHEABLE)
     710           0 :                         fputs(" cachable", f);
     711           0 :                 if (flags & DNS_ANSWER_SHARED_OWNER)
     712           0 :                         fputs(" shared-owner", f);
     713             : 
     714           0 :                 fputc('\n', f);
     715             :         }
     716           0 : }
     717             : 
     718           0 : int dns_answer_has_dname_for_cname(DnsAnswer *a, DnsResourceRecord *cname) {
     719             :         DnsResourceRecord *rr;
     720             :         int r;
     721             : 
     722           0 :         assert(cname);
     723             : 
     724             :         /* Checks whether the answer contains a DNAME record that indicates that the specified CNAME record is
     725             :          * synthesized from it */
     726             : 
     727           0 :         if (cname->key->type != DNS_TYPE_CNAME)
     728           0 :                 return 0;
     729             : 
     730           0 :         DNS_ANSWER_FOREACH(rr, a) {
     731           0 :                 _cleanup_free_ char *n = NULL;
     732             : 
     733           0 :                 if (rr->key->type != DNS_TYPE_DNAME)
     734           0 :                         continue;
     735           0 :                 if (rr->key->class != cname->key->class)
     736           0 :                         continue;
     737             : 
     738           0 :                 r = dns_name_change_suffix(cname->cname.name, rr->dname.name, dns_resource_key_name(rr->key), &n);
     739           0 :                 if (r < 0)
     740           0 :                         return r;
     741           0 :                 if (r == 0)
     742           0 :                         continue;
     743             : 
     744           0 :                 r = dns_name_equal(n, dns_resource_key_name(cname->key));
     745           0 :                 if (r < 0)
     746           0 :                         return r;
     747           0 :                 if (r > 0)
     748           0 :                         return 1;
     749             :         }
     750             : 
     751           0 :         return 0;
     752             : }

Generated by: LCOV version 1.14