]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-query.c
resolved: beef up complex dnssec test to also use ResolveAddress() and do IDNA checks
[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
74b2466e 312DnsQuery *dns_query_free(DnsQuery *q) {
74b2466e
LP
313 if (!q)
314 return NULL;
315
45ec7efb
LP
316 while (q->auxiliary_queries)
317 dns_query_free(q->auxiliary_queries);
318
319 if (q->auxiliary_for) {
320 assert(q->auxiliary_for->n_auxiliary_queries > 0);
321 q->auxiliary_for->n_auxiliary_queries--;
322 LIST_REMOVE(auxiliary_queries, q->auxiliary_for->auxiliary_queries, q);
323 }
324
801ad6a6
LP
325 while (q->candidates)
326 dns_query_candidate_free(q->candidates);
322345fd 327
23b298bc
LP
328 dns_question_unref(q->question_idna);
329 dns_question_unref(q->question_utf8);
faa133f3 330 dns_answer_unref(q->answer);
801ad6a6 331 dns_search_domain_unref(q->answer_search_domain);
322345fd 332
ec2c5e43 333 sd_bus_message_unref(q->request);
82bd6ddd 334 sd_bus_track_unref(q->bus_track);
74b2466e 335
23b298bc
LP
336 free(q->request_address_string);
337
39762fdf 338 if (q->manager) {
74b2466e 339 LIST_REMOVE(queries, q->manager->dns_queries, q);
39762fdf
LP
340 q->manager->n_dns_queries--;
341 }
74b2466e 342
74b2466e
LP
343 free(q);
344
345 return NULL;
346}
347
23b298bc
LP
348int dns_query_new(
349 Manager *m,
350 DnsQuery **ret,
351 DnsQuestion *question_utf8,
352 DnsQuestion *question_idna,
353 int ifindex, uint64_t flags) {
354
74b2466e 355 _cleanup_(dns_query_freep) DnsQuery *q = NULL;
23b298bc
LP
356 DnsResourceKey *key;
357 bool good = false;
faa133f3 358 int r;
74b2466e
LP
359
360 assert(m);
361
23b298bc
LP
362 if (dns_question_size(question_utf8) > 0) {
363 r = dns_question_is_valid_for_query(question_utf8);
364 if (r < 0)
365 return r;
366 if (r == 0)
367 return -EINVAL;
368
369 good = true;
370 }
371
372 /* If the IDNA and UTF8 questions are the same, merge their references */
373 r = dns_question_is_equal(question_idna, question_utf8);
faa133f3
LP
374 if (r < 0)
375 return r;
23b298bc
LP
376 if (r > 0)
377 question_idna = question_utf8;
378 else {
379 if (dns_question_size(question_idna) > 0) {
380 r = dns_question_is_valid_for_query(question_idna);
381 if (r < 0)
382 return r;
383 if (r == 0)
384 return -EINVAL;
385
386 good = true;
387 }
388 }
389
390 if (!good) /* don't allow empty queries */
391 return -EINVAL;
74b2466e 392
39762fdf
LP
393 if (m->n_dns_queries >= QUERIES_MAX)
394 return -EBUSY;
395
74b2466e
LP
396 q = new0(DnsQuery, 1);
397 if (!q)
398 return -ENOMEM;
399
23b298bc
LP
400 q->question_utf8 = dns_question_ref(question_utf8);
401 q->question_idna = dns_question_ref(question_idna);
51323288
LP
402 q->ifindex = ifindex;
403 q->flags = flags;
801ad6a6
LP
404 q->answer_family = AF_UNSPEC;
405 q->answer_protocol = _DNS_PROTOCOL_INVALID;
322345fd 406
23b298bc
LP
407 /* First dump UTF8 question */
408 DNS_QUESTION_FOREACH(key, question_utf8) {
409 _cleanup_free_ char *p = NULL;
e4501ed4 410
23b298bc 411 r = dns_resource_key_to_string(key, &p);
e4501ed4
LP
412 if (r < 0)
413 return r;
414
23b298bc
LP
415 log_debug("Looking up RR for %s.", strstrip(p));
416 }
417
418 /* And then dump the IDNA question, but only what hasn't been dumped already through the UTF8 question. */
419 DNS_QUESTION_FOREACH(key, question_idna) {
420 _cleanup_free_ char *p = NULL;
421
422 r = dns_question_contains(question_utf8, key);
423 if (r < 0)
424 return r;
425 if (r > 0)
426 continue;
427
428 r = dns_resource_key_to_string(key, &p);
429 if (r < 0)
430 return r;
431
432 log_debug("Looking up IDNA RR for %s.", strstrip(p));
74b2466e
LP
433 }
434
435 LIST_PREPEND(queries, m->dns_queries, q);
39762fdf 436 m->n_dns_queries++;
74b2466e
LP
437 q->manager = m;
438
8ba9fd9c
LP
439 if (ret)
440 *ret = q;
441 q = NULL;
442
443 return 0;
444}
445
45ec7efb
LP
446int dns_query_make_auxiliary(DnsQuery *q, DnsQuery *auxiliary_for) {
447 assert(q);
448 assert(auxiliary_for);
449
450 /* Ensure that that the query is not auxiliary yet, and
451 * nothing else is auxiliary to it either */
452 assert(!q->auxiliary_for);
453 assert(!q->auxiliary_queries);
454
455 /* Ensure that the unit we shall be made auxiliary for isn't
456 * auxiliary itself */
457 assert(!auxiliary_for->auxiliary_for);
458
459 if (auxiliary_for->n_auxiliary_queries >= AUXILIARY_QUERIES_MAX)
460 return -EAGAIN;
461
462 LIST_PREPEND(auxiliary_queries, auxiliary_for->auxiliary_queries, q);
463 q->auxiliary_for = auxiliary_for;
464
465 auxiliary_for->n_auxiliary_queries++;
466 return 0;
467}
468
ec2c5e43 469static void dns_query_complete(DnsQuery *q, DnsTransactionState state) {
8ba9fd9c 470 assert(q);
547973de
LP
471 assert(!DNS_TRANSACTION_IS_LIVE(state));
472 assert(DNS_TRANSACTION_IS_LIVE(q->state));
8ba9fd9c 473
322345fd
LP
474 /* Note that this call might invalidate the query. Callers
475 * should hence not attempt to access the query or transaction
476 * after calling this function. */
8ba9fd9c 477
8ba9fd9c
LP
478 q->state = state;
479
322345fd
LP
480 dns_query_stop(q);
481 if (q->complete)
482 q->complete(q);
8ba9fd9c
LP
483}
484
485static int on_query_timeout(sd_event_source *s, usec_t usec, void *userdata) {
486 DnsQuery *q = userdata;
487
488 assert(s);
489 assert(q);
490
ec2c5e43 491 dns_query_complete(q, DNS_TRANSACTION_TIMEOUT);
8ba9fd9c
LP
492 return 0;
493}
494
801ad6a6
LP
495static int dns_query_add_candidate(DnsQuery *q, DnsScope *s) {
496 DnsQueryCandidate *c;
faa133f3
LP
497 int r;
498
499 assert(q);
ec2c5e43 500 assert(s);
faa133f3 501
801ad6a6 502 r = dns_query_candidate_new(&c, q, s);
faa133f3
LP
503 if (r < 0)
504 return r;
505
801ad6a6 506 /* If this a single-label domain on DNS, we might append a suitable search domain first. */
22f711bb 507 if ((q->flags & SD_RESOLVED_NO_SEARCH) == 0) {
23b298bc 508 r = dns_scope_name_needs_search_domain(s, dns_question_first_name(q->question_idna));
22f711bb 509 if (r < 0)
801ad6a6 510 goto fail;
22f711bb
LP
511 if (r > 0) {
512 /* OK, we need a search domain now. Let's find one for this scope */
513
514 r = dns_query_candidate_next_search_domain(c);
515 if (r <= 0) /* if there's no search domain, then we won't add any transaction. */
516 goto fail;
517 }
faa133f3
LP
518 }
519
801ad6a6
LP
520 r = dns_query_candidate_setup_transactions(c);
521 if (r < 0)
522 goto fail;
523
faa133f3
LP
524 return 0;
525
801ad6a6
LP
526fail:
527 dns_query_candidate_free(c);
faa133f3
LP
528 return r;
529}
530
2a1037af
LP
531static int SYNTHESIZE_IFINDEX(int ifindex) {
532
78c6a153
LP
533 /* When the caller asked for resolving on a specific
534 * interface, we synthesize the answer for that
535 * interface. However, if nothing specific was claimed and we
536 * only return localhost RRs, we synthesize the answer for
2a1037af
LP
537 * localhost. */
538
539 if (ifindex > 0)
540 return ifindex;
541
542 return LOOPBACK_IFINDEX;
543}
544
545static int SYNTHESIZE_FAMILY(uint64_t flags) {
546
547 /* Picks an address family depending on set flags. This is
548 * purely for synthesized answers, where the family we return
549 * for the reply should match what was requested in the
550 * question, even though we are synthesizing the answer
551 * here. */
552
553 if (!(flags & SD_RESOLVED_DNS)) {
554 if (flags & SD_RESOLVED_LLMNR_IPV4)
555 return AF_INET;
556 if (flags & SD_RESOLVED_LLMNR_IPV6)
557 return AF_INET6;
558 }
559
560 return AF_UNSPEC;
561}
562
563static DnsProtocol SYNTHESIZE_PROTOCOL(uint64_t flags) {
564
565 /* Similar as SYNTHESIZE_FAMILY() but does this for the
566 * protocol. If resolving via DNS was requested, we claim it
567 * was DNS. Similar, if nothing specific was
568 * requested. However, if only resolving via LLMNR was
569 * requested we return that. */
570
571 if (flags & SD_RESOLVED_DNS)
572 return DNS_PROTOCOL_DNS;
573 if (flags & SD_RESOLVED_LLMNR)
574 return DNS_PROTOCOL_LLMNR;
575
576 return DNS_PROTOCOL_DNS;
577}
578
78c6a153
LP
579static int dns_type_to_af(uint16_t t) {
580 switch (t) {
581
582 case DNS_TYPE_A:
583 return AF_INET;
584
585 case DNS_TYPE_AAAA:
586 return AF_INET6;
587
588 case DNS_TYPE_ANY:
589 return AF_UNSPEC;
590
591 default:
592 return -EINVAL;
593 }
594}
595
23b298bc 596static int synthesize_localhost_rr(DnsQuery *q, const DnsResourceKey *key, DnsAnswer **answer) {
78c6a153
LP
597 int r;
598
599 assert(q);
600 assert(key);
601 assert(answer);
602
603 r = dns_answer_reserve(answer, 2);
604 if (r < 0)
605 return r;
606
607 if (IN_SET(key->type, DNS_TYPE_A, DNS_TYPE_ANY)) {
608 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
609
610 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, DNS_RESOURCE_KEY_NAME(key));
611 if (!rr)
612 return -ENOMEM;
613
614 rr->a.in_addr.s_addr = htobe32(INADDR_LOOPBACK);
615
105e1512 616 r = dns_answer_add(*answer, rr, SYNTHESIZE_IFINDEX(q->ifindex), DNS_ANSWER_AUTHENTICATED);
78c6a153
LP
617 if (r < 0)
618 return r;
619 }
620
621 if (IN_SET(key->type, DNS_TYPE_AAAA, DNS_TYPE_ANY)) {
622 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
623
624 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, DNS_RESOURCE_KEY_NAME(key));
625 if (!rr)
626 return -ENOMEM;
627
628 rr->aaaa.in6_addr = in6addr_loopback;
629
105e1512 630 r = dns_answer_add(*answer, rr, SYNTHESIZE_IFINDEX(q->ifindex), DNS_ANSWER_AUTHENTICATED);
78c6a153
LP
631 if (r < 0)
632 return r;
633 }
634
635 return 0;
636}
637
105e1512 638static int answer_add_ptr(DnsAnswer **answer, const char *from, const char *to, int ifindex, DnsAnswerFlags flags) {
78c6a153
LP
639 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
640
641 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_PTR, from);
642 if (!rr)
643 return -ENOMEM;
644
645 rr->ptr.name = strdup(to);
646 if (!rr->ptr.name)
647 return -ENOMEM;
648
105e1512 649 return dns_answer_add(*answer, rr, ifindex, flags);
78c6a153
LP
650}
651
23b298bc 652static int synthesize_localhost_ptr(DnsQuery *q, const DnsResourceKey *key, DnsAnswer **answer) {
78c6a153
LP
653 int r;
654
655 assert(q);
656 assert(key);
657 assert(answer);
658
78c6a153 659 if (IN_SET(key->type, DNS_TYPE_PTR, DNS_TYPE_ANY)) {
105e1512
LP
660 r = dns_answer_reserve(answer, 1);
661 if (r < 0)
662 return r;
663
664 r = answer_add_ptr(answer, DNS_RESOURCE_KEY_NAME(key), "localhost", SYNTHESIZE_IFINDEX(q->ifindex), DNS_ANSWER_AUTHENTICATED);
78c6a153
LP
665 if (r < 0)
666 return r;
667 }
668
669 return 0;
670}
671
672static int answer_add_addresses_rr(
673 DnsAnswer **answer,
674 const char *name,
675 struct local_address *addresses,
676 unsigned n_addresses) {
677
678 unsigned j;
679 int r;
680
681 assert(answer);
682 assert(name);
683
684 r = dns_answer_reserve(answer, n_addresses);
685 if (r < 0)
686 return r;
687
688 for (j = 0; j < n_addresses; j++) {
689 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
690
691 r = dns_resource_record_new_address(&rr, addresses[j].family, &addresses[j].address, name);
692 if (r < 0)
693 return r;
694
105e1512 695 r = dns_answer_add(*answer, rr, addresses[j].ifindex, DNS_ANSWER_AUTHENTICATED);
78c6a153
LP
696 if (r < 0)
697 return r;
698 }
699
700 return 0;
701}
702
703static int answer_add_addresses_ptr(
704 DnsAnswer **answer,
705 const char *name,
706 struct local_address *addresses,
707 unsigned n_addresses,
708 int af, const union in_addr_union *match) {
709
710 unsigned j;
711 int r;
712
713 assert(answer);
714 assert(name);
715
716 for (j = 0; j < n_addresses; j++) {
717 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
718
719 if (af != AF_UNSPEC) {
720
721 if (addresses[j].family != af)
722 continue;
723
724 if (match && !in_addr_equal(af, match, &addresses[j].address))
725 continue;
726 }
727
728 r = dns_answer_reserve(answer, 1);
729 if (r < 0)
730 return r;
731
732 r = dns_resource_record_new_reverse(&rr, addresses[j].family, &addresses[j].address, name);
733 if (r < 0)
734 return r;
735
105e1512 736 r = dns_answer_add(*answer, rr, addresses[j].ifindex, DNS_ANSWER_AUTHENTICATED);
78c6a153
LP
737 if (r < 0)
738 return r;
739 }
740
741 return 0;
742}
743
23b298bc 744static int synthesize_system_hostname_rr(DnsQuery *q, const DnsResourceKey *key, DnsAnswer **answer) {
78c6a153
LP
745 _cleanup_free_ struct local_address *addresses = NULL;
746 int n = 0, af;
747
748 assert(q);
749 assert(key);
750 assert(answer);
751
752 af = dns_type_to_af(key->type);
753 if (af >= 0) {
754 n = local_addresses(q->manager->rtnl, q->ifindex, af, &addresses);
755 if (n < 0)
756 return n;
757
758 if (n == 0) {
759 struct local_address buffer[2];
760
761 /* If we have no local addresses then use ::1
762 * and 127.0.0.2 as local ones. */
763
764 if (af == AF_INET || af == AF_UNSPEC)
765 buffer[n++] = (struct local_address) {
766 .family = AF_INET,
767 .ifindex = SYNTHESIZE_IFINDEX(q->ifindex),
768 .address.in.s_addr = htobe32(0x7F000002),
769 };
770
771 if (af == AF_INET6 || af == AF_UNSPEC)
772 buffer[n++] = (struct local_address) {
773 .family = AF_INET6,
774 .ifindex = SYNTHESIZE_IFINDEX(q->ifindex),
775 .address.in6 = in6addr_loopback,
776 };
777
778 return answer_add_addresses_rr(answer, DNS_RESOURCE_KEY_NAME(key), buffer, n);
779 }
780 }
781
782 return answer_add_addresses_rr(answer, DNS_RESOURCE_KEY_NAME(key), addresses, n);
783}
784
785static int synthesize_system_hostname_ptr(DnsQuery *q, int af, const union in_addr_union *address, DnsAnswer **answer) {
786 _cleanup_free_ struct local_address *addresses = NULL;
787 int n, r;
788
789 assert(q);
790 assert(address);
791 assert(answer);
792
793 if (af == AF_INET && address->in.s_addr == htobe32(0x7F000002)) {
794
795 /* Always map the IPv4 address 127.0.0.2 to the local
796 * hostname, in addition to "localhost": */
797
798 r = dns_answer_reserve(answer, 3);
799 if (r < 0)
800 return r;
801
105e1512 802 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
803 if (r < 0)
804 return r;
805
105e1512 806 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
807 if (r < 0)
808 return r;
809
105e1512 810 r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", "localhost", SYNTHESIZE_IFINDEX(q->ifindex), DNS_ANSWER_AUTHENTICATED);
78c6a153
LP
811 if (r < 0)
812 return r;
813
814 return 0;
815 }
816
817 n = local_addresses(q->manager->rtnl, q->ifindex, af, &addresses);
818 if (n < 0)
819 return n;
820
821 r = answer_add_addresses_ptr(answer, q->manager->llmnr_hostname, addresses, n, af, address);
822 if (r < 0)
823 return r;
824
825 return answer_add_addresses_ptr(answer, q->manager->mdns_hostname, addresses, n, af, address);
826}
827
23b298bc 828static int synthesize_gateway_rr(DnsQuery *q, const DnsResourceKey *key, DnsAnswer **answer) {
78c6a153
LP
829 _cleanup_free_ struct local_address *addresses = NULL;
830 int n = 0, af;
831
832 assert(q);
833 assert(key);
834 assert(answer);
835
836 af = dns_type_to_af(key->type);
837 if (af >= 0) {
838 n = local_gateways(q->manager->rtnl, q->ifindex, af, &addresses);
839 if (n < 0)
840 return n;
841 }
842
843 return answer_add_addresses_rr(answer, DNS_RESOURCE_KEY_NAME(key), addresses, n);
844}
845
846static int synthesize_gateway_ptr(DnsQuery *q, int af, const union in_addr_union *address, DnsAnswer **answer) {
847 _cleanup_free_ struct local_address *addresses = NULL;
848 int n;
849
850 assert(q);
851 assert(address);
852 assert(answer);
853
854 n = local_gateways(q->manager->rtnl, q->ifindex, af, &addresses);
855 if (n < 0)
856 return n;
857
858 return answer_add_addresses_ptr(answer, "gateway", addresses, n, af, address);
859}
860
861static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) {
2a1037af 862 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
23b298bc 863 DnsResourceKey *key;
2a1037af
LP
864 int r;
865
866 assert(q);
867 assert(state);
868
869 /* Tries to synthesize localhost RR replies where appropriate */
870
871 if (!IN_SET(*state,
3bbdc31d 872 DNS_TRANSACTION_RCODE_FAILURE,
2a1037af
LP
873 DNS_TRANSACTION_NO_SERVERS,
874 DNS_TRANSACTION_TIMEOUT,
875 DNS_TRANSACTION_ATTEMPTS_MAX_REACHED))
78c6a153 876 return 0;
2a1037af 877
23b298bc 878 DNS_QUESTION_FOREACH(key, q->question_utf8) {
78c6a153 879 union in_addr_union address;
2a1037af 880 const char *name;
78c6a153 881 int af;
2a1037af 882
23b298bc
LP
883 if (key->class != DNS_CLASS_IN &&
884 key->class != DNS_CLASS_ANY)
2a1037af
LP
885 continue;
886
23b298bc 887 name = DNS_RESOURCE_KEY_NAME(key);
2a1037af
LP
888
889 if (is_localhost(name)) {
890
23b298bc 891 r = synthesize_localhost_rr(q, key, &answer);
78c6a153
LP
892 if (r < 0)
893 return log_error_errno(r, "Failed to synthesize localhost RRs: %m");
2a1037af 894
78c6a153 895 } else if (manager_is_own_hostname(q->manager, name)) {
2a1037af 896
23b298bc 897 r = synthesize_system_hostname_rr(q, key, &answer);
78c6a153
LP
898 if (r < 0)
899 return log_error_errno(r, "Failed to synthesize system hostname RRs: %m");
2a1037af 900
78c6a153 901 } else if (is_gateway_hostname(name)) {
2a1037af 902
23b298bc 903 r = synthesize_gateway_rr(q, key, &answer);
78c6a153
LP
904 if (r < 0)
905 return log_error_errno(r, "Failed to synthesize gateway RRs: %m");
2a1037af 906
78c6a153
LP
907 } else if ((dns_name_endswith(name, "127.in-addr.arpa") > 0 && dns_name_equal(name, "2.0.0.127.in-addr.arpa") == 0) ||
908 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 909
23b298bc 910 r = synthesize_localhost_ptr(q, key, &answer);
78c6a153
LP
911 if (r < 0)
912 return log_error_errno(r, "Failed to synthesize localhost PTR RRs: %m");
2a1037af 913
78c6a153 914 } else if (dns_name_address(name, &af, &address) > 0) {
2a1037af 915
78c6a153
LP
916 r = synthesize_system_hostname_ptr(q, af, &address, &answer);
917 if (r < 0)
918 return log_error_errno(r, "Failed to synthesize system hostname PTR RR: %m");
2a1037af 919
78c6a153
LP
920 r = synthesize_gateway_ptr(q, af, &address, &answer);
921 if (r < 0)
922 return log_error_errno(r, "Failed to synthesize gateway hostname PTR RR: %m");
2a1037af
LP
923 }
924 }
925
926 if (!answer)
78c6a153 927 return 0;
2a1037af
LP
928
929 dns_answer_unref(q->answer);
930 q->answer = answer;
931 answer = NULL;
932
2a1037af 933 q->answer_rcode = DNS_RCODE_SUCCESS;
801ad6a6
LP
934 q->answer_protocol = SYNTHESIZE_PROTOCOL(q->flags);
935 q->answer_family = SYNTHESIZE_FAMILY(q->flags);
2a1037af
LP
936
937 *state = DNS_TRANSACTION_SUCCESS;
78c6a153
LP
938
939 return 1;
2a1037af
LP
940}
941
322345fd 942int dns_query_go(DnsQuery *q) {
8ba9fd9c
LP
943 DnsScopeMatch found = DNS_SCOPE_NO;
944 DnsScope *s, *first = NULL;
801ad6a6 945 DnsQueryCandidate *c;
8ba9fd9c
LP
946 int r;
947
948 assert(q);
949
ec2c5e43 950 if (q->state != DNS_TRANSACTION_NULL)
8ba9fd9c
LP
951 return 0;
952
8ba9fd9c 953 LIST_FOREACH(scopes, s, q->manager->dns_scopes) {
74b2466e 954 DnsScopeMatch match;
23b298bc
LP
955 const char *name;
956
957 name = dns_question_first_name(dns_query_question_for_protocol(q, s->protocol));
958 if (!name)
959 continue;
74b2466e 960
51323288 961 match = dns_scope_good_domain(s, q->ifindex, q->flags, name);
74b2466e
LP
962 if (match < 0)
963 return match;
964
965 if (match == DNS_SCOPE_NO)
966 continue;
967
968 found = match;
969
970 if (match == DNS_SCOPE_YES) {
971 first = s;
972 break;
973 } else {
974 assert(match == DNS_SCOPE_MAYBE);
975
976 if (!first)
977 first = s;
978 }
979 }
980
2a1037af
LP
981 if (found == DNS_SCOPE_NO) {
982 DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS;
983
984 dns_query_synthesize_reply(q, &state);
d634711b
LP
985 dns_query_complete(q, state);
986 return 1;
2a1037af 987 }
74b2466e 988
801ad6a6 989 r = dns_query_add_candidate(q, first);
74b2466e 990 if (r < 0)
ec2c5e43 991 goto fail;
74b2466e 992
74b2466e
LP
993 LIST_FOREACH(scopes, s, first->scopes_next) {
994 DnsScopeMatch match;
23b298bc
LP
995 const char *name;
996
997 name = dns_question_first_name(dns_query_question_for_protocol(q, s->protocol));
998 if (!name)
999 continue;
74b2466e 1000
51323288 1001 match = dns_scope_good_domain(s, q->ifindex, q->flags, name);
74b2466e 1002 if (match < 0)
ec2c5e43 1003 goto fail;
74b2466e
LP
1004
1005 if (match != found)
1006 continue;
1007
801ad6a6 1008 r = dns_query_add_candidate(q, s);
74b2466e 1009 if (r < 0)
ec2c5e43 1010 goto fail;
74b2466e
LP
1011 }
1012
faa133f3 1013 q->answer = dns_answer_unref(q->answer);
faa133f3 1014 q->answer_rcode = 0;
51323288
LP
1015 q->answer_family = AF_UNSPEC;
1016 q->answer_protocol = _DNS_PROTOCOL_INVALID;
74b2466e 1017
9a015429
LP
1018 r = sd_event_add_time(
1019 q->manager->event,
1020 &q->timeout_event_source,
1021 clock_boottime_or_monotonic(),
1022 now(clock_boottime_or_monotonic()) + QUERY_TIMEOUT_USEC, 0,
1023 on_query_timeout, q);
74b2466e
LP
1024 if (r < 0)
1025 goto fail;
1026
aa4a9deb
LP
1027 (void) sd_event_source_set_description(q->timeout_event_source, "query-timeout");
1028
ec2c5e43 1029 q->state = DNS_TRANSACTION_PENDING;
faa133f3 1030 q->block_ready++;
74b2466e 1031
801ad6a6
LP
1032 /* Start the transactions */
1033 LIST_FOREACH(candidates_by_query, c, q->candidates) {
1034 r = dns_query_candidate_go(c);
1035 if (r < 0) {
1036 q->block_ready--;
ec2c5e43 1037 goto fail;
801ad6a6 1038 }
74b2466e
LP
1039 }
1040
faa133f3
LP
1041 q->block_ready--;
1042 dns_query_ready(q);
322345fd 1043
8ba9fd9c 1044 return 1;
74b2466e
LP
1045
1046fail:
8ba9fd9c 1047 dns_query_stop(q);
74b2466e
LP
1048 return r;
1049}
1050
801ad6a6 1051static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) {
ec2c5e43 1052 DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS;
547973de 1053 bool has_authenticated = false, has_non_authenticated = false;
019036a4 1054 DnssecResult dnssec_result_authenticated = _DNSSEC_RESULT_INVALID, dnssec_result_non_authenticated = _DNSSEC_RESULT_INVALID;
801ad6a6 1055 DnsTransaction *t;
faa133f3 1056 Iterator i;
547973de 1057 int r;
74b2466e
LP
1058
1059 assert(q);
1060
801ad6a6
LP
1061 if (!c) {
1062 dns_query_synthesize_reply(q, &state);
1063 dns_query_complete(q, state);
74b2466e 1064 return;
801ad6a6 1065 }
74b2466e 1066
801ad6a6 1067 SET_FOREACH(t, c->transactions, i) {
74b2466e 1068
801ad6a6 1069 switch (t->state) {
934e9b10 1070
801ad6a6
LP
1071 case DNS_TRANSACTION_SUCCESS: {
1072 /* We found a successfuly reply, merge it into the answer */
547973de
LP
1073 r = dns_answer_extend(&q->answer, t->answer);
1074 if (r < 0) {
801ad6a6
LP
1075 dns_query_complete(q, DNS_TRANSACTION_RESOURCES);
1076 return;
1077 }
019036a4 1078
ae6a4bbf 1079 q->answer_rcode = t->answer_rcode;
801ad6a6 1080
019036a4 1081 if (t->answer_authenticated) {
931851e8 1082 has_authenticated = true;
019036a4
LP
1083 dnssec_result_authenticated = t->answer_dnssec_result;
1084 } else {
931851e8 1085 has_non_authenticated = true;
019036a4
LP
1086 dnssec_result_non_authenticated = t->answer_dnssec_result;
1087 }
931851e8 1088
801ad6a6
LP
1089 state = DNS_TRANSACTION_SUCCESS;
1090 break;
1091 }
1092
801ad6a6 1093 case DNS_TRANSACTION_NULL:
547973de
LP
1094 case DNS_TRANSACTION_PENDING:
1095 case DNS_TRANSACTION_VALIDATING:
801ad6a6
LP
1096 case DNS_TRANSACTION_ABORTED:
1097 /* Ignore transactions that didn't complete */
1098 continue;
1099
1100 default:
1101 /* Any kind of failure? Store the data away,
1102 * if there's nothing stored yet. */
934e9b10 1103
019036a4
LP
1104 if (state == DNS_TRANSACTION_SUCCESS)
1105 continue;
934e9b10 1106
d38d5ca6 1107 q->answer = dns_answer_unref(q->answer);
019036a4
LP
1108 q->answer_rcode = t->answer_rcode;
1109 q->answer_dnssec_result = t->answer_dnssec_result;
934e9b10 1110
019036a4 1111 state = t->state;
801ad6a6 1112 break;
74b2466e 1113 }
801ad6a6 1114 }
74b2466e 1115
019036a4
LP
1116 if (state == DNS_TRANSACTION_SUCCESS) {
1117 q->answer_authenticated = has_authenticated && !has_non_authenticated;
1118 q->answer_dnssec_result = q->answer_authenticated ? dnssec_result_authenticated : dnssec_result_non_authenticated;
1119 }
1120
801ad6a6
LP
1121 q->answer_protocol = c->scope->protocol;
1122 q->answer_family = c->scope->family;
934e9b10 1123
801ad6a6
LP
1124 dns_search_domain_unref(q->answer_search_domain);
1125 q->answer_search_domain = dns_search_domain_ref(c->search_domain);
7e8e0422 1126
801ad6a6
LP
1127 dns_query_synthesize_reply(q, &state);
1128 dns_query_complete(q, state);
1129}
934e9b10 1130
801ad6a6 1131void dns_query_ready(DnsQuery *q) {
74b2466e 1132
801ad6a6
LP
1133 DnsQueryCandidate *bad = NULL, *c;
1134 bool pending = false;
74b2466e 1135
801ad6a6 1136 assert(q);
547973de 1137 assert(DNS_TRANSACTION_IS_LIVE(q->state));
e4501ed4 1138
801ad6a6
LP
1139 /* Note that this call might invalidate the query. Callers
1140 * should hence not attempt to access the query or transaction
1141 * after calling this function, unless the block_ready
1142 * counter was explicitly bumped before doing so. */
1143
1144 if (q->block_ready > 0)
1145 return;
1146
1147 LIST_FOREACH(candidates_by_query, c, q->candidates) {
1148 DnsTransactionState state;
1149
1150 state = dns_query_candidate_state(c);
1151 switch (state) {
1152
1153 case DNS_TRANSACTION_SUCCESS:
547973de 1154 /* One of the candidates is successful,
801ad6a6
LP
1155 * let's use it, and copy its data out */
1156 dns_query_accept(q, c);
e4501ed4
LP
1157 return;
1158
801ad6a6 1159 case DNS_TRANSACTION_NULL:
547973de
LP
1160 case DNS_TRANSACTION_PENDING:
1161 case DNS_TRANSACTION_VALIDATING:
1162 /* One of the candidates is still going on,
1163 * let's maybe wait for it */
801ad6a6
LP
1164 pending = true;
1165 break;
e4501ed4 1166
801ad6a6
LP
1167 default:
1168 /* Any kind of failure */
1169 bad = c;
1170 break;
1171 }
faa133f3 1172 }
74b2466e 1173
801ad6a6
LP
1174 if (pending)
1175 return;
2a1037af 1176
801ad6a6 1177 dns_query_accept(q, bad);
74b2466e 1178}
8ba9fd9c 1179
45ec7efb 1180static int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname) {
23b298bc
LP
1181 _cleanup_(dns_question_unrefp) DnsQuestion *nq_idna = NULL, *nq_utf8 = NULL;
1182 int r, k;
8ba9fd9c
LP
1183
1184 assert(q);
1185
45ec7efb 1186 q->n_cname_redirects ++;
faa133f3 1187 if (q->n_cname_redirects > CNAME_MAX)
8ba9fd9c
LP
1188 return -ELOOP;
1189
23b298bc 1190 r = dns_question_cname_redirect(q->question_idna, cname, &nq_idna);
faa133f3
LP
1191 if (r < 0)
1192 return r;
23b298bc
LP
1193 else if (r > 0)
1194 log_debug("Following CNAME/DNAME %s → %s", dns_question_first_name(q->question_idna), dns_question_first_name(nq_idna));
1195
1196 k = dns_question_is_equal(q->question_idna, q->question_utf8);
1197 if (k < 0)
1198 return r;
1199 if (k > 0) {
1200 /* Same question? Shortcut new question generation */
1201 nq_utf8 = dns_question_ref(nq_idna);
1202 k = r;
1203 } else {
1204 k = dns_question_cname_redirect(q->question_utf8, cname, &nq_utf8);
1205 if (k < 0)
1206 return k;
1207 else if (k > 0)
1208 log_debug("Following UTF8 CNAME/DNAME %s → %s", dns_question_first_name(q->question_utf8), dns_question_first_name(nq_utf8));
1209 }
8ba9fd9c 1210
23b298bc
LP
1211 if (r == 0 && k == 0) /* No actual cname happened? */
1212 return -ELOOP;
1213
1214 dns_question_unref(q->question_idna);
1215 q->question_idna = nq_idna;
1216 nq_idna = NULL;
bc7669cf 1217
23b298bc
LP
1218 dns_question_unref(q->question_utf8);
1219 q->question_utf8 = nq_utf8;
1220 nq_utf8 = NULL;
8ba9fd9c 1221
322345fd 1222 dns_query_stop(q);
ec2c5e43 1223 q->state = DNS_TRANSACTION_NULL;
322345fd 1224
8ba9fd9c
LP
1225 return 0;
1226}
82bd6ddd 1227
45ec7efb
LP
1228int dns_query_process_cname(DnsQuery *q) {
1229 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *cname = NULL;
23b298bc 1230 DnsQuestion *question;
45ec7efb
LP
1231 DnsResourceRecord *rr;
1232 int r;
1233
1234 assert(q);
1235
7588460a
TG
1236 if (!IN_SET(q->state, DNS_TRANSACTION_SUCCESS, DNS_TRANSACTION_NULL))
1237 return DNS_QUERY_NOMATCH;
45ec7efb 1238
23b298bc 1239 question = dns_query_question_for_protocol(q, q->answer_protocol);
45ec7efb 1240
23b298bc
LP
1241 DNS_ANSWER_FOREACH(rr, q->answer) {
1242 r = dns_question_matches_rr(question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain));
45ec7efb
LP
1243 if (r < 0)
1244 return r;
1245 if (r > 0)
7588460a 1246 return DNS_QUERY_MATCH; /* The answer matches directly, no need to follow cnames */
45ec7efb 1247
23b298bc 1248 r = dns_question_matches_cname(question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain));
45ec7efb
LP
1249 if (r < 0)
1250 return r;
1251 if (r > 0 && !cname)
1252 cname = dns_resource_record_ref(rr);
1253 }
1254
1255 if (!cname)
7588460a 1256 return DNS_QUERY_NOMATCH; /* No match and no cname to follow */
45ec7efb
LP
1257
1258 if (q->flags & SD_RESOLVED_NO_CNAME)
1259 return -ELOOP;
1260
1261 /* OK, let's actually follow the CNAME */
1262 r = dns_query_cname_redirect(q, cname);
1263 if (r < 0)
1264 return r;
1265
1266 /* Let's see if the answer can already answer the new
1267 * redirected question */
7588460a
TG
1268 r = dns_query_process_cname(q);
1269 if (r != DNS_QUERY_NOMATCH)
1270 return r;
45ec7efb
LP
1271
1272 /* OK, it cannot, let's begin with the new query */
1273 r = dns_query_go(q);
1274 if (r < 0)
1275 return r;
1276
7588460a 1277 return DNS_QUERY_RESTARTED; /* We restarted the query for a new cname */
45ec7efb
LP
1278}
1279
82bd6ddd
LP
1280static int on_bus_track(sd_bus_track *t, void *userdata) {
1281 DnsQuery *q = userdata;
1282
1283 assert(t);
1284 assert(q);
1285
1286 log_debug("Client of active query vanished, aborting query.");
1287 dns_query_complete(q, DNS_TRANSACTION_ABORTED);
1288 return 0;
1289}
1290
966c66e3 1291int dns_query_bus_track(DnsQuery *q, sd_bus_message *m) {
82bd6ddd
LP
1292 int r;
1293
1294 assert(q);
1295 assert(m);
1296
1297 if (!q->bus_track) {
966c66e3 1298 r = sd_bus_track_new(sd_bus_message_get_bus(m), &q->bus_track, on_bus_track, q);
82bd6ddd
LP
1299 if (r < 0)
1300 return r;
1301 }
1302
1303 r = sd_bus_track_add_sender(q->bus_track, m);
1304 if (r < 0)
1305 return r;
1306
1307 return 0;
1308}
23b298bc
LP
1309
1310DnsQuestion* dns_query_question_for_protocol(DnsQuery *q, DnsProtocol protocol) {
1311 assert(q);
1312
1313 switch (protocol) {
1314
1315 case DNS_PROTOCOL_DNS:
1316 return q->question_idna;
1317
1318 case DNS_PROTOCOL_MDNS:
1319 case DNS_PROTOCOL_LLMNR:
1320 return q->question_utf8;
1321
1322 default:
1323 return NULL;
1324 }
1325}
1326
1327const char *dns_query_string(DnsQuery *q) {
1328 const char *name;
1329 int r;
1330
1331 /* Returns a somewhat useful human-readable lookup key string for this query */
1332
1333 if (q->request_address_string)
1334 return q->request_address_string;
1335
1336 if (q->request_address_valid) {
1337 r = in_addr_to_string(q->request_family, &q->request_address, &q->request_address_string);
1338 if (r >= 0)
1339 return q->request_address_string;
1340 }
1341
1342 name = dns_question_first_name(q->question_utf8);
1343 if (name)
1344 return name;
1345
1346 return dns_question_first_name(q->question_idna);
1347}