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