]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-query.c
resolved: move dns_type_to_af() to dns-type.c
[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
23b298bc 598static int synthesize_localhost_rr(DnsQuery *q, const DnsResourceKey *key, DnsAnswer **answer) {
78c6a153
LP
599 int r;
600
601 assert(q);
602 assert(key);
603 assert(answer);
604
605 r = dns_answer_reserve(answer, 2);
606 if (r < 0)
607 return r;
608
609 if (IN_SET(key->type, DNS_TYPE_A, DNS_TYPE_ANY)) {
610 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
611
612 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, DNS_RESOURCE_KEY_NAME(key));
613 if (!rr)
614 return -ENOMEM;
615
616 rr->a.in_addr.s_addr = htobe32(INADDR_LOOPBACK);
617
105e1512 618 r = dns_answer_add(*answer, rr, SYNTHESIZE_IFINDEX(q->ifindex), DNS_ANSWER_AUTHENTICATED);
78c6a153
LP
619 if (r < 0)
620 return r;
621 }
622
623 if (IN_SET(key->type, DNS_TYPE_AAAA, DNS_TYPE_ANY)) {
624 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
625
626 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, DNS_RESOURCE_KEY_NAME(key));
627 if (!rr)
628 return -ENOMEM;
629
630 rr->aaaa.in6_addr = in6addr_loopback;
631
105e1512 632 r = dns_answer_add(*answer, rr, SYNTHESIZE_IFINDEX(q->ifindex), DNS_ANSWER_AUTHENTICATED);
78c6a153
LP
633 if (r < 0)
634 return r;
635 }
636
637 return 0;
638}
639
105e1512 640static int answer_add_ptr(DnsAnswer **answer, const char *from, const char *to, int ifindex, DnsAnswerFlags flags) {
78c6a153
LP
641 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
642
643 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_PTR, from);
644 if (!rr)
645 return -ENOMEM;
646
647 rr->ptr.name = strdup(to);
648 if (!rr->ptr.name)
649 return -ENOMEM;
650
105e1512 651 return dns_answer_add(*answer, rr, ifindex, flags);
78c6a153
LP
652}
653
23b298bc 654static int synthesize_localhost_ptr(DnsQuery *q, const DnsResourceKey *key, DnsAnswer **answer) {
78c6a153
LP
655 int r;
656
657 assert(q);
658 assert(key);
659 assert(answer);
660
78c6a153 661 if (IN_SET(key->type, DNS_TYPE_PTR, DNS_TYPE_ANY)) {
105e1512
LP
662 r = dns_answer_reserve(answer, 1);
663 if (r < 0)
664 return r;
665
666 r = answer_add_ptr(answer, DNS_RESOURCE_KEY_NAME(key), "localhost", SYNTHESIZE_IFINDEX(q->ifindex), DNS_ANSWER_AUTHENTICATED);
78c6a153
LP
667 if (r < 0)
668 return r;
669 }
670
671 return 0;
672}
673
674static int answer_add_addresses_rr(
675 DnsAnswer **answer,
676 const char *name,
677 struct local_address *addresses,
678 unsigned n_addresses) {
679
680 unsigned j;
681 int r;
682
683 assert(answer);
684 assert(name);
685
686 r = dns_answer_reserve(answer, n_addresses);
687 if (r < 0)
688 return r;
689
690 for (j = 0; j < n_addresses; j++) {
691 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
692
693 r = dns_resource_record_new_address(&rr, addresses[j].family, &addresses[j].address, name);
694 if (r < 0)
695 return r;
696
105e1512 697 r = dns_answer_add(*answer, rr, addresses[j].ifindex, DNS_ANSWER_AUTHENTICATED);
78c6a153
LP
698 if (r < 0)
699 return r;
700 }
701
702 return 0;
703}
704
705static int answer_add_addresses_ptr(
706 DnsAnswer **answer,
707 const char *name,
708 struct local_address *addresses,
709 unsigned n_addresses,
710 int af, const union in_addr_union *match) {
711
712 unsigned j;
713 int r;
714
715 assert(answer);
716 assert(name);
717
718 for (j = 0; j < n_addresses; j++) {
719 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
720
721 if (af != AF_UNSPEC) {
722
723 if (addresses[j].family != af)
724 continue;
725
726 if (match && !in_addr_equal(af, match, &addresses[j].address))
727 continue;
728 }
729
730 r = dns_answer_reserve(answer, 1);
731 if (r < 0)
732 return r;
733
734 r = dns_resource_record_new_reverse(&rr, addresses[j].family, &addresses[j].address, name);
735 if (r < 0)
736 return r;
737
105e1512 738 r = dns_answer_add(*answer, rr, addresses[j].ifindex, DNS_ANSWER_AUTHENTICATED);
78c6a153
LP
739 if (r < 0)
740 return r;
741 }
742
743 return 0;
744}
745
23b298bc 746static int synthesize_system_hostname_rr(DnsQuery *q, const DnsResourceKey *key, DnsAnswer **answer) {
78c6a153
LP
747 _cleanup_free_ struct local_address *addresses = NULL;
748 int n = 0, af;
749
750 assert(q);
751 assert(key);
752 assert(answer);
753
754 af = dns_type_to_af(key->type);
755 if (af >= 0) {
756 n = local_addresses(q->manager->rtnl, q->ifindex, af, &addresses);
757 if (n < 0)
758 return n;
759
760 if (n == 0) {
761 struct local_address buffer[2];
762
763 /* If we have no local addresses then use ::1
764 * and 127.0.0.2 as local ones. */
765
766 if (af == AF_INET || af == AF_UNSPEC)
767 buffer[n++] = (struct local_address) {
768 .family = AF_INET,
769 .ifindex = SYNTHESIZE_IFINDEX(q->ifindex),
770 .address.in.s_addr = htobe32(0x7F000002),
771 };
772
773 if (af == AF_INET6 || af == AF_UNSPEC)
774 buffer[n++] = (struct local_address) {
775 .family = AF_INET6,
776 .ifindex = SYNTHESIZE_IFINDEX(q->ifindex),
777 .address.in6 = in6addr_loopback,
778 };
779
780 return answer_add_addresses_rr(answer, DNS_RESOURCE_KEY_NAME(key), buffer, n);
781 }
782 }
783
784 return answer_add_addresses_rr(answer, DNS_RESOURCE_KEY_NAME(key), addresses, n);
785}
786
787static int synthesize_system_hostname_ptr(DnsQuery *q, int af, const union in_addr_union *address, DnsAnswer **answer) {
788 _cleanup_free_ struct local_address *addresses = NULL;
789 int n, r;
790
791 assert(q);
792 assert(address);
793 assert(answer);
794
795 if (af == AF_INET && address->in.s_addr == htobe32(0x7F000002)) {
796
797 /* Always map the IPv4 address 127.0.0.2 to the local
798 * hostname, in addition to "localhost": */
799
800 r = dns_answer_reserve(answer, 3);
801 if (r < 0)
802 return r;
803
105e1512 804 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
805 if (r < 0)
806 return r;
807
105e1512 808 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
809 if (r < 0)
810 return r;
811
105e1512 812 r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", "localhost", SYNTHESIZE_IFINDEX(q->ifindex), DNS_ANSWER_AUTHENTICATED);
78c6a153
LP
813 if (r < 0)
814 return r;
815
816 return 0;
817 }
818
819 n = local_addresses(q->manager->rtnl, q->ifindex, af, &addresses);
820 if (n < 0)
821 return n;
822
823 r = answer_add_addresses_ptr(answer, q->manager->llmnr_hostname, addresses, n, af, address);
824 if (r < 0)
825 return r;
826
827 return answer_add_addresses_ptr(answer, q->manager->mdns_hostname, addresses, n, af, address);
828}
829
23b298bc 830static int synthesize_gateway_rr(DnsQuery *q, const DnsResourceKey *key, DnsAnswer **answer) {
78c6a153
LP
831 _cleanup_free_ struct local_address *addresses = NULL;
832 int n = 0, af;
833
834 assert(q);
835 assert(key);
836 assert(answer);
837
838 af = dns_type_to_af(key->type);
839 if (af >= 0) {
840 n = local_gateways(q->manager->rtnl, q->ifindex, af, &addresses);
841 if (n < 0)
842 return n;
843 }
844
845 return answer_add_addresses_rr(answer, DNS_RESOURCE_KEY_NAME(key), addresses, n);
846}
847
848static int synthesize_gateway_ptr(DnsQuery *q, int af, const union in_addr_union *address, DnsAnswer **answer) {
849 _cleanup_free_ struct local_address *addresses = NULL;
850 int n;
851
852 assert(q);
853 assert(address);
854 assert(answer);
855
856 n = local_gateways(q->manager->rtnl, q->ifindex, af, &addresses);
857 if (n < 0)
858 return n;
859
860 return answer_add_addresses_ptr(answer, "gateway", addresses, n, af, address);
861}
862
863static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) {
2a1037af 864 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
23b298bc 865 DnsResourceKey *key;
2a1037af
LP
866 int r;
867
868 assert(q);
869 assert(state);
870
871 /* Tries to synthesize localhost RR replies where appropriate */
872
873 if (!IN_SET(*state,
3bbdc31d 874 DNS_TRANSACTION_RCODE_FAILURE,
2a1037af
LP
875 DNS_TRANSACTION_NO_SERVERS,
876 DNS_TRANSACTION_TIMEOUT,
edbcc1fd
LP
877 DNS_TRANSACTION_ATTEMPTS_MAX_REACHED,
878 DNS_TRANSACTION_NETWORK_DOWN))
78c6a153 879 return 0;
2a1037af 880
23b298bc 881 DNS_QUESTION_FOREACH(key, q->question_utf8) {
78c6a153 882 union in_addr_union address;
2a1037af 883 const char *name;
78c6a153 884 int af;
2a1037af 885
23b298bc
LP
886 if (key->class != DNS_CLASS_IN &&
887 key->class != DNS_CLASS_ANY)
2a1037af
LP
888 continue;
889
23b298bc 890 name = DNS_RESOURCE_KEY_NAME(key);
2a1037af
LP
891
892 if (is_localhost(name)) {
893
23b298bc 894 r = synthesize_localhost_rr(q, key, &answer);
78c6a153
LP
895 if (r < 0)
896 return log_error_errno(r, "Failed to synthesize localhost RRs: %m");
2a1037af 897
78c6a153 898 } else if (manager_is_own_hostname(q->manager, name)) {
2a1037af 899
23b298bc 900 r = synthesize_system_hostname_rr(q, key, &answer);
78c6a153
LP
901 if (r < 0)
902 return log_error_errno(r, "Failed to synthesize system hostname RRs: %m");
2a1037af 903
78c6a153 904 } else if (is_gateway_hostname(name)) {
2a1037af 905
23b298bc 906 r = synthesize_gateway_rr(q, key, &answer);
78c6a153
LP
907 if (r < 0)
908 return log_error_errno(r, "Failed to synthesize gateway RRs: %m");
2a1037af 909
78c6a153
LP
910 } else if ((dns_name_endswith(name, "127.in-addr.arpa") > 0 && dns_name_equal(name, "2.0.0.127.in-addr.arpa") == 0) ||
911 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 912
23b298bc 913 r = synthesize_localhost_ptr(q, key, &answer);
78c6a153
LP
914 if (r < 0)
915 return log_error_errno(r, "Failed to synthesize localhost PTR RRs: %m");
2a1037af 916
78c6a153 917 } else if (dns_name_address(name, &af, &address) > 0) {
2a1037af 918
78c6a153
LP
919 r = synthesize_system_hostname_ptr(q, af, &address, &answer);
920 if (r < 0)
921 return log_error_errno(r, "Failed to synthesize system hostname PTR RR: %m");
2a1037af 922
78c6a153
LP
923 r = synthesize_gateway_ptr(q, af, &address, &answer);
924 if (r < 0)
925 return log_error_errno(r, "Failed to synthesize gateway hostname PTR RR: %m");
2a1037af
LP
926 }
927 }
928
929 if (!answer)
78c6a153 930 return 0;
2a1037af
LP
931
932 dns_answer_unref(q->answer);
933 q->answer = answer;
934 answer = NULL;
935
2a1037af 936 q->answer_rcode = DNS_RCODE_SUCCESS;
801ad6a6
LP
937 q->answer_protocol = SYNTHESIZE_PROTOCOL(q->flags);
938 q->answer_family = SYNTHESIZE_FAMILY(q->flags);
2a1037af
LP
939
940 *state = DNS_TRANSACTION_SUCCESS;
78c6a153
LP
941
942 return 1;
2a1037af
LP
943}
944
322345fd 945int dns_query_go(DnsQuery *q) {
8ba9fd9c
LP
946 DnsScopeMatch found = DNS_SCOPE_NO;
947 DnsScope *s, *first = NULL;
801ad6a6 948 DnsQueryCandidate *c;
8ba9fd9c
LP
949 int r;
950
951 assert(q);
952
ec2c5e43 953 if (q->state != DNS_TRANSACTION_NULL)
8ba9fd9c
LP
954 return 0;
955
8ba9fd9c 956 LIST_FOREACH(scopes, s, q->manager->dns_scopes) {
74b2466e 957 DnsScopeMatch match;
23b298bc
LP
958 const char *name;
959
960 name = dns_question_first_name(dns_query_question_for_protocol(q, s->protocol));
961 if (!name)
962 continue;
74b2466e 963
51323288 964 match = dns_scope_good_domain(s, q->ifindex, q->flags, name);
74b2466e
LP
965 if (match < 0)
966 return match;
967
968 if (match == DNS_SCOPE_NO)
969 continue;
970
971 found = match;
972
973 if (match == DNS_SCOPE_YES) {
974 first = s;
975 break;
976 } else {
977 assert(match == DNS_SCOPE_MAYBE);
978
979 if (!first)
980 first = s;
981 }
982 }
983
2a1037af
LP
984 if (found == DNS_SCOPE_NO) {
985 DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS;
986
987 dns_query_synthesize_reply(q, &state);
d634711b
LP
988 dns_query_complete(q, state);
989 return 1;
2a1037af 990 }
74b2466e 991
801ad6a6 992 r = dns_query_add_candidate(q, first);
74b2466e 993 if (r < 0)
ec2c5e43 994 goto fail;
74b2466e 995
74b2466e
LP
996 LIST_FOREACH(scopes, s, first->scopes_next) {
997 DnsScopeMatch match;
23b298bc
LP
998 const char *name;
999
1000 name = dns_question_first_name(dns_query_question_for_protocol(q, s->protocol));
1001 if (!name)
1002 continue;
74b2466e 1003
51323288 1004 match = dns_scope_good_domain(s, q->ifindex, q->flags, name);
74b2466e 1005 if (match < 0)
ec2c5e43 1006 goto fail;
74b2466e
LP
1007
1008 if (match != found)
1009 continue;
1010
801ad6a6 1011 r = dns_query_add_candidate(q, s);
74b2466e 1012 if (r < 0)
ec2c5e43 1013 goto fail;
74b2466e
LP
1014 }
1015
faa133f3 1016 q->answer = dns_answer_unref(q->answer);
faa133f3 1017 q->answer_rcode = 0;
51323288
LP
1018 q->answer_family = AF_UNSPEC;
1019 q->answer_protocol = _DNS_PROTOCOL_INVALID;
74b2466e 1020
9a015429
LP
1021 r = sd_event_add_time(
1022 q->manager->event,
1023 &q->timeout_event_source,
1024 clock_boottime_or_monotonic(),
1025 now(clock_boottime_or_monotonic()) + QUERY_TIMEOUT_USEC, 0,
1026 on_query_timeout, q);
74b2466e
LP
1027 if (r < 0)
1028 goto fail;
1029
aa4a9deb
LP
1030 (void) sd_event_source_set_description(q->timeout_event_source, "query-timeout");
1031
ec2c5e43 1032 q->state = DNS_TRANSACTION_PENDING;
faa133f3 1033 q->block_ready++;
74b2466e 1034
801ad6a6
LP
1035 /* Start the transactions */
1036 LIST_FOREACH(candidates_by_query, c, q->candidates) {
1037 r = dns_query_candidate_go(c);
1038 if (r < 0) {
1039 q->block_ready--;
ec2c5e43 1040 goto fail;
801ad6a6 1041 }
74b2466e
LP
1042 }
1043
faa133f3
LP
1044 q->block_ready--;
1045 dns_query_ready(q);
322345fd 1046
8ba9fd9c 1047 return 1;
74b2466e
LP
1048
1049fail:
8ba9fd9c 1050 dns_query_stop(q);
74b2466e
LP
1051 return r;
1052}
1053
801ad6a6 1054static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) {
ec2c5e43 1055 DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS;
547973de 1056 bool has_authenticated = false, has_non_authenticated = false;
019036a4 1057 DnssecResult dnssec_result_authenticated = _DNSSEC_RESULT_INVALID, dnssec_result_non_authenticated = _DNSSEC_RESULT_INVALID;
801ad6a6 1058 DnsTransaction *t;
faa133f3 1059 Iterator i;
547973de 1060 int r;
74b2466e
LP
1061
1062 assert(q);
1063
801ad6a6
LP
1064 if (!c) {
1065 dns_query_synthesize_reply(q, &state);
1066 dns_query_complete(q, state);
74b2466e 1067 return;
801ad6a6 1068 }
74b2466e 1069
801ad6a6 1070 SET_FOREACH(t, c->transactions, i) {
74b2466e 1071
801ad6a6 1072 switch (t->state) {
934e9b10 1073
801ad6a6
LP
1074 case DNS_TRANSACTION_SUCCESS: {
1075 /* We found a successfuly reply, merge it into the answer */
547973de
LP
1076 r = dns_answer_extend(&q->answer, t->answer);
1077 if (r < 0) {
801ad6a6
LP
1078 dns_query_complete(q, DNS_TRANSACTION_RESOURCES);
1079 return;
1080 }
019036a4 1081
ae6a4bbf 1082 q->answer_rcode = t->answer_rcode;
801ad6a6 1083
019036a4 1084 if (t->answer_authenticated) {
931851e8 1085 has_authenticated = true;
019036a4
LP
1086 dnssec_result_authenticated = t->answer_dnssec_result;
1087 } else {
931851e8 1088 has_non_authenticated = true;
019036a4
LP
1089 dnssec_result_non_authenticated = t->answer_dnssec_result;
1090 }
931851e8 1091
801ad6a6
LP
1092 state = DNS_TRANSACTION_SUCCESS;
1093 break;
1094 }
1095
801ad6a6 1096 case DNS_TRANSACTION_NULL:
547973de
LP
1097 case DNS_TRANSACTION_PENDING:
1098 case DNS_TRANSACTION_VALIDATING:
801ad6a6
LP
1099 case DNS_TRANSACTION_ABORTED:
1100 /* Ignore transactions that didn't complete */
1101 continue;
1102
1103 default:
1104 /* Any kind of failure? Store the data away,
1105 * if there's nothing stored yet. */
934e9b10 1106
019036a4
LP
1107 if (state == DNS_TRANSACTION_SUCCESS)
1108 continue;
934e9b10 1109
d38d5ca6 1110 q->answer = dns_answer_unref(q->answer);
019036a4
LP
1111 q->answer_rcode = t->answer_rcode;
1112 q->answer_dnssec_result = t->answer_dnssec_result;
934e9b10 1113
019036a4 1114 state = t->state;
801ad6a6 1115 break;
74b2466e 1116 }
801ad6a6 1117 }
74b2466e 1118
019036a4
LP
1119 if (state == DNS_TRANSACTION_SUCCESS) {
1120 q->answer_authenticated = has_authenticated && !has_non_authenticated;
1121 q->answer_dnssec_result = q->answer_authenticated ? dnssec_result_authenticated : dnssec_result_non_authenticated;
1122 }
1123
801ad6a6
LP
1124 q->answer_protocol = c->scope->protocol;
1125 q->answer_family = c->scope->family;
934e9b10 1126
801ad6a6
LP
1127 dns_search_domain_unref(q->answer_search_domain);
1128 q->answer_search_domain = dns_search_domain_ref(c->search_domain);
7e8e0422 1129
801ad6a6
LP
1130 dns_query_synthesize_reply(q, &state);
1131 dns_query_complete(q, state);
1132}
934e9b10 1133
801ad6a6 1134void dns_query_ready(DnsQuery *q) {
74b2466e 1135
801ad6a6
LP
1136 DnsQueryCandidate *bad = NULL, *c;
1137 bool pending = false;
74b2466e 1138
801ad6a6 1139 assert(q);
547973de 1140 assert(DNS_TRANSACTION_IS_LIVE(q->state));
e4501ed4 1141
801ad6a6
LP
1142 /* Note that this call might invalidate the query. Callers
1143 * should hence not attempt to access the query or transaction
1144 * after calling this function, unless the block_ready
1145 * counter was explicitly bumped before doing so. */
1146
1147 if (q->block_ready > 0)
1148 return;
1149
1150 LIST_FOREACH(candidates_by_query, c, q->candidates) {
1151 DnsTransactionState state;
1152
1153 state = dns_query_candidate_state(c);
1154 switch (state) {
1155
1156 case DNS_TRANSACTION_SUCCESS:
547973de 1157 /* One of the candidates is successful,
801ad6a6
LP
1158 * let's use it, and copy its data out */
1159 dns_query_accept(q, c);
e4501ed4
LP
1160 return;
1161
801ad6a6 1162 case DNS_TRANSACTION_NULL:
547973de
LP
1163 case DNS_TRANSACTION_PENDING:
1164 case DNS_TRANSACTION_VALIDATING:
1165 /* One of the candidates is still going on,
1166 * let's maybe wait for it */
801ad6a6
LP
1167 pending = true;
1168 break;
e4501ed4 1169
801ad6a6
LP
1170 default:
1171 /* Any kind of failure */
1172 bad = c;
1173 break;
1174 }
faa133f3 1175 }
74b2466e 1176
801ad6a6
LP
1177 if (pending)
1178 return;
2a1037af 1179
801ad6a6 1180 dns_query_accept(q, bad);
74b2466e 1181}
8ba9fd9c 1182
45ec7efb 1183static int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname) {
23b298bc
LP
1184 _cleanup_(dns_question_unrefp) DnsQuestion *nq_idna = NULL, *nq_utf8 = NULL;
1185 int r, k;
8ba9fd9c
LP
1186
1187 assert(q);
1188
45ec7efb 1189 q->n_cname_redirects ++;
faa133f3 1190 if (q->n_cname_redirects > CNAME_MAX)
8ba9fd9c
LP
1191 return -ELOOP;
1192
23b298bc 1193 r = dns_question_cname_redirect(q->question_idna, cname, &nq_idna);
faa133f3
LP
1194 if (r < 0)
1195 return r;
23b298bc 1196 else if (r > 0)
8ec76e6a 1197 log_debug("Following CNAME/DNAME %s → %s.", dns_question_first_name(q->question_idna), dns_question_first_name(nq_idna));
23b298bc
LP
1198
1199 k = dns_question_is_equal(q->question_idna, q->question_utf8);
1200 if (k < 0)
1201 return r;
1202 if (k > 0) {
1203 /* Same question? Shortcut new question generation */
1204 nq_utf8 = dns_question_ref(nq_idna);
1205 k = r;
1206 } else {
1207 k = dns_question_cname_redirect(q->question_utf8, cname, &nq_utf8);
1208 if (k < 0)
1209 return k;
1210 else if (k > 0)
8ec76e6a 1211 log_debug("Following UTF8 CNAME/DNAME %s → %s.", dns_question_first_name(q->question_utf8), dns_question_first_name(nq_utf8));
23b298bc 1212 }
8ba9fd9c 1213
23b298bc
LP
1214 if (r == 0 && k == 0) /* No actual cname happened? */
1215 return -ELOOP;
1216
1217 dns_question_unref(q->question_idna);
1218 q->question_idna = nq_idna;
1219 nq_idna = NULL;
bc7669cf 1220
23b298bc
LP
1221 dns_question_unref(q->question_utf8);
1222 q->question_utf8 = nq_utf8;
1223 nq_utf8 = NULL;
8ba9fd9c 1224
7820b320
LP
1225 dns_query_free_candidates(q);
1226 dns_query_reset_answer(q);
ec2c5e43 1227 q->state = DNS_TRANSACTION_NULL;
322345fd 1228
59a89990
LP
1229 /* Turn off searching for the new name */
1230 q->flags |= SD_RESOLVED_NO_SEARCH;
1231
8ba9fd9c
LP
1232 return 0;
1233}
82bd6ddd 1234
45ec7efb
LP
1235int dns_query_process_cname(DnsQuery *q) {
1236 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *cname = NULL;
23b298bc 1237 DnsQuestion *question;
45ec7efb
LP
1238 DnsResourceRecord *rr;
1239 int r;
1240
1241 assert(q);
1242
7588460a
TG
1243 if (!IN_SET(q->state, DNS_TRANSACTION_SUCCESS, DNS_TRANSACTION_NULL))
1244 return DNS_QUERY_NOMATCH;
45ec7efb 1245
23b298bc 1246 question = dns_query_question_for_protocol(q, q->answer_protocol);
45ec7efb 1247
23b298bc
LP
1248 DNS_ANSWER_FOREACH(rr, q->answer) {
1249 r = dns_question_matches_rr(question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain));
45ec7efb
LP
1250 if (r < 0)
1251 return r;
1252 if (r > 0)
7588460a 1253 return DNS_QUERY_MATCH; /* The answer matches directly, no need to follow cnames */
45ec7efb 1254
542e0c84 1255 r = dns_question_matches_cname_or_dname(question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain));
45ec7efb
LP
1256 if (r < 0)
1257 return r;
1258 if (r > 0 && !cname)
1259 cname = dns_resource_record_ref(rr);
1260 }
1261
1262 if (!cname)
7588460a 1263 return DNS_QUERY_NOMATCH; /* No match and no cname to follow */
45ec7efb
LP
1264
1265 if (q->flags & SD_RESOLVED_NO_CNAME)
1266 return -ELOOP;
1267
1268 /* OK, let's actually follow the CNAME */
1269 r = dns_query_cname_redirect(q, cname);
1270 if (r < 0)
1271 return r;
1272
1273 /* Let's see if the answer can already answer the new
1274 * redirected question */
7588460a
TG
1275 r = dns_query_process_cname(q);
1276 if (r != DNS_QUERY_NOMATCH)
1277 return r;
45ec7efb
LP
1278
1279 /* OK, it cannot, let's begin with the new query */
1280 r = dns_query_go(q);
1281 if (r < 0)
1282 return r;
1283
7588460a 1284 return DNS_QUERY_RESTARTED; /* We restarted the query for a new cname */
45ec7efb
LP
1285}
1286
82bd6ddd
LP
1287static int on_bus_track(sd_bus_track *t, void *userdata) {
1288 DnsQuery *q = userdata;
1289
1290 assert(t);
1291 assert(q);
1292
1293 log_debug("Client of active query vanished, aborting query.");
1294 dns_query_complete(q, DNS_TRANSACTION_ABORTED);
1295 return 0;
1296}
1297
966c66e3 1298int dns_query_bus_track(DnsQuery *q, sd_bus_message *m) {
82bd6ddd
LP
1299 int r;
1300
1301 assert(q);
1302 assert(m);
1303
1304 if (!q->bus_track) {
966c66e3 1305 r = sd_bus_track_new(sd_bus_message_get_bus(m), &q->bus_track, on_bus_track, q);
82bd6ddd
LP
1306 if (r < 0)
1307 return r;
1308 }
1309
1310 r = sd_bus_track_add_sender(q->bus_track, m);
1311 if (r < 0)
1312 return r;
1313
1314 return 0;
1315}
23b298bc
LP
1316
1317DnsQuestion* dns_query_question_for_protocol(DnsQuery *q, DnsProtocol protocol) {
1318 assert(q);
1319
1320 switch (protocol) {
1321
1322 case DNS_PROTOCOL_DNS:
1323 return q->question_idna;
1324
1325 case DNS_PROTOCOL_MDNS:
1326 case DNS_PROTOCOL_LLMNR:
1327 return q->question_utf8;
1328
1329 default:
1330 return NULL;
1331 }
1332}
1333
1334const char *dns_query_string(DnsQuery *q) {
1335 const char *name;
1336 int r;
1337
1338 /* Returns a somewhat useful human-readable lookup key string for this query */
1339
1340 if (q->request_address_string)
1341 return q->request_address_string;
1342
1343 if (q->request_address_valid) {
1344 r = in_addr_to_string(q->request_family, &q->request_address, &q->request_address_string);
1345 if (r >= 0)
1346 return q->request_address_string;
1347 }
1348
1349 name = dns_question_first_name(q->question_utf8);
1350 if (name)
1351 return name;
1352
1353 return dns_question_first_name(q->question_idna);
1354}