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