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