]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-dns-query.c
resolved: add LLMNR support for looking up names
[thirdparty/systemd.git] / src / resolve / resolved-dns-query.c
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
28 #define CNAME_MAX 8
29 #define QUERIES_MAX 2048
30
31 static int dns_query_transaction_go(DnsQueryTransaction *t);
32
33 DnsQueryTransaction* dns_query_transaction_free(DnsQueryTransaction *t) {
34 if (!t)
35 return NULL;
36
37 sd_event_source_unref(t->timeout_event_source);
38
39 dns_packet_unref(t->sent);
40 dns_packet_unref(t->received);
41
42 dns_resource_record_freev(t->cached_rrs, t->n_cached_rrs);
43
44 sd_event_source_unref(t->tcp_event_source);
45 safe_close(t->tcp_fd);
46
47 if (t->query) {
48 LIST_REMOVE(transactions_by_query, t->query->transactions, t);
49 hashmap_remove(t->query->manager->dns_query_transactions, UINT_TO_PTR(t->id));
50 }
51
52 if (t->scope)
53 LIST_REMOVE(transactions_by_scope, t->scope->transactions, t);
54
55 free(t);
56 return NULL;
57 }
58
59 DEFINE_TRIVIAL_CLEANUP_FUNC(DnsQueryTransaction*, dns_query_transaction_free);
60
61 static int dns_query_transaction_new(DnsQuery *q, DnsQueryTransaction **ret, DnsScope *s) {
62 _cleanup_(dns_query_transaction_freep) DnsQueryTransaction *t = NULL;
63 int r;
64
65 assert(q);
66 assert(s);
67
68 r = hashmap_ensure_allocated(&q->manager->dns_query_transactions, NULL, NULL);
69 if (r < 0)
70 return r;
71
72 t = new0(DnsQueryTransaction, 1);
73 if (!t)
74 return -ENOMEM;
75
76 t->tcp_fd = -1;
77
78 do
79 random_bytes(&t->id, sizeof(t->id));
80 while (t->id == 0 ||
81 hashmap_get(q->manager->dns_query_transactions, UINT_TO_PTR(t->id)));
82
83 r = hashmap_put(q->manager->dns_query_transactions, UINT_TO_PTR(t->id), t);
84 if (r < 0) {
85 t->id = 0;
86 return r;
87 }
88
89 LIST_PREPEND(transactions_by_query, q->transactions, t);
90 t->query = q;
91
92 LIST_PREPEND(transactions_by_scope, s->transactions, t);
93 t->scope = s;
94
95 if (ret)
96 *ret = t;
97
98 t = NULL;
99
100 return 0;
101 }
102
103 static void dns_query_transaction_stop(DnsQueryTransaction *t) {
104 assert(t);
105
106 t->timeout_event_source = sd_event_source_unref(t->timeout_event_source);
107 t->tcp_event_source = sd_event_source_unref(t->tcp_event_source);
108 t->tcp_fd = safe_close(t->tcp_fd);
109 }
110
111 static void dns_query_transaction_complete(DnsQueryTransaction *t, DnsQueryState state) {
112 assert(t);
113 assert(!IN_SET(state, DNS_QUERY_NULL, DNS_QUERY_PENDING));
114 assert(IN_SET(t->state, DNS_QUERY_NULL, DNS_QUERY_PENDING));
115
116 /* Note that this call might invalidate the query. Callers
117 * should hence not attempt to access the query or transaction
118 * after calling this function. */
119
120 t->state = state;
121
122 dns_query_transaction_stop(t);
123 dns_query_finish(t->query);
124 }
125
126 static int on_tcp_ready(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
127 DnsQueryTransaction *t = userdata;
128 int r;
129
130 assert(t);
131
132 if (revents & EPOLLOUT) {
133 struct iovec iov[2];
134 be16_t sz;
135 ssize_t ss;
136
137 sz = htobe16(t->sent->size);
138
139 iov[0].iov_base = &sz;
140 iov[0].iov_len = sizeof(sz);
141 iov[1].iov_base = DNS_PACKET_DATA(t->sent);
142 iov[1].iov_len = t->sent->size;
143
144 IOVEC_INCREMENT(iov, 2, t->tcp_written);
145
146 ss = writev(fd, iov, 2);
147 if (ss < 0) {
148 if (errno != EINTR && errno != EAGAIN) {
149 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
150 return -errno;
151 }
152 } else
153 t->tcp_written += ss;
154
155 /* Are we done? If so, disable the event source for EPOLLOUT */
156 if (t->tcp_written >= sizeof(sz) + t->sent->size) {
157 r = sd_event_source_set_io_events(s, EPOLLIN);
158 if (r < 0) {
159 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
160 return r;
161 }
162 }
163 }
164
165 if (revents & (EPOLLIN|EPOLLHUP|EPOLLRDHUP)) {
166
167 if (t->tcp_read < sizeof(t->tcp_read_size)) {
168 ssize_t ss;
169
170 ss = read(fd, (uint8_t*) &t->tcp_read_size + t->tcp_read, sizeof(t->tcp_read_size) - t->tcp_read);
171 if (ss < 0) {
172 if (errno != EINTR && errno != EAGAIN) {
173 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
174 return -errno;
175 }
176 } else if (ss == 0) {
177 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
178 return -EIO;
179 } else
180 t->tcp_read += ss;
181 }
182
183 if (t->tcp_read >= sizeof(t->tcp_read_size)) {
184
185 if (be16toh(t->tcp_read_size) < DNS_PACKET_HEADER_SIZE) {
186 dns_query_transaction_complete(t, DNS_QUERY_INVALID_REPLY);
187 return -EBADMSG;
188 }
189
190 if (t->tcp_read < sizeof(t->tcp_read_size) + be16toh(t->tcp_read_size)) {
191 ssize_t ss;
192
193 if (!t->received) {
194 r = dns_packet_new(&t->received, t->scope->protocol, be16toh(t->tcp_read_size));
195 if (r < 0) {
196 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
197 return r;
198 }
199 }
200
201 ss = read(fd,
202 (uint8_t*) DNS_PACKET_DATA(t->received) + t->tcp_read - sizeof(t->tcp_read_size),
203 sizeof(t->tcp_read_size) + be16toh(t->tcp_read_size) - t->tcp_read);
204 if (ss < 0) {
205 if (errno != EINTR && errno != EAGAIN) {
206 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
207 return -errno;
208 }
209 } else if (ss == 0) {
210 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
211 return -EIO;
212 } else
213 t->tcp_read += ss;
214 }
215
216 if (t->tcp_read >= sizeof(t->tcp_read_size) + be16toh(t->tcp_read_size)) {
217 t->received->size = be16toh(t->tcp_read_size);
218 dns_query_transaction_reply(t, t->received);
219 return 0;
220 }
221 }
222 }
223
224 return 0;
225 }
226
227 static int dns_query_transaction_open_tcp(DnsQueryTransaction *t) {
228 int r;
229
230 assert(t);
231
232 if (t->scope->protocol == DNS_PROTOCOL_DNS)
233 return -ENOTSUP;
234
235 if (t->tcp_fd >= 0)
236 return 0;
237
238 t->tcp_written = 0;
239 t->tcp_read = 0;
240 t->received = dns_packet_unref(t->received);
241
242 t->tcp_fd = dns_scope_tcp_socket(t->scope);
243 if (t->tcp_fd < 0)
244 return t->tcp_fd;
245
246 r = sd_event_add_io(t->query->manager->event, &t->tcp_event_source, t->tcp_fd, EPOLLIN|EPOLLOUT, on_tcp_ready, t);
247 if (r < 0) {
248 t->tcp_fd = safe_close(t->tcp_fd);
249 return r;
250 }
251
252 return 0;
253 }
254
255 void dns_query_transaction_reply(DnsQueryTransaction *t, DnsPacket *p) {
256 int r;
257
258 assert(t);
259 assert(p);
260 assert(t->state == DNS_QUERY_PENDING);
261
262 /* Note that this call might invalidate the query. Callers
263 * should hence not attempt to access the query or transaction
264 * after calling this function. */
265
266 if (t->received != p) {
267 dns_packet_unref(t->received);
268 t->received = dns_packet_ref(p);
269 }
270
271 if (t->tcp_fd >= 0) {
272 if (DNS_PACKET_TC(p)) {
273 /* Truncated via TCP? Somebody must be fucking with us */
274 dns_query_transaction_complete(t, DNS_QUERY_INVALID_REPLY);
275 return;
276 }
277
278 if (DNS_PACKET_ID(p) != t->id) {
279 /* Not the reply to our query? Somebody must be fucking with us */
280 dns_query_transaction_complete(t, DNS_QUERY_INVALID_REPLY);
281 return;
282 }
283 }
284
285 if (DNS_PACKET_TC(p)) {
286 /* Response was truncated, let's try again with good old TCP */
287 r = dns_query_transaction_open_tcp(t);
288 if (r == -ESRCH) {
289 /* No servers found? Damn! */
290 dns_query_transaction_complete(t, DNS_QUERY_NO_SERVERS);
291 return;
292 }
293 if (r < 0) {
294 /* Couldn't send? Try immediately again, with a new server */
295 dns_scope_next_dns_server(t->scope);
296
297 r = dns_query_transaction_go(t);
298 if (r < 0) {
299 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
300 return;
301 }
302
303 return;
304 }
305 }
306
307 /* Parse and update the cache */
308 r = dns_packet_extract_rrs(p);
309 if (r < 0) {
310 dns_query_transaction_complete(t, DNS_QUERY_INVALID_REPLY);
311 return;
312 } else if (r > 0)
313 dns_cache_put_rrs(&t->scope->cache, p->rrs, r, 0);
314
315 if (DNS_PACKET_RCODE(p) == DNS_RCODE_SUCCESS)
316 dns_query_transaction_complete(t, DNS_QUERY_SUCCESS);
317 else
318 dns_query_transaction_complete(t, DNS_QUERY_FAILURE);
319 }
320
321 static int on_transaction_timeout(sd_event_source *s, usec_t usec, void *userdata) {
322 DnsQueryTransaction *t = userdata;
323 int r;
324
325 assert(s);
326 assert(t);
327
328 /* Timeout reached? Try again, with a new server */
329 dns_scope_next_dns_server(t->scope);
330
331 r = dns_query_transaction_go(t);
332 if (r < 0)
333 dns_query_transaction_complete(t, DNS_QUERY_RESOURCES);
334
335 return 0;
336 }
337
338 static int dns_query_make_packet(DnsQueryTransaction *t) {
339 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
340 unsigned n, added = 0;
341 int r;
342
343 assert(t);
344
345 if (t->sent)
346 return 0;
347
348 r = dns_packet_new_query(&p, t->scope->protocol, 0);
349 if (r < 0)
350 return r;
351
352 for (n = 0; n < t->query->n_keys; n++) {
353 r = dns_scope_good_key(t->scope, &t->query->keys[n]);
354 if (r < 0)
355 return r;
356 if (r == 0)
357 continue;
358
359 r = dns_packet_append_key(p, &t->query->keys[n], NULL);
360 if (r < 0)
361 return r;
362
363 added++;
364 }
365
366 if (added <= 0)
367 return -EDOM;
368
369 DNS_PACKET_HEADER(p)->qdcount = htobe16(added);
370 DNS_PACKET_HEADER(p)->id = t->id;
371
372 t->sent = p;
373 p = NULL;
374
375 return 0;
376 }
377
378 static int dns_query_transaction_go(DnsQueryTransaction *t) {
379 int r;
380
381 assert(t);
382
383 dns_query_transaction_stop(t);
384
385 if (t->n_attempts >= ATTEMPTS_MAX) {
386 dns_query_transaction_complete(t, DNS_QUERY_ATTEMPTS_MAX);
387 return 0;
388 }
389
390 t->n_attempts++;
391 t->received = dns_packet_unref(t->received);
392 t->cached_rrs = dns_resource_record_freev(t->cached_rrs, t->n_cached_rrs);
393 t->n_cached_rrs = 0;
394
395 /* First, let's try the cache */
396 dns_cache_prune(&t->scope->cache);
397 r = dns_cache_lookup_many(&t->scope->cache, t->query->keys, t->query->n_keys, &t->cached_rrs);
398 if (r < 0)
399 return r;
400 if (r > 0) {
401 t->n_cached_rrs = r;
402 dns_query_transaction_complete(t, DNS_QUERY_SUCCESS);
403 return 0;
404 }
405
406 /* Otherwise, we need to ask the network */
407 r = dns_query_make_packet(t);
408 if (r == -EDOM) {
409 /* Not the right request to make on this network?
410 * (i.e. an A request made on IPv6 or an AAAA request
411 * made on IPv4, on LLMNR or mDNS.) */
412 dns_query_transaction_complete(t, DNS_QUERY_NO_SERVERS);
413 return 0;
414 }
415 if (r < 0)
416 return r;
417
418 /* Try via UDP, and if that fails due to large size try via TCP */
419 r = dns_scope_send(t->scope, t->sent);
420 if (r == -EMSGSIZE)
421 r = dns_query_transaction_open_tcp(t);
422 if (r == -ESRCH) {
423 /* No servers to send this to? */
424 dns_query_transaction_complete(t, DNS_QUERY_NO_SERVERS);
425 return 0;
426 }
427 if (r < 0) {
428 /* Couldn't send? Try immediately again, with a new server */
429 dns_scope_next_dns_server(t->scope);
430
431 return dns_query_transaction_go(t);
432 }
433
434 r = sd_event_add_time(t->query->manager->event, &t->timeout_event_source, CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + TRANSACTION_TIMEOUT_USEC, 0, on_transaction_timeout, t);
435 if (r < 0)
436 return r;
437
438 t->state = DNS_QUERY_PENDING;
439 return 1;
440 }
441
442 DnsQuery *dns_query_free(DnsQuery *q) {
443 unsigned n;
444
445 if (!q)
446 return NULL;
447
448 sd_bus_message_unref(q->request);
449 dns_packet_unref(q->received);
450
451 dns_resource_record_freev(q->cached_rrs, q->n_cached_rrs);
452
453 sd_event_source_unref(q->timeout_event_source);
454
455 while (q->transactions)
456 dns_query_transaction_free(q->transactions);
457
458 if (q->manager) {
459 LIST_REMOVE(queries, q->manager->dns_queries, q);
460 q->manager->n_dns_queries--;
461 }
462
463 for (n = 0; n < q->n_keys; n++)
464 free(q->keys[n].name);
465 free(q->keys);
466 free(q);
467
468 return NULL;
469 }
470
471 int dns_query_new(Manager *m, DnsQuery **ret, DnsResourceKey *keys, unsigned n_keys) {
472 _cleanup_(dns_query_freep) DnsQuery *q = NULL;
473 const char *name = NULL;
474
475 assert(m);
476
477 if (n_keys <= 0 || n_keys >= 65535)
478 return -EINVAL;
479
480 if (m->n_dns_queries >= QUERIES_MAX)
481 return -EBUSY;
482
483 assert(keys);
484
485 q = new0(DnsQuery, 1);
486 if (!q)
487 return -ENOMEM;
488
489 q->keys = new(DnsResourceKey, n_keys);
490 if (!q->keys)
491 return -ENOMEM;
492
493 for (q->n_keys = 0; q->n_keys < n_keys; q->n_keys++) {
494 q->keys[q->n_keys].class = keys[q->n_keys].class;
495 q->keys[q->n_keys].type = keys[q->n_keys].type;
496 q->keys[q->n_keys].name = strdup(keys[q->n_keys].name);
497 if (!q->keys[q->n_keys].name)
498 return -ENOMEM;
499
500 if (!name)
501 name = q->keys[q->n_keys].name;
502 else if (!dns_name_equal(name, q->keys[q->n_keys].name))
503 return -EINVAL;
504
505 log_debug("Looking up RR for %s %s %s",
506 strna(dns_class_to_string(keys[q->n_keys].class)),
507 strna(dns_type_to_string(keys[q->n_keys].type)),
508 keys[q->n_keys].name);
509 }
510
511 LIST_PREPEND(queries, m->dns_queries, q);
512 m->n_dns_queries++;
513 q->manager = m;
514
515 if (ret)
516 *ret = q;
517 q = NULL;
518
519 return 0;
520 }
521
522 static void dns_query_stop(DnsQuery *q) {
523 assert(q);
524
525 q->timeout_event_source = sd_event_source_unref(q->timeout_event_source);
526
527 while (q->transactions)
528 dns_query_transaction_free(q->transactions);
529 }
530
531 static void dns_query_complete(DnsQuery *q, DnsQueryState state) {
532 assert(q);
533 assert(!IN_SET(state, DNS_QUERY_NULL, DNS_QUERY_PENDING));
534 assert(IN_SET(q->state, DNS_QUERY_NULL, DNS_QUERY_PENDING));
535
536 /* Note that this call might invalidate the query. Callers
537 * should hence not attempt to access the query or transaction
538 * after calling this function. */
539
540 q->state = state;
541
542 dns_query_stop(q);
543 if (q->complete)
544 q->complete(q);
545 }
546
547 static int on_query_timeout(sd_event_source *s, usec_t usec, void *userdata) {
548 DnsQuery *q = userdata;
549
550 assert(s);
551 assert(q);
552
553 dns_query_complete(q, DNS_QUERY_TIMEOUT);
554 return 0;
555 }
556
557 int dns_query_go(DnsQuery *q) {
558 DnsScopeMatch found = DNS_SCOPE_NO;
559 DnsScope *s, *first = NULL;
560 DnsQueryTransaction *t;
561 int r;
562
563 assert(q);
564
565 if (q->state != DNS_QUERY_NULL)
566 return 0;
567
568 assert(q->n_keys > 0);
569
570 LIST_FOREACH(scopes, s, q->manager->dns_scopes) {
571 DnsScopeMatch match;
572
573 match = dns_scope_good_domain(s, q->keys[0].name);
574 if (match < 0)
575 return match;
576
577 if (match == DNS_SCOPE_NO)
578 continue;
579
580 found = match;
581
582 if (match == DNS_SCOPE_YES) {
583 first = s;
584 break;
585 } else {
586 assert(match == DNS_SCOPE_MAYBE);
587
588 if (!first)
589 first = s;
590 }
591 }
592
593 if (found == DNS_SCOPE_NO)
594 return -ESRCH;
595
596 r = dns_query_transaction_new(q, NULL, first);
597 if (r < 0)
598 return r;
599
600 LIST_FOREACH(scopes, s, first->scopes_next) {
601 DnsScopeMatch match;
602
603 match = dns_scope_good_domain(s, q->keys[0].name);
604 if (match < 0)
605 return match;
606
607 if (match != found)
608 continue;
609
610 r = dns_query_transaction_new(q, NULL, s);
611 if (r < 0)
612 return r;
613 }
614
615 q->received = dns_packet_unref(q->received);
616
617 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);
618 if (r < 0)
619 goto fail;
620
621 q->state = DNS_QUERY_PENDING;
622 q->block_finish++;
623
624 LIST_FOREACH(transactions_by_query, t, q->transactions) {
625 r = dns_query_transaction_go(t);
626 if (r < 0)
627 goto fail;
628 }
629
630 q->block_finish--;
631 dns_query_finish(q);
632
633 return 1;
634
635 fail:
636 dns_query_stop(q);
637 return r;
638 }
639
640 void dns_query_finish(DnsQuery *q) {
641 DnsQueryTransaction *t;
642 DnsQueryState state = DNS_QUERY_NO_SERVERS;
643 DnsPacket *received = NULL;
644
645 assert(q);
646 assert(IN_SET(q->state, DNS_QUERY_NULL, DNS_QUERY_PENDING));
647
648 /* Note that this call might invalidate the query. Callers
649 * should hence not attempt to access the query or transaction
650 * after calling this function, unless the block_finish
651 * counter was explicitly bumped before doing so. */
652
653 if (q->block_finish > 0)
654 return;
655
656 LIST_FOREACH(transactions_by_query, t, q->transactions) {
657
658 /* One of the transactions is still going on, let's wait for it */
659 if (t->state == DNS_QUERY_PENDING || t->state == DNS_QUERY_NULL)
660 return;
661
662 /* One of the transactions is successful, let's use
663 * it, and copy its data out */
664 if (t->state == DNS_QUERY_SUCCESS) {
665 q->received = dns_packet_ref(t->received);
666
667 /* We simply steal the cached RRs array */
668 q->cached_rrs = t->cached_rrs;
669 q->n_cached_rrs = t->n_cached_rrs;
670 t->cached_rrs = NULL;
671 t->n_cached_rrs = 0;
672
673 dns_query_complete(q, DNS_QUERY_SUCCESS);
674 return;
675 }
676
677 /* One of the transactions has failed, let's see
678 * whether we find anything better, but if not, return
679 * its response packet */
680 if (t->state == DNS_QUERY_FAILURE) {
681 received = t->received;
682 state = DNS_QUERY_FAILURE;
683 continue;
684 }
685
686 if (state == DNS_QUERY_NO_SERVERS && t->state != DNS_QUERY_NO_SERVERS)
687 state = t->state;
688 }
689
690 if (state == DNS_QUERY_FAILURE)
691 q->received = dns_packet_ref(received);
692
693 dns_query_complete(q, state);
694 }
695
696 int dns_query_cname_redirect(DnsQuery *q, const char *name) {
697 DnsResourceKey *keys;
698 unsigned i;
699
700 assert(q);
701
702 if (q->n_cname > CNAME_MAX)
703 return -ELOOP;
704
705 keys = new(DnsResourceKey, q->n_keys);
706 if (!keys)
707 return -ENOMEM;
708
709 for (i = 0; i < q->n_keys; i++) {
710 keys[i].class = q->keys[i].class;
711 keys[i].type = q->keys[i].type;
712 keys[i].name = strdup(name);
713 if (!keys[i].name) {
714
715 for (; i > 0; i--)
716 free(keys[i-1].name);
717 free(keys);
718 return -ENOMEM;
719 }
720 }
721
722 for (i = 0; i < q->n_keys; i++)
723 free(q->keys[i].name);
724 free(q->keys);
725
726 q->keys = keys;
727
728 q->n_cname++;
729
730 dns_query_stop(q);
731 q->state = DNS_QUERY_NULL;
732
733 return 0;
734 }
735
736 int dns_query_matches_rr(DnsQuery *q, DnsResourceRecord *rr) {
737 unsigned i;
738 int r;
739
740 assert(q);
741 assert(rr);
742
743 for (i = 0; i < q->n_keys; i++) {
744
745 if (rr->key.class != q->keys[i].class)
746 continue;
747
748 if (rr->key.type != q->keys[i].type &&
749 q->keys[i].type != DNS_TYPE_ANY)
750 continue;
751
752 r = dns_name_equal(rr->key.name, q->keys[i].name);
753 if (r != 0)
754 return r;
755 }
756
757 return 0;
758 }
759
760 int dns_query_matches_cname(DnsQuery *q, DnsResourceRecord *rr) {
761 unsigned i;
762 int r;
763
764 assert(q);
765 assert(rr);
766
767 for (i = 0; i < q->n_keys; i++) {
768
769 if (rr->key.class != q->keys[i].class)
770 continue;
771
772 if (rr->key.type != DNS_TYPE_CNAME)
773 continue;
774
775 r = dns_name_equal(rr->key.name, q->keys[i].name);
776 if (r != 0)
777 return r;
778 }
779
780 return 0;
781 }
782
783 int dns_query_get_rrs(DnsQuery *q, DnsResourceRecord ***rrs) {
784 int r;
785
786 assert(q);
787 assert(rrs);
788
789 if (IN_SET(q->state, DNS_QUERY_NULL, DNS_QUERY_PENDING))
790 return -EBUSY;
791
792 if (q->received) {
793 r = dns_packet_extract_rrs(q->received);
794 if (r < 0)
795 return r;
796 if (r == 0) {
797 *rrs = NULL;
798 return r;
799 }
800
801 *rrs = q->received->rrs;
802 return r;
803 }
804
805 if (q->cached_rrs) {
806 *rrs = q->cached_rrs;
807 return q->n_cached_rrs;
808 }
809
810 return -ESRCH;
811 }
812
813 int dns_query_get_rcode(DnsQuery *q) {
814 assert(q);
815
816 if (IN_SET(q->state, DNS_QUERY_NULL, DNS_QUERY_PENDING))
817 return -EBUSY;
818
819 if (!q->received)
820 return -ESRCH;
821
822 return DNS_PACKET_RCODE(q->received);
823 }
824
825 int dns_query_get_ifindex(DnsQuery *q) {
826 assert(q);
827
828 if (IN_SET(q->state, DNS_QUERY_NULL, DNS_QUERY_PENDING))
829 return -EBUSY;
830
831 if (!q->received)
832 return -ESRCH;
833
834 return q->received->ifindex;
835 }