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