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