]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-query.c
resolved: set LLMNR TCP and UDP TTLs to the values suggested by the RFC
[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
22#include "resolved-dns-query.h"
23#include "resolved-dns-domain.h"
24
25#define TRANSACTION_TIMEOUT_USEC (5 * USEC_PER_SEC)
26#define QUERY_TIMEOUT_USEC (30 * USEC_PER_SEC)
27#define ATTEMPTS_MAX 8
8ba9fd9c 28#define CNAME_MAX 8
39762fdf 29#define QUERIES_MAX 2048
8ba9fd9c 30
322345fd 31static int dns_query_transaction_go(DnsQueryTransaction *t);
74b2466e
LP
32
33DnsQueryTransaction* dns_query_transaction_free(DnsQueryTransaction *t) {
faa133f3
LP
34 DnsQuery *q;
35
74b2466e
LP
36 if (!t)
37 return NULL;
38
39 sd_event_source_unref(t->timeout_event_source);
ad867662 40
faa133f3 41 dns_question_unref(t->question);
ad867662
LP
42 dns_packet_unref(t->sent);
43 dns_packet_unref(t->received);
faa133f3 44 dns_answer_unref(t->cached);
322345fd 45
623a4c97 46 dns_stream_free(t->stream);
74b2466e 47
faa133f3
LP
48 if (t->scope) {
49 LIST_REMOVE(transactions_by_scope, t->scope->transactions, t);
50
51 if (t->id != 0)
52 hashmap_remove(t->scope->manager->dns_query_transactions, UINT_TO_PTR(t->id));
74b2466e
LP
53 }
54
faa133f3
LP
55 while ((q = set_steal_first(t->queries)))
56 set_remove(q->transactions, t);
57
58 set_free(t->queries);
74b2466e
LP
59
60 free(t);
61 return NULL;
62}
63
64DEFINE_TRIVIAL_CLEANUP_FUNC(DnsQueryTransaction*, dns_query_transaction_free);
65
faa133f3
LP
66static void dns_query_transaction_gc(DnsQueryTransaction *t) {
67 assert(t);
68
69 if (t->block_gc > 0)
70 return;
71
72 if (set_isempty(t->queries))
73 dns_query_transaction_free(t);
74}
75
76static int dns_query_transaction_new(DnsQueryTransaction **ret, DnsScope *s, DnsQuestion *q) {
74b2466e
LP
77 _cleanup_(dns_query_transaction_freep) DnsQueryTransaction *t = NULL;
78 int r;
79
faa133f3 80 assert(ret);
74b2466e 81 assert(s);
faa133f3 82 assert(q);
74b2466e 83
faa133f3 84 r = hashmap_ensure_allocated(&s->manager->dns_query_transactions, NULL, NULL);
74b2466e
LP
85 if (r < 0)
86 return r;
87
88 t = new0(DnsQueryTransaction, 1);
89 if (!t)
90 return -ENOMEM;
91
faa133f3 92 t->question = dns_question_ref(q);
ad867662 93
74b2466e
LP
94 do
95 random_bytes(&t->id, sizeof(t->id));
96 while (t->id == 0 ||
faa133f3 97 hashmap_get(s->manager->dns_query_transactions, UINT_TO_PTR(t->id)));
74b2466e 98
faa133f3 99 r = hashmap_put(s->manager->dns_query_transactions, UINT_TO_PTR(t->id), t);
74b2466e
LP
100 if (r < 0) {
101 t->id = 0;
102 return r;
103 }
104
74b2466e
LP
105 LIST_PREPEND(transactions_by_scope, s->transactions, t);
106 t->scope = s;
107
108 if (ret)
109 *ret = t;
110
111 t = NULL;
112
113 return 0;
114}
115
ad867662
LP
116static void dns_query_transaction_stop(DnsQueryTransaction *t) {
117 assert(t);
118
119 t->timeout_event_source = sd_event_source_unref(t->timeout_event_source);
623a4c97 120 t->stream = dns_stream_free(t->stream);
ad867662
LP
121}
122
faa133f3
LP
123void dns_query_transaction_complete(DnsQueryTransaction *t, DnsQueryState state) {
124 DnsQuery *q;
125 Iterator i;
126
74b2466e 127 assert(t);
322345fd
LP
128 assert(!IN_SET(state, DNS_QUERY_NULL, DNS_QUERY_PENDING));
129 assert(IN_SET(t->state, DNS_QUERY_NULL, DNS_QUERY_PENDING));
74b2466e 130
322345fd
LP
131 /* Note that this call might invalidate the query. Callers
132 * should hence not attempt to access the query or transaction
133 * after calling this function. */
74b2466e
LP
134
135 t->state = state;
136
322345fd 137 dns_query_transaction_stop(t);
faa133f3
LP
138
139 /* Notify all queries that are interested, but make sure the
140 * transaction isn't freed while we are still looking at it */
141 t->block_gc++;
142 SET_FOREACH(q, t->queries, i)
143 dns_query_ready(q);
144 t->block_gc--;
145
146 dns_query_transaction_gc(t);
ad867662
LP
147}
148
623a4c97
LP
149static int on_stream_complete(DnsStream *s, int error) {
150 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
151 DnsQueryTransaction *t;
ad867662 152
623a4c97
LP
153 assert(s);
154 assert(s->transaction);
ad867662 155
623a4c97
LP
156 /* Copy the data we care about out of the stream before we
157 * destroy it. */
158 t = s->transaction;
159 p = dns_packet_ref(s->read_packet);
ad867662 160
623a4c97 161 t->stream = dns_stream_free(t->stream);
ad867662 162
623a4c97
LP
163 if (error != 0) {
164 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
165 return 0;
ad867662
LP
166 }
167
b914e211 168 t->block_gc++;
623a4c97 169 dns_query_transaction_process_reply(t, p);
b914e211
LP
170 t->block_gc--;
171
172 /* If the response wasn't useful, then complete the transition now */
173 if (t->state == DNS_QUERY_PENDING)
174 dns_query_transaction_complete(t, DNS_QUERY_INVALID_REPLY);
175
ad867662
LP
176 return 0;
177}
178
322345fd 179static int dns_query_transaction_open_tcp(DnsQueryTransaction *t) {
623a4c97 180 _cleanup_close_ int fd = -1;
ad867662
LP
181 int r;
182
183 assert(t);
184
623a4c97
LP
185 if (t->stream)
186 return 0;
187
1716f6dc 188 if (t->scope->protocol == DNS_PROTOCOL_DNS)
623a4c97
LP
189 fd = dns_scope_tcp_socket(t->scope, AF_UNSPEC, NULL, 53);
190 else if (t->scope->protocol == DNS_PROTOCOL_LLMNR) {
1716f6dc 191
b914e211
LP
192 /* When we already received a query to this (but it was truncated), send to its sender address */
193 if (t->received)
194 fd = dns_scope_tcp_socket(t->scope, t->received->family, &t->received->sender, t->received->sender_port);
195 else {
196 union in_addr_union address;
197 int family;
198
199 /* Otherwise, try to talk to the owner of a
200 * the IP address, in case this is a reverse
201 * PTR lookup */
202 r = dns_question_extract_reverse_address(t->question, &family, &address);
203 if (r < 0)
204 return r;
205 if (r == 0)
206 return -EINVAL;
207
208 fd = dns_scope_tcp_socket(t->scope, family, &address, 5355);
209 }
623a4c97
LP
210 } else
211 return -EAFNOSUPPORT;
ad867662 212
623a4c97
LP
213 if (fd < 0)
214 return fd;
ad867662 215
623a4c97
LP
216 r = dns_stream_new(t->scope->manager, &t->stream, t->scope->protocol, fd);
217 if (r < 0)
218 return r;
ad867662 219
623a4c97
LP
220 fd = -1;
221
222 r = dns_stream_write_packet(t->stream, t->sent);
ad867662 223 if (r < 0) {
623a4c97 224 t->stream = dns_stream_free(t->stream);
ad867662
LP
225 return r;
226 }
74b2466e 227
623a4c97
LP
228 t->received = dns_packet_unref(t->received);
229 t->stream->complete = on_stream_complete;
b914e211
LP
230 t->stream->transaction = t;
231
232 /* The interface index is difficult to determine if we are
233 * connecting to the local host, hence fill this in right away
234 * instead of determining it from the socket */
235 if (t->scope->link)
236 t->stream->ifindex = t->scope->link->ifindex;
623a4c97 237
ad867662 238 return 0;
74b2466e
LP
239}
240
faa133f3 241void dns_query_transaction_process_reply(DnsQueryTransaction *t, DnsPacket *p) {
ad867662
LP
242 int r;
243
74b2466e
LP
244 assert(t);
245 assert(p);
322345fd 246 assert(t->state == DNS_QUERY_PENDING);
74b2466e 247
322345fd
LP
248 /* Note that this call might invalidate the query. Callers
249 * should hence not attempt to access the query or transaction
250 * after calling this function. */
ad867662 251
623a4c97
LP
252 if (t->scope->protocol == DNS_PROTOCOL_LLMNR) {
253 assert(t->scope->link);
254
255 /* For LLMNR we will not accept any packets from other
256 * interfaces */
257
258 if (p->ifindex != t->scope->link->ifindex)
259 return;
260
261 if (p->family != t->scope->family)
262 return;
263
ea917db9
LP
264 /* Don't accept UDP packets directed to anything but
265 * the LLMNR multicast addresses. */
266
623a4c97
LP
267 if (p->ipproto == IPPROTO_UDP) {
268 if (p->family == AF_INET && !in_addr_equal(AF_INET, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV4_ADDRESS))
269 return;
270
271 if (p->family == AF_INET6 && !in_addr_equal(AF_INET6, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV6_ADDRESS))
272 return;
273 }
ea917db9
LP
274
275 /* Tentative replies shall be discarded, see RFC 4795,
276 * 2.1.1 */
277
278 if (DNS_PACKET_T(p))
279 return;
623a4c97
LP
280 }
281
282 if (t->scope->protocol == DNS_PROTOCOL_DNS) {
283
284 /* For DNS we are fine with accepting packets on any
285 * interface, but the source IP address must be one of
286 * a valid DNS server */
287
288 if (!dns_scope_good_dns_server(t->scope, p->family, &p->sender))
289 return;
290
291 if (p->sender_port != 53)
292 return;
293 }
294
ad867662
LP
295 if (t->received != p) {
296 dns_packet_unref(t->received);
297 t->received = dns_packet_ref(p);
298 }
299
623a4c97 300 if (p->ipproto == IPPROTO_TCP) {
ad867662
LP
301 if (DNS_PACKET_TC(p)) {
302 /* Truncated via TCP? Somebody must be fucking with us */
322345fd 303 dns_query_transaction_complete(t, DNS_QUERY_INVALID_REPLY);
ad867662
LP
304 return;
305 }
306
307 if (DNS_PACKET_ID(p) != t->id) {
308 /* Not the reply to our query? Somebody must be fucking with us */
322345fd 309 dns_query_transaction_complete(t, DNS_QUERY_INVALID_REPLY);
ad867662
LP
310 return;
311 }
312 }
313
314 if (DNS_PACKET_TC(p)) {
315 /* Response was truncated, let's try again with good old TCP */
322345fd 316 r = dns_query_transaction_open_tcp(t);
8ba9fd9c
LP
317 if (r == -ESRCH) {
318 /* No servers found? Damn! */
322345fd 319 dns_query_transaction_complete(t, DNS_QUERY_NO_SERVERS);
8ba9fd9c
LP
320 return;
321 }
ad867662 322 if (r < 0) {
623a4c97
LP
323 /* On LLMNR, if we cannot connect to the host,
324 * we immediately give up */
325 if (t->scope->protocol == DNS_PROTOCOL_LLMNR) {
326 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
327 return;
328 }
329
330 /* On DNS, couldn't send? Try immediately again, with a new server */
8ba9fd9c
LP
331 dns_scope_next_dns_server(t->scope);
332
322345fd 333 r = dns_query_transaction_go(t);
8ba9fd9c 334 if (r < 0) {
322345fd 335 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
8ba9fd9c
LP
336 return;
337 }
338
ad867662
LP
339 return;
340 }
341 }
74b2466e 342
322345fd 343 /* Parse and update the cache */
faa133f3 344 r = dns_packet_extract(p);
322345fd
LP
345 if (r < 0) {
346 dns_query_transaction_complete(t, DNS_QUERY_INVALID_REPLY);
347 return;
934e9b10
LP
348 }
349
350 dns_cache_put(&t->scope->cache, p->question, DNS_PACKET_RCODE(p), p->answer, 0);
322345fd 351
b9d394ea 352 if (DNS_PACKET_RCODE(p) == DNS_RCODE_SUCCESS)
322345fd 353 dns_query_transaction_complete(t, DNS_QUERY_SUCCESS);
b9d394ea 354 else
322345fd 355 dns_query_transaction_complete(t, DNS_QUERY_FAILURE);
74b2466e
LP
356}
357
358static int on_transaction_timeout(sd_event_source *s, usec_t usec, void *userdata) {
359 DnsQueryTransaction *t = userdata;
360 int r;
361
362 assert(s);
363 assert(t);
364
365 /* Timeout reached? Try again, with a new server */
366 dns_scope_next_dns_server(t->scope);
367
322345fd 368 r = dns_query_transaction_go(t);
74b2466e 369 if (r < 0)
322345fd 370 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
74b2466e
LP
371
372 return 0;
373}
374
ad867662 375static int dns_query_make_packet(DnsQueryTransaction *t) {
74b2466e 376 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
1716f6dc 377 unsigned n, added = 0;
74b2466e
LP
378 int r;
379
380 assert(t);
381
ad867662 382 if (t->sent)
74b2466e 383 return 0;
74b2466e 384
1716f6dc 385 r = dns_packet_new_query(&p, t->scope->protocol, 0);
74b2466e
LP
386 if (r < 0)
387 return r;
388
faa133f3
LP
389 for (n = 0; n < t->question->n_keys; n++) {
390 r = dns_scope_good_key(t->scope, t->question->keys[n]);
1716f6dc
LP
391 if (r < 0)
392 return r;
393 if (r == 0)
394 continue;
395
faa133f3 396 r = dns_packet_append_key(p, t->question->keys[n], NULL);
74b2466e
LP
397 if (r < 0)
398 return r;
1716f6dc
LP
399
400 added++;
74b2466e
LP
401 }
402
1716f6dc
LP
403 if (added <= 0)
404 return -EDOM;
405
406 DNS_PACKET_HEADER(p)->qdcount = htobe16(added);
74b2466e
LP
407 DNS_PACKET_HEADER(p)->id = t->id;
408
ad867662
LP
409 t->sent = p;
410 p = NULL;
411
412 return 0;
413}
414
322345fd 415static int dns_query_transaction_go(DnsQueryTransaction *t) {
ad867662
LP
416 int r;
417
418 assert(t);
419
420 dns_query_transaction_stop(t);
421
422 if (t->n_attempts >= ATTEMPTS_MAX) {
322345fd 423 dns_query_transaction_complete(t, DNS_QUERY_ATTEMPTS_MAX);
ad867662
LP
424 return 0;
425 }
ad867662 426
322345fd
LP
427 t->n_attempts++;
428 t->received = dns_packet_unref(t->received);
faa133f3 429 t->cached = dns_answer_unref(t->cached);
7e8e0422 430 t->cached_rcode = 0;
322345fd
LP
431
432 /* First, let's try the cache */
433 dns_cache_prune(&t->scope->cache);
7e8e0422 434 r = dns_cache_lookup(&t->scope->cache, t->question, &t->cached_rcode, &t->cached);
ad867662
LP
435 if (r < 0)
436 return r;
322345fd 437 if (r > 0) {
7e8e0422
LP
438 if (t->cached_rcode == DNS_RCODE_SUCCESS)
439 dns_query_transaction_complete(t, DNS_QUERY_SUCCESS);
440 else
441 dns_query_transaction_complete(t, DNS_QUERY_FAILURE);
322345fd
LP
442 return 0;
443 }
ad867662 444
322345fd
LP
445 /* Otherwise, we need to ask the network */
446 r = dns_query_make_packet(t);
1716f6dc
LP
447 if (r == -EDOM) {
448 /* Not the right request to make on this network?
449 * (i.e. an A request made on IPv6 or an AAAA request
450 * made on IPv4, on LLMNR or mDNS.) */
451 dns_query_transaction_complete(t, DNS_QUERY_NO_SERVERS);
452 return 0;
453 }
322345fd
LP
454 if (r < 0)
455 return r;
8ba9fd9c 456
b914e211
LP
457 if (t->scope->protocol == DNS_PROTOCOL_LLMNR &&
458 (dns_question_endswith(t->question, "in-addr.arpa") > 0 ||
459 dns_question_endswith(t->question, "ip6.arpa") > 0)) {
460
461 /* RFC 4795, Section 2.4. says reverse lookups shall
462 * always be made via TCP on LLMNR */
322345fd 463 r = dns_query_transaction_open_tcp(t);
b914e211
LP
464 } else {
465 /* Try via UDP, and if that fails due to large size try via TCP */
466 r = dns_scope_send(t->scope, t->sent);
467 if (r == -EMSGSIZE)
468 r = dns_query_transaction_open_tcp(t);
469 }
ad867662 470 if (r == -ESRCH) {
1716f6dc 471 /* No servers to send this to? */
322345fd 472 dns_query_transaction_complete(t, DNS_QUERY_NO_SERVERS);
ad867662
LP
473 return 0;
474 }
74b2466e
LP
475 if (r < 0) {
476 /* Couldn't send? Try immediately again, with a new server */
477 dns_scope_next_dns_server(t->scope);
478
322345fd 479 return dns_query_transaction_go(t);
74b2466e
LP
480 }
481
faa133f3 482 r = sd_event_add_time(t->scope->manager->event, &t->timeout_event_source, CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + TRANSACTION_TIMEOUT_USEC, 0, on_transaction_timeout, t);
ad867662
LP
483 if (r < 0)
484 return r;
74b2466e 485
322345fd 486 t->state = DNS_QUERY_PENDING;
ad867662 487 return 1;
74b2466e
LP
488}
489
490DnsQuery *dns_query_free(DnsQuery *q) {
faa133f3 491 DnsQueryTransaction *t;
74b2466e
LP
492
493 if (!q)
494 return NULL;
495
496 sd_bus_message_unref(q->request);
322345fd 497
faa133f3
LP
498 dns_question_unref(q->question);
499 dns_answer_unref(q->answer);
322345fd 500
74b2466e
LP
501 sd_event_source_unref(q->timeout_event_source);
502
faa133f3
LP
503 while ((t = set_steal_first(q->transactions))) {
504 set_remove(t->queries, q);
505 dns_query_transaction_gc(t);
506 }
507
508 set_free(q->transactions);
74b2466e 509
39762fdf 510 if (q->manager) {
74b2466e 511 LIST_REMOVE(queries, q->manager->dns_queries, q);
39762fdf
LP
512 q->manager->n_dns_queries--;
513 }
74b2466e 514
74b2466e
LP
515 free(q);
516
517 return NULL;
518}
519
faa133f3 520int dns_query_new(Manager *m, DnsQuery **ret, DnsQuestion *question) {
74b2466e 521 _cleanup_(dns_query_freep) DnsQuery *q = NULL;
faa133f3
LP
522 unsigned i;
523 int r;
74b2466e
LP
524
525 assert(m);
faa133f3 526 assert(question);
74b2466e 527
faa133f3
LP
528 r = dns_question_is_valid(question);
529 if (r < 0)
530 return r;
74b2466e 531
39762fdf
LP
532 if (m->n_dns_queries >= QUERIES_MAX)
533 return -EBUSY;
534
74b2466e
LP
535 q = new0(DnsQuery, 1);
536 if (!q)
537 return -ENOMEM;
538
faa133f3 539 q->question = dns_question_ref(question);
322345fd 540
faa133f3 541 for (i = 0; i < question->n_keys; i++) {
322345fd 542 log_debug("Looking up RR for %s %s %s",
faa133f3
LP
543 strna(dns_class_to_string(question->keys[i]->class)),
544 strna(dns_type_to_string(question->keys[i]->type)),
545 DNS_RESOURCE_KEY_NAME(question->keys[i]));
74b2466e
LP
546 }
547
548 LIST_PREPEND(queries, m->dns_queries, q);
39762fdf 549 m->n_dns_queries++;
74b2466e
LP
550 q->manager = m;
551
8ba9fd9c
LP
552 if (ret)
553 *ret = q;
554 q = NULL;
555
556 return 0;
557}
558
559static void dns_query_stop(DnsQuery *q) {
faa133f3
LP
560 DnsQueryTransaction *t;
561
8ba9fd9c
LP
562 assert(q);
563
564 q->timeout_event_source = sd_event_source_unref(q->timeout_event_source);
565
faa133f3
LP
566 while ((t = set_steal_first(q->transactions))) {
567 set_remove(t->queries, q);
568 dns_query_transaction_gc(t);
569 }
8ba9fd9c
LP
570}
571
322345fd 572static void dns_query_complete(DnsQuery *q, DnsQueryState state) {
8ba9fd9c 573 assert(q);
322345fd
LP
574 assert(!IN_SET(state, DNS_QUERY_NULL, DNS_QUERY_PENDING));
575 assert(IN_SET(q->state, DNS_QUERY_NULL, DNS_QUERY_PENDING));
8ba9fd9c 576
322345fd
LP
577 /* Note that this call might invalidate the query. Callers
578 * should hence not attempt to access the query or transaction
579 * after calling this function. */
8ba9fd9c 580
8ba9fd9c
LP
581 q->state = state;
582
322345fd
LP
583 dns_query_stop(q);
584 if (q->complete)
585 q->complete(q);
8ba9fd9c
LP
586}
587
588static int on_query_timeout(sd_event_source *s, usec_t usec, void *userdata) {
589 DnsQuery *q = userdata;
590
591 assert(s);
592 assert(q);
593
322345fd 594 dns_query_complete(q, DNS_QUERY_TIMEOUT);
8ba9fd9c
LP
595 return 0;
596}
597
934e9b10
LP
598static int dns_query_add_transaction(DnsQuery *q, DnsScope *s, DnsResourceKey *key) {
599 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
faa133f3
LP
600 DnsQueryTransaction *t;
601 int r;
602
603 assert(q);
604
605 r = set_ensure_allocated(&q->transactions, NULL, NULL);
606 if (r < 0)
607 return r;
608
934e9b10
LP
609 if (key) {
610 question = dns_question_new(1);
611 if (!question)
612 return -ENOMEM;
613
614 r = dns_question_add(question, key);
615 if (r < 0)
616 return r;
617 } else
618 question = dns_question_ref(q->question);
619
faa133f3 620 LIST_FOREACH(transactions_by_scope, t, s->transactions)
934e9b10 621 if (dns_question_is_superset(t->question, question))
faa133f3
LP
622 break;
623
624 if (!t) {
934e9b10 625 r = dns_query_transaction_new(&t, s, question);
faa133f3
LP
626 if (r < 0)
627 return r;
628 }
629
630 r = set_ensure_allocated(&t->queries, NULL, NULL);
631 if (r < 0)
632 goto fail;
633
634 r = set_put(t->queries, q);
635 if (r < 0)
636 goto fail;
637
638 r = set_put(q->transactions, t);
639 if (r < 0) {
640 set_remove(t->queries, q);
641 goto fail;
642 }
643
644 return 0;
645
646fail:
647 dns_query_transaction_gc(t);
648 return r;
649}
650
934e9b10
LP
651static int dns_query_add_transaction_split(DnsQuery *q, DnsScope *s) {
652 int r;
653
654 assert(q);
655 assert(s);
656
657 if (s->protocol == DNS_PROTOCOL_MDNS) {
658 r = dns_query_add_transaction(q, s, NULL);
659 if (r < 0)
660 return r;
661 } else {
662 unsigned i;
663
664 /* On DNS and LLMNR we can only send a single
665 * question per datagram, hence issue multiple
666 * transactions. */
667
668 for (i = 0; i < q->question->n_keys; i++) {
669 r = dns_query_add_transaction(q, s, q->question->keys[i]);
670 if (r < 0)
671 return r;
672 }
673 }
674
675 return 0;
676}
677
322345fd 678int dns_query_go(DnsQuery *q) {
8ba9fd9c
LP
679 DnsScopeMatch found = DNS_SCOPE_NO;
680 DnsScope *s, *first = NULL;
681 DnsQueryTransaction *t;
faa133f3
LP
682 const char *name;
683 Iterator i;
8ba9fd9c
LP
684 int r;
685
686 assert(q);
687
688 if (q->state != DNS_QUERY_NULL)
689 return 0;
690
faa133f3
LP
691 assert(q->question);
692 assert(q->question->n_keys > 0);
693
694 name = DNS_RESOURCE_KEY_NAME(q->question->keys[0]);
8ba9fd9c
LP
695
696 LIST_FOREACH(scopes, s, q->manager->dns_scopes) {
74b2466e
LP
697 DnsScopeMatch match;
698
faa133f3 699 match = dns_scope_good_domain(s, name);
74b2466e
LP
700 if (match < 0)
701 return match;
702
703 if (match == DNS_SCOPE_NO)
704 continue;
705
706 found = match;
707
708 if (match == DNS_SCOPE_YES) {
709 first = s;
710 break;
711 } else {
712 assert(match == DNS_SCOPE_MAYBE);
713
714 if (!first)
715 first = s;
716 }
717 }
718
719 if (found == DNS_SCOPE_NO)
8ba9fd9c 720 return -ESRCH;
74b2466e 721
934e9b10 722 r = dns_query_add_transaction_split(q, first);
74b2466e
LP
723 if (r < 0)
724 return r;
725
74b2466e
LP
726 LIST_FOREACH(scopes, s, first->scopes_next) {
727 DnsScopeMatch match;
728
faa133f3 729 match = dns_scope_good_domain(s, name);
74b2466e
LP
730 if (match < 0)
731 return match;
732
733 if (match != found)
734 continue;
735
934e9b10 736 r = dns_query_add_transaction_split(q, s);
74b2466e
LP
737 if (r < 0)
738 return r;
74b2466e
LP
739 }
740
faa133f3
LP
741 q->answer = dns_answer_unref(q->answer);
742 q->answer_ifindex = 0;
743 q->answer_rcode = 0;
74b2466e
LP
744
745 r = sd_event_add_time(q->manager->event, &q->timeout_event_source, CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + QUERY_TIMEOUT_USEC, 0, on_query_timeout, q);
746 if (r < 0)
747 goto fail;
748
322345fd 749 q->state = DNS_QUERY_PENDING;
faa133f3 750 q->block_ready++;
74b2466e 751
faa133f3
LP
752 SET_FOREACH(t, q->transactions, i) {
753 if (t->state == DNS_QUERY_NULL) {
754 r = dns_query_transaction_go(t);
755 if (r < 0)
756 goto fail;
757 }
74b2466e
LP
758 }
759
faa133f3
LP
760 q->block_ready--;
761 dns_query_ready(q);
322345fd 762
8ba9fd9c 763 return 1;
74b2466e
LP
764
765fail:
8ba9fd9c 766 dns_query_stop(q);
74b2466e
LP
767 return r;
768}
769
faa133f3 770void dns_query_ready(DnsQuery *q) {
74b2466e 771 DnsQueryTransaction *t;
ad867662 772 DnsQueryState state = DNS_QUERY_NO_SERVERS;
934e9b10
LP
773 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
774 int rcode = 0;
775 DnsScope *scope = NULL;
faa133f3 776 Iterator i;
74b2466e
LP
777
778 assert(q);
322345fd 779 assert(IN_SET(q->state, DNS_QUERY_NULL, DNS_QUERY_PENDING));
74b2466e 780
322345fd
LP
781 /* Note that this call might invalidate the query. Callers
782 * should hence not attempt to access the query or transaction
faa133f3 783 * after calling this function, unless the block_ready
322345fd
LP
784 * counter was explicitly bumped before doing so. */
785
faa133f3 786 if (q->block_ready > 0)
74b2466e
LP
787 return;
788
faa133f3 789 SET_FOREACH(t, q->transactions, i) {
74b2466e 790
934e9b10
LP
791 /* If we found a successful answer, ignore all answers from other scopes */
792 if (state == DNS_QUERY_SUCCESS && t->scope != scope)
793 continue;
794
74b2466e 795 /* One of the transactions is still going on, let's wait for it */
8ba9fd9c 796 if (t->state == DNS_QUERY_PENDING || t->state == DNS_QUERY_NULL)
74b2466e
LP
797 return;
798
322345fd
LP
799 /* One of the transactions is successful, let's use
800 * it, and copy its data out */
74b2466e 801 if (t->state == DNS_QUERY_SUCCESS) {
934e9b10
LP
802 DnsAnswer *a;
803
faa133f3 804 if (t->received) {
934e9b10
LP
805 rcode = DNS_PACKET_RCODE(t->received);
806 a = t->received->answer;
faa133f3 807 } else {
934e9b10
LP
808 rcode = t->cached_rcode;
809 a = t->cached;
faa133f3 810 }
322345fd 811
934e9b10
LP
812 if (state == DNS_QUERY_SUCCESS) {
813 DnsAnswer *merged;
814
815 merged = dns_answer_merge(answer, a);
816 if (!merged) {
817 dns_query_complete(q, DNS_QUERY_RESOURCES);
818 return;
819 }
820
821 dns_answer_unref(answer);
822 answer = merged;
823 } else {
824 dns_answer_unref(answer);
825 answer = dns_answer_ref(a);
826 }
827
828 scope = t->scope;
829 state = DNS_QUERY_SUCCESS;
830 continue;
74b2466e
LP
831 }
832
ad867662
LP
833 /* One of the transactions has failed, let's see
834 * whether we find anything better, but if not, return
934e9b10
LP
835 * its response data */
836 if (state != DNS_QUERY_SUCCESS && t->state == DNS_QUERY_FAILURE) {
837 DnsAnswer *a;
838
7e8e0422 839 if (t->received) {
934e9b10
LP
840 rcode = DNS_PACKET_RCODE(t->received);
841 a = t->received->answer;
7e8e0422 842 } else {
934e9b10
LP
843 rcode = t->cached_rcode;
844 a = t->cached;
7e8e0422
LP
845 }
846
934e9b10
LP
847 dns_answer_unref(answer);
848 answer = dns_answer_ref(a);
849
850 scope = t->scope;
74b2466e 851 state = DNS_QUERY_FAILURE;
ad867662
LP
852 continue;
853 }
74b2466e 854
ad867662 855 if (state == DNS_QUERY_NO_SERVERS && t->state != DNS_QUERY_NO_SERVERS)
74b2466e
LP
856 state = t->state;
857 }
858
934e9b10
LP
859 if (IN_SET(state, DNS_QUERY_SUCCESS, DNS_QUERY_FAILURE)) {
860 q->answer = dns_answer_ref(answer);
861 q->answer_rcode = rcode;
862 q->answer_ifindex = (scope && scope->link) ? scope->link->ifindex : 0;
faa133f3 863 }
74b2466e 864
322345fd 865 dns_query_complete(q, state);
74b2466e 866}
8ba9fd9c 867
322345fd 868int dns_query_cname_redirect(DnsQuery *q, const char *name) {
faa133f3
LP
869 _cleanup_(dns_question_unrefp) DnsQuestion *nq = NULL;
870 int r;
8ba9fd9c
LP
871
872 assert(q);
873
faa133f3 874 if (q->n_cname_redirects > CNAME_MAX)
8ba9fd9c
LP
875 return -ELOOP;
876
faa133f3
LP
877 r = dns_question_cname_redirect(q->question, name, &nq);
878 if (r < 0)
879 return r;
8ba9fd9c 880
faa133f3
LP
881 dns_question_unref(q->question);
882 q->question = nq;
883 nq = NULL;
8ba9fd9c 884
faa133f3 885 q->n_cname_redirects++;
8ba9fd9c 886
322345fd
LP
887 dns_query_stop(q);
888 q->state = DNS_QUERY_NULL;
889
8ba9fd9c
LP
890 return 0;
891}