]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-query.c
resolved: when checking whether a link is relevant, check kernel operstate
[thirdparty/systemd.git] / src / resolve / resolved-dns-query.c
CommitLineData
74b2466e
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2014 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
b5efdb8a 22#include "alloc-util.h"
2a1037af 23#include "dns-domain.h"
b5efdb8a 24#include "hostname-util.h"
78c6a153 25#include "local-addresses.h"
74b2466e 26#include "resolved-dns-query.h"
23b298bc 27#include "string-util.h"
74b2466e 28
0c903ae7 29/* How long to wait for the query in total */
74b2466e 30#define QUERY_TIMEOUT_USEC (30 * USEC_PER_SEC)
0c903ae7 31
8ba9fd9c 32#define CNAME_MAX 8
39762fdf 33#define QUERIES_MAX 2048
45ec7efb 34#define AUXILIARY_QUERIES_MAX 64
8ba9fd9c 35
801ad6a6
LP
36static int dns_query_candidate_new(DnsQueryCandidate **ret, DnsQuery *q, DnsScope *s) {
37 DnsQueryCandidate *c;
74b2466e 38
801ad6a6 39 assert(ret);
faa133f3 40 assert(q);
801ad6a6 41 assert(s);
74b2466e 42
801ad6a6
LP
43 c = new0(DnsQueryCandidate, 1);
44 if (!c)
45 return -ENOMEM;
46
47 c->query = q;
48 c->scope = s;
49
50 LIST_PREPEND(candidates_by_query, q->candidates, c);
51 LIST_PREPEND(candidates_by_scope, s->query_candidates, c);
52
53 *ret = c;
54 return 0;
55}
56
57static void dns_query_candidate_stop(DnsQueryCandidate *c) {
58 DnsTransaction *t;
74b2466e 59
801ad6a6
LP
60 assert(c);
61
62 while ((t = set_steal_first(c->transactions))) {
547973de 63 set_remove(t->notify_query_candidates, c);
ec2c5e43 64 dns_transaction_gc(t);
74b2466e 65 }
74b2466e
LP
66}
67
801ad6a6
LP
68DnsQueryCandidate* dns_query_candidate_free(DnsQueryCandidate *c) {
69
70 if (!c)
71 return NULL;
72
73 dns_query_candidate_stop(c);
74
75 set_free(c->transactions);
76 dns_search_domain_unref(c->search_domain);
77
78 if (c->query)
79 LIST_REMOVE(candidates_by_query, c->query->candidates, c);
80
81 if (c->scope)
82 LIST_REMOVE(candidates_by_scope, c->scope->query_candidates, c);
83
84 free(c);
85
86 return NULL;
87}
88
89static int dns_query_candidate_next_search_domain(DnsQueryCandidate *c) {
801ad6a6
LP
90 DnsSearchDomain *next = NULL;
91
92 assert(c);
93
94 if (c->search_domain && c->search_domain->linked) {
95 next = c->search_domain->domains_next;
96
6627b7e2
LP
97 if (!next) /* We hit the end of the list */
98 return 0;
801ad6a6
LP
99
100 } else {
801ad6a6
LP
101 next = dns_scope_get_search_domains(c->scope);
102
6627b7e2 103 if (!next) /* OK, there's nothing. */
801ad6a6
LP
104 return 0;
105 }
106
107 dns_search_domain_unref(c->search_domain);
108 c->search_domain = dns_search_domain_ref(next);
6627b7e2 109
801ad6a6
LP
110 return 1;
111}
112
113static int dns_query_candidate_add_transaction(DnsQueryCandidate *c, DnsResourceKey *key) {
114 DnsTransaction *t;
115 int r;
116
117 assert(c);
118 assert(key);
119
801ad6a6
LP
120 t = dns_scope_find_transaction(c->scope, key, true);
121 if (!t) {
122 r = dns_transaction_new(&t, c->scope, key);
123 if (r < 0)
124 return r;
547973de
LP
125 } else {
126 if (set_contains(c->transactions, t))
127 return 0;
801ad6a6
LP
128 }
129
547973de
LP
130 r = set_ensure_allocated(&c->transactions, NULL);
131 if (r < 0)
132 goto gc;
133
134 r = set_ensure_allocated(&t->notify_query_candidates, NULL);
801ad6a6
LP
135 if (r < 0)
136 goto gc;
137
547973de 138 r = set_put(t->notify_query_candidates, c);
801ad6a6
LP
139 if (r < 0)
140 goto gc;
141
142 r = set_put(c->transactions, t);
143 if (r < 0) {
547973de 144 (void) set_remove(t->notify_query_candidates, c);
801ad6a6
LP
145 goto gc;
146 }
147
547973de 148 return 1;
801ad6a6
LP
149
150gc:
151 dns_transaction_gc(t);
152 return r;
153}
154
155static int dns_query_candidate_go(DnsQueryCandidate *c) {
156 DnsTransaction *t;
157 Iterator i;
158 int r;
159
160 assert(c);
161
162 /* Start the transactions that are not started yet */
163 SET_FOREACH(t, c->transactions, i) {
164 if (t->state != DNS_TRANSACTION_NULL)
165 continue;
166
167 r = dns_transaction_go(t);
168 if (r < 0)
169 return r;
170 }
171
172 return 0;
173}
174
175static DnsTransactionState dns_query_candidate_state(DnsQueryCandidate *c) {
176 DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS;
177 DnsTransaction *t;
178 Iterator i;
179
180 assert(c);
181
182 if (c->error_code != 0)
183 return DNS_TRANSACTION_RESOURCES;
184
185 SET_FOREACH(t, c->transactions, i) {
186
187 switch (t->state) {
188
5264131a
LP
189 case DNS_TRANSACTION_NULL:
190 /* If there's a NULL transaction pending, then
191 * this means not all transactions where
192 * started yet, and we were called from within
193 * the stackframe that is supposed to start
194 * remaining transactions. In this case,
195 * simply claim the candidate is pending. */
196
801ad6a6 197 case DNS_TRANSACTION_PENDING:
547973de
LP
198 case DNS_TRANSACTION_VALIDATING:
199 /* If there's one transaction currently in
200 * VALIDATING state, then this means there's
201 * also one in PENDING state, hence we can
202 * return PENDING immediately. */
203 return DNS_TRANSACTION_PENDING;
801ad6a6
LP
204
205 case DNS_TRANSACTION_SUCCESS:
206 state = t->state;
207 break;
208
209 default:
210 if (state != DNS_TRANSACTION_SUCCESS)
211 state = t->state;
212
213 break;
214 }
215 }
216
217 return state;
218}
219
220static int dns_query_candidate_setup_transactions(DnsQueryCandidate *c) {
23b298bc 221 DnsQuestion *question;
801ad6a6
LP
222 DnsResourceKey *key;
223 int n = 0, r;
224
225 assert(c);
226
227 dns_query_candidate_stop(c);
228
23b298bc
LP
229 question = dns_query_question_for_protocol(c->query, c->scope->protocol);
230
801ad6a6 231 /* Create one transaction per question key */
23b298bc 232 DNS_QUESTION_FOREACH(key, question) {
801ad6a6
LP
233 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *new_key = NULL;
234
235 if (c->search_domain) {
236 r = dns_resource_key_new_append_suffix(&new_key, key, c->search_domain->name);
237 if (r < 0)
238 goto fail;
239 }
240
241 r = dns_query_candidate_add_transaction(c, new_key ?: key);
242 if (r < 0)
243 goto fail;
244
245 n++;
246 }
247
248 return n;
249
250fail:
251 dns_query_candidate_stop(c);
252 return r;
253}
254
547973de 255void dns_query_candidate_notify(DnsQueryCandidate *c) {
801ad6a6
LP
256 DnsTransactionState state;
257 int r;
258
259 assert(c);
260
261 state = dns_query_candidate_state(c);
262
547973de 263 if (DNS_TRANSACTION_IS_LIVE(state))
801ad6a6
LP
264 return;
265
266 if (state != DNS_TRANSACTION_SUCCESS && c->search_domain) {
267
268 r = dns_query_candidate_next_search_domain(c);
269 if (r < 0)
270 goto fail;
271
272 if (r > 0) {
273 /* OK, there's another search domain to try, let's do so. */
274
275 r = dns_query_candidate_setup_transactions(c);
276 if (r < 0)
277 goto fail;
278
279 if (r > 0) {
280 /* New transactions where queued. Start them and wait */
281
282 r = dns_query_candidate_go(c);
283 if (r < 0)
284 goto fail;
285
286 return;
287 }
288 }
289
290 }
291
292 dns_query_ready(c->query);
293 return;
294
295fail:
296 log_warning_errno(r, "Failed to follow search domains: %m");
297 c->error_code = r;
298 dns_query_ready(c->query);
299}
300
301static void dns_query_stop(DnsQuery *q) {
302 DnsQueryCandidate *c;
303
304 assert(q);
305
306 q->timeout_event_source = sd_event_source_unref(q->timeout_event_source);
307
308 LIST_FOREACH(candidates_by_query, c, q->candidates)
309 dns_query_candidate_stop(c);
310}
311
7820b320
LP
312static void dns_query_free_candidates(DnsQuery *q) {
313 assert(q);
314
315 while (q->candidates)
316 dns_query_candidate_free(q->candidates);
317}
318
319static void dns_query_reset_answer(DnsQuery *q) {
320 assert(q);
321
322 q->answer = dns_answer_unref(q->answer);
323 q->answer_rcode = 0;
324 q->answer_dnssec_result = _DNSSEC_RESULT_INVALID;
325 q->answer_authenticated = false;
326 q->answer_protocol = _DNS_PROTOCOL_INVALID;
327 q->answer_family = AF_UNSPEC;
328 q->answer_search_domain = dns_search_domain_unref(q->answer_search_domain);
329}
330
74b2466e 331DnsQuery *dns_query_free(DnsQuery *q) {
74b2466e
LP
332 if (!q)
333 return NULL;
334
45ec7efb
LP
335 while (q->auxiliary_queries)
336 dns_query_free(q->auxiliary_queries);
337
338 if (q->auxiliary_for) {
339 assert(q->auxiliary_for->n_auxiliary_queries > 0);
340 q->auxiliary_for->n_auxiliary_queries--;
341 LIST_REMOVE(auxiliary_queries, q->auxiliary_for->auxiliary_queries, q);
342 }
343
7820b320 344 dns_query_free_candidates(q);
322345fd 345
23b298bc
LP
346 dns_question_unref(q->question_idna);
347 dns_question_unref(q->question_utf8);
7820b320
LP
348
349 dns_query_reset_answer(q);
322345fd 350
ec2c5e43 351 sd_bus_message_unref(q->request);
82bd6ddd 352 sd_bus_track_unref(q->bus_track);
74b2466e 353
23b298bc
LP
354 free(q->request_address_string);
355
39762fdf 356 if (q->manager) {
74b2466e 357 LIST_REMOVE(queries, q->manager->dns_queries, q);
39762fdf
LP
358 q->manager->n_dns_queries--;
359 }
74b2466e 360
74b2466e
LP
361 free(q);
362
363 return NULL;
364}
365
23b298bc
LP
366int dns_query_new(
367 Manager *m,
368 DnsQuery **ret,
369 DnsQuestion *question_utf8,
370 DnsQuestion *question_idna,
371 int ifindex, uint64_t flags) {
372
74b2466e 373 _cleanup_(dns_query_freep) DnsQuery *q = NULL;
23b298bc
LP
374 DnsResourceKey *key;
375 bool good = false;
faa133f3 376 int r;
74b2466e
LP
377
378 assert(m);
379
23b298bc
LP
380 if (dns_question_size(question_utf8) > 0) {
381 r = dns_question_is_valid_for_query(question_utf8);
382 if (r < 0)
383 return r;
384 if (r == 0)
385 return -EINVAL;
386
387 good = true;
388 }
389
390 /* If the IDNA and UTF8 questions are the same, merge their references */
391 r = dns_question_is_equal(question_idna, question_utf8);
faa133f3
LP
392 if (r < 0)
393 return r;
23b298bc
LP
394 if (r > 0)
395 question_idna = question_utf8;
396 else {
397 if (dns_question_size(question_idna) > 0) {
398 r = dns_question_is_valid_for_query(question_idna);
399 if (r < 0)
400 return r;
401 if (r == 0)
402 return -EINVAL;
403
404 good = true;
405 }
406 }
407
408 if (!good) /* don't allow empty queries */
409 return -EINVAL;
74b2466e 410
39762fdf
LP
411 if (m->n_dns_queries >= QUERIES_MAX)
412 return -EBUSY;
413
74b2466e
LP
414 q = new0(DnsQuery, 1);
415 if (!q)
416 return -ENOMEM;
417
23b298bc
LP
418 q->question_utf8 = dns_question_ref(question_utf8);
419 q->question_idna = dns_question_ref(question_idna);
51323288
LP
420 q->ifindex = ifindex;
421 q->flags = flags;
7820b320 422 q->answer_dnssec_result = _DNSSEC_RESULT_INVALID;
801ad6a6 423 q->answer_protocol = _DNS_PROTOCOL_INVALID;
7820b320 424 q->answer_family = AF_UNSPEC;
322345fd 425
23b298bc
LP
426 /* First dump UTF8 question */
427 DNS_QUESTION_FOREACH(key, question_utf8) {
428 _cleanup_free_ char *p = NULL;
e4501ed4 429
23b298bc 430 r = dns_resource_key_to_string(key, &p);
e4501ed4
LP
431 if (r < 0)
432 return r;
433
23b298bc
LP
434 log_debug("Looking up RR for %s.", strstrip(p));
435 }
436
437 /* And then dump the IDNA question, but only what hasn't been dumped already through the UTF8 question. */
438 DNS_QUESTION_FOREACH(key, question_idna) {
439 _cleanup_free_ char *p = NULL;
440
441 r = dns_question_contains(question_utf8, key);
442 if (r < 0)
443 return r;
444 if (r > 0)
445 continue;
446
447 r = dns_resource_key_to_string(key, &p);
448 if (r < 0)
449 return r;
450
451 log_debug("Looking up IDNA RR for %s.", strstrip(p));
74b2466e
LP
452 }
453
454 LIST_PREPEND(queries, m->dns_queries, q);
39762fdf 455 m->n_dns_queries++;
74b2466e
LP
456 q->manager = m;
457
8ba9fd9c
LP
458 if (ret)
459 *ret = q;
460 q = NULL;
461
462 return 0;
463}
464
45ec7efb
LP
465int dns_query_make_auxiliary(DnsQuery *q, DnsQuery *auxiliary_for) {
466 assert(q);
467 assert(auxiliary_for);
468
469 /* Ensure that that the query is not auxiliary yet, and
470 * nothing else is auxiliary to it either */
471 assert(!q->auxiliary_for);
472 assert(!q->auxiliary_queries);
473
474 /* Ensure that the unit we shall be made auxiliary for isn't
475 * auxiliary itself */
476 assert(!auxiliary_for->auxiliary_for);
477
478 if (auxiliary_for->n_auxiliary_queries >= AUXILIARY_QUERIES_MAX)
479 return -EAGAIN;
480
481 LIST_PREPEND(auxiliary_queries, auxiliary_for->auxiliary_queries, q);
482 q->auxiliary_for = auxiliary_for;
483
484 auxiliary_for->n_auxiliary_queries++;
485 return 0;
486}
487
ec2c5e43 488static void dns_query_complete(DnsQuery *q, DnsTransactionState state) {
8ba9fd9c 489 assert(q);
547973de
LP
490 assert(!DNS_TRANSACTION_IS_LIVE(state));
491 assert(DNS_TRANSACTION_IS_LIVE(q->state));
8ba9fd9c 492
322345fd
LP
493 /* Note that this call might invalidate the query. Callers
494 * should hence not attempt to access the query or transaction
495 * after calling this function. */
8ba9fd9c 496
8ba9fd9c
LP
497 q->state = state;
498
322345fd
LP
499 dns_query_stop(q);
500 if (q->complete)
501 q->complete(q);
8ba9fd9c
LP
502}
503
504static int on_query_timeout(sd_event_source *s, usec_t usec, void *userdata) {
505 DnsQuery *q = userdata;
506
507 assert(s);
508 assert(q);
509
ec2c5e43 510 dns_query_complete(q, DNS_TRANSACTION_TIMEOUT);
8ba9fd9c
LP
511 return 0;
512}
513
801ad6a6
LP
514static int dns_query_add_candidate(DnsQuery *q, DnsScope *s) {
515 DnsQueryCandidate *c;
faa133f3
LP
516 int r;
517
518 assert(q);
ec2c5e43 519 assert(s);
faa133f3 520
801ad6a6 521 r = dns_query_candidate_new(&c, q, s);
faa133f3
LP
522 if (r < 0)
523 return r;
524
801ad6a6 525 /* If this a single-label domain on DNS, we might append a suitable search domain first. */
22f711bb 526 if ((q->flags & SD_RESOLVED_NO_SEARCH) == 0) {
23b298bc 527 r = dns_scope_name_needs_search_domain(s, dns_question_first_name(q->question_idna));
22f711bb 528 if (r < 0)
801ad6a6 529 goto fail;
22f711bb
LP
530 if (r > 0) {
531 /* OK, we need a search domain now. Let's find one for this scope */
532
533 r = dns_query_candidate_next_search_domain(c);
534 if (r <= 0) /* if there's no search domain, then we won't add any transaction. */
535 goto fail;
536 }
faa133f3
LP
537 }
538
801ad6a6
LP
539 r = dns_query_candidate_setup_transactions(c);
540 if (r < 0)
541 goto fail;
542
faa133f3
LP
543 return 0;
544
801ad6a6
LP
545fail:
546 dns_query_candidate_free(c);
faa133f3
LP
547 return r;
548}
549
2a1037af
LP
550static int SYNTHESIZE_IFINDEX(int ifindex) {
551
78c6a153
LP
552 /* When the caller asked for resolving on a specific
553 * interface, we synthesize the answer for that
554 * interface. However, if nothing specific was claimed and we
555 * only return localhost RRs, we synthesize the answer for
2a1037af
LP
556 * localhost. */
557
558 if (ifindex > 0)
559 return ifindex;
560
561 return LOOPBACK_IFINDEX;
562}
563
564static int SYNTHESIZE_FAMILY(uint64_t flags) {
565
566 /* Picks an address family depending on set flags. This is
567 * purely for synthesized answers, where the family we return
568 * for the reply should match what was requested in the
569 * question, even though we are synthesizing the answer
570 * here. */
571
572 if (!(flags & SD_RESOLVED_DNS)) {
573 if (flags & SD_RESOLVED_LLMNR_IPV4)
574 return AF_INET;
575 if (flags & SD_RESOLVED_LLMNR_IPV6)
576 return AF_INET6;
577 }
578
579 return AF_UNSPEC;
580}
581
582static DnsProtocol SYNTHESIZE_PROTOCOL(uint64_t flags) {
583
584 /* Similar as SYNTHESIZE_FAMILY() but does this for the
585 * protocol. If resolving via DNS was requested, we claim it
586 * was DNS. Similar, if nothing specific was
587 * requested. However, if only resolving via LLMNR was
588 * requested we return that. */
589
590 if (flags & SD_RESOLVED_DNS)
591 return DNS_PROTOCOL_DNS;
592 if (flags & SD_RESOLVED_LLMNR)
593 return DNS_PROTOCOL_LLMNR;
594
595 return DNS_PROTOCOL_DNS;
596}
597
78c6a153
LP
598static int dns_type_to_af(uint16_t t) {
599 switch (t) {
600
601 case DNS_TYPE_A:
602 return AF_INET;
603
604 case DNS_TYPE_AAAA:
605 return AF_INET6;
606
607 case DNS_TYPE_ANY:
608 return AF_UNSPEC;
609
610 default:
611 return -EINVAL;
612 }
613}
614
23b298bc 615static int synthesize_localhost_rr(DnsQuery *q, const DnsResourceKey *key, DnsAnswer **answer) {
78c6a153
LP
616 int r;
617
618 assert(q);
619 assert(key);
620 assert(answer);
621
622 r = dns_answer_reserve(answer, 2);
623 if (r < 0)
624 return r;
625
626 if (IN_SET(key->type, DNS_TYPE_A, DNS_TYPE_ANY)) {
627 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
628
629 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, DNS_RESOURCE_KEY_NAME(key));
630 if (!rr)
631 return -ENOMEM;
632
633 rr->a.in_addr.s_addr = htobe32(INADDR_LOOPBACK);
634
105e1512 635 r = dns_answer_add(*answer, rr, SYNTHESIZE_IFINDEX(q->ifindex), DNS_ANSWER_AUTHENTICATED);
78c6a153
LP
636 if (r < 0)
637 return r;
638 }
639
640 if (IN_SET(key->type, DNS_TYPE_AAAA, DNS_TYPE_ANY)) {
641 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
642
643 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, DNS_RESOURCE_KEY_NAME(key));
644 if (!rr)
645 return -ENOMEM;
646
647 rr->aaaa.in6_addr = in6addr_loopback;
648
105e1512 649 r = dns_answer_add(*answer, rr, SYNTHESIZE_IFINDEX(q->ifindex), DNS_ANSWER_AUTHENTICATED);
78c6a153
LP
650 if (r < 0)
651 return r;
652 }
653
654 return 0;
655}
656
105e1512 657static int answer_add_ptr(DnsAnswer **answer, const char *from, const char *to, int ifindex, DnsAnswerFlags flags) {
78c6a153
LP
658 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
659
660 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_PTR, from);
661 if (!rr)
662 return -ENOMEM;
663
664 rr->ptr.name = strdup(to);
665 if (!rr->ptr.name)
666 return -ENOMEM;
667
105e1512 668 return dns_answer_add(*answer, rr, ifindex, flags);
78c6a153
LP
669}
670
23b298bc 671static int synthesize_localhost_ptr(DnsQuery *q, const DnsResourceKey *key, DnsAnswer **answer) {
78c6a153
LP
672 int r;
673
674 assert(q);
675 assert(key);
676 assert(answer);
677
78c6a153 678 if (IN_SET(key->type, DNS_TYPE_PTR, DNS_TYPE_ANY)) {
105e1512
LP
679 r = dns_answer_reserve(answer, 1);
680 if (r < 0)
681 return r;
682
683 r = answer_add_ptr(answer, DNS_RESOURCE_KEY_NAME(key), "localhost", SYNTHESIZE_IFINDEX(q->ifindex), DNS_ANSWER_AUTHENTICATED);
78c6a153
LP
684 if (r < 0)
685 return r;
686 }
687
688 return 0;
689}
690
691static int answer_add_addresses_rr(
692 DnsAnswer **answer,
693 const char *name,
694 struct local_address *addresses,
695 unsigned n_addresses) {
696
697 unsigned j;
698 int r;
699
700 assert(answer);
701 assert(name);
702
703 r = dns_answer_reserve(answer, n_addresses);
704 if (r < 0)
705 return r;
706
707 for (j = 0; j < n_addresses; j++) {
708 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
709
710 r = dns_resource_record_new_address(&rr, addresses[j].family, &addresses[j].address, name);
711 if (r < 0)
712 return r;
713
105e1512 714 r = dns_answer_add(*answer, rr, addresses[j].ifindex, DNS_ANSWER_AUTHENTICATED);
78c6a153
LP
715 if (r < 0)
716 return r;
717 }
718
719 return 0;
720}
721
722static int answer_add_addresses_ptr(
723 DnsAnswer **answer,
724 const char *name,
725 struct local_address *addresses,
726 unsigned n_addresses,
727 int af, const union in_addr_union *match) {
728
729 unsigned j;
730 int r;
731
732 assert(answer);
733 assert(name);
734
735 for (j = 0; j < n_addresses; j++) {
736 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
737
738 if (af != AF_UNSPEC) {
739
740 if (addresses[j].family != af)
741 continue;
742
743 if (match && !in_addr_equal(af, match, &addresses[j].address))
744 continue;
745 }
746
747 r = dns_answer_reserve(answer, 1);
748 if (r < 0)
749 return r;
750
751 r = dns_resource_record_new_reverse(&rr, addresses[j].family, &addresses[j].address, name);
752 if (r < 0)
753 return r;
754
105e1512 755 r = dns_answer_add(*answer, rr, addresses[j].ifindex, DNS_ANSWER_AUTHENTICATED);
78c6a153
LP
756 if (r < 0)
757 return r;
758 }
759
760 return 0;
761}
762
23b298bc 763static int synthesize_system_hostname_rr(DnsQuery *q, const DnsResourceKey *key, DnsAnswer **answer) {
78c6a153
LP
764 _cleanup_free_ struct local_address *addresses = NULL;
765 int n = 0, af;
766
767 assert(q);
768 assert(key);
769 assert(answer);
770
771 af = dns_type_to_af(key->type);
772 if (af >= 0) {
773 n = local_addresses(q->manager->rtnl, q->ifindex, af, &addresses);
774 if (n < 0)
775 return n;
776
777 if (n == 0) {
778 struct local_address buffer[2];
779
780 /* If we have no local addresses then use ::1
781 * and 127.0.0.2 as local ones. */
782
783 if (af == AF_INET || af == AF_UNSPEC)
784 buffer[n++] = (struct local_address) {
785 .family = AF_INET,
786 .ifindex = SYNTHESIZE_IFINDEX(q->ifindex),
787 .address.in.s_addr = htobe32(0x7F000002),
788 };
789
790 if (af == AF_INET6 || af == AF_UNSPEC)
791 buffer[n++] = (struct local_address) {
792 .family = AF_INET6,
793 .ifindex = SYNTHESIZE_IFINDEX(q->ifindex),
794 .address.in6 = in6addr_loopback,
795 };
796
797 return answer_add_addresses_rr(answer, DNS_RESOURCE_KEY_NAME(key), buffer, n);
798 }
799 }
800
801 return answer_add_addresses_rr(answer, DNS_RESOURCE_KEY_NAME(key), addresses, n);
802}
803
804static int synthesize_system_hostname_ptr(DnsQuery *q, int af, const union in_addr_union *address, DnsAnswer **answer) {
805 _cleanup_free_ struct local_address *addresses = NULL;
806 int n, r;
807
808 assert(q);
809 assert(address);
810 assert(answer);
811
812 if (af == AF_INET && address->in.s_addr == htobe32(0x7F000002)) {
813
814 /* Always map the IPv4 address 127.0.0.2 to the local
815 * hostname, in addition to "localhost": */
816
817 r = dns_answer_reserve(answer, 3);
818 if (r < 0)
819 return r;
820
105e1512 821 r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", q->manager->llmnr_hostname, SYNTHESIZE_IFINDEX(q->ifindex), DNS_ANSWER_AUTHENTICATED);
78c6a153
LP
822 if (r < 0)
823 return r;
824
105e1512 825 r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", q->manager->mdns_hostname, SYNTHESIZE_IFINDEX(q->ifindex), DNS_ANSWER_AUTHENTICATED);
78c6a153
LP
826 if (r < 0)
827 return r;
828
105e1512 829 r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", "localhost", SYNTHESIZE_IFINDEX(q->ifindex), DNS_ANSWER_AUTHENTICATED);
78c6a153
LP
830 if (r < 0)
831 return r;
832
833 return 0;
834 }
835
836 n = local_addresses(q->manager->rtnl, q->ifindex, af, &addresses);
837 if (n < 0)
838 return n;
839
840 r = answer_add_addresses_ptr(answer, q->manager->llmnr_hostname, addresses, n, af, address);
841 if (r < 0)
842 return r;
843
844 return answer_add_addresses_ptr(answer, q->manager->mdns_hostname, addresses, n, af, address);
845}
846
23b298bc 847static int synthesize_gateway_rr(DnsQuery *q, const DnsResourceKey *key, DnsAnswer **answer) {
78c6a153
LP
848 _cleanup_free_ struct local_address *addresses = NULL;
849 int n = 0, af;
850
851 assert(q);
852 assert(key);
853 assert(answer);
854
855 af = dns_type_to_af(key->type);
856 if (af >= 0) {
857 n = local_gateways(q->manager->rtnl, q->ifindex, af, &addresses);
858 if (n < 0)
859 return n;
860 }
861
862 return answer_add_addresses_rr(answer, DNS_RESOURCE_KEY_NAME(key), addresses, n);
863}
864
865static int synthesize_gateway_ptr(DnsQuery *q, int af, const union in_addr_union *address, DnsAnswer **answer) {
866 _cleanup_free_ struct local_address *addresses = NULL;
867 int n;
868
869 assert(q);
870 assert(address);
871 assert(answer);
872
873 n = local_gateways(q->manager->rtnl, q->ifindex, af, &addresses);
874 if (n < 0)
875 return n;
876
877 return answer_add_addresses_ptr(answer, "gateway", addresses, n, af, address);
878}
879
880static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) {
2a1037af 881 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
23b298bc 882 DnsResourceKey *key;
2a1037af
LP
883 int r;
884
885 assert(q);
886 assert(state);
887
888 /* Tries to synthesize localhost RR replies where appropriate */
889
890 if (!IN_SET(*state,
3bbdc31d 891 DNS_TRANSACTION_RCODE_FAILURE,
2a1037af
LP
892 DNS_TRANSACTION_NO_SERVERS,
893 DNS_TRANSACTION_TIMEOUT,
894 DNS_TRANSACTION_ATTEMPTS_MAX_REACHED))
78c6a153 895 return 0;
2a1037af 896
23b298bc 897 DNS_QUESTION_FOREACH(key, q->question_utf8) {
78c6a153 898 union in_addr_union address;
2a1037af 899 const char *name;
78c6a153 900 int af;
2a1037af 901
23b298bc
LP
902 if (key->class != DNS_CLASS_IN &&
903 key->class != DNS_CLASS_ANY)
2a1037af
LP
904 continue;
905
23b298bc 906 name = DNS_RESOURCE_KEY_NAME(key);
2a1037af
LP
907
908 if (is_localhost(name)) {
909
23b298bc 910 r = synthesize_localhost_rr(q, key, &answer);
78c6a153
LP
911 if (r < 0)
912 return log_error_errno(r, "Failed to synthesize localhost RRs: %m");
2a1037af 913
78c6a153 914 } else if (manager_is_own_hostname(q->manager, name)) {
2a1037af 915
23b298bc 916 r = synthesize_system_hostname_rr(q, key, &answer);
78c6a153
LP
917 if (r < 0)
918 return log_error_errno(r, "Failed to synthesize system hostname RRs: %m");
2a1037af 919
78c6a153 920 } else if (is_gateway_hostname(name)) {
2a1037af 921
23b298bc 922 r = synthesize_gateway_rr(q, key, &answer);
78c6a153
LP
923 if (r < 0)
924 return log_error_errno(r, "Failed to synthesize gateway RRs: %m");
2a1037af 925
78c6a153
LP
926 } else if ((dns_name_endswith(name, "127.in-addr.arpa") > 0 && dns_name_equal(name, "2.0.0.127.in-addr.arpa") == 0) ||
927 dns_name_equal(name, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa") > 0) {
2a1037af 928
23b298bc 929 r = synthesize_localhost_ptr(q, key, &answer);
78c6a153
LP
930 if (r < 0)
931 return log_error_errno(r, "Failed to synthesize localhost PTR RRs: %m");
2a1037af 932
78c6a153 933 } else if (dns_name_address(name, &af, &address) > 0) {
2a1037af 934
78c6a153
LP
935 r = synthesize_system_hostname_ptr(q, af, &address, &answer);
936 if (r < 0)
937 return log_error_errno(r, "Failed to synthesize system hostname PTR RR: %m");
2a1037af 938
78c6a153
LP
939 r = synthesize_gateway_ptr(q, af, &address, &answer);
940 if (r < 0)
941 return log_error_errno(r, "Failed to synthesize gateway hostname PTR RR: %m");
2a1037af
LP
942 }
943 }
944
945 if (!answer)
78c6a153 946 return 0;
2a1037af
LP
947
948 dns_answer_unref(q->answer);
949 q->answer = answer;
950 answer = NULL;
951
2a1037af 952 q->answer_rcode = DNS_RCODE_SUCCESS;
801ad6a6
LP
953 q->answer_protocol = SYNTHESIZE_PROTOCOL(q->flags);
954 q->answer_family = SYNTHESIZE_FAMILY(q->flags);
2a1037af
LP
955
956 *state = DNS_TRANSACTION_SUCCESS;
78c6a153
LP
957
958 return 1;
2a1037af
LP
959}
960
322345fd 961int dns_query_go(DnsQuery *q) {
8ba9fd9c
LP
962 DnsScopeMatch found = DNS_SCOPE_NO;
963 DnsScope *s, *first = NULL;
801ad6a6 964 DnsQueryCandidate *c;
8ba9fd9c
LP
965 int r;
966
967 assert(q);
968
ec2c5e43 969 if (q->state != DNS_TRANSACTION_NULL)
8ba9fd9c
LP
970 return 0;
971
8ba9fd9c 972 LIST_FOREACH(scopes, s, q->manager->dns_scopes) {
74b2466e 973 DnsScopeMatch match;
23b298bc
LP
974 const char *name;
975
976 name = dns_question_first_name(dns_query_question_for_protocol(q, s->protocol));
977 if (!name)
978 continue;
74b2466e 979
51323288 980 match = dns_scope_good_domain(s, q->ifindex, q->flags, name);
74b2466e
LP
981 if (match < 0)
982 return match;
983
984 if (match == DNS_SCOPE_NO)
985 continue;
986
987 found = match;
988
989 if (match == DNS_SCOPE_YES) {
990 first = s;
991 break;
992 } else {
993 assert(match == DNS_SCOPE_MAYBE);
994
995 if (!first)
996 first = s;
997 }
998 }
999
2a1037af
LP
1000 if (found == DNS_SCOPE_NO) {
1001 DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS;
1002
1003 dns_query_synthesize_reply(q, &state);
d634711b
LP
1004 dns_query_complete(q, state);
1005 return 1;
2a1037af 1006 }
74b2466e 1007
801ad6a6 1008 r = dns_query_add_candidate(q, first);
74b2466e 1009 if (r < 0)
ec2c5e43 1010 goto fail;
74b2466e 1011
74b2466e
LP
1012 LIST_FOREACH(scopes, s, first->scopes_next) {
1013 DnsScopeMatch match;
23b298bc
LP
1014 const char *name;
1015
1016 name = dns_question_first_name(dns_query_question_for_protocol(q, s->protocol));
1017 if (!name)
1018 continue;
74b2466e 1019
51323288 1020 match = dns_scope_good_domain(s, q->ifindex, q->flags, name);
74b2466e 1021 if (match < 0)
ec2c5e43 1022 goto fail;
74b2466e
LP
1023
1024 if (match != found)
1025 continue;
1026
801ad6a6 1027 r = dns_query_add_candidate(q, s);
74b2466e 1028 if (r < 0)
ec2c5e43 1029 goto fail;
74b2466e
LP
1030 }
1031
faa133f3 1032 q->answer = dns_answer_unref(q->answer);
faa133f3 1033 q->answer_rcode = 0;
51323288
LP
1034 q->answer_family = AF_UNSPEC;
1035 q->answer_protocol = _DNS_PROTOCOL_INVALID;
74b2466e 1036
9a015429
LP
1037 r = sd_event_add_time(
1038 q->manager->event,
1039 &q->timeout_event_source,
1040 clock_boottime_or_monotonic(),
1041 now(clock_boottime_or_monotonic()) + QUERY_TIMEOUT_USEC, 0,
1042 on_query_timeout, q);
74b2466e
LP
1043 if (r < 0)
1044 goto fail;
1045
aa4a9deb
LP
1046 (void) sd_event_source_set_description(q->timeout_event_source, "query-timeout");
1047
ec2c5e43 1048 q->state = DNS_TRANSACTION_PENDING;
faa133f3 1049 q->block_ready++;
74b2466e 1050
801ad6a6
LP
1051 /* Start the transactions */
1052 LIST_FOREACH(candidates_by_query, c, q->candidates) {
1053 r = dns_query_candidate_go(c);
1054 if (r < 0) {
1055 q->block_ready--;
ec2c5e43 1056 goto fail;
801ad6a6 1057 }
74b2466e
LP
1058 }
1059
faa133f3
LP
1060 q->block_ready--;
1061 dns_query_ready(q);
322345fd 1062
8ba9fd9c 1063 return 1;
74b2466e
LP
1064
1065fail:
8ba9fd9c 1066 dns_query_stop(q);
74b2466e
LP
1067 return r;
1068}
1069
801ad6a6 1070static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) {
ec2c5e43 1071 DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS;
547973de 1072 bool has_authenticated = false, has_non_authenticated = false;
019036a4 1073 DnssecResult dnssec_result_authenticated = _DNSSEC_RESULT_INVALID, dnssec_result_non_authenticated = _DNSSEC_RESULT_INVALID;
801ad6a6 1074 DnsTransaction *t;
faa133f3 1075 Iterator i;
547973de 1076 int r;
74b2466e
LP
1077
1078 assert(q);
1079
801ad6a6
LP
1080 if (!c) {
1081 dns_query_synthesize_reply(q, &state);
1082 dns_query_complete(q, state);
74b2466e 1083 return;
801ad6a6 1084 }
74b2466e 1085
801ad6a6 1086 SET_FOREACH(t, c->transactions, i) {
74b2466e 1087
801ad6a6 1088 switch (t->state) {
934e9b10 1089
801ad6a6
LP
1090 case DNS_TRANSACTION_SUCCESS: {
1091 /* We found a successfuly reply, merge it into the answer */
547973de
LP
1092 r = dns_answer_extend(&q->answer, t->answer);
1093 if (r < 0) {
801ad6a6
LP
1094 dns_query_complete(q, DNS_TRANSACTION_RESOURCES);
1095 return;
1096 }
019036a4 1097
ae6a4bbf 1098 q->answer_rcode = t->answer_rcode;
801ad6a6 1099
019036a4 1100 if (t->answer_authenticated) {
931851e8 1101 has_authenticated = true;
019036a4
LP
1102 dnssec_result_authenticated = t->answer_dnssec_result;
1103 } else {
931851e8 1104 has_non_authenticated = true;
019036a4
LP
1105 dnssec_result_non_authenticated = t->answer_dnssec_result;
1106 }
931851e8 1107
801ad6a6
LP
1108 state = DNS_TRANSACTION_SUCCESS;
1109 break;
1110 }
1111
801ad6a6 1112 case DNS_TRANSACTION_NULL:
547973de
LP
1113 case DNS_TRANSACTION_PENDING:
1114 case DNS_TRANSACTION_VALIDATING:
801ad6a6
LP
1115 case DNS_TRANSACTION_ABORTED:
1116 /* Ignore transactions that didn't complete */
1117 continue;
1118
1119 default:
1120 /* Any kind of failure? Store the data away,
1121 * if there's nothing stored yet. */
934e9b10 1122
019036a4
LP
1123 if (state == DNS_TRANSACTION_SUCCESS)
1124 continue;
934e9b10 1125
d38d5ca6 1126 q->answer = dns_answer_unref(q->answer);
019036a4
LP
1127 q->answer_rcode = t->answer_rcode;
1128 q->answer_dnssec_result = t->answer_dnssec_result;
934e9b10 1129
019036a4 1130 state = t->state;
801ad6a6 1131 break;
74b2466e 1132 }
801ad6a6 1133 }
74b2466e 1134
019036a4
LP
1135 if (state == DNS_TRANSACTION_SUCCESS) {
1136 q->answer_authenticated = has_authenticated && !has_non_authenticated;
1137 q->answer_dnssec_result = q->answer_authenticated ? dnssec_result_authenticated : dnssec_result_non_authenticated;
1138 }
1139
801ad6a6
LP
1140 q->answer_protocol = c->scope->protocol;
1141 q->answer_family = c->scope->family;
934e9b10 1142
801ad6a6
LP
1143 dns_search_domain_unref(q->answer_search_domain);
1144 q->answer_search_domain = dns_search_domain_ref(c->search_domain);
7e8e0422 1145
801ad6a6
LP
1146 dns_query_synthesize_reply(q, &state);
1147 dns_query_complete(q, state);
1148}
934e9b10 1149
801ad6a6 1150void dns_query_ready(DnsQuery *q) {
74b2466e 1151
801ad6a6
LP
1152 DnsQueryCandidate *bad = NULL, *c;
1153 bool pending = false;
74b2466e 1154
801ad6a6 1155 assert(q);
547973de 1156 assert(DNS_TRANSACTION_IS_LIVE(q->state));
e4501ed4 1157
801ad6a6
LP
1158 /* Note that this call might invalidate the query. Callers
1159 * should hence not attempt to access the query or transaction
1160 * after calling this function, unless the block_ready
1161 * counter was explicitly bumped before doing so. */
1162
1163 if (q->block_ready > 0)
1164 return;
1165
1166 LIST_FOREACH(candidates_by_query, c, q->candidates) {
1167 DnsTransactionState state;
1168
1169 state = dns_query_candidate_state(c);
1170 switch (state) {
1171
1172 case DNS_TRANSACTION_SUCCESS:
547973de 1173 /* One of the candidates is successful,
801ad6a6
LP
1174 * let's use it, and copy its data out */
1175 dns_query_accept(q, c);
e4501ed4
LP
1176 return;
1177
801ad6a6 1178 case DNS_TRANSACTION_NULL:
547973de
LP
1179 case DNS_TRANSACTION_PENDING:
1180 case DNS_TRANSACTION_VALIDATING:
1181 /* One of the candidates is still going on,
1182 * let's maybe wait for it */
801ad6a6
LP
1183 pending = true;
1184 break;
e4501ed4 1185
801ad6a6
LP
1186 default:
1187 /* Any kind of failure */
1188 bad = c;
1189 break;
1190 }
faa133f3 1191 }
74b2466e 1192
801ad6a6
LP
1193 if (pending)
1194 return;
2a1037af 1195
801ad6a6 1196 dns_query_accept(q, bad);
74b2466e 1197}
8ba9fd9c 1198
45ec7efb 1199static int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname) {
23b298bc
LP
1200 _cleanup_(dns_question_unrefp) DnsQuestion *nq_idna = NULL, *nq_utf8 = NULL;
1201 int r, k;
8ba9fd9c
LP
1202
1203 assert(q);
1204
45ec7efb 1205 q->n_cname_redirects ++;
faa133f3 1206 if (q->n_cname_redirects > CNAME_MAX)
8ba9fd9c
LP
1207 return -ELOOP;
1208
23b298bc 1209 r = dns_question_cname_redirect(q->question_idna, cname, &nq_idna);
faa133f3
LP
1210 if (r < 0)
1211 return r;
23b298bc 1212 else if (r > 0)
8ec76e6a 1213 log_debug("Following CNAME/DNAME %s → %s.", dns_question_first_name(q->question_idna), dns_question_first_name(nq_idna));
23b298bc
LP
1214
1215 k = dns_question_is_equal(q->question_idna, q->question_utf8);
1216 if (k < 0)
1217 return r;
1218 if (k > 0) {
1219 /* Same question? Shortcut new question generation */
1220 nq_utf8 = dns_question_ref(nq_idna);
1221 k = r;
1222 } else {
1223 k = dns_question_cname_redirect(q->question_utf8, cname, &nq_utf8);
1224 if (k < 0)
1225 return k;
1226 else if (k > 0)
8ec76e6a 1227 log_debug("Following UTF8 CNAME/DNAME %s → %s.", dns_question_first_name(q->question_utf8), dns_question_first_name(nq_utf8));
23b298bc 1228 }
8ba9fd9c 1229
23b298bc
LP
1230 if (r == 0 && k == 0) /* No actual cname happened? */
1231 return -ELOOP;
1232
1233 dns_question_unref(q->question_idna);
1234 q->question_idna = nq_idna;
1235 nq_idna = NULL;
bc7669cf 1236
23b298bc
LP
1237 dns_question_unref(q->question_utf8);
1238 q->question_utf8 = nq_utf8;
1239 nq_utf8 = NULL;
8ba9fd9c 1240
7820b320
LP
1241 dns_query_free_candidates(q);
1242 dns_query_reset_answer(q);
ec2c5e43 1243 q->state = DNS_TRANSACTION_NULL;
322345fd 1244
59a89990
LP
1245 /* Turn off searching for the new name */
1246 q->flags |= SD_RESOLVED_NO_SEARCH;
1247
8ba9fd9c
LP
1248 return 0;
1249}
82bd6ddd 1250
45ec7efb
LP
1251int dns_query_process_cname(DnsQuery *q) {
1252 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *cname = NULL;
23b298bc 1253 DnsQuestion *question;
45ec7efb
LP
1254 DnsResourceRecord *rr;
1255 int r;
1256
1257 assert(q);
1258
7588460a
TG
1259 if (!IN_SET(q->state, DNS_TRANSACTION_SUCCESS, DNS_TRANSACTION_NULL))
1260 return DNS_QUERY_NOMATCH;
45ec7efb 1261
23b298bc 1262 question = dns_query_question_for_protocol(q, q->answer_protocol);
45ec7efb 1263
23b298bc
LP
1264 DNS_ANSWER_FOREACH(rr, q->answer) {
1265 r = dns_question_matches_rr(question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain));
45ec7efb
LP
1266 if (r < 0)
1267 return r;
1268 if (r > 0)
7588460a 1269 return DNS_QUERY_MATCH; /* The answer matches directly, no need to follow cnames */
45ec7efb 1270
542e0c84 1271 r = dns_question_matches_cname_or_dname(question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain));
45ec7efb
LP
1272 if (r < 0)
1273 return r;
1274 if (r > 0 && !cname)
1275 cname = dns_resource_record_ref(rr);
1276 }
1277
1278 if (!cname)
7588460a 1279 return DNS_QUERY_NOMATCH; /* No match and no cname to follow */
45ec7efb
LP
1280
1281 if (q->flags & SD_RESOLVED_NO_CNAME)
1282 return -ELOOP;
1283
1284 /* OK, let's actually follow the CNAME */
1285 r = dns_query_cname_redirect(q, cname);
1286 if (r < 0)
1287 return r;
1288
1289 /* Let's see if the answer can already answer the new
1290 * redirected question */
7588460a
TG
1291 r = dns_query_process_cname(q);
1292 if (r != DNS_QUERY_NOMATCH)
1293 return r;
45ec7efb
LP
1294
1295 /* OK, it cannot, let's begin with the new query */
1296 r = dns_query_go(q);
1297 if (r < 0)
1298 return r;
1299
7588460a 1300 return DNS_QUERY_RESTARTED; /* We restarted the query for a new cname */
45ec7efb
LP
1301}
1302
82bd6ddd
LP
1303static int on_bus_track(sd_bus_track *t, void *userdata) {
1304 DnsQuery *q = userdata;
1305
1306 assert(t);
1307 assert(q);
1308
1309 log_debug("Client of active query vanished, aborting query.");
1310 dns_query_complete(q, DNS_TRANSACTION_ABORTED);
1311 return 0;
1312}
1313
966c66e3 1314int dns_query_bus_track(DnsQuery *q, sd_bus_message *m) {
82bd6ddd
LP
1315 int r;
1316
1317 assert(q);
1318 assert(m);
1319
1320 if (!q->bus_track) {
966c66e3 1321 r = sd_bus_track_new(sd_bus_message_get_bus(m), &q->bus_track, on_bus_track, q);
82bd6ddd
LP
1322 if (r < 0)
1323 return r;
1324 }
1325
1326 r = sd_bus_track_add_sender(q->bus_track, m);
1327 if (r < 0)
1328 return r;
1329
1330 return 0;
1331}
23b298bc
LP
1332
1333DnsQuestion* dns_query_question_for_protocol(DnsQuery *q, DnsProtocol protocol) {
1334 assert(q);
1335
1336 switch (protocol) {
1337
1338 case DNS_PROTOCOL_DNS:
1339 return q->question_idna;
1340
1341 case DNS_PROTOCOL_MDNS:
1342 case DNS_PROTOCOL_LLMNR:
1343 return q->question_utf8;
1344
1345 default:
1346 return NULL;
1347 }
1348}
1349
1350const char *dns_query_string(DnsQuery *q) {
1351 const char *name;
1352 int r;
1353
1354 /* Returns a somewhat useful human-readable lookup key string for this query */
1355
1356 if (q->request_address_string)
1357 return q->request_address_string;
1358
1359 if (q->request_address_valid) {
1360 r = in_addr_to_string(q->request_family, &q->request_address, &q->request_address_string);
1361 if (r >= 0)
1362 return q->request_address_string;
1363 }
1364
1365 name = dns_question_first_name(q->question_utf8);
1366 if (name)
1367 return name;
1368
1369 return dns_question_first_name(q->question_idna);
1370}