LCOV - code coverage report
Current view: top level - resolve - resolved-dns-query.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 0 609 0.0 %
Date: 2019-08-23 13:36:53 Functions: 0 31 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 497 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 "dns-type.h"
       6                 :            : #include "hostname-util.h"
       7                 :            : #include "local-addresses.h"
       8                 :            : #include "resolved-dns-query.h"
       9                 :            : #include "resolved-dns-synthesize.h"
      10                 :            : #include "resolved-etc-hosts.h"
      11                 :            : #include "string-util.h"
      12                 :            : 
      13                 :            : #define CNAME_MAX 8
      14                 :            : #define QUERIES_MAX 2048
      15                 :            : #define AUXILIARY_QUERIES_MAX 64
      16                 :            : 
      17                 :          0 : static int dns_query_candidate_new(DnsQueryCandidate **ret, DnsQuery *q, DnsScope *s) {
      18                 :            :         DnsQueryCandidate *c;
      19                 :            : 
      20         [ #  # ]:          0 :         assert(ret);
      21         [ #  # ]:          0 :         assert(q);
      22         [ #  # ]:          0 :         assert(s);
      23                 :            : 
      24                 :          0 :         c = new0(DnsQueryCandidate, 1);
      25         [ #  # ]:          0 :         if (!c)
      26                 :          0 :                 return -ENOMEM;
      27                 :            : 
      28                 :          0 :         c->query = q;
      29                 :          0 :         c->scope = s;
      30                 :            : 
      31   [ #  #  #  # ]:          0 :         LIST_PREPEND(candidates_by_query, q->candidates, c);
      32   [ #  #  #  # ]:          0 :         LIST_PREPEND(candidates_by_scope, s->query_candidates, c);
      33                 :            : 
      34                 :          0 :         *ret = c;
      35                 :          0 :         return 0;
      36                 :            : }
      37                 :            : 
      38                 :          0 : static void dns_query_candidate_stop(DnsQueryCandidate *c) {
      39                 :            :         DnsTransaction *t;
      40                 :            : 
      41         [ #  # ]:          0 :         assert(c);
      42                 :            : 
      43         [ #  # ]:          0 :         while ((t = set_steal_first(c->transactions))) {
      44                 :          0 :                 set_remove(t->notify_query_candidates, c);
      45                 :          0 :                 set_remove(t->notify_query_candidates_done, c);
      46                 :          0 :                 dns_transaction_gc(t);
      47                 :            :         }
      48                 :          0 : }
      49                 :            : 
      50                 :          0 : DnsQueryCandidate* dns_query_candidate_free(DnsQueryCandidate *c) {
      51                 :            : 
      52         [ #  # ]:          0 :         if (!c)
      53                 :          0 :                 return NULL;
      54                 :            : 
      55                 :          0 :         dns_query_candidate_stop(c);
      56                 :            : 
      57                 :          0 :         set_free(c->transactions);
      58                 :          0 :         dns_search_domain_unref(c->search_domain);
      59                 :            : 
      60         [ #  # ]:          0 :         if (c->query)
      61   [ #  #  #  #  :          0 :                 LIST_REMOVE(candidates_by_query, c->query->candidates, c);
             #  #  #  # ]
      62                 :            : 
      63         [ #  # ]:          0 :         if (c->scope)
      64   [ #  #  #  #  :          0 :                 LIST_REMOVE(candidates_by_scope, c->scope->query_candidates, c);
             #  #  #  # ]
      65                 :            : 
      66                 :          0 :         return mfree(c);
      67                 :            : }
      68                 :            : 
      69                 :          0 : static int dns_query_candidate_next_search_domain(DnsQueryCandidate *c) {
      70                 :          0 :         DnsSearchDomain *next = NULL;
      71                 :            : 
      72         [ #  # ]:          0 :         assert(c);
      73                 :            : 
      74   [ #  #  #  # ]:          0 :         if (c->search_domain && c->search_domain->linked)
      75                 :          0 :                 next = c->search_domain->domains_next;
      76                 :            :         else
      77                 :          0 :                 next = dns_scope_get_search_domains(c->scope);
      78                 :            : 
      79                 :            :         for (;;) {
      80         [ #  # ]:          0 :                 if (!next) /* We hit the end of the list */
      81                 :          0 :                         return 0;
      82                 :            : 
      83         [ #  # ]:          0 :                 if (!next->route_only)
      84                 :          0 :                         break;
      85                 :            : 
      86                 :            :                 /* Skip over route-only domains */
      87                 :          0 :                 next = next->domains_next;
      88                 :            :         }
      89                 :            : 
      90                 :          0 :         dns_search_domain_unref(c->search_domain);
      91                 :          0 :         c->search_domain = dns_search_domain_ref(next);
      92                 :            : 
      93                 :          0 :         return 1;
      94                 :            : }
      95                 :            : 
      96                 :          0 : static int dns_query_candidate_add_transaction(DnsQueryCandidate *c, DnsResourceKey *key) {
      97                 :            :         DnsTransaction *t;
      98                 :            :         int r;
      99                 :            : 
     100         [ #  # ]:          0 :         assert(c);
     101         [ #  # ]:          0 :         assert(key);
     102                 :            : 
     103                 :          0 :         t = dns_scope_find_transaction(c->scope, key, true);
     104         [ #  # ]:          0 :         if (!t) {
     105                 :          0 :                 r = dns_transaction_new(&t, c->scope, key);
     106         [ #  # ]:          0 :                 if (r < 0)
     107                 :          0 :                         return r;
     108                 :            :         } else {
     109         [ #  # ]:          0 :                 if (set_contains(c->transactions, t))
     110                 :          0 :                         return 0;
     111                 :            :         }
     112                 :            : 
     113                 :          0 :         r = set_ensure_allocated(&c->transactions, NULL);
     114         [ #  # ]:          0 :         if (r < 0)
     115                 :          0 :                 goto gc;
     116                 :            : 
     117                 :          0 :         r = set_ensure_allocated(&t->notify_query_candidates, NULL);
     118         [ #  # ]:          0 :         if (r < 0)
     119                 :          0 :                 goto gc;
     120                 :            : 
     121                 :          0 :         r = set_ensure_allocated(&t->notify_query_candidates_done, NULL);
     122         [ #  # ]:          0 :         if (r < 0)
     123                 :          0 :                 goto gc;
     124                 :            : 
     125                 :          0 :         r = set_put(t->notify_query_candidates, c);
     126         [ #  # ]:          0 :         if (r < 0)
     127                 :          0 :                 goto gc;
     128                 :            : 
     129                 :          0 :         r = set_put(c->transactions, t);
     130         [ #  # ]:          0 :         if (r < 0) {
     131                 :          0 :                 (void) set_remove(t->notify_query_candidates, c);
     132                 :          0 :                 goto gc;
     133                 :            :         }
     134                 :            : 
     135                 :          0 :         t->clamp_ttl = c->query->clamp_ttl;
     136                 :          0 :         return 1;
     137                 :            : 
     138                 :          0 : gc:
     139                 :          0 :         dns_transaction_gc(t);
     140                 :          0 :         return r;
     141                 :            : }
     142                 :            : 
     143                 :          0 : static int dns_query_candidate_go(DnsQueryCandidate *c) {
     144                 :            :         DnsTransaction *t;
     145                 :            :         Iterator i;
     146                 :            :         int r;
     147                 :          0 :         unsigned n = 0;
     148                 :            : 
     149         [ #  # ]:          0 :         assert(c);
     150                 :            : 
     151                 :            :         /* Start the transactions that are not started yet */
     152         [ #  # ]:          0 :         SET_FOREACH(t, c->transactions, i) {
     153         [ #  # ]:          0 :                 if (t->state != DNS_TRANSACTION_NULL)
     154                 :          0 :                         continue;
     155                 :            : 
     156                 :          0 :                 r = dns_transaction_go(t);
     157         [ #  # ]:          0 :                 if (r < 0)
     158                 :          0 :                         return r;
     159                 :            : 
     160                 :          0 :                 n++;
     161                 :            :         }
     162                 :            : 
     163                 :            :         /* If there was nothing to start, then let's proceed immediately */
     164         [ #  # ]:          0 :         if (n == 0)
     165                 :          0 :                 dns_query_candidate_notify(c);
     166                 :            : 
     167                 :          0 :         return 0;
     168                 :            : }
     169                 :            : 
     170                 :          0 : static DnsTransactionState dns_query_candidate_state(DnsQueryCandidate *c) {
     171                 :          0 :         DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS;
     172                 :            :         DnsTransaction *t;
     173                 :            :         Iterator i;
     174                 :            : 
     175         [ #  # ]:          0 :         assert(c);
     176                 :            : 
     177         [ #  # ]:          0 :         if (c->error_code != 0)
     178                 :          0 :                 return DNS_TRANSACTION_ERRNO;
     179                 :            : 
     180         [ #  # ]:          0 :         SET_FOREACH(t, c->transactions, i) {
     181                 :            : 
     182      [ #  #  # ]:          0 :                 switch (t->state) {
     183                 :            : 
     184                 :          0 :                 case DNS_TRANSACTION_NULL:
     185                 :            :                         /* If there's a NULL transaction pending, then
     186                 :            :                          * this means not all transactions where
     187                 :            :                          * started yet, and we were called from within
     188                 :            :                          * the stackframe that is supposed to start
     189                 :            :                          * remaining transactions. In this case,
     190                 :            :                          * simply claim the candidate is pending. */
     191                 :            : 
     192                 :            :                 case DNS_TRANSACTION_PENDING:
     193                 :            :                 case DNS_TRANSACTION_VALIDATING:
     194                 :            :                         /* If there's one transaction currently in
     195                 :            :                          * VALIDATING state, then this means there's
     196                 :            :                          * also one in PENDING state, hence we can
     197                 :            :                          * return PENDING immediately. */
     198                 :          0 :                         return DNS_TRANSACTION_PENDING;
     199                 :            : 
     200                 :          0 :                 case DNS_TRANSACTION_SUCCESS:
     201                 :          0 :                         state = t->state;
     202                 :          0 :                         break;
     203                 :            : 
     204                 :          0 :                 default:
     205         [ #  # ]:          0 :                         if (state != DNS_TRANSACTION_SUCCESS)
     206                 :          0 :                                 state = t->state;
     207                 :            : 
     208                 :          0 :                         break;
     209                 :            :                 }
     210                 :            :         }
     211                 :            : 
     212                 :          0 :         return state;
     213                 :            : }
     214                 :            : 
     215                 :          0 : static bool dns_query_candidate_is_routable(DnsQueryCandidate *c, uint16_t type) {
     216                 :            :         int family;
     217                 :            : 
     218         [ #  # ]:          0 :         assert(c);
     219                 :            : 
     220                 :            :         /* Checks whether the specified RR type matches an address family that is routable on the link(s) the scope of
     221                 :            :          * this candidate belongs to. Specifically, whether there's a routable IPv4 address on it if we query an A RR,
     222                 :            :          * or a routable IPv6 address if we query an AAAA RR. */
     223                 :            : 
     224         [ #  # ]:          0 :         if (!c->query->suppress_unroutable_family)
     225                 :          0 :                 return true;
     226                 :            : 
     227         [ #  # ]:          0 :         if (c->scope->protocol != DNS_PROTOCOL_DNS)
     228                 :          0 :                 return true;
     229                 :            : 
     230                 :          0 :         family = dns_type_to_af(type);
     231         [ #  # ]:          0 :         if (family < 0)
     232                 :          0 :                 return true;
     233                 :            : 
     234         [ #  # ]:          0 :         if (c->scope->link)
     235                 :          0 :                 return link_relevant(c->scope->link, family, false);
     236                 :            :         else
     237                 :          0 :                 return manager_routable(c->scope->manager, family);
     238                 :            : }
     239                 :            : 
     240                 :          0 : static int dns_query_candidate_setup_transactions(DnsQueryCandidate *c) {
     241                 :            :         DnsQuestion *question;
     242                 :            :         DnsResourceKey *key;
     243                 :          0 :         int n = 0, r;
     244                 :            : 
     245         [ #  # ]:          0 :         assert(c);
     246                 :            : 
     247                 :          0 :         dns_query_candidate_stop(c);
     248                 :            : 
     249                 :          0 :         question = dns_query_question_for_protocol(c->query, c->scope->protocol);
     250                 :            : 
     251                 :            :         /* Create one transaction per question key */
     252   [ #  #  #  #  :          0 :         DNS_QUESTION_FOREACH(key, question) {
          #  #  #  #  #  
                      # ]
     253      [ #  #  # ]:          0 :                 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *new_key = NULL;
     254                 :            :                 DnsResourceKey *qkey;
     255                 :            : 
     256         [ #  # ]:          0 :                 if (!dns_query_candidate_is_routable(c, key->type))
     257                 :          0 :                         continue;
     258                 :            : 
     259         [ #  # ]:          0 :                 if (c->search_domain) {
     260                 :          0 :                         r = dns_resource_key_new_append_suffix(&new_key, key, c->search_domain->name);
     261         [ #  # ]:          0 :                         if (r < 0)
     262                 :          0 :                                 goto fail;
     263                 :            : 
     264                 :          0 :                         qkey = new_key;
     265                 :            :                 } else
     266                 :          0 :                         qkey = key;
     267                 :            : 
     268         [ #  # ]:          0 :                 if (!dns_scope_good_key(c->scope, qkey))
     269                 :          0 :                         continue;
     270                 :            : 
     271                 :          0 :                 r = dns_query_candidate_add_transaction(c, qkey);
     272         [ #  # ]:          0 :                 if (r < 0)
     273                 :          0 :                         goto fail;
     274                 :            : 
     275                 :          0 :                 n++;
     276                 :            :         }
     277                 :            : 
     278                 :          0 :         return n;
     279                 :            : 
     280                 :          0 : fail:
     281                 :          0 :         dns_query_candidate_stop(c);
     282                 :          0 :         return r;
     283                 :            : }
     284                 :            : 
     285                 :          0 : void dns_query_candidate_notify(DnsQueryCandidate *c) {
     286                 :            :         DnsTransactionState state;
     287                 :            :         int r;
     288                 :            : 
     289         [ #  # ]:          0 :         assert(c);
     290                 :            : 
     291                 :          0 :         state = dns_query_candidate_state(c);
     292                 :            : 
     293   [ #  #  #  # ]:          0 :         if (DNS_TRANSACTION_IS_LIVE(state))
     294                 :          0 :                 return;
     295                 :            : 
     296   [ #  #  #  # ]:          0 :         if (state != DNS_TRANSACTION_SUCCESS && c->search_domain) {
     297                 :            : 
     298                 :          0 :                 r = dns_query_candidate_next_search_domain(c);
     299         [ #  # ]:          0 :                 if (r < 0)
     300                 :          0 :                         goto fail;
     301                 :            : 
     302         [ #  # ]:          0 :                 if (r > 0) {
     303                 :            :                         /* OK, there's another search domain to try, let's do so. */
     304                 :            : 
     305                 :          0 :                         r = dns_query_candidate_setup_transactions(c);
     306         [ #  # ]:          0 :                         if (r < 0)
     307                 :          0 :                                 goto fail;
     308                 :            : 
     309         [ #  # ]:          0 :                         if (r > 0) {
     310                 :            :                                 /* New transactions where queued. Start them and wait */
     311                 :            : 
     312                 :          0 :                                 r = dns_query_candidate_go(c);
     313         [ #  # ]:          0 :                                 if (r < 0)
     314                 :          0 :                                         goto fail;
     315                 :            : 
     316                 :          0 :                                 return;
     317                 :            :                         }
     318                 :            :                 }
     319                 :            : 
     320                 :            :         }
     321                 :            : 
     322                 :          0 :         dns_query_ready(c->query);
     323                 :          0 :         return;
     324                 :            : 
     325                 :          0 : fail:
     326         [ #  # ]:          0 :         log_warning_errno(r, "Failed to follow search domains: %m");
     327                 :          0 :         c->error_code = r;
     328                 :          0 :         dns_query_ready(c->query);
     329                 :            : }
     330                 :            : 
     331                 :          0 : static void dns_query_stop(DnsQuery *q) {
     332                 :            :         DnsQueryCandidate *c;
     333                 :            : 
     334         [ #  # ]:          0 :         assert(q);
     335                 :            : 
     336                 :          0 :         q->timeout_event_source = sd_event_source_unref(q->timeout_event_source);
     337                 :            : 
     338         [ #  # ]:          0 :         LIST_FOREACH(candidates_by_query, c, q->candidates)
     339                 :          0 :                 dns_query_candidate_stop(c);
     340                 :          0 : }
     341                 :            : 
     342                 :          0 : static void dns_query_free_candidates(DnsQuery *q) {
     343         [ #  # ]:          0 :         assert(q);
     344                 :            : 
     345         [ #  # ]:          0 :         while (q->candidates)
     346                 :          0 :                 dns_query_candidate_free(q->candidates);
     347                 :          0 : }
     348                 :            : 
     349                 :          0 : static void dns_query_reset_answer(DnsQuery *q) {
     350         [ #  # ]:          0 :         assert(q);
     351                 :            : 
     352                 :          0 :         q->answer = dns_answer_unref(q->answer);
     353                 :          0 :         q->answer_rcode = 0;
     354                 :          0 :         q->answer_dnssec_result = _DNSSEC_RESULT_INVALID;
     355                 :          0 :         q->answer_errno = 0;
     356                 :          0 :         q->answer_authenticated = false;
     357                 :          0 :         q->answer_protocol = _DNS_PROTOCOL_INVALID;
     358                 :          0 :         q->answer_family = AF_UNSPEC;
     359                 :          0 :         q->answer_search_domain = dns_search_domain_unref(q->answer_search_domain);
     360                 :          0 : }
     361                 :            : 
     362                 :          0 : DnsQuery *dns_query_free(DnsQuery *q) {
     363         [ #  # ]:          0 :         if (!q)
     364                 :          0 :                 return NULL;
     365                 :            : 
     366         [ #  # ]:          0 :         while (q->auxiliary_queries)
     367                 :          0 :                 dns_query_free(q->auxiliary_queries);
     368                 :            : 
     369         [ #  # ]:          0 :         if (q->auxiliary_for) {
     370         [ #  # ]:          0 :                 assert(q->auxiliary_for->n_auxiliary_queries > 0);
     371                 :          0 :                 q->auxiliary_for->n_auxiliary_queries--;
     372   [ #  #  #  #  :          0 :                 LIST_REMOVE(auxiliary_queries, q->auxiliary_for->auxiliary_queries, q);
             #  #  #  # ]
     373                 :            :         }
     374                 :            : 
     375                 :          0 :         dns_query_free_candidates(q);
     376                 :            : 
     377                 :          0 :         dns_question_unref(q->question_idna);
     378                 :          0 :         dns_question_unref(q->question_utf8);
     379                 :            : 
     380                 :          0 :         dns_query_reset_answer(q);
     381                 :            : 
     382                 :          0 :         sd_bus_message_unref(q->request);
     383                 :          0 :         sd_bus_track_unref(q->bus_track);
     384                 :            : 
     385                 :          0 :         dns_packet_unref(q->request_dns_packet);
     386                 :          0 :         dns_packet_unref(q->reply_dns_packet);
     387                 :            : 
     388         [ #  # ]:          0 :         if (q->request_dns_stream) {
     389                 :            :                 /* Detach the stream from our query, in case something else keeps a reference to it. */
     390                 :          0 :                 (void) set_remove(q->request_dns_stream->queries, q);
     391                 :          0 :                 q->request_dns_stream = dns_stream_unref(q->request_dns_stream);
     392                 :            :         }
     393                 :            : 
     394                 :          0 :         free(q->request_address_string);
     395                 :            : 
     396         [ #  # ]:          0 :         if (q->manager) {
     397   [ #  #  #  #  :          0 :                 LIST_REMOVE(queries, q->manager->dns_queries, q);
             #  #  #  # ]
     398                 :          0 :                 q->manager->n_dns_queries--;
     399                 :            :         }
     400                 :            : 
     401                 :          0 :         return mfree(q);
     402                 :            : }
     403                 :            : 
     404                 :          0 : int dns_query_new(
     405                 :            :                 Manager *m,
     406                 :            :                 DnsQuery **ret,
     407                 :            :                 DnsQuestion *question_utf8,
     408                 :            :                 DnsQuestion *question_idna,
     409                 :            :                 int ifindex,
     410                 :            :                 uint64_t flags) {
     411                 :            : 
     412                 :          0 :         _cleanup_(dns_query_freep) DnsQuery *q = NULL;
     413                 :            :         DnsResourceKey *key;
     414                 :          0 :         bool good = false;
     415                 :            :         int r;
     416                 :            :         char key_str[DNS_RESOURCE_KEY_STRING_MAX];
     417                 :            : 
     418         [ #  # ]:          0 :         assert(m);
     419                 :            : 
     420         [ #  # ]:          0 :         if (dns_question_size(question_utf8) > 0) {
     421                 :          0 :                 r = dns_question_is_valid_for_query(question_utf8);
     422         [ #  # ]:          0 :                 if (r < 0)
     423                 :          0 :                         return r;
     424         [ #  # ]:          0 :                 if (r == 0)
     425                 :          0 :                         return -EINVAL;
     426                 :            : 
     427                 :          0 :                 good = true;
     428                 :            :         }
     429                 :            : 
     430                 :            :         /* If the IDNA and UTF8 questions are the same, merge their references */
     431                 :          0 :         r = dns_question_is_equal(question_idna, question_utf8);
     432         [ #  # ]:          0 :         if (r < 0)
     433                 :          0 :                 return r;
     434         [ #  # ]:          0 :         if (r > 0)
     435                 :          0 :                 question_idna = question_utf8;
     436                 :            :         else {
     437         [ #  # ]:          0 :                 if (dns_question_size(question_idna) > 0) {
     438                 :          0 :                         r = dns_question_is_valid_for_query(question_idna);
     439         [ #  # ]:          0 :                         if (r < 0)
     440                 :          0 :                                 return r;
     441         [ #  # ]:          0 :                         if (r == 0)
     442                 :          0 :                                 return -EINVAL;
     443                 :            : 
     444                 :          0 :                         good = true;
     445                 :            :                 }
     446                 :            :         }
     447                 :            : 
     448         [ #  # ]:          0 :         if (!good) /* don't allow empty queries */
     449                 :          0 :                 return -EINVAL;
     450                 :            : 
     451         [ #  # ]:          0 :         if (m->n_dns_queries >= QUERIES_MAX)
     452                 :          0 :                 return -EBUSY;
     453                 :            : 
     454                 :          0 :         q = new0(DnsQuery, 1);
     455         [ #  # ]:          0 :         if (!q)
     456                 :          0 :                 return -ENOMEM;
     457                 :            : 
     458                 :          0 :         q->question_utf8 = dns_question_ref(question_utf8);
     459                 :          0 :         q->question_idna = dns_question_ref(question_idna);
     460                 :          0 :         q->ifindex = ifindex;
     461                 :          0 :         q->flags = flags;
     462                 :          0 :         q->answer_dnssec_result = _DNSSEC_RESULT_INVALID;
     463                 :          0 :         q->answer_protocol = _DNS_PROTOCOL_INVALID;
     464                 :          0 :         q->answer_family = AF_UNSPEC;
     465                 :            : 
     466                 :            :         /* First dump UTF8  question */
     467   [ #  #  #  #  :          0 :         DNS_QUESTION_FOREACH(key, question_utf8)
             #  #  #  # ]
     468   [ #  #  #  # ]:          0 :                 log_debug("Looking up RR for %s.",
     469                 :            :                           dns_resource_key_to_string(key, key_str, sizeof key_str));
     470                 :            : 
     471                 :            :         /* And then dump the IDNA question, but only what hasn't been dumped already through the UTF8 question. */
     472   [ #  #  #  #  :          0 :         DNS_QUESTION_FOREACH(key, question_idna) {
          #  #  #  #  #  
                      # ]
     473                 :          0 :                 r = dns_question_contains(question_utf8, key);
     474         [ #  # ]:          0 :                 if (r < 0)
     475                 :          0 :                         return r;
     476         [ #  # ]:          0 :                 if (r > 0)
     477                 :          0 :                         continue;
     478                 :            : 
     479         [ #  # ]:          0 :                 log_debug("Looking up IDNA RR for %s.",
     480                 :            :                           dns_resource_key_to_string(key, key_str, sizeof key_str));
     481                 :            :         }
     482                 :            : 
     483   [ #  #  #  # ]:          0 :         LIST_PREPEND(queries, m->dns_queries, q);
     484                 :          0 :         m->n_dns_queries++;
     485                 :          0 :         q->manager = m;
     486                 :            : 
     487         [ #  # ]:          0 :         if (ret)
     488                 :          0 :                 *ret = q;
     489                 :          0 :         q = NULL;
     490                 :            : 
     491                 :          0 :         return 0;
     492                 :            : }
     493                 :            : 
     494                 :          0 : int dns_query_make_auxiliary(DnsQuery *q, DnsQuery *auxiliary_for) {
     495         [ #  # ]:          0 :         assert(q);
     496         [ #  # ]:          0 :         assert(auxiliary_for);
     497                 :            : 
     498                 :            :         /* Ensure that the query is not auxiliary yet, and
     499                 :            :          * nothing else is auxiliary to it either */
     500         [ #  # ]:          0 :         assert(!q->auxiliary_for);
     501         [ #  # ]:          0 :         assert(!q->auxiliary_queries);
     502                 :            : 
     503                 :            :         /* Ensure that the unit we shall be made auxiliary for isn't
     504                 :            :          * auxiliary itself */
     505         [ #  # ]:          0 :         assert(!auxiliary_for->auxiliary_for);
     506                 :            : 
     507         [ #  # ]:          0 :         if (auxiliary_for->n_auxiliary_queries >= AUXILIARY_QUERIES_MAX)
     508                 :          0 :                 return -EAGAIN;
     509                 :            : 
     510   [ #  #  #  # ]:          0 :         LIST_PREPEND(auxiliary_queries, auxiliary_for->auxiliary_queries, q);
     511                 :          0 :         q->auxiliary_for = auxiliary_for;
     512                 :            : 
     513                 :          0 :         auxiliary_for->n_auxiliary_queries++;
     514                 :          0 :         return 0;
     515                 :            : }
     516                 :            : 
     517                 :          0 : static void dns_query_complete(DnsQuery *q, DnsTransactionState state) {
     518         [ #  # ]:          0 :         assert(q);
     519   [ #  #  #  # ]:          0 :         assert(!DNS_TRANSACTION_IS_LIVE(state));
     520   [ #  #  #  # ]:          0 :         assert(DNS_TRANSACTION_IS_LIVE(q->state));
     521                 :            : 
     522                 :            :         /* Note that this call might invalidate the query. Callers
     523                 :            :          * should hence not attempt to access the query or transaction
     524                 :            :          * after calling this function. */
     525                 :            : 
     526                 :          0 :         q->state = state;
     527                 :            : 
     528                 :          0 :         dns_query_stop(q);
     529         [ #  # ]:          0 :         if (q->complete)
     530                 :          0 :                 q->complete(q);
     531                 :          0 : }
     532                 :            : 
     533                 :          0 : static int on_query_timeout(sd_event_source *s, usec_t usec, void *userdata) {
     534                 :          0 :         DnsQuery *q = userdata;
     535                 :            : 
     536         [ #  # ]:          0 :         assert(s);
     537         [ #  # ]:          0 :         assert(q);
     538                 :            : 
     539                 :          0 :         dns_query_complete(q, DNS_TRANSACTION_TIMEOUT);
     540                 :          0 :         return 0;
     541                 :            : }
     542                 :            : 
     543                 :          0 : static int dns_query_add_candidate(DnsQuery *q, DnsScope *s) {
     544                 :            :         DnsQueryCandidate *c;
     545                 :            :         int r;
     546                 :            : 
     547         [ #  # ]:          0 :         assert(q);
     548         [ #  # ]:          0 :         assert(s);
     549                 :            : 
     550                 :          0 :         r = dns_query_candidate_new(&c, q, s);
     551         [ #  # ]:          0 :         if (r < 0)
     552                 :          0 :                 return r;
     553                 :            : 
     554                 :            :         /* If this a single-label domain on DNS, we might append a suitable search domain first. */
     555   [ #  #  #  # ]:          0 :         if ((q->flags & SD_RESOLVED_NO_SEARCH) == 0 &&
     556                 :          0 :             dns_scope_name_needs_search_domain(s, dns_question_first_name(q->question_idna))) {
     557                 :            :                 /* OK, we need a search domain now. Let's find one for this scope */
     558                 :            : 
     559                 :          0 :                 r = dns_query_candidate_next_search_domain(c);
     560         [ #  # ]:          0 :                 if (r <= 0) /* if there's no search domain, then we won't add any transaction. */
     561                 :          0 :                         goto fail;
     562                 :            :         }
     563                 :            : 
     564                 :          0 :         r = dns_query_candidate_setup_transactions(c);
     565         [ #  # ]:          0 :         if (r < 0)
     566                 :          0 :                 goto fail;
     567                 :            : 
     568                 :          0 :         return 0;
     569                 :            : 
     570                 :          0 : fail:
     571                 :          0 :         dns_query_candidate_free(c);
     572                 :          0 :         return r;
     573                 :            : }
     574                 :            : 
     575                 :          0 : static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) {
     576                 :          0 :         _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
     577                 :            :         int r;
     578                 :            : 
     579         [ #  # ]:          0 :         assert(q);
     580         [ #  # ]:          0 :         assert(state);
     581                 :            : 
     582                 :            :         /* Tries to synthesize localhost RR replies (and others) where appropriate. Note that this is done *after* the
     583                 :            :          * the normal lookup finished. The data from the network hence takes precedence over the data we
     584                 :            :          * synthesize. (But note that many scopes refuse to resolve certain domain names) */
     585                 :            : 
     586   [ #  #  #  # ]:          0 :         if (!IN_SET(*state,
     587                 :            :                     DNS_TRANSACTION_RCODE_FAILURE,
     588                 :            :                     DNS_TRANSACTION_NO_SERVERS,
     589                 :            :                     DNS_TRANSACTION_TIMEOUT,
     590                 :            :                     DNS_TRANSACTION_ATTEMPTS_MAX_REACHED,
     591                 :            :                     DNS_TRANSACTION_NETWORK_DOWN,
     592                 :            :                     DNS_TRANSACTION_NOT_FOUND))
     593                 :          0 :                 return 0;
     594                 :            : 
     595                 :          0 :         r = dns_synthesize_answer(
     596                 :            :                         q->manager,
     597                 :            :                         q->question_utf8,
     598                 :            :                         q->ifindex,
     599                 :            :                         &answer);
     600         [ #  # ]:          0 :         if (r == -ENXIO) {
     601                 :            :                 /* If we get ENXIO this tells us to generate NXDOMAIN unconditionally. */
     602                 :            : 
     603                 :          0 :                 dns_query_reset_answer(q);
     604                 :          0 :                 q->answer_rcode = DNS_RCODE_NXDOMAIN;
     605                 :          0 :                 q->answer_protocol = dns_synthesize_protocol(q->flags);
     606                 :          0 :                 q->answer_family = dns_synthesize_family(q->flags);
     607                 :          0 :                 q->answer_authenticated = true;
     608                 :          0 :                 *state = DNS_TRANSACTION_RCODE_FAILURE;
     609                 :            : 
     610                 :          0 :                 return 0;
     611                 :            :         }
     612         [ #  # ]:          0 :         if (r <= 0)
     613                 :          0 :                 return r;
     614                 :            : 
     615                 :          0 :         dns_query_reset_answer(q);
     616                 :            : 
     617                 :          0 :         q->answer = TAKE_PTR(answer);
     618                 :          0 :         q->answer_rcode = DNS_RCODE_SUCCESS;
     619                 :          0 :         q->answer_protocol = dns_synthesize_protocol(q->flags);
     620                 :          0 :         q->answer_family = dns_synthesize_family(q->flags);
     621                 :          0 :         q->answer_authenticated = true;
     622                 :            : 
     623                 :          0 :         *state = DNS_TRANSACTION_SUCCESS;
     624                 :            : 
     625                 :          0 :         return 1;
     626                 :            : }
     627                 :            : 
     628                 :          0 : static int dns_query_try_etc_hosts(DnsQuery *q) {
     629                 :          0 :         _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
     630                 :            :         int r;
     631                 :            : 
     632         [ #  # ]:          0 :         assert(q);
     633                 :            : 
     634                 :            :         /* Looks in /etc/hosts for matching entries. Note that this is done *before* the normal lookup is done. The
     635                 :            :          * data from /etc/hosts hence takes precedence over the network. */
     636                 :            : 
     637                 :          0 :         r = manager_etc_hosts_lookup(
     638                 :            :                         q->manager,
     639                 :            :                         q->question_utf8,
     640                 :            :                         &answer);
     641         [ #  # ]:          0 :         if (r <= 0)
     642                 :          0 :                 return r;
     643                 :            : 
     644                 :          0 :         dns_query_reset_answer(q);
     645                 :            : 
     646                 :          0 :         q->answer = TAKE_PTR(answer);
     647                 :          0 :         q->answer_rcode = DNS_RCODE_SUCCESS;
     648                 :          0 :         q->answer_protocol = dns_synthesize_protocol(q->flags);
     649                 :          0 :         q->answer_family = dns_synthesize_family(q->flags);
     650                 :          0 :         q->answer_authenticated = true;
     651                 :            : 
     652                 :          0 :         return 1;
     653                 :            : }
     654                 :            : 
     655                 :          0 : int dns_query_go(DnsQuery *q) {
     656                 :          0 :         DnsScopeMatch found = DNS_SCOPE_NO;
     657                 :          0 :         DnsScope *s, *first = NULL;
     658                 :            :         DnsQueryCandidate *c;
     659                 :            :         int r;
     660                 :            : 
     661         [ #  # ]:          0 :         assert(q);
     662                 :            : 
     663         [ #  # ]:          0 :         if (q->state != DNS_TRANSACTION_NULL)
     664                 :          0 :                 return 0;
     665                 :            : 
     666                 :          0 :         r = dns_query_try_etc_hosts(q);
     667         [ #  # ]:          0 :         if (r < 0)
     668                 :          0 :                 return r;
     669         [ #  # ]:          0 :         if (r > 0) {
     670                 :          0 :                 dns_query_complete(q, DNS_TRANSACTION_SUCCESS);
     671                 :          0 :                 return 1;
     672                 :            :         }
     673                 :            : 
     674         [ #  # ]:          0 :         LIST_FOREACH(scopes, s, q->manager->dns_scopes) {
     675                 :            :                 DnsScopeMatch match;
     676                 :            :                 const char *name;
     677                 :            : 
     678                 :          0 :                 name = dns_question_first_name(dns_query_question_for_protocol(q, s->protocol));
     679         [ #  # ]:          0 :                 if (!name)
     680                 :          0 :                         continue;
     681                 :            : 
     682                 :          0 :                 match = dns_scope_good_domain(s, q->ifindex, q->flags, name);
     683         [ #  # ]:          0 :                 if (match < 0) {
     684         [ #  # ]:          0 :                         log_debug("Couldn't check if '%s' matches against scope, ignoring.", name);
     685                 :          0 :                         continue;
     686                 :            :                 }
     687                 :            : 
     688         [ #  # ]:          0 :                 if (match > found) { /* Does this match better? If so, remember how well it matched, and the first one
     689                 :            :                                       * that matches this well */
     690                 :          0 :                         found = match;
     691                 :          0 :                         first = s;
     692                 :            :                 }
     693                 :            :         }
     694                 :            : 
     695         [ #  # ]:          0 :         if (found == DNS_SCOPE_NO) {
     696                 :          0 :                 DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS;
     697                 :            : 
     698                 :          0 :                 r = dns_query_synthesize_reply(q, &state);
     699         [ #  # ]:          0 :                 if (r < 0)
     700                 :          0 :                         return r;
     701                 :            : 
     702                 :          0 :                 dns_query_complete(q, state);
     703                 :          0 :                 return 1;
     704                 :            :         }
     705                 :            : 
     706                 :          0 :         r = dns_query_add_candidate(q, first);
     707         [ #  # ]:          0 :         if (r < 0)
     708                 :          0 :                 goto fail;
     709                 :            : 
     710         [ #  # ]:          0 :         LIST_FOREACH(scopes, s, first->scopes_next) {
     711                 :            :                 DnsScopeMatch match;
     712                 :            :                 const char *name;
     713                 :            : 
     714                 :          0 :                 name = dns_question_first_name(dns_query_question_for_protocol(q, s->protocol));
     715         [ #  # ]:          0 :                 if (!name)
     716                 :          0 :                         continue;
     717                 :            : 
     718                 :          0 :                 match = dns_scope_good_domain(s, q->ifindex, q->flags, name);
     719         [ #  # ]:          0 :                 if (match < 0) {
     720         [ #  # ]:          0 :                         log_debug("Couldn't check if '%s' matches against scope, ignoring.", name);
     721                 :          0 :                         continue;
     722                 :            :                 }
     723                 :            : 
     724         [ #  # ]:          0 :                 if (match < found)
     725                 :          0 :                         continue;
     726                 :            : 
     727                 :          0 :                 r = dns_query_add_candidate(q, s);
     728         [ #  # ]:          0 :                 if (r < 0)
     729                 :          0 :                         goto fail;
     730                 :            :         }
     731                 :            : 
     732                 :          0 :         dns_query_reset_answer(q);
     733                 :            : 
     734                 :          0 :         r = sd_event_add_time(
     735                 :          0 :                         q->manager->event,
     736                 :            :                         &q->timeout_event_source,
     737                 :            :                         clock_boottime_or_monotonic(),
     738                 :          0 :                         now(clock_boottime_or_monotonic()) + SD_RESOLVED_QUERY_TIMEOUT_USEC,
     739                 :            :                         0, on_query_timeout, q);
     740         [ #  # ]:          0 :         if (r < 0)
     741                 :          0 :                 goto fail;
     742                 :            : 
     743                 :          0 :         (void) sd_event_source_set_description(q->timeout_event_source, "query-timeout");
     744                 :            : 
     745                 :          0 :         q->state = DNS_TRANSACTION_PENDING;
     746                 :          0 :         q->block_ready++;
     747                 :            : 
     748                 :            :         /* Start the transactions */
     749         [ #  # ]:          0 :         LIST_FOREACH(candidates_by_query, c, q->candidates) {
     750                 :          0 :                 r = dns_query_candidate_go(c);
     751         [ #  # ]:          0 :                 if (r < 0) {
     752                 :          0 :                         q->block_ready--;
     753                 :          0 :                         goto fail;
     754                 :            :                 }
     755                 :            :         }
     756                 :            : 
     757                 :          0 :         q->block_ready--;
     758                 :          0 :         dns_query_ready(q);
     759                 :            : 
     760                 :          0 :         return 1;
     761                 :            : 
     762                 :          0 : fail:
     763                 :          0 :         dns_query_stop(q);
     764                 :          0 :         return r;
     765                 :            : }
     766                 :            : 
     767                 :          0 : static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) {
     768                 :          0 :         DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS;
     769                 :          0 :         bool has_authenticated = false, has_non_authenticated = false;
     770                 :          0 :         DnssecResult dnssec_result_authenticated = _DNSSEC_RESULT_INVALID, dnssec_result_non_authenticated = _DNSSEC_RESULT_INVALID;
     771                 :            :         DnsTransaction *t;
     772                 :            :         Iterator i;
     773                 :            :         int r;
     774                 :            : 
     775         [ #  # ]:          0 :         assert(q);
     776                 :            : 
     777         [ #  # ]:          0 :         if (!c) {
     778                 :          0 :                 r = dns_query_synthesize_reply(q, &state);
     779         [ #  # ]:          0 :                 if (r < 0)
     780                 :          0 :                         goto fail;
     781                 :            : 
     782                 :          0 :                 dns_query_complete(q, state);
     783                 :          0 :                 return;
     784                 :            :         }
     785                 :            : 
     786         [ #  # ]:          0 :         if (c->error_code != 0) {
     787                 :            :                 /* If the candidate had an error condition of its own, start with that. */
     788                 :          0 :                 state = DNS_TRANSACTION_ERRNO;
     789                 :          0 :                 q->answer = dns_answer_unref(q->answer);
     790                 :          0 :                 q->answer_rcode = 0;
     791                 :          0 :                 q->answer_dnssec_result = _DNSSEC_RESULT_INVALID;
     792                 :          0 :                 q->answer_authenticated = false;
     793                 :          0 :                 q->answer_errno = c->error_code;
     794                 :            :         }
     795                 :            : 
     796         [ #  # ]:          0 :         SET_FOREACH(t, c->transactions, i) {
     797                 :            : 
     798      [ #  #  # ]:          0 :                 switch (t->state) {
     799                 :            : 
     800                 :          0 :                 case DNS_TRANSACTION_SUCCESS: {
     801                 :            :                         /* We found a successfully reply, merge it into the answer */
     802                 :          0 :                         r = dns_answer_extend(&q->answer, t->answer);
     803         [ #  # ]:          0 :                         if (r < 0)
     804                 :          0 :                                 goto fail;
     805                 :            : 
     806                 :          0 :                         q->answer_rcode = t->answer_rcode;
     807                 :          0 :                         q->answer_errno = 0;
     808                 :            : 
     809         [ #  # ]:          0 :                         if (t->answer_authenticated) {
     810                 :          0 :                                 has_authenticated = true;
     811                 :          0 :                                 dnssec_result_authenticated = t->answer_dnssec_result;
     812                 :            :                         } else {
     813                 :          0 :                                 has_non_authenticated = true;
     814                 :          0 :                                 dnssec_result_non_authenticated = t->answer_dnssec_result;
     815                 :            :                         }
     816                 :            : 
     817                 :          0 :                         state = DNS_TRANSACTION_SUCCESS;
     818                 :          0 :                         break;
     819                 :            :                 }
     820                 :            : 
     821                 :          0 :                 case DNS_TRANSACTION_NULL:
     822                 :            :                 case DNS_TRANSACTION_PENDING:
     823                 :            :                 case DNS_TRANSACTION_VALIDATING:
     824                 :            :                 case DNS_TRANSACTION_ABORTED:
     825                 :            :                         /* Ignore transactions that didn't complete */
     826                 :          0 :                         continue;
     827                 :            : 
     828                 :          0 :                 default:
     829                 :            :                         /* Any kind of failure? Store the data away, if there's nothing stored yet. */
     830         [ #  # ]:          0 :                         if (state == DNS_TRANSACTION_SUCCESS)
     831                 :          0 :                                 continue;
     832                 :            : 
     833                 :            :                         /* If there's already an authenticated negative reply stored, then prefer that over any unauthenticated one */
     834   [ #  #  #  # ]:          0 :                         if (q->answer_authenticated && !t->answer_authenticated)
     835                 :          0 :                                 continue;
     836                 :            : 
     837                 :          0 :                         q->answer = dns_answer_unref(q->answer);
     838                 :          0 :                         q->answer_rcode = t->answer_rcode;
     839                 :          0 :                         q->answer_dnssec_result = t->answer_dnssec_result;
     840                 :          0 :                         q->answer_authenticated = t->answer_authenticated;
     841                 :          0 :                         q->answer_errno = t->answer_errno;
     842                 :            : 
     843                 :          0 :                         state = t->state;
     844                 :          0 :                         break;
     845                 :            :                 }
     846                 :            :         }
     847                 :            : 
     848         [ #  # ]:          0 :         if (state == DNS_TRANSACTION_SUCCESS) {
     849   [ #  #  #  # ]:          0 :                 q->answer_authenticated = has_authenticated && !has_non_authenticated;
     850         [ #  # ]:          0 :                 q->answer_dnssec_result = q->answer_authenticated ? dnssec_result_authenticated : dnssec_result_non_authenticated;
     851                 :            :         }
     852                 :            : 
     853                 :          0 :         q->answer_protocol = c->scope->protocol;
     854                 :          0 :         q->answer_family = c->scope->family;
     855                 :            : 
     856                 :          0 :         dns_search_domain_unref(q->answer_search_domain);
     857                 :          0 :         q->answer_search_domain = dns_search_domain_ref(c->search_domain);
     858                 :            : 
     859                 :          0 :         r = dns_query_synthesize_reply(q, &state);
     860         [ #  # ]:          0 :         if (r < 0)
     861                 :          0 :                 goto fail;
     862                 :            : 
     863                 :          0 :         dns_query_complete(q, state);
     864                 :          0 :         return;
     865                 :            : 
     866                 :          0 : fail:
     867                 :          0 :         q->answer_errno = -r;
     868                 :          0 :         dns_query_complete(q, DNS_TRANSACTION_ERRNO);
     869                 :            : }
     870                 :            : 
     871                 :          0 : void dns_query_ready(DnsQuery *q) {
     872                 :            : 
     873                 :          0 :         DnsQueryCandidate *bad = NULL, *c;
     874                 :          0 :         bool pending = false;
     875                 :            : 
     876         [ #  # ]:          0 :         assert(q);
     877   [ #  #  #  # ]:          0 :         assert(DNS_TRANSACTION_IS_LIVE(q->state));
     878                 :            : 
     879                 :            :         /* Note that this call might invalidate the query. Callers
     880                 :            :          * should hence not attempt to access the query or transaction
     881                 :            :          * after calling this function, unless the block_ready
     882                 :            :          * counter was explicitly bumped before doing so. */
     883                 :            : 
     884         [ #  # ]:          0 :         if (q->block_ready > 0)
     885                 :          0 :                 return;
     886                 :            : 
     887         [ #  # ]:          0 :         LIST_FOREACH(candidates_by_query, c, q->candidates) {
     888                 :            :                 DnsTransactionState state;
     889                 :            : 
     890                 :          0 :                 state = dns_query_candidate_state(c);
     891      [ #  #  # ]:          0 :                 switch (state) {
     892                 :            : 
     893                 :          0 :                 case DNS_TRANSACTION_SUCCESS:
     894                 :            :                         /* One of the candidates is successful,
     895                 :            :                          * let's use it, and copy its data out */
     896                 :          0 :                         dns_query_accept(q, c);
     897                 :          0 :                         return;
     898                 :            : 
     899                 :          0 :                 case DNS_TRANSACTION_NULL:
     900                 :            :                 case DNS_TRANSACTION_PENDING:
     901                 :            :                 case DNS_TRANSACTION_VALIDATING:
     902                 :            :                         /* One of the candidates is still going on,
     903                 :            :                          * let's maybe wait for it */
     904                 :          0 :                         pending = true;
     905                 :          0 :                         break;
     906                 :            : 
     907                 :          0 :                 default:
     908                 :            :                         /* Any kind of failure */
     909                 :          0 :                         bad = c;
     910                 :          0 :                         break;
     911                 :            :                 }
     912                 :            :         }
     913                 :            : 
     914         [ #  # ]:          0 :         if (pending)
     915                 :          0 :                 return;
     916                 :            : 
     917                 :          0 :         dns_query_accept(q, bad);
     918                 :            : }
     919                 :            : 
     920                 :          0 : static int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname) {
     921                 :          0 :         _cleanup_(dns_question_unrefp) DnsQuestion *nq_idna = NULL, *nq_utf8 = NULL;
     922                 :            :         int r, k;
     923                 :            : 
     924         [ #  # ]:          0 :         assert(q);
     925                 :            : 
     926                 :          0 :         q->n_cname_redirects++;
     927         [ #  # ]:          0 :         if (q->n_cname_redirects > CNAME_MAX)
     928                 :          0 :                 return -ELOOP;
     929                 :            : 
     930                 :          0 :         r = dns_question_cname_redirect(q->question_idna, cname, &nq_idna);
     931         [ #  # ]:          0 :         if (r < 0)
     932                 :          0 :                 return r;
     933         [ #  # ]:          0 :         else if (r > 0)
     934         [ #  # ]:          0 :                 log_debug("Following CNAME/DNAME %s → %s.", dns_question_first_name(q->question_idna), dns_question_first_name(nq_idna));
     935                 :            : 
     936                 :          0 :         k = dns_question_is_equal(q->question_idna, q->question_utf8);
     937         [ #  # ]:          0 :         if (k < 0)
     938                 :          0 :                 return r;
     939         [ #  # ]:          0 :         if (k > 0) {
     940                 :            :                 /* Same question? Shortcut new question generation */
     941                 :          0 :                 nq_utf8 = dns_question_ref(nq_idna);
     942                 :          0 :                 k = r;
     943                 :            :         } else {
     944                 :          0 :                 k = dns_question_cname_redirect(q->question_utf8, cname, &nq_utf8);
     945         [ #  # ]:          0 :                 if (k < 0)
     946                 :          0 :                         return k;
     947         [ #  # ]:          0 :                 else if (k > 0)
     948         [ #  # ]:          0 :                         log_debug("Following UTF8 CNAME/DNAME %s → %s.", dns_question_first_name(q->question_utf8), dns_question_first_name(nq_utf8));
     949                 :            :         }
     950                 :            : 
     951   [ #  #  #  # ]:          0 :         if (r == 0 && k == 0) /* No actual cname happened? */
     952                 :          0 :                 return -ELOOP;
     953                 :            : 
     954         [ #  # ]:          0 :         if (q->answer_protocol == DNS_PROTOCOL_DNS) {
     955                 :            :                 /* Don't permit CNAME redirects from unicast DNS to LLMNR or MulticastDNS, so that global resources
     956                 :            :                  * cannot invade the local namespace. The opposite way we permit: local names may redirect to global
     957                 :            :                  * ones. */
     958                 :            : 
     959                 :          0 :                 q->flags &= ~(SD_RESOLVED_LLMNR|SD_RESOLVED_MDNS); /* mask away the local protocols */
     960                 :            :         }
     961                 :            : 
     962                 :            :         /* Turn off searching for the new name */
     963                 :          0 :         q->flags |= SD_RESOLVED_NO_SEARCH;
     964                 :            : 
     965                 :          0 :         dns_question_unref(q->question_idna);
     966                 :          0 :         q->question_idna = TAKE_PTR(nq_idna);
     967                 :            : 
     968                 :          0 :         dns_question_unref(q->question_utf8);
     969                 :          0 :         q->question_utf8 = TAKE_PTR(nq_utf8);
     970                 :            : 
     971                 :          0 :         dns_query_free_candidates(q);
     972                 :          0 :         dns_query_reset_answer(q);
     973                 :            : 
     974                 :          0 :         q->state = DNS_TRANSACTION_NULL;
     975                 :            : 
     976                 :          0 :         return 0;
     977                 :            : }
     978                 :            : 
     979                 :          0 : int dns_query_process_cname(DnsQuery *q) {
     980                 :          0 :         _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *cname = NULL;
     981                 :            :         DnsQuestion *question;
     982                 :            :         DnsResourceRecord *rr;
     983                 :            :         int r;
     984                 :            : 
     985         [ #  # ]:          0 :         assert(q);
     986                 :            : 
     987   [ #  #  #  # ]:          0 :         if (!IN_SET(q->state, DNS_TRANSACTION_SUCCESS, DNS_TRANSACTION_NULL))
     988                 :          0 :                 return DNS_QUERY_NOMATCH;
     989                 :            : 
     990                 :          0 :         question = dns_query_question_for_protocol(q, q->answer_protocol);
     991                 :            : 
     992   [ #  #  #  #  :          0 :         DNS_ANSWER_FOREACH(rr, q->answer) {
          #  #  #  #  #  
                      # ]
     993                 :          0 :                 r = dns_question_matches_rr(question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain));
     994         [ #  # ]:          0 :                 if (r < 0)
     995                 :          0 :                         return r;
     996         [ #  # ]:          0 :                 if (r > 0)
     997                 :          0 :                         return DNS_QUERY_MATCH; /* The answer matches directly, no need to follow cnames */
     998                 :            : 
     999                 :          0 :                 r = dns_question_matches_cname_or_dname(question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain));
    1000         [ #  # ]:          0 :                 if (r < 0)
    1001                 :          0 :                         return r;
    1002   [ #  #  #  # ]:          0 :                 if (r > 0 && !cname)
    1003                 :          0 :                         cname = dns_resource_record_ref(rr);
    1004                 :            :         }
    1005                 :            : 
    1006         [ #  # ]:          0 :         if (!cname)
    1007                 :          0 :                 return DNS_QUERY_NOMATCH; /* No match and no cname to follow */
    1008                 :            : 
    1009         [ #  # ]:          0 :         if (q->flags & SD_RESOLVED_NO_CNAME)
    1010                 :          0 :                 return -ELOOP;
    1011                 :            : 
    1012         [ #  # ]:          0 :         if (!q->answer_authenticated)
    1013                 :          0 :                 q->previous_redirect_unauthenticated = true;
    1014                 :            : 
    1015                 :            :         /* OK, let's actually follow the CNAME */
    1016                 :          0 :         r = dns_query_cname_redirect(q, cname);
    1017         [ #  # ]:          0 :         if (r < 0)
    1018                 :          0 :                 return r;
    1019                 :            : 
    1020                 :            :         /* Let's see if the answer can already answer the new
    1021                 :            :          * redirected question */
    1022                 :          0 :         r = dns_query_process_cname(q);
    1023         [ #  # ]:          0 :         if (r != DNS_QUERY_NOMATCH)
    1024                 :          0 :                 return r;
    1025                 :            : 
    1026                 :            :         /* OK, it cannot, let's begin with the new query */
    1027                 :          0 :         r = dns_query_go(q);
    1028         [ #  # ]:          0 :         if (r < 0)
    1029                 :          0 :                 return r;
    1030                 :            : 
    1031                 :          0 :         return DNS_QUERY_RESTARTED; /* We restarted the query for a new cname */
    1032                 :            : }
    1033                 :            : 
    1034                 :          0 : static int on_bus_track(sd_bus_track *t, void *userdata) {
    1035                 :          0 :         DnsQuery *q = userdata;
    1036                 :            : 
    1037         [ #  # ]:          0 :         assert(t);
    1038         [ #  # ]:          0 :         assert(q);
    1039                 :            : 
    1040         [ #  # ]:          0 :         log_debug("Client of active query vanished, aborting query.");
    1041                 :          0 :         dns_query_complete(q, DNS_TRANSACTION_ABORTED);
    1042                 :          0 :         return 0;
    1043                 :            : }
    1044                 :            : 
    1045                 :          0 : int dns_query_bus_track(DnsQuery *q, sd_bus_message *m) {
    1046                 :            :         int r;
    1047                 :            : 
    1048         [ #  # ]:          0 :         assert(q);
    1049         [ #  # ]:          0 :         assert(m);
    1050                 :            : 
    1051         [ #  # ]:          0 :         if (!q->bus_track) {
    1052                 :          0 :                 r = sd_bus_track_new(sd_bus_message_get_bus(m), &q->bus_track, on_bus_track, q);
    1053         [ #  # ]:          0 :                 if (r < 0)
    1054                 :          0 :                         return r;
    1055                 :            :         }
    1056                 :            : 
    1057                 :          0 :         r = sd_bus_track_add_sender(q->bus_track, m);
    1058         [ #  # ]:          0 :         if (r < 0)
    1059                 :          0 :                 return r;
    1060                 :            : 
    1061                 :          0 :         return 0;
    1062                 :            : }
    1063                 :            : 
    1064                 :          0 : DnsQuestion* dns_query_question_for_protocol(DnsQuery *q, DnsProtocol protocol) {
    1065         [ #  # ]:          0 :         assert(q);
    1066                 :            : 
    1067      [ #  #  # ]:          0 :         switch (protocol) {
    1068                 :            : 
    1069                 :          0 :         case DNS_PROTOCOL_DNS:
    1070                 :          0 :                 return q->question_idna;
    1071                 :            : 
    1072                 :          0 :         case DNS_PROTOCOL_MDNS:
    1073                 :            :         case DNS_PROTOCOL_LLMNR:
    1074                 :          0 :                 return q->question_utf8;
    1075                 :            : 
    1076                 :          0 :         default:
    1077                 :          0 :                 return NULL;
    1078                 :            :         }
    1079                 :            : }
    1080                 :            : 
    1081                 :          0 : const char *dns_query_string(DnsQuery *q) {
    1082                 :            :         const char *name;
    1083                 :            :         int r;
    1084                 :            : 
    1085                 :            :         /* Returns a somewhat useful human-readable lookup key string for this query */
    1086                 :            : 
    1087         [ #  # ]:          0 :         if (q->request_address_string)
    1088                 :          0 :                 return q->request_address_string;
    1089                 :            : 
    1090         [ #  # ]:          0 :         if (q->request_address_valid) {
    1091                 :          0 :                 r = in_addr_to_string(q->request_family, &q->request_address, &q->request_address_string);
    1092         [ #  # ]:          0 :                 if (r >= 0)
    1093                 :          0 :                         return q->request_address_string;
    1094                 :            :         }
    1095                 :            : 
    1096                 :          0 :         name = dns_question_first_name(q->question_utf8);
    1097         [ #  # ]:          0 :         if (name)
    1098                 :          0 :                 return name;
    1099                 :            : 
    1100                 :          0 :         return dns_question_first_name(q->question_idna);
    1101                 :            : }
    1102                 :            : 
    1103                 :          0 : bool dns_query_fully_authenticated(DnsQuery *q) {
    1104         [ #  # ]:          0 :         assert(q);
    1105                 :            : 
    1106   [ #  #  #  # ]:          0 :         return q->answer_authenticated && !q->previous_redirect_unauthenticated;
    1107                 :            : }

Generated by: LCOV version 1.14