LCOV - code coverage report
Current view: top level - resolve - resolved-dns-zone.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 0 383 0.0 %
Date: 2019-08-23 13:36:53 Functions: 0 23 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 364 0.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : 
       3                 :            : #include "alloc-util.h"
       4                 :            : #include "dns-domain.h"
       5                 :            : #include "list.h"
       6                 :            : #include "resolved-dns-packet.h"
       7                 :            : #include "resolved-dns-zone.h"
       8                 :            : #include "resolved-dnssd.h"
       9                 :            : #include "string-util.h"
      10                 :            : 
      11                 :            : /* Never allow more than 1K entries */
      12                 :            : #define ZONE_MAX 1024
      13                 :            : 
      14                 :          0 : void dns_zone_item_probe_stop(DnsZoneItem *i) {
      15                 :            :         DnsTransaction *t;
      16         [ #  # ]:          0 :         assert(i);
      17                 :            : 
      18         [ #  # ]:          0 :         if (!i->probe_transaction)
      19                 :          0 :                 return;
      20                 :            : 
      21                 :          0 :         t = TAKE_PTR(i->probe_transaction);
      22                 :            : 
      23                 :          0 :         set_remove(t->notify_zone_items, i);
      24                 :          0 :         set_remove(t->notify_zone_items_done, i);
      25                 :          0 :         dns_transaction_gc(t);
      26                 :            : }
      27                 :            : 
      28                 :          0 : static void dns_zone_item_free(DnsZoneItem *i) {
      29         [ #  # ]:          0 :         if (!i)
      30                 :          0 :                 return;
      31                 :            : 
      32                 :          0 :         dns_zone_item_probe_stop(i);
      33                 :          0 :         dns_resource_record_unref(i->rr);
      34                 :            : 
      35                 :          0 :         free(i);
      36                 :            : }
      37                 :            : 
      38         [ #  # ]:          0 : DEFINE_TRIVIAL_CLEANUP_FUNC(DnsZoneItem*, dns_zone_item_free);
      39                 :            : 
      40                 :          0 : static void dns_zone_item_remove_and_free(DnsZone *z, DnsZoneItem *i) {
      41                 :            :         DnsZoneItem *first;
      42                 :            : 
      43         [ #  # ]:          0 :         assert(z);
      44                 :            : 
      45         [ #  # ]:          0 :         if (!i)
      46                 :          0 :                 return;
      47                 :            : 
      48                 :          0 :         first = hashmap_get(z->by_key, i->rr->key);
      49   [ #  #  #  #  :          0 :         LIST_REMOVE(by_key, first, i);
             #  #  #  # ]
      50         [ #  # ]:          0 :         if (first)
      51         [ #  # ]:          0 :                 assert_se(hashmap_replace(z->by_key, first->rr->key, first) >= 0);
      52                 :            :         else
      53                 :          0 :                 hashmap_remove(z->by_key, i->rr->key);
      54                 :            : 
      55                 :          0 :         first = hashmap_get(z->by_name, dns_resource_key_name(i->rr->key));
      56   [ #  #  #  #  :          0 :         LIST_REMOVE(by_name, first, i);
             #  #  #  # ]
      57         [ #  # ]:          0 :         if (first)
      58         [ #  # ]:          0 :                 assert_se(hashmap_replace(z->by_name, dns_resource_key_name(first->rr->key), first) >= 0);
      59                 :            :         else
      60                 :          0 :                 hashmap_remove(z->by_name, dns_resource_key_name(i->rr->key));
      61                 :            : 
      62                 :          0 :         dns_zone_item_free(i);
      63                 :            : }
      64                 :            : 
      65                 :          0 : void dns_zone_flush(DnsZone *z) {
      66                 :            :         DnsZoneItem *i;
      67                 :            : 
      68         [ #  # ]:          0 :         assert(z);
      69                 :            : 
      70         [ #  # ]:          0 :         while ((i = hashmap_first(z->by_key)))
      71                 :          0 :                 dns_zone_item_remove_and_free(z, i);
      72                 :            : 
      73         [ #  # ]:          0 :         assert(hashmap_size(z->by_key) == 0);
      74         [ #  # ]:          0 :         assert(hashmap_size(z->by_name) == 0);
      75                 :            : 
      76                 :          0 :         z->by_key = hashmap_free(z->by_key);
      77                 :          0 :         z->by_name = hashmap_free(z->by_name);
      78                 :          0 : }
      79                 :            : 
      80                 :          0 : DnsZoneItem* dns_zone_get(DnsZone *z, DnsResourceRecord *rr) {
      81                 :            :         DnsZoneItem *i;
      82                 :            : 
      83         [ #  # ]:          0 :         assert(z);
      84         [ #  # ]:          0 :         assert(rr);
      85                 :            : 
      86         [ #  # ]:          0 :         LIST_FOREACH(by_key, i, hashmap_get(z->by_key, rr->key))
      87         [ #  # ]:          0 :                 if (dns_resource_record_equal(i->rr, rr) > 0)
      88                 :          0 :                         return i;
      89                 :            : 
      90                 :          0 :         return NULL;
      91                 :            : }
      92                 :            : 
      93                 :          0 : void dns_zone_remove_rr(DnsZone *z, DnsResourceRecord *rr) {
      94                 :            :         DnsZoneItem *i;
      95                 :            : 
      96         [ #  # ]:          0 :         assert(z);
      97         [ #  # ]:          0 :         assert(rr);
      98                 :            : 
      99                 :          0 :         i = dns_zone_get(z, rr);
     100         [ #  # ]:          0 :         if (i)
     101                 :          0 :                 dns_zone_item_remove_and_free(z, i);
     102                 :          0 : }
     103                 :            : 
     104                 :          0 : int dns_zone_remove_rrs_by_key(DnsZone *z, DnsResourceKey *key) {
     105                 :          0 :         _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL;
     106                 :            :         DnsResourceRecord *rr;
     107                 :            :         bool tentative;
     108                 :            :         int r;
     109                 :            : 
     110                 :          0 :         r = dns_zone_lookup(z, key, 0, &answer, &soa, &tentative);
     111         [ #  # ]:          0 :         if (r < 0)
     112                 :          0 :                 return r;
     113                 :            : 
     114   [ #  #  #  #  :          0 :         DNS_ANSWER_FOREACH(rr, answer)
          #  #  #  #  #  
                      # ]
     115                 :          0 :                 dns_zone_remove_rr(z, rr);
     116                 :            : 
     117                 :          0 :         return 0;
     118                 :            : }
     119                 :            : 
     120                 :          0 : static int dns_zone_init(DnsZone *z) {
     121                 :            :         int r;
     122                 :            : 
     123         [ #  # ]:          0 :         assert(z);
     124                 :            : 
     125                 :          0 :         r = hashmap_ensure_allocated(&z->by_key, &dns_resource_key_hash_ops);
     126         [ #  # ]:          0 :         if (r < 0)
     127                 :          0 :                 return r;
     128                 :            : 
     129                 :          0 :         r = hashmap_ensure_allocated(&z->by_name, &dns_name_hash_ops);
     130         [ #  # ]:          0 :         if (r < 0)
     131                 :          0 :                 return r;
     132                 :            : 
     133                 :          0 :         return 0;
     134                 :            : }
     135                 :            : 
     136                 :          0 : static int dns_zone_link_item(DnsZone *z, DnsZoneItem *i) {
     137                 :            :         DnsZoneItem *first;
     138                 :            :         int r;
     139                 :            : 
     140                 :          0 :         first = hashmap_get(z->by_key, i->rr->key);
     141         [ #  # ]:          0 :         if (first) {
     142   [ #  #  #  # ]:          0 :                 LIST_PREPEND(by_key, first, i);
     143         [ #  # ]:          0 :                 assert_se(hashmap_replace(z->by_key, first->rr->key, first) >= 0);
     144                 :            :         } else {
     145                 :          0 :                 r = hashmap_put(z->by_key, i->rr->key, i);
     146         [ #  # ]:          0 :                 if (r < 0)
     147                 :          0 :                         return r;
     148                 :            :         }
     149                 :            : 
     150                 :          0 :         first = hashmap_get(z->by_name, dns_resource_key_name(i->rr->key));
     151         [ #  # ]:          0 :         if (first) {
     152   [ #  #  #  # ]:          0 :                 LIST_PREPEND(by_name, first, i);
     153         [ #  # ]:          0 :                 assert_se(hashmap_replace(z->by_name, dns_resource_key_name(first->rr->key), first) >= 0);
     154                 :            :         } else {
     155                 :          0 :                 r = hashmap_put(z->by_name, dns_resource_key_name(i->rr->key), i);
     156         [ #  # ]:          0 :                 if (r < 0)
     157                 :          0 :                         return r;
     158                 :            :         }
     159                 :            : 
     160                 :          0 :         return 0;
     161                 :            : }
     162                 :            : 
     163                 :          0 : static int dns_zone_item_probe_start(DnsZoneItem *i)  {
     164                 :            :         DnsTransaction *t;
     165                 :            :         int r;
     166                 :            : 
     167         [ #  # ]:          0 :         assert(i);
     168                 :            : 
     169         [ #  # ]:          0 :         if (i->probe_transaction)
     170                 :          0 :                 return 0;
     171                 :            : 
     172                 :          0 :         t = dns_scope_find_transaction(i->scope, &DNS_RESOURCE_KEY_CONST(i->rr->key->class, DNS_TYPE_ANY, dns_resource_key_name(i->rr->key)), false);
     173         [ #  # ]:          0 :         if (!t) {
     174         [ #  # ]:          0 :                 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
     175                 :            : 
     176                 :          0 :                 key = dns_resource_key_new(i->rr->key->class, DNS_TYPE_ANY, dns_resource_key_name(i->rr->key));
     177         [ #  # ]:          0 :                 if (!key)
     178                 :          0 :                         return -ENOMEM;
     179                 :            : 
     180                 :          0 :                 r = dns_transaction_new(&t, i->scope, key);
     181         [ #  # ]:          0 :                 if (r < 0)
     182                 :          0 :                         return r;
     183                 :            :         }
     184                 :            : 
     185                 :          0 :         r = set_ensure_allocated(&t->notify_zone_items, NULL);
     186         [ #  # ]:          0 :         if (r < 0)
     187                 :          0 :                 goto gc;
     188                 :            : 
     189                 :          0 :         r = set_ensure_allocated(&t->notify_zone_items_done, NULL);
     190         [ #  # ]:          0 :         if (r < 0)
     191                 :          0 :                 goto gc;
     192                 :            : 
     193                 :          0 :         r = set_put(t->notify_zone_items, i);
     194         [ #  # ]:          0 :         if (r < 0)
     195                 :          0 :                 goto gc;
     196                 :            : 
     197                 :          0 :         i->probe_transaction = t;
     198                 :          0 :         t->probing = true;
     199                 :            : 
     200         [ #  # ]:          0 :         if (t->state == DNS_TRANSACTION_NULL) {
     201                 :            : 
     202                 :          0 :                 i->block_ready++;
     203                 :          0 :                 r = dns_transaction_go(t);
     204                 :          0 :                 i->block_ready--;
     205                 :            : 
     206         [ #  # ]:          0 :                 if (r < 0) {
     207                 :          0 :                         dns_zone_item_probe_stop(i);
     208                 :          0 :                         return r;
     209                 :            :                 }
     210                 :            :         }
     211                 :            : 
     212                 :          0 :         dns_zone_item_notify(i);
     213                 :          0 :         return 0;
     214                 :            : 
     215                 :          0 : gc:
     216                 :          0 :         dns_transaction_gc(t);
     217                 :          0 :         return r;
     218                 :            : }
     219                 :            : 
     220                 :          0 : int dns_zone_put(DnsZone *z, DnsScope *s, DnsResourceRecord *rr, bool probe) {
     221                 :          0 :         _cleanup_(dns_zone_item_freep) DnsZoneItem *i = NULL;
     222                 :            :         DnsZoneItem *existing;
     223                 :            :         int r;
     224                 :            : 
     225         [ #  # ]:          0 :         assert(z);
     226         [ #  # ]:          0 :         assert(s);
     227         [ #  # ]:          0 :         assert(rr);
     228                 :            : 
     229         [ #  # ]:          0 :         if (dns_class_is_pseudo(rr->key->class))
     230                 :          0 :                 return -EINVAL;
     231         [ #  # ]:          0 :         if (dns_type_is_pseudo(rr->key->type))
     232                 :          0 :                 return -EINVAL;
     233                 :            : 
     234                 :          0 :         existing = dns_zone_get(z, rr);
     235         [ #  # ]:          0 :         if (existing)
     236                 :          0 :                 return 0;
     237                 :            : 
     238                 :          0 :         r = dns_zone_init(z);
     239         [ #  # ]:          0 :         if (r < 0)
     240                 :          0 :                 return r;
     241                 :            : 
     242                 :          0 :         i = new0(DnsZoneItem, 1);
     243         [ #  # ]:          0 :         if (!i)
     244                 :          0 :                 return -ENOMEM;
     245                 :            : 
     246                 :          0 :         i->scope = s;
     247                 :          0 :         i->rr = dns_resource_record_ref(rr);
     248                 :          0 :         i->probing_enabled = probe;
     249                 :            : 
     250                 :          0 :         r = dns_zone_link_item(z, i);
     251         [ #  # ]:          0 :         if (r < 0)
     252                 :          0 :                 return r;
     253                 :            : 
     254         [ #  # ]:          0 :         if (probe) {
     255                 :            :                 DnsZoneItem *first, *j;
     256                 :          0 :                 bool established = false;
     257                 :            : 
     258                 :            :                 /* Check if there's already an RR with the same name
     259                 :            :                  * established. If so, it has been probed already, and
     260                 :            :                  * we don't need to probe again. */
     261                 :            : 
     262   [ #  #  #  # ]:          0 :                 LIST_FIND_HEAD(by_name, i, first);
     263         [ #  # ]:          0 :                 LIST_FOREACH(by_name, j, first) {
     264         [ #  # ]:          0 :                         if (i == j)
     265                 :          0 :                                 continue;
     266                 :            : 
     267         [ #  # ]:          0 :                         if (j->state == DNS_ZONE_ITEM_ESTABLISHED)
     268                 :          0 :                                 established = true;
     269                 :            :                 }
     270                 :            : 
     271         [ #  # ]:          0 :                 if (established)
     272                 :          0 :                         i->state = DNS_ZONE_ITEM_ESTABLISHED;
     273                 :            :                 else {
     274                 :          0 :                         i->state = DNS_ZONE_ITEM_PROBING;
     275                 :            : 
     276                 :          0 :                         r = dns_zone_item_probe_start(i);
     277         [ #  # ]:          0 :                         if (r < 0) {
     278                 :          0 :                                 dns_zone_item_remove_and_free(z, i);
     279                 :          0 :                                 i = NULL;
     280                 :          0 :                                 return r;
     281                 :            :                         }
     282                 :            :                 }
     283                 :            :         } else
     284                 :          0 :                 i->state = DNS_ZONE_ITEM_ESTABLISHED;
     285                 :            : 
     286                 :          0 :         i = NULL;
     287                 :          0 :         return 0;
     288                 :            : }
     289                 :            : 
     290                 :          0 : static int dns_zone_add_authenticated_answer(DnsAnswer *a, DnsZoneItem *i, int ifindex) {
     291                 :            :         DnsAnswerFlags flags;
     292                 :            : 
     293                 :            :         /* From RFC 6762, Section 10.2
     294                 :            :          * "They (the rules about when to set the cache-flush bit) apply to
     295                 :            :          * startup announcements as described in Section 8.3, "Announcing",
     296                 :            :          * and to responses generated as a result of receiving query messages."
     297                 :            :          * So, set the cache-flush bit for mDNS answers except for DNS-SD
     298                 :            :          * service enumeration PTRs described in RFC 6763, Section 4.1. */
     299         [ #  # ]:          0 :         if (i->scope->protocol == DNS_PROTOCOL_MDNS &&
     300         [ #  # ]:          0 :             !dns_resource_key_is_dnssd_ptr(i->rr->key))
     301                 :          0 :                 flags = DNS_ANSWER_AUTHENTICATED|DNS_ANSWER_CACHE_FLUSH;
     302                 :            :         else
     303                 :          0 :                 flags = DNS_ANSWER_AUTHENTICATED;
     304                 :            : 
     305                 :          0 :         return dns_answer_add(a, i->rr, ifindex, flags);
     306                 :            : }
     307                 :            : 
     308                 :          0 : int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, int ifindex, DnsAnswer **ret_answer, DnsAnswer **ret_soa, bool *ret_tentative) {
     309                 :          0 :         _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL;
     310                 :          0 :         unsigned n_answer = 0;
     311                 :            :         DnsZoneItem *j, *first;
     312                 :          0 :         bool tentative = true, need_soa = false;
     313                 :            :         int r;
     314                 :            : 
     315                 :            :         /* Note that we don't actually need the ifindex for anything. However when it is passed we'll initialize the
     316                 :            :          * ifindex field in the answer with it */
     317                 :            : 
     318         [ #  # ]:          0 :         assert(z);
     319         [ #  # ]:          0 :         assert(key);
     320         [ #  # ]:          0 :         assert(ret_answer);
     321                 :            : 
     322                 :            :         /* First iteration, count what we have */
     323                 :            : 
     324   [ #  #  #  # ]:          0 :         if (key->type == DNS_TYPE_ANY || key->class == DNS_CLASS_ANY) {
     325                 :          0 :                 bool found = false, added = false;
     326                 :            :                 int k;
     327                 :            : 
     328                 :            :                 /* If this is a generic match, then we have to
     329                 :            :                  * go through the list by the name and look
     330                 :            :                  * for everything manually */
     331                 :            : 
     332                 :          0 :                 first = hashmap_get(z->by_name, dns_resource_key_name(key));
     333         [ #  # ]:          0 :                 LIST_FOREACH(by_name, j, first) {
     334   [ #  #  #  # ]:          0 :                         if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
     335                 :          0 :                                 continue;
     336                 :            : 
     337                 :          0 :                         found = true;
     338                 :            : 
     339                 :          0 :                         k = dns_resource_key_match_rr(key, j->rr, NULL);
     340         [ #  # ]:          0 :                         if (k < 0)
     341                 :          0 :                                 return k;
     342         [ #  # ]:          0 :                         if (k > 0) {
     343                 :          0 :                                 n_answer++;
     344                 :          0 :                                 added = true;
     345                 :            :                         }
     346                 :            : 
     347                 :            :                 }
     348                 :            : 
     349   [ #  #  #  # ]:          0 :                 if (found && !added)
     350                 :          0 :                         need_soa = true;
     351                 :            : 
     352                 :            :         } else {
     353                 :          0 :                 bool found = false;
     354                 :            : 
     355                 :            :                 /* If this is a specific match, then look for
     356                 :            :                  * the right key immediately */
     357                 :            : 
     358                 :          0 :                 first = hashmap_get(z->by_key, key);
     359         [ #  # ]:          0 :                 LIST_FOREACH(by_key, j, first) {
     360   [ #  #  #  # ]:          0 :                         if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
     361                 :          0 :                                 continue;
     362                 :            : 
     363                 :          0 :                         found = true;
     364                 :          0 :                         n_answer++;
     365                 :            :                 }
     366                 :            : 
     367         [ #  # ]:          0 :                 if (!found) {
     368                 :          0 :                         first = hashmap_get(z->by_name, dns_resource_key_name(key));
     369         [ #  # ]:          0 :                         LIST_FOREACH(by_name, j, first) {
     370   [ #  #  #  # ]:          0 :                                 if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
     371                 :          0 :                                         continue;
     372                 :            : 
     373                 :          0 :                                 need_soa = true;
     374                 :          0 :                                 break;
     375                 :            :                         }
     376                 :            :                 }
     377                 :            :         }
     378                 :            : 
     379   [ #  #  #  # ]:          0 :         if (n_answer <= 0 && !need_soa)
     380                 :          0 :                 goto return_empty;
     381                 :            : 
     382         [ #  # ]:          0 :         if (n_answer > 0) {
     383                 :          0 :                 answer = dns_answer_new(n_answer);
     384         [ #  # ]:          0 :                 if (!answer)
     385                 :          0 :                         return -ENOMEM;
     386                 :            :         }
     387                 :            : 
     388         [ #  # ]:          0 :         if (need_soa) {
     389                 :          0 :                 soa = dns_answer_new(1);
     390         [ #  # ]:          0 :                 if (!soa)
     391                 :          0 :                         return -ENOMEM;
     392                 :            :         }
     393                 :            : 
     394                 :            :         /* Second iteration, actually add the RRs to the answers */
     395   [ #  #  #  # ]:          0 :         if (key->type == DNS_TYPE_ANY || key->class == DNS_CLASS_ANY) {
     396                 :          0 :                 bool found = false, added = false;
     397                 :            :                 int k;
     398                 :            : 
     399                 :          0 :                 first = hashmap_get(z->by_name, dns_resource_key_name(key));
     400         [ #  # ]:          0 :                 LIST_FOREACH(by_name, j, first) {
     401   [ #  #  #  # ]:          0 :                         if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
     402                 :          0 :                                 continue;
     403                 :            : 
     404                 :          0 :                         found = true;
     405                 :            : 
     406         [ #  # ]:          0 :                         if (j->state != DNS_ZONE_ITEM_PROBING)
     407                 :          0 :                                 tentative = false;
     408                 :            : 
     409                 :          0 :                         k = dns_resource_key_match_rr(key, j->rr, NULL);
     410         [ #  # ]:          0 :                         if (k < 0)
     411                 :          0 :                                 return k;
     412         [ #  # ]:          0 :                         if (k > 0) {
     413                 :          0 :                                 r = dns_zone_add_authenticated_answer(answer, j, ifindex);
     414         [ #  # ]:          0 :                                 if (r < 0)
     415                 :          0 :                                         return r;
     416                 :            : 
     417                 :          0 :                                 added = true;
     418                 :            :                         }
     419                 :            :                 }
     420                 :            : 
     421   [ #  #  #  # ]:          0 :                 if (found && !added) {
     422                 :          0 :                         r = dns_answer_add_soa(soa, dns_resource_key_name(key), LLMNR_DEFAULT_TTL, ifindex);
     423         [ #  # ]:          0 :                         if (r < 0)
     424                 :          0 :                                 return r;
     425                 :            :                 }
     426                 :            :         } else {
     427                 :          0 :                 bool found = false;
     428                 :            : 
     429                 :          0 :                 first = hashmap_get(z->by_key, key);
     430         [ #  # ]:          0 :                 LIST_FOREACH(by_key, j, first) {
     431   [ #  #  #  # ]:          0 :                         if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
     432                 :          0 :                                 continue;
     433                 :            : 
     434                 :          0 :                         found = true;
     435                 :            : 
     436         [ #  # ]:          0 :                         if (j->state != DNS_ZONE_ITEM_PROBING)
     437                 :          0 :                                 tentative = false;
     438                 :            : 
     439                 :          0 :                         r = dns_zone_add_authenticated_answer(answer, j, ifindex);
     440         [ #  # ]:          0 :                         if (r < 0)
     441                 :          0 :                                 return r;
     442                 :            :                 }
     443                 :            : 
     444         [ #  # ]:          0 :                 if (!found) {
     445                 :          0 :                         bool add_soa = false;
     446                 :            : 
     447                 :          0 :                         first = hashmap_get(z->by_name, dns_resource_key_name(key));
     448         [ #  # ]:          0 :                         LIST_FOREACH(by_name, j, first) {
     449   [ #  #  #  # ]:          0 :                                 if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
     450                 :          0 :                                         continue;
     451                 :            : 
     452         [ #  # ]:          0 :                                 if (j->state != DNS_ZONE_ITEM_PROBING)
     453                 :          0 :                                         tentative = false;
     454                 :            : 
     455                 :          0 :                                 add_soa = true;
     456                 :            :                         }
     457                 :            : 
     458         [ #  # ]:          0 :                         if (add_soa) {
     459                 :          0 :                                 r = dns_answer_add_soa(soa, dns_resource_key_name(key), LLMNR_DEFAULT_TTL, ifindex);
     460         [ #  # ]:          0 :                                 if (r < 0)
     461                 :          0 :                                         return r;
     462                 :            :                         }
     463                 :            :                 }
     464                 :            :         }
     465                 :            : 
     466                 :            :         /* If the caller sets ret_tentative to NULL, then use this as
     467                 :            :          * indication to not return tentative entries */
     468                 :            : 
     469   [ #  #  #  # ]:          0 :         if (!ret_tentative && tentative)
     470                 :          0 :                 goto return_empty;
     471                 :            : 
     472                 :          0 :         *ret_answer = TAKE_PTR(answer);
     473                 :            : 
     474         [ #  # ]:          0 :         if (ret_soa)
     475                 :          0 :                 *ret_soa = TAKE_PTR(soa);
     476                 :            : 
     477         [ #  # ]:          0 :         if (ret_tentative)
     478                 :          0 :                 *ret_tentative = tentative;
     479                 :            : 
     480                 :          0 :         return 1;
     481                 :            : 
     482                 :          0 : return_empty:
     483                 :          0 :         *ret_answer = NULL;
     484                 :            : 
     485         [ #  # ]:          0 :         if (ret_soa)
     486                 :          0 :                 *ret_soa = NULL;
     487                 :            : 
     488         [ #  # ]:          0 :         if (ret_tentative)
     489                 :          0 :                 *ret_tentative = false;
     490                 :            : 
     491                 :          0 :         return 0;
     492                 :            : }
     493                 :            : 
     494                 :          0 : void dns_zone_item_conflict(DnsZoneItem *i) {
     495         [ #  # ]:          0 :         assert(i);
     496                 :            : 
     497   [ #  #  #  # ]:          0 :         if (!IN_SET(i->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_VERIFYING, DNS_ZONE_ITEM_ESTABLISHED))
     498                 :          0 :                 return;
     499                 :            : 
     500         [ #  # ]:          0 :         log_info("Detected conflict on %s", strna(dns_resource_record_to_string(i->rr)));
     501                 :            : 
     502                 :          0 :         dns_zone_item_probe_stop(i);
     503                 :            : 
     504                 :            :         /* Withdraw the conflict item */
     505                 :          0 :         i->state = DNS_ZONE_ITEM_WITHDRAWN;
     506                 :            : 
     507                 :          0 :         dnssd_signal_conflict(i->scope->manager, dns_resource_key_name(i->rr->key));
     508                 :            : 
     509                 :            :         /* Maybe change the hostname */
     510         [ #  # ]:          0 :         if (manager_is_own_hostname(i->scope->manager, dns_resource_key_name(i->rr->key)) > 0)
     511                 :          0 :                 manager_next_hostname(i->scope->manager);
     512                 :            : }
     513                 :            : 
     514                 :          0 : void dns_zone_item_notify(DnsZoneItem *i) {
     515         [ #  # ]:          0 :         assert(i);
     516         [ #  # ]:          0 :         assert(i->probe_transaction);
     517                 :            : 
     518         [ #  # ]:          0 :         if (i->block_ready > 0)
     519                 :          0 :                 return;
     520                 :            : 
     521   [ #  #  #  # ]:          0 :         if (IN_SET(i->probe_transaction->state, DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING, DNS_TRANSACTION_VALIDATING))
     522                 :          0 :                 return;
     523                 :            : 
     524         [ #  # ]:          0 :         if (i->probe_transaction->state == DNS_TRANSACTION_SUCCESS) {
     525                 :          0 :                 bool we_lost = false;
     526                 :            : 
     527                 :            :                 /* The probe got a successful reply. If we so far
     528                 :            :                  * weren't established we just give up.
     529                 :            :                  *
     530                 :            :                  * In LLMNR case if we already
     531                 :            :                  * were established, and the peer has the
     532                 :            :                  * lexicographically larger IP address we continue
     533                 :            :                  * and defend it. */
     534                 :            : 
     535   [ #  #  #  # ]:          0 :                 if (!IN_SET(i->state, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING)) {
     536         [ #  # ]:          0 :                         log_debug("Got a successful probe for not yet established RR, we lost.");
     537                 :          0 :                         we_lost = true;
     538         [ #  # ]:          0 :                 } else if (i->probe_transaction->scope->protocol == DNS_PROTOCOL_LLMNR) {
     539         [ #  # ]:          0 :                         assert(i->probe_transaction->received);
     540                 :          0 :                         we_lost = memcmp(&i->probe_transaction->received->sender, &i->probe_transaction->received->destination, FAMILY_ADDRESS_SIZE(i->probe_transaction->received->family)) < 0;
     541         [ #  # ]:          0 :                         if (we_lost)
     542         [ #  # ]:          0 :                                 log_debug("Got a successful probe reply for an established RR, and we have a lexicographically larger IP address and thus lost.");
     543                 :            :                 }
     544                 :            : 
     545         [ #  # ]:          0 :                 if (we_lost) {
     546                 :          0 :                         dns_zone_item_conflict(i);
     547                 :          0 :                         return;
     548                 :            :                 }
     549                 :            : 
     550         [ #  # ]:          0 :                 log_debug("Got a successful probe reply, but peer has lexicographically lower IP address and thus lost.");
     551                 :            :         }
     552                 :            : 
     553         [ #  # ]:          0 :         log_debug("Record %s successfully probed.", strna(dns_resource_record_to_string(i->rr)));
     554                 :            : 
     555                 :          0 :         dns_zone_item_probe_stop(i);
     556                 :          0 :         i->state = DNS_ZONE_ITEM_ESTABLISHED;
     557                 :            : }
     558                 :            : 
     559                 :          0 : static int dns_zone_item_verify(DnsZoneItem *i) {
     560                 :            :         int r;
     561                 :            : 
     562         [ #  # ]:          0 :         assert(i);
     563                 :            : 
     564         [ #  # ]:          0 :         if (i->state != DNS_ZONE_ITEM_ESTABLISHED)
     565                 :          0 :                 return 0;
     566                 :            : 
     567         [ #  # ]:          0 :         log_debug("Verifying RR %s", strna(dns_resource_record_to_string(i->rr)));
     568                 :            : 
     569                 :          0 :         i->state = DNS_ZONE_ITEM_VERIFYING;
     570                 :          0 :         r = dns_zone_item_probe_start(i);
     571         [ #  # ]:          0 :         if (r < 0) {
     572         [ #  # ]:          0 :                 log_error_errno(r, "Failed to start probing for verifying RR: %m");
     573                 :          0 :                 i->state = DNS_ZONE_ITEM_ESTABLISHED;
     574                 :          0 :                 return r;
     575                 :            :         }
     576                 :            : 
     577                 :          0 :         return 0;
     578                 :            : }
     579                 :            : 
     580                 :          0 : int dns_zone_check_conflicts(DnsZone *zone, DnsResourceRecord *rr) {
     581                 :            :         DnsZoneItem *i, *first;
     582                 :          0 :         int c = 0;
     583                 :            : 
     584         [ #  # ]:          0 :         assert(zone);
     585         [ #  # ]:          0 :         assert(rr);
     586                 :            : 
     587                 :            :         /* This checks whether a response RR we received from somebody
     588                 :            :          * else is one that we actually thought was uniquely ours. If
     589                 :            :          * so, we'll verify our RRs. */
     590                 :            : 
     591                 :            :         /* No conflict if we don't have the name at all. */
     592                 :          0 :         first = hashmap_get(zone->by_name, dns_resource_key_name(rr->key));
     593         [ #  # ]:          0 :         if (!first)
     594                 :          0 :                 return 0;
     595                 :            : 
     596                 :            :         /* No conflict if we have the exact same RR */
     597         [ #  # ]:          0 :         if (dns_zone_get(zone, rr))
     598                 :          0 :                 return 0;
     599                 :            : 
     600                 :            :         /* No conflict if it is DNS-SD RR used for service enumeration. */
     601         [ #  # ]:          0 :         if (dns_resource_key_is_dnssd_ptr(rr->key))
     602                 :          0 :                 return 0;
     603                 :            : 
     604                 :            :         /* OK, somebody else has RRs for the same name. Yuck! Let's
     605                 :            :          * start probing again */
     606                 :            : 
     607         [ #  # ]:          0 :         LIST_FOREACH(by_name, i, first) {
     608         [ #  # ]:          0 :                 if (dns_resource_record_equal(i->rr, rr))
     609                 :          0 :                         continue;
     610                 :            : 
     611                 :          0 :                 dns_zone_item_verify(i);
     612                 :          0 :                 c++;
     613                 :            :         }
     614                 :            : 
     615                 :          0 :         return c;
     616                 :            : }
     617                 :            : 
     618                 :          0 : int dns_zone_verify_conflicts(DnsZone *zone, DnsResourceKey *key) {
     619                 :            :         DnsZoneItem *i, *first;
     620                 :          0 :         int c = 0;
     621                 :            : 
     622         [ #  # ]:          0 :         assert(zone);
     623                 :            : 
     624                 :            :         /* Somebody else notified us about a possible conflict. Let's
     625                 :            :          * verify if that's true. */
     626                 :            : 
     627                 :          0 :         first = hashmap_get(zone->by_name, dns_resource_key_name(key));
     628         [ #  # ]:          0 :         if (!first)
     629                 :          0 :                 return 0;
     630                 :            : 
     631         [ #  # ]:          0 :         LIST_FOREACH(by_name, i, first) {
     632                 :          0 :                 dns_zone_item_verify(i);
     633                 :          0 :                 c++;
     634                 :            :         }
     635                 :            : 
     636                 :          0 :         return c;
     637                 :            : }
     638                 :            : 
     639                 :          0 : void dns_zone_verify_all(DnsZone *zone) {
     640                 :            :         DnsZoneItem *i;
     641                 :            :         Iterator iterator;
     642                 :            : 
     643         [ #  # ]:          0 :         assert(zone);
     644                 :            : 
     645         [ #  # ]:          0 :         HASHMAP_FOREACH(i, zone->by_key, iterator) {
     646                 :            :                 DnsZoneItem *j;
     647                 :            : 
     648         [ #  # ]:          0 :                 LIST_FOREACH(by_key, j, i)
     649                 :          0 :                         dns_zone_item_verify(j);
     650                 :            :         }
     651                 :          0 : }
     652                 :            : 
     653                 :          0 : void dns_zone_dump(DnsZone *zone, FILE *f) {
     654                 :            :         Iterator iterator;
     655                 :            :         DnsZoneItem *i;
     656                 :            : 
     657         [ #  # ]:          0 :         if (!zone)
     658                 :          0 :                 return;
     659                 :            : 
     660         [ #  # ]:          0 :         if (!f)
     661                 :          0 :                 f = stdout;
     662                 :            : 
     663         [ #  # ]:          0 :         HASHMAP_FOREACH(i, zone->by_key, iterator) {
     664                 :            :                 DnsZoneItem *j;
     665                 :            : 
     666         [ #  # ]:          0 :                 LIST_FOREACH(by_key, j, i) {
     667                 :            :                         const char *t;
     668                 :            : 
     669                 :          0 :                         t = dns_resource_record_to_string(j->rr);
     670         [ #  # ]:          0 :                         if (!t) {
     671                 :          0 :                                 log_oom();
     672                 :          0 :                                 continue;
     673                 :            :                         }
     674                 :            : 
     675                 :          0 :                         fputc('\t', f);
     676                 :          0 :                         fputs(t, f);
     677                 :          0 :                         fputc('\n', f);
     678                 :            :                 }
     679                 :            :         }
     680                 :            : }
     681                 :            : 
     682                 :          0 : bool dns_zone_is_empty(DnsZone *zone) {
     683         [ #  # ]:          0 :         if (!zone)
     684                 :          0 :                 return true;
     685                 :            : 
     686                 :          0 :         return hashmap_isempty(zone->by_key);
     687                 :            : }
     688                 :            : 
     689                 :          0 : bool dns_zone_contains_name(DnsZone *z, const char *name) {
     690                 :            :         DnsZoneItem *i, *first;
     691                 :            : 
     692                 :          0 :         first = hashmap_get(z->by_name, name);
     693         [ #  # ]:          0 :         if (!first)
     694                 :          0 :                 return false;
     695                 :            : 
     696         [ #  # ]:          0 :         LIST_FOREACH(by_name, i, first) {
     697   [ #  #  #  # ]:          0 :                 if (!IN_SET(i->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
     698                 :          0 :                         continue;
     699                 :            : 
     700                 :          0 :                 return true;
     701                 :            :         }
     702                 :            : 
     703                 :          0 :         return false;
     704                 :            : }

Generated by: LCOV version 1.14