]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-answer.c
resolved: fix the rcode to SUCCESS if we find at least one matching RR in a DNS response
[thirdparty/systemd.git] / src / resolve / resolved-dns-answer.c
CommitLineData
faa133f3
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"
4ad7f276 23#include "dns-domain.h"
07630cea 24#include "resolved-dns-answer.h"
72667f08 25#include "resolved-dns-dnssec.h"
07630cea 26#include "string-util.h"
faa133f3
LP
27
28DnsAnswer *dns_answer_new(unsigned n) {
29 DnsAnswer *a;
30
78c6a153 31 a = malloc0(offsetof(DnsAnswer, items) + sizeof(DnsAnswerItem) * n);
faa133f3
LP
32 if (!a)
33 return NULL;
34
35 a->n_ref = 1;
36 a->n_allocated = n;
37
38 return a;
39}
40
41DnsAnswer *dns_answer_ref(DnsAnswer *a) {
42 if (!a)
43 return NULL;
44
45 assert(a->n_ref > 0);
46 a->n_ref++;
47 return a;
48}
49
d42800f1
LP
50static void dns_answer_flush(DnsAnswer *a) {
51 DnsResourceRecord *rr;
52
53 if (!a)
54 return;
55
56 DNS_ANSWER_FOREACH(rr, a)
57 dns_resource_record_unref(rr);
58
59 a->n_rrs = 0;
60}
61
faa133f3
LP
62DnsAnswer *dns_answer_unref(DnsAnswer *a) {
63 if (!a)
64 return NULL;
65
66 assert(a->n_ref > 0);
67
68 if (a->n_ref == 1) {
d42800f1 69 dns_answer_flush(a);
faa133f3
LP
70 free(a);
71 } else
72 a->n_ref--;
73
74 return NULL;
75}
76
105e1512 77static int dns_answer_add_raw(DnsAnswer *a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags) {
547973de
LP
78 assert(rr);
79
80 if (!a)
81 return -ENOSPC;
82
83 if (a->n_rrs >= a->n_allocated)
84 return -ENOSPC;
85
105e1512
LP
86 a->items[a->n_rrs++] = (DnsAnswerItem) {
87 .rr = dns_resource_record_ref(rr),
88 .ifindex = ifindex,
89 .flags = flags,
90 };
547973de
LP
91
92 return 1;
93}
94
95static int dns_answer_add_raw_all(DnsAnswer *a, DnsAnswer *source) {
96 DnsResourceRecord *rr;
105e1512 97 DnsAnswerFlags flags;
547973de
LP
98 int ifindex, r;
99
105e1512
LP
100 DNS_ANSWER_FOREACH_FULL(rr, ifindex, flags, source) {
101 r = dns_answer_add_raw(a, rr, ifindex, flags);
547973de
LP
102 if (r < 0)
103 return r;
104 }
105
106 return 0;
107}
108
105e1512 109int dns_answer_add(DnsAnswer *a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags) {
7e8e0422
LP
110 unsigned i;
111 int r;
112
faa133f3
LP
113 assert(rr);
114
78c6a153
LP
115 if (!a)
116 return -ENOSPC;
c296dd2e
LP
117 if (a->n_ref > 1)
118 return -EBUSY;
78c6a153 119
7e8e0422 120 for (i = 0; i < a->n_rrs; i++) {
78c6a153
LP
121 if (a->items[i].ifindex != ifindex)
122 continue;
123
124 r = dns_resource_record_equal(a->items[i].rr, rr);
7e8e0422
LP
125 if (r < 0)
126 return r;
127 if (r > 0) {
7feea00b
LP
128 /* Don't mix contradicting TTLs (see below) */
129 if ((rr->ttl == 0) != (a->items[i].rr->ttl == 0))
130 return -EINVAL;
7e8e0422 131
7feea00b
LP
132 /* Entry already exists, keep the entry with
133 * the higher RR. */
134 if (rr->ttl > a->items[i].rr->ttl) {
7e8e0422 135 dns_resource_record_ref(rr);
78c6a153
LP
136 dns_resource_record_unref(a->items[i].rr);
137 a->items[i].rr = rr;
7e8e0422
LP
138 }
139
105e1512 140 a->items[i].flags |= flags;
7e8e0422
LP
141 return 0;
142 }
7feea00b
LP
143
144 r = dns_resource_key_equal(a->items[i].rr->key, rr->key);
145 if (r < 0)
146 return r;
147 if (r > 0) {
148 /* There's already an RR of the same RRset in
149 * place! Let's see if the TTLs more or less
150 * match. We don't really care if they match
151 * precisely, but we do care whether one is 0
152 * and the other is not. See RFC 2181, Section
153 * 5.2.*/
154
155 if ((rr->ttl == 0) != (a->items[i].rr->ttl == 0))
156 return -EINVAL;
157 }
7e8e0422
LP
158 }
159
105e1512 160 return dns_answer_add_raw(a, rr, ifindex, flags);
547973de 161}
faa133f3 162
547973de
LP
163static int dns_answer_add_all(DnsAnswer *a, DnsAnswer *b) {
164 DnsResourceRecord *rr;
105e1512 165 DnsAnswerFlags flags;
547973de 166 int ifindex, r;
78c6a153 167
105e1512
LP
168 DNS_ANSWER_FOREACH_FULL(rr, ifindex, flags, b) {
169 r = dns_answer_add(a, rr, ifindex, flags);
547973de
LP
170 if (r < 0)
171 return r;
172 }
173
174 return 0;
175}
176
105e1512 177int dns_answer_add_extend(DnsAnswer **a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags) {
547973de
LP
178 int r;
179
180 assert(a);
181 assert(rr);
182
183 r = dns_answer_reserve_or_clone(a, 1);
184 if (r < 0)
185 return r;
186
105e1512 187 return dns_answer_add(*a, rr, ifindex, flags);
7e8e0422
LP
188}
189
57f5ad31 190int dns_answer_add_soa(DnsAnswer *a, const char *name, uint32_t ttl) {
8bf52d3d
LP
191 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *soa = NULL;
192
193 soa = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_SOA, name);
194 if (!soa)
195 return -ENOMEM;
196
57f5ad31
LP
197 soa->ttl = ttl;
198
8bf52d3d
LP
199 soa->soa.mname = strdup(name);
200 if (!soa->soa.mname)
201 return -ENOMEM;
202
203 soa->soa.rname = strappend("root.", name);
204 if (!soa->soa.rname)
205 return -ENOMEM;
206
207 soa->soa.serial = 1;
208 soa->soa.refresh = 1;
209 soa->soa.retry = 1;
210 soa->soa.expire = 1;
57f5ad31 211 soa->soa.minimum = ttl;
8bf52d3d 212
105e1512 213 return dns_answer_add(a, soa, 0, DNS_ANSWER_AUTHENTICATED);
8bf52d3d
LP
214}
215
105e1512
LP
216int dns_answer_match_key(DnsAnswer *a, const DnsResourceKey *key, DnsAnswerFlags *ret_flags) {
217 DnsAnswerFlags flags = 0, i_flags;
547973de 218 DnsResourceRecord *i;
105e1512 219 bool found = false;
7e8e0422
LP
220 int r;
221
7e8e0422
LP
222 assert(key);
223
105e1512 224 DNS_ANSWER_FOREACH_FLAGS(i, i_flags, a) {
547973de 225 r = dns_resource_key_match_rr(key, i, NULL);
7e8e0422
LP
226 if (r < 0)
227 return r;
105e1512
LP
228 if (r == 0)
229 continue;
230
231 if (!ret_flags)
7e8e0422 232 return 1;
105e1512
LP
233
234 if (found)
235 flags &= i_flags;
236 else {
237 flags = i_flags;
238 found = true;
239 }
7e8e0422
LP
240 }
241
105e1512
LP
242 if (ret_flags)
243 *ret_flags = flags;
244
245 return found;
7e8e0422
LP
246}
247
105e1512
LP
248int dns_answer_contains_rr(DnsAnswer *a, DnsResourceRecord *rr, DnsAnswerFlags *ret_flags) {
249 DnsAnswerFlags flags = 0, i_flags;
547973de 250 DnsResourceRecord *i;
105e1512 251 bool found = false;
547973de 252 int r;
5eefe544 253
547973de 254 assert(rr);
5eefe544 255
105e1512 256 DNS_ANSWER_FOREACH_FLAGS(i, i_flags, a) {
547973de
LP
257 r = dns_resource_record_equal(i, rr);
258 if (r < 0)
259 return r;
105e1512
LP
260 if (r == 0)
261 continue;
262
263 if (!ret_flags)
547973de 264 return 1;
105e1512
LP
265
266 if (found)
267 flags &= i_flags;
268 else {
269 flags = i_flags;
270 found = true;
271 }
547973de 272 }
5eefe544 273
105e1512
LP
274 if (ret_flags)
275 *ret_flags = flags;
276
277 return found;
278}
279
280int dns_answer_contains_key(DnsAnswer *a, const DnsResourceKey *key, DnsAnswerFlags *ret_flags) {
281 DnsAnswerFlags flags = 0, i_flags;
282 DnsResourceRecord *i;
283 bool found = false;
284 int r;
285
286 assert(key);
287
288 DNS_ANSWER_FOREACH_FLAGS(i, i_flags, a) {
289 r = dns_resource_key_equal(i->key, key);
290 if (r < 0)
291 return r;
292 if (r == 0)
293 continue;
294
295 if (!ret_flags)
296 return true;
297
298 if (found)
299 flags &= i_flags;
300 else {
301 flags = i_flags;
302 found = true;
303 }
304 }
305
306 if (ret_flags)
307 *ret_flags = flags;
308
309 return found;
310}
311
312int dns_answer_contains_nsec_or_nsec3(DnsAnswer *a) {
313 DnsResourceRecord *i;
314
315 DNS_ANSWER_FOREACH(i, a) {
316 if (IN_SET(i->key->type, DNS_TYPE_NSEC, DNS_TYPE_NSEC3))
317 return true;
318 }
319
320 return false;
5eefe544
TG
321}
322
e926785a
LP
323int dns_answer_contains_zone_nsec3(DnsAnswer *answer, const char *zone) {
324 DnsResourceRecord *rr;
325 int r;
326
327 /* Checks whether the specified answer contains at least one NSEC3 RR in the specified zone */
328
329 DNS_ANSWER_FOREACH(rr, answer) {
330 const char *p;
331
332 if (rr->key->type != DNS_TYPE_NSEC3)
333 continue;
334
335 p = DNS_RESOURCE_KEY_NAME(rr->key);
336 r = dns_name_parent(&p);
337 if (r < 0)
338 return r;
339 if (r == 0)
340 continue;
341
342 r = dns_name_equal(p, zone);
343 if (r != 0)
344 return r;
345 }
346
347 return false;
348}
349
fd009cd8 350int dns_answer_find_soa(DnsAnswer *a, const DnsResourceKey *key, DnsResourceRecord **ret, DnsAnswerFlags *flags) {
81f7fc5e
LP
351 DnsResourceRecord *rr, *soa = NULL;
352 DnsAnswerFlags rr_flags, soa_flags = 0;
29c1519e 353 int r;
7e8e0422 354
7e8e0422 355 assert(key);
7e8e0422 356
0f05c387
LP
357 /* For a SOA record we can never find a matching SOA record */
358 if (key->type == DNS_TYPE_SOA)
359 return 0;
360
fd009cd8 361 DNS_ANSWER_FOREACH_FLAGS(rr, rr_flags, a) {
29c1519e
LP
362 r = dns_resource_key_match_soa(key, rr->key);
363 if (r < 0)
364 return r;
365 if (r > 0) {
81f7fc5e
LP
366
367 if (soa) {
368 r = dns_name_endswith(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(soa->key));
369 if (r < 0)
370 return r;
371 if (r > 0)
372 continue;
373 }
374
375 soa = rr;
376 soa_flags = rr_flags;
7e8e0422
LP
377 }
378 }
379
81f7fc5e
LP
380 if (!soa)
381 return 0;
382
383 if (ret)
384 *ret = soa;
385 if (flags)
386 *flags = soa_flags;
387
388 return 1;
faa133f3 389}
934e9b10 390
105e1512 391int dns_answer_find_cname_or_dname(DnsAnswer *a, const DnsResourceKey *key, DnsResourceRecord **ret, DnsAnswerFlags *flags) {
5d27351f 392 DnsResourceRecord *rr;
105e1512 393 DnsAnswerFlags rr_flags;
29c1519e 394 int r;
5d27351f
TG
395
396 assert(key);
397
5d27351f 398 /* For a {C,D}NAME record we can never find a matching {C,D}NAME record */
6b2f7093 399 if (!dns_type_may_redirect(key->type))
5d27351f
TG
400 return 0;
401
105e1512 402 DNS_ANSWER_FOREACH_FLAGS(rr, rr_flags, a) {
29c1519e
LP
403 r = dns_resource_key_match_cname_or_dname(key, rr->key, NULL);
404 if (r < 0)
405 return r;
406 if (r > 0) {
5d27351f
TG
407 if (ret)
408 *ret = rr;
105e1512
LP
409 if (flags)
410 *flags = rr_flags;
5d27351f
TG
411 return 1;
412 }
413 }
414
415 return 0;
416}
417
547973de
LP
418int dns_answer_merge(DnsAnswer *a, DnsAnswer *b, DnsAnswer **ret) {
419 _cleanup_(dns_answer_unrefp) DnsAnswer *k = NULL;
420 int r;
421
422 assert(ret);
423
424 if (dns_answer_size(a) <= 0) {
425 *ret = dns_answer_ref(b);
426 return 0;
427 }
428
429 if (dns_answer_size(b) <= 0) {
430 *ret = dns_answer_ref(a);
431 return 0;
432 }
433
434 k = dns_answer_new(a->n_rrs + b->n_rrs);
435 if (!k)
436 return -ENOMEM;
437
438 r = dns_answer_add_raw_all(k, a);
439 if (r < 0)
440 return r;
441
442 r = dns_answer_add_all(k, b);
443 if (r < 0)
444 return r;
445
446 *ret = k;
447 k = NULL;
448
449 return 0;
450}
451
452int dns_answer_extend(DnsAnswer **a, DnsAnswer *b) {
453 DnsAnswer *merged;
454 int r;
455
456 assert(a);
457
458 r = dns_answer_merge(*a, b, &merged);
459 if (r < 0)
460 return r;
461
462 dns_answer_unref(*a);
463 *a = merged;
464
465 return 0;
466}
467
468int dns_answer_remove_by_key(DnsAnswer **a, const DnsResourceKey *key) {
469 bool found = false, other = false;
470 DnsResourceRecord *rr;
934e9b10
LP
471 unsigned i;
472 int r;
473
547973de
LP
474 assert(a);
475 assert(key);
934e9b10 476
547973de 477 /* Remove all entries matching the specified key from *a */
934e9b10 478
547973de
LP
479 DNS_ANSWER_FOREACH(rr, *a) {
480 r = dns_resource_key_equal(rr->key, key);
481 if (r < 0)
482 return r;
483 if (r > 0)
484 found = true;
485 else
486 other = true;
487
488 if (found && other)
489 break;
490 }
491
492 if (!found)
493 return 0;
494
495 if (!other) {
496 *a = dns_answer_unref(*a); /* Return NULL for the empty answer */
497 return 1;
934e9b10
LP
498 }
499
547973de
LP
500 if ((*a)->n_ref > 1) {
501 _cleanup_(dns_answer_unrefp) DnsAnswer *copy = NULL;
105e1512 502 DnsAnswerFlags flags;
547973de
LP
503 int ifindex;
504
505 copy = dns_answer_new((*a)->n_rrs);
506 if (!copy)
507 return -ENOMEM;
508
105e1512 509 DNS_ANSWER_FOREACH_FULL(rr, ifindex, flags, *a) {
547973de 510 r = dns_resource_key_equal(rr->key, key);
934e9b10 511 if (r < 0)
547973de
LP
512 return r;
513 if (r > 0)
514 continue;
515
105e1512 516 r = dns_answer_add_raw(copy, rr, ifindex, flags);
547973de
LP
517 if (r < 0)
518 return r;
934e9b10 519 }
547973de
LP
520
521 dns_answer_unref(*a);
522 *a = copy;
523 copy = NULL;
524
525 return 1;
526 }
527
528 /* Only a single reference, edit in-place */
529
530 i = 0;
531 for (;;) {
532 if (i >= (*a)->n_rrs)
533 break;
534
535 r = dns_resource_key_equal((*a)->items[i].rr->key, key);
536 if (r < 0)
537 return r;
538 if (r > 0) {
539 /* Kill this entry */
540
541 dns_resource_record_unref((*a)->items[i].rr);
542 memmove((*a)->items + i, (*a)->items + i + 1, sizeof(DnsAnswerItem) * ((*a)->n_rrs - i - 1));
543 (*a)->n_rrs --;
544 continue;
545
546 } else
547 /* Keep this entry */
548 i++;
934e9b10
LP
549 }
550
547973de
LP
551 return 1;
552}
553
0c857028
LP
554int dns_answer_remove_by_rr(DnsAnswer **a, DnsResourceRecord *rm) {
555 bool found = false, other = false;
556 DnsResourceRecord *rr;
557 unsigned i;
558 int r;
559
560 assert(a);
561 assert(rm);
562
563 /* Remove all entries matching the specified RR from *a */
564
565 DNS_ANSWER_FOREACH(rr, *a) {
566 r = dns_resource_record_equal(rr, rm);
567 if (r < 0)
568 return r;
569 if (r > 0)
570 found = true;
571 else
572 other = true;
573
574 if (found && other)
575 break;
576 }
577
578 if (!found)
579 return 0;
580
581 if (!other) {
582 *a = dns_answer_unref(*a); /* Return NULL for the empty answer */
583 return 1;
584 }
585
586 if ((*a)->n_ref > 1) {
587 _cleanup_(dns_answer_unrefp) DnsAnswer *copy = NULL;
588 DnsAnswerFlags flags;
589 int ifindex;
590
591 copy = dns_answer_new((*a)->n_rrs);
592 if (!copy)
593 return -ENOMEM;
594
595 DNS_ANSWER_FOREACH_FULL(rr, ifindex, flags, *a) {
596 r = dns_resource_record_equal(rr, rm);
597 if (r < 0)
598 return r;
599 if (r > 0)
600 continue;
601
602 r = dns_answer_add_raw(copy, rr, ifindex, flags);
603 if (r < 0)
604 return r;
605 }
606
607 dns_answer_unref(*a);
608 *a = copy;
609 copy = NULL;
610
611 return 1;
612 }
613
614 /* Only a single reference, edit in-place */
615
616 i = 0;
617 for (;;) {
618 if (i >= (*a)->n_rrs)
619 break;
620
621 r = dns_resource_record_equal((*a)->items[i].rr, rm);
622 if (r < 0)
623 return r;
624 if (r > 0) {
625 /* Kill this entry */
626
627 dns_resource_record_unref((*a)->items[i].rr);
628 memmove((*a)->items + i, (*a)->items + i + 1, sizeof(DnsAnswerItem) * ((*a)->n_rrs - i - 1));
629 (*a)->n_rrs --;
630 continue;
631
632 } else
633 /* Keep this entry */
634 i++;
635 }
636
637 return 1;
638}
639
105e1512 640int dns_answer_copy_by_key(DnsAnswer **a, DnsAnswer *source, const DnsResourceKey *key, DnsAnswerFlags or_flags) {
547973de
LP
641 DnsResourceRecord *rr_source;
642 int ifindex_source, r;
105e1512 643 DnsAnswerFlags flags_source;
547973de
LP
644
645 assert(a);
646 assert(key);
647
648 /* Copy all RRs matching the specified key from source into *a */
649
105e1512 650 DNS_ANSWER_FOREACH_FULL(rr_source, ifindex_source, flags_source, source) {
547973de
LP
651
652 r = dns_resource_key_equal(rr_source->key, key);
653 if (r < 0)
654 return r;
655 if (r == 0)
656 continue;
657
658 /* Make space for at least one entry */
659 r = dns_answer_reserve_or_clone(a, 1);
660 if (r < 0)
661 return r;
934e9b10 662
105e1512 663 r = dns_answer_add(*a, rr_source, ifindex_source, flags_source|or_flags);
547973de
LP
664 if (r < 0)
665 return r;
666 }
667
668 return 0;
934e9b10 669}
af93291c 670
105e1512
LP
671int dns_answer_move_by_key(DnsAnswer **to, DnsAnswer **from, const DnsResourceKey *key, DnsAnswerFlags or_flags) {
672 int r;
673
674 assert(to);
675 assert(from);
676 assert(key);
677
678 r = dns_answer_copy_by_key(to, *from, key, or_flags);
679 if (r < 0)
680 return r;
681
682 return dns_answer_remove_by_key(from, key);
683}
684
af93291c 685void dns_answer_order_by_scope(DnsAnswer *a, bool prefer_link_local) {
78c6a153 686 DnsAnswerItem *items;
af93291c 687 unsigned i, start, end;
78c6a153
LP
688
689 if (!a)
690 return;
af93291c
LP
691
692 if (a->n_rrs <= 1)
693 return;
694
695 start = 0;
696 end = a->n_rrs-1;
697
698 /* RFC 4795, Section 2.6 suggests we should order entries
699 * depending on whether the sender is a link-local address. */
700
78c6a153 701 items = newa(DnsAnswerItem, a->n_rrs);
af93291c
LP
702 for (i = 0; i < a->n_rrs; i++) {
703
78c6a153
LP
704 if (a->items[i].rr->key->class == DNS_CLASS_IN &&
705 ((a->items[i].rr->key->type == DNS_TYPE_A && in_addr_is_link_local(AF_INET, (union in_addr_union*) &a->items[i].rr->a.in_addr) != prefer_link_local) ||
706 (a->items[i].rr->key->type == DNS_TYPE_AAAA && in_addr_is_link_local(AF_INET6, (union in_addr_union*) &a->items[i].rr->aaaa.in6_addr) != prefer_link_local)))
af93291c 707 /* Order address records that are are not preferred to the end of the array */
78c6a153 708 items[end--] = a->items[i];
af93291c
LP
709 else
710 /* Order all other records to the beginning of the array */
78c6a153 711 items[start++] = a->items[i];
af93291c
LP
712 }
713
714 assert(start == end+1);
78c6a153
LP
715 memcpy(a->items, items, sizeof(DnsAnswerItem) * a->n_rrs);
716}
717
718int dns_answer_reserve(DnsAnswer **a, unsigned n_free) {
719 DnsAnswer *n;
720
2f763887
LP
721 assert(a);
722
78c6a153
LP
723 if (n_free <= 0)
724 return 0;
725
726 if (*a) {
727 unsigned ns;
728
729 if ((*a)->n_ref > 1)
730 return -EBUSY;
731
732 ns = (*a)->n_rrs + n_free;
733
734 if ((*a)->n_allocated >= ns)
735 return 0;
736
2f763887
LP
737 /* Allocate more than we need */
738 ns *= 2;
739
78c6a153
LP
740 n = realloc(*a, offsetof(DnsAnswer, items) + sizeof(DnsAnswerItem) * ns);
741 if (!n)
742 return -ENOMEM;
743
744 n->n_allocated = ns;
745 } else {
746 n = dns_answer_new(n_free);
747 if (!n)
748 return -ENOMEM;
749 }
750
751 *a = n;
752 return 0;
af93291c 753}
547973de
LP
754
755int dns_answer_reserve_or_clone(DnsAnswer **a, unsigned n_free) {
756 _cleanup_(dns_answer_unrefp) DnsAnswer *n = NULL;
757 int r;
758
759 assert(a);
760
761 /* Tries to extend the DnsAnswer object. And if that's not
762 * possibly, since we are not the sole owner, then allocate a
763 * new, appropriately sized one. Either way, after this call
764 * the object will only have a single reference, and has room
765 * for at least the specified number of RRs. */
766
767 r = dns_answer_reserve(a, n_free);
768 if (r != -EBUSY)
769 return r;
770
771 assert(*a);
772
773 n = dns_answer_new(((*a)->n_rrs + n_free) * 2);
774 if (!n)
775 return -ENOMEM;
776
777 r = dns_answer_add_raw_all(n, *a);
778 if (r < 0)
779 return r;
780
781 dns_answer_unref(*a);
782 *a = n;
783 n = NULL;
784
785 return 0;
786}
26156910
LP
787
788void dns_answer_dump(DnsAnswer *answer, FILE *f) {
789 DnsResourceRecord *rr;
790 DnsAnswerFlags flags;
7b50eb2e 791 int ifindex;
26156910
LP
792
793 if (!f)
794 f = stdout;
795
796 DNS_ANSWER_FOREACH_FULL(rr, ifindex, flags, answer) {
7b50eb2e 797 const char *t;
26156910
LP
798
799 fputc('\t', f);
800
7b50eb2e
LP
801 t = dns_resource_record_to_string(rr);
802 if (!t) {
26156910
LP
803 log_oom();
804 continue;
805 }
806
807 fputs(t, f);
808
809 if (ifindex != 0 || flags & (DNS_ANSWER_AUTHENTICATED|DNS_ANSWER_CACHEABLE|DNS_ANSWER_SHARED_OWNER))
810 fputs("\t;", f);
811
812 if (ifindex != 0)
813 printf(" ifindex=%i", ifindex);
814 if (flags & DNS_ANSWER_AUTHENTICATED)
815 fputs(" authenticated", f);
816 if (flags & DNS_ANSWER_CACHEABLE)
817 fputs(" cachable", f);
818 if (flags & DNS_ANSWER_SHARED_OWNER)
819 fputs(" shared-owner", f);
820
821 fputc('\n', f);
822 }
823}
43e6779a
LP
824
825bool dns_answer_has_dname_for_cname(DnsAnswer *a, DnsResourceRecord *cname) {
826 DnsResourceRecord *rr;
827 int r;
828
829 assert(cname);
830
831 /* Checks whether the answer contains a DNAME record that indicates that the specified CNAME record is
832 * synthesized from it */
833
834 if (cname->key->type != DNS_TYPE_CNAME)
835 return 0;
836
837 DNS_ANSWER_FOREACH(rr, a) {
838 _cleanup_free_ char *n = NULL;
839
840 if (rr->key->type != DNS_TYPE_DNAME)
841 continue;
842 if (rr->key->class != cname->key->class)
843 continue;
844
845 r = dns_name_change_suffix(cname->cname.name, rr->dname.name, DNS_RESOURCE_KEY_NAME(rr->key), &n);
846 if (r < 0)
847 return r;
848 if (r == 0)
849 continue;
850
851 r = dns_name_equal(n, DNS_RESOURCE_KEY_NAME(cname->key));
852 if (r < 0)
853 return r;
854 if (r > 0)
855 return 1;
856
857 }
858
859 return 0;
860}