LCOV - code coverage report
Current view: top level - resolve - resolved-dns-answer.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 29 414 7.0 %
Date: 2019-08-23 13:36:53 Functions: 6 27 22.2 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 20 533 3.8 %

           Branch data     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                 :         16 : DnsAnswer *dns_answer_new(size_t n) {
      12                 :            :         DnsAnswer *a;
      13                 :            : 
      14                 :         16 :         a = malloc0(offsetof(DnsAnswer, items) + sizeof(DnsAnswerItem) * n);
      15         [ -  + ]:         16 :         if (!a)
      16                 :          0 :                 return NULL;
      17                 :            : 
      18                 :         16 :         a->n_ref = 1;
      19                 :         16 :         a->n_allocated = n;
      20                 :            : 
      21                 :         16 :         return a;
      22                 :            : }
      23                 :            : 
      24                 :         16 : static void dns_answer_flush(DnsAnswer *a) {
      25                 :            :         DnsResourceRecord *rr;
      26                 :            : 
      27         [ -  + ]:         16 :         if (!a)
      28                 :          0 :                 return;
      29                 :            : 
      30   [ +  -  +  -  :         32 :         DNS_ANSWER_FOREACH(rr, a)
          -  +  +  -  +  
                      + ]
      31                 :         16 :                 dns_resource_record_unref(rr);
      32                 :            : 
      33                 :         16 :         a->n_rrs = 0;
      34                 :            : }
      35                 :            : 
      36                 :         16 : static DnsAnswer *dns_answer_free(DnsAnswer *a) {
      37         [ -  + ]:         16 :         assert(a);
      38                 :            : 
      39                 :         16 :         dns_answer_flush(a);
      40                 :         16 :         return mfree(a);
      41                 :            : }
      42                 :            : 
      43   [ +  +  -  +  :       5048 : DEFINE_TRIVIAL_REF_UNREF_FUNC(DnsAnswer, dns_answer, dns_answer_free);
                   -  + ]
      44                 :            : 
      45                 :         16 : static int dns_answer_add_raw(DnsAnswer *a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags) {
      46         [ -  + ]:         16 :         assert(rr);
      47                 :            : 
      48         [ -  + ]:         16 :         if (!a)
      49                 :          0 :                 return -ENOSPC;
      50                 :            : 
      51         [ -  + ]:         16 :         if (a->n_rrs >= a->n_allocated)
      52                 :          0 :                 return -ENOSPC;
      53                 :            : 
      54                 :         32 :         a->items[a->n_rrs++] = (DnsAnswerItem) {
      55                 :         16 :                 .rr = dns_resource_record_ref(rr),
      56                 :            :                 .ifindex = ifindex,
      57                 :            :                 .flags = flags,
      58                 :            :         };
      59                 :            : 
      60                 :         16 :         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                 :         16 : int dns_answer_add(DnsAnswer *a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags) {
      78                 :            :         size_t i;
      79                 :            :         int r;
      80                 :            : 
      81         [ -  + ]:         16 :         assert(rr);
      82                 :            : 
      83         [ -  + ]:         16 :         if (!a)
      84                 :          0 :                 return -ENOSPC;
      85         [ -  + ]:         16 :         if (a->n_ref > 1)
      86                 :          0 :                 return -EBUSY;
      87                 :            : 
      88         [ -  + ]:         16 :         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                 :         16 :         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