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