]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-zone.c
man: Fix a typo of session
[thirdparty/systemd.git] / src / resolve / resolved-dns-zone.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
623a4c97 2
b5efdb8a 3#include "alloc-util.h"
4ad7f276 4#include "dns-domain.h"
07630cea 5#include "list.h"
623a4c97 6#include "resolved-dns-packet.h"
07630cea 7#include "resolved-dns-zone.h"
c3036641 8#include "resolved-dnssd.h"
be28f72d 9#include "resolved-manager.h"
07630cea 10#include "string-util.h"
623a4c97
LP
11
12/* Never allow more than 1K entries */
13#define ZONE_MAX 1024
14
3ef64445 15void dns_zone_item_probe_stop(DnsZoneItem *i) {
ec2c5e43
LP
16 DnsTransaction *t;
17 assert(i);
623a4c97 18
ec2c5e43
LP
19 if (!i->probe_transaction)
20 return;
21
ae2a15bc 22 t = TAKE_PTR(i->probe_transaction);
ec2c5e43 23
547973de 24 set_remove(t->notify_zone_items, i);
35aa04e9 25 set_remove(t->notify_zone_items_done, i);
ec2c5e43
LP
26 dns_transaction_gc(t);
27}
623a4c97
LP
28
29static void dns_zone_item_free(DnsZoneItem *i) {
30 if (!i)
31 return;
32
ec2c5e43 33 dns_zone_item_probe_stop(i);
623a4c97 34 dns_resource_record_unref(i->rr);
ec2c5e43 35
623a4c97
LP
36 free(i);
37}
38
39DEFINE_TRIVIAL_CLEANUP_FUNC(DnsZoneItem*, dns_zone_item_free);
40
41static void dns_zone_item_remove_and_free(DnsZone *z, DnsZoneItem *i) {
42 DnsZoneItem *first;
43
44 assert(z);
45
46 if (!i)
47 return;
48
49 first = hashmap_get(z->by_key, i->rr->key);
50 LIST_REMOVE(by_key, first, i);
51 if (first)
52 assert_se(hashmap_replace(z->by_key, first->rr->key, first) >= 0);
53 else
54 hashmap_remove(z->by_key, i->rr->key);
55
1c02e7ba 56 first = hashmap_get(z->by_name, dns_resource_key_name(i->rr->key));
623a4c97
LP
57 LIST_REMOVE(by_name, first, i);
58 if (first)
1c02e7ba 59 assert_se(hashmap_replace(z->by_name, dns_resource_key_name(first->rr->key), first) >= 0);
623a4c97 60 else
1c02e7ba 61 hashmap_remove(z->by_name, dns_resource_key_name(i->rr->key));
623a4c97
LP
62
63 dns_zone_item_free(i);
64}
65
66void dns_zone_flush(DnsZone *z) {
67 DnsZoneItem *i;
68
69 assert(z);
70
71 while ((i = hashmap_first(z->by_key)))
72 dns_zone_item_remove_and_free(z, i);
73
74 assert(hashmap_size(z->by_key) == 0);
75 assert(hashmap_size(z->by_name) == 0);
76
525d3cc7
LP
77 z->by_key = hashmap_free(z->by_key);
78 z->by_name = hashmap_free(z->by_name);
623a4c97
LP
79}
80
8d67e72c 81DnsZoneItem* dns_zone_get(DnsZone *z, DnsResourceRecord *rr) {
623a4c97
LP
82 DnsZoneItem *i;
83
84 assert(z);
85 assert(rr);
86
87 LIST_FOREACH(by_key, i, hashmap_get(z->by_key, rr->key))
3ef77d04 88 if (dns_resource_record_equal(i->rr, rr) > 0)
623a4c97
LP
89 return i;
90
91 return NULL;
92}
93
94void dns_zone_remove_rr(DnsZone *z, DnsResourceRecord *rr) {
95 DnsZoneItem *i;
96
97 assert(z);
98 assert(rr);
99
100 i = dns_zone_get(z, rr);
101 if (i)
102 dns_zone_item_remove_and_free(z, i);
103}
104
6db6a464
DR
105int dns_zone_remove_rrs_by_key(DnsZone *z, DnsResourceKey *key) {
106 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL;
107 DnsResourceRecord *rr;
108 bool tentative;
109 int r;
110
111 r = dns_zone_lookup(z, key, 0, &answer, &soa, &tentative);
112 if (r < 0)
113 return r;
114
115 DNS_ANSWER_FOREACH(rr, answer)
116 dns_zone_remove_rr(z, rr);
117
118 return 0;
119}
120
623a4c97
LP
121static int dns_zone_init(DnsZone *z) {
122 int r;
123
124 assert(z);
125
d5099efc 126 r = hashmap_ensure_allocated(&z->by_key, &dns_resource_key_hash_ops);
623a4c97
LP
127 if (r < 0)
128 return r;
129
d5099efc 130 r = hashmap_ensure_allocated(&z->by_name, &dns_name_hash_ops);
623a4c97
LP
131 if (r < 0)
132 return r;
133
134 return 0;
135}
136
137static int dns_zone_link_item(DnsZone *z, DnsZoneItem *i) {
138 DnsZoneItem *first;
139 int r;
140
141 first = hashmap_get(z->by_key, i->rr->key);
142 if (first) {
143 LIST_PREPEND(by_key, first, i);
144 assert_se(hashmap_replace(z->by_key, first->rr->key, first) >= 0);
145 } else {
146 r = hashmap_put(z->by_key, i->rr->key, i);
147 if (r < 0)
148 return r;
149 }
150
1c02e7ba 151 first = hashmap_get(z->by_name, dns_resource_key_name(i->rr->key));
623a4c97
LP
152 if (first) {
153 LIST_PREPEND(by_name, first, i);
1c02e7ba 154 assert_se(hashmap_replace(z->by_name, dns_resource_key_name(first->rr->key), first) >= 0);
623a4c97 155 } else {
1c02e7ba 156 r = hashmap_put(z->by_name, dns_resource_key_name(i->rr->key), i);
623a4c97
LP
157 if (r < 0)
158 return r;
159 }
160
161 return 0;
162}
163
ec2c5e43 164static int dns_zone_item_probe_start(DnsZoneItem *i) {
ec2c5e43
LP
165 DnsTransaction *t;
166 int r;
167
168 assert(i);
169
170 if (i->probe_transaction)
171 return 0;
172
1c02e7ba 173 t = dns_scope_find_transaction(i->scope, &DNS_RESOURCE_KEY_CONST(i->rr->key->class, DNS_TYPE_ANY, dns_resource_key_name(i->rr->key)), false);
ec2c5e43 174 if (!t) {
1b4f6e79
LP
175 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
176
1c02e7ba 177 key = dns_resource_key_new(i->rr->key->class, DNS_TYPE_ANY, dns_resource_key_name(i->rr->key));
1b4f6e79
LP
178 if (!key)
179 return -ENOMEM;
180
f52e61da 181 r = dns_transaction_new(&t, i->scope, key);
ec2c5e43
LP
182 if (r < 0)
183 return r;
184 }
185
547973de 186 r = set_ensure_allocated(&t->notify_zone_items, NULL);
ec2c5e43
LP
187 if (r < 0)
188 goto gc;
189
35aa04e9
LP
190 r = set_ensure_allocated(&t->notify_zone_items_done, NULL);
191 if (r < 0)
192 goto gc;
193
547973de 194 r = set_put(t->notify_zone_items, i);
ec2c5e43
LP
195 if (r < 0)
196 goto gc;
197
198 i->probe_transaction = t;
53fda2bb 199 t->probing = true;
ec2c5e43
LP
200
201 if (t->state == DNS_TRANSACTION_NULL) {
202
203 i->block_ready++;
204 r = dns_transaction_go(t);
205 i->block_ready--;
206
207 if (r < 0) {
208 dns_zone_item_probe_stop(i);
209 return r;
210 }
211 }
212
547973de 213 dns_zone_item_notify(i);
ec2c5e43
LP
214 return 0;
215
216gc:
217 dns_transaction_gc(t);
218 return r;
219}
220
221int dns_zone_put(DnsZone *z, DnsScope *s, DnsResourceRecord *rr, bool probe) {
623a4c97
LP
222 _cleanup_(dns_zone_item_freep) DnsZoneItem *i = NULL;
223 DnsZoneItem *existing;
224 int r;
225
226 assert(z);
ec2c5e43 227 assert(s);
623a4c97
LP
228 assert(rr);
229
222148b6 230 if (dns_class_is_pseudo(rr->key->class))
1d3b690f 231 return -EINVAL;
222148b6 232 if (dns_type_is_pseudo(rr->key->type))
1d3b690f
LP
233 return -EINVAL;
234
623a4c97
LP
235 existing = dns_zone_get(z, rr);
236 if (existing)
237 return 0;
238
239 r = dns_zone_init(z);
240 if (r < 0)
241 return r;
242
243 i = new0(DnsZoneItem, 1);
244 if (!i)
245 return -ENOMEM;
246
ec2c5e43 247 i->scope = s;
623a4c97 248 i->rr = dns_resource_record_ref(rr);
ec2c5e43 249 i->probing_enabled = probe;
623a4c97
LP
250
251 r = dns_zone_link_item(z, i);
252 if (r < 0)
253 return r;
254
ec2c5e43 255 if (probe) {
cd1b20f9
LP
256 DnsZoneItem *first, *j;
257 bool established = false;
258
259 /* Check if there's already an RR with the same name
260 * established. If so, it has been probed already, and
5238e957 261 * we don't need to probe again. */
cd1b20f9
LP
262
263 LIST_FIND_HEAD(by_name, i, first);
264 LIST_FOREACH(by_name, j, first) {
265 if (i == j)
266 continue;
267
268 if (j->state == DNS_ZONE_ITEM_ESTABLISHED)
269 established = true;
ec2c5e43
LP
270 }
271
cd1b20f9
LP
272 if (established)
273 i->state = DNS_ZONE_ITEM_ESTABLISHED;
274 else {
60eb3f7c
LP
275 i->state = DNS_ZONE_ITEM_PROBING;
276
cd1b20f9
LP
277 r = dns_zone_item_probe_start(i);
278 if (r < 0) {
279 dns_zone_item_remove_and_free(z, i);
280 i = NULL;
281 return r;
282 }
cd1b20f9 283 }
ec2c5e43
LP
284 } else
285 i->state = DNS_ZONE_ITEM_ESTABLISHED;
286
623a4c97
LP
287 i = NULL;
288 return 0;
289}
290
748a548e
DR
291static int dns_zone_add_authenticated_answer(DnsAnswer *a, DnsZoneItem *i, int ifindex) {
292 DnsAnswerFlags flags;
293
294 /* From RFC 6762, Section 10.2
295 * "They (the rules about when to set the cache-flush bit) apply to
296 * startup announcements as described in Section 8.3, "Announcing",
297 * and to responses generated as a result of receiving query messages."
298 * So, set the cache-flush bit for mDNS answers except for DNS-SD
299 * service enumeration PTRs described in RFC 6763, Section 4.1. */
300 if (i->scope->protocol == DNS_PROTOCOL_MDNS &&
301 !dns_resource_key_is_dnssd_ptr(i->rr->key))
302 flags = DNS_ANSWER_AUTHENTICATED|DNS_ANSWER_CACHE_FLUSH;
303 else
304 flags = DNS_ANSWER_AUTHENTICATED;
305
306 return dns_answer_add(a, i->rr, ifindex, flags);
307}
308
97ebebbc 309int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, int ifindex, DnsAnswer **ret_answer, DnsAnswer **ret_soa, bool *ret_tentative) {
8bf52d3d 310 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL;
5032b16d
LP
311 unsigned n_answer = 0;
312 DnsZoneItem *j, *first;
313 bool tentative = true, need_soa = false;
d5323661 314 int r;
623a4c97 315
97ebebbc
LP
316 /* Note that we don't actually need the ifindex for anything. However when it is passed we'll initialize the
317 * ifindex field in the answer with it */
318
623a4c97 319 assert(z);
5032b16d 320 assert(key);
8bf52d3d 321 assert(ret_answer);
623a4c97 322
5032b16d 323 /* First iteration, count what we have */
ec2c5e43 324
5032b16d
LP
325 if (key->type == DNS_TYPE_ANY || key->class == DNS_CLASS_ANY) {
326 bool found = false, added = false;
327 int k;
623a4c97 328
5032b16d
LP
329 /* If this is a generic match, then we have to
330 * go through the list by the name and look
331 * for everything manually */
623a4c97 332
1c02e7ba 333 first = hashmap_get(z->by_name, dns_resource_key_name(key));
5032b16d
LP
334 LIST_FOREACH(by_name, j, first) {
335 if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
336 continue;
d5323661 337
5032b16d 338 found = true;
d5323661 339
801ad6a6 340 k = dns_resource_key_match_rr(key, j->rr, NULL);
5032b16d
LP
341 if (k < 0)
342 return k;
343 if (k > 0) {
344 n_answer++;
345 added = true;
346 }
ec2c5e43 347
5032b16d 348 }
ec2c5e43 349
5032b16d
LP
350 if (found && !added)
351 need_soa = true;
ec2c5e43 352
5032b16d
LP
353 } else {
354 bool found = false;
d5323661 355
5032b16d
LP
356 /* If this is a specific match, then look for
357 * the right key immediately */
ec2c5e43 358
5032b16d
LP
359 first = hashmap_get(z->by_key, key);
360 LIST_FOREACH(by_key, j, first) {
361 if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
362 continue;
ec2c5e43 363
5032b16d
LP
364 found = true;
365 n_answer++;
366 }
ec2c5e43 367
5032b16d 368 if (!found) {
1c02e7ba 369 first = hashmap_get(z->by_name, dns_resource_key_name(key));
5032b16d 370 LIST_FOREACH(by_name, j, first) {
ec2c5e43
LP
371 if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
372 continue;
373
5032b16d
LP
374 need_soa = true;
375 break;
d5323661 376 }
d5323661 377 }
623a4c97
LP
378 }
379
5032b16d
LP
380 if (n_answer <= 0 && !need_soa)
381 goto return_empty;
623a4c97 382
8bf52d3d
LP
383 if (n_answer > 0) {
384 answer = dns_answer_new(n_answer);
385 if (!answer)
386 return -ENOMEM;
387 }
623a4c97 388
5032b16d
LP
389 if (need_soa) {
390 soa = dns_answer_new(1);
8bf52d3d
LP
391 if (!soa)
392 return -ENOMEM;
393 }
394
395 /* Second iteration, actually add the RRs to the answers */
5032b16d
LP
396 if (key->type == DNS_TYPE_ANY || key->class == DNS_CLASS_ANY) {
397 bool found = false, added = false;
398 int k;
d5323661 399
1c02e7ba 400 first = hashmap_get(z->by_name, dns_resource_key_name(key));
5032b16d
LP
401 LIST_FOREACH(by_name, j, first) {
402 if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
403 continue;
ec2c5e43 404
5032b16d 405 found = true;
ec2c5e43 406
5032b16d
LP
407 if (j->state != DNS_ZONE_ITEM_PROBING)
408 tentative = false;
ec2c5e43 409
801ad6a6 410 k = dns_resource_key_match_rr(key, j->rr, NULL);
5032b16d
LP
411 if (k < 0)
412 return k;
413 if (k > 0) {
748a548e 414 r = dns_zone_add_authenticated_answer(answer, j, ifindex);
d5323661
LP
415 if (r < 0)
416 return r;
5032b16d
LP
417
418 added = true;
d5323661 419 }
5032b16d 420 }
d5323661 421
5032b16d 422 if (found && !added) {
97ebebbc 423 r = dns_answer_add_soa(soa, dns_resource_key_name(key), LLMNR_DEFAULT_TTL, ifindex);
5032b16d
LP
424 if (r < 0)
425 return r;
426 }
427 } else {
428 bool found = false;
ec2c5e43 429
5032b16d
LP
430 first = hashmap_get(z->by_key, key);
431 LIST_FOREACH(by_key, j, first) {
432 if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
433 continue;
ec2c5e43 434
5032b16d 435 found = true;
ec2c5e43 436
5032b16d
LP
437 if (j->state != DNS_ZONE_ITEM_PROBING)
438 tentative = false;
ec2c5e43 439
748a548e 440 r = dns_zone_add_authenticated_answer(answer, j, ifindex);
5032b16d
LP
441 if (r < 0)
442 return r;
443 }
ec2c5e43 444
5032b16d
LP
445 if (!found) {
446 bool add_soa = false;
ec2c5e43 447
1c02e7ba 448 first = hashmap_get(z->by_name, dns_resource_key_name(key));
5032b16d
LP
449 LIST_FOREACH(by_name, j, first) {
450 if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
451 continue;
ec2c5e43 452
5032b16d
LP
453 if (j->state != DNS_ZONE_ITEM_PROBING)
454 tentative = false;
ec2c5e43 455
5032b16d
LP
456 add_soa = true;
457 }
458
459 if (add_soa) {
97ebebbc 460 r = dns_answer_add_soa(soa, dns_resource_key_name(key), LLMNR_DEFAULT_TTL, ifindex);
5032b16d
LP
461 if (r < 0)
462 return r;
d5323661 463 }
623a4c97
LP
464 }
465 }
466
5032b16d
LP
467 /* If the caller sets ret_tentative to NULL, then use this as
468 * indication to not return tentative entries */
469
470 if (!ret_tentative && tentative)
471 goto return_empty;
472
1cc6c93a 473 *ret_answer = TAKE_PTR(answer);
623a4c97 474
1cc6c93a
YW
475 if (ret_soa)
476 *ret_soa = TAKE_PTR(soa);
8bf52d3d 477
ec2c5e43
LP
478 if (ret_tentative)
479 *ret_tentative = tentative;
480
623a4c97 481 return 1;
5032b16d
LP
482
483return_empty:
484 *ret_answer = NULL;
485
486 if (ret_soa)
487 *ret_soa = NULL;
488
489 if (ret_tentative)
490 *ret_tentative = false;
491
492 return 0;
623a4c97 493}
ec2c5e43
LP
494
495void dns_zone_item_conflict(DnsZoneItem *i) {
ec2c5e43
LP
496 assert(i);
497
a4076574
LP
498 if (!IN_SET(i->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_VERIFYING, DNS_ZONE_ITEM_ESTABLISHED))
499 return;
500
7b50eb2e 501 log_info("Detected conflict on %s", strna(dns_resource_record_to_string(i->rr)));
ec2c5e43 502
d84b686f
LP
503 dns_zone_item_probe_stop(i);
504
ec2c5e43
LP
505 /* Withdraw the conflict item */
506 i->state = DNS_ZONE_ITEM_WITHDRAWN;
507
c3036641
DR
508 dnssd_signal_conflict(i->scope->manager, dns_resource_key_name(i->rr->key));
509
ec2c5e43 510 /* Maybe change the hostname */
1c02e7ba 511 if (manager_is_own_hostname(i->scope->manager, dns_resource_key_name(i->rr->key)) > 0)
ec2c5e43
LP
512 manager_next_hostname(i->scope->manager);
513}
514
547973de 515void dns_zone_item_notify(DnsZoneItem *i) {
ec2c5e43
LP
516 assert(i);
517 assert(i->probe_transaction);
518
519 if (i->block_ready > 0)
520 return;
521
547973de 522 if (IN_SET(i->probe_transaction->state, DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING, DNS_TRANSACTION_VALIDATING))
ec2c5e43
LP
523 return;
524
a4076574
LP
525 if (i->probe_transaction->state == DNS_TRANSACTION_SUCCESS) {
526 bool we_lost = false;
ec2c5e43 527
a4076574 528 /* The probe got a successful reply. If we so far
008d4ab7
DR
529 * weren't established we just give up.
530 *
531 * In LLMNR case if we already
a4076574 532 * were established, and the peer has the
4d91eec4 533 * lexicographically larger IP address we continue
a4076574
LP
534 * and defend it. */
535
2fb3034c
LP
536 if (!IN_SET(i->state, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING)) {
537 log_debug("Got a successful probe for not yet established RR, we lost.");
a4076574 538 we_lost = true;
008d4ab7 539 } else if (i->probe_transaction->scope->protocol == DNS_PROTOCOL_LLMNR) {
a4076574 540 assert(i->probe_transaction->received);
4d91eec4 541 we_lost = memcmp(&i->probe_transaction->received->sender, &i->probe_transaction->received->destination, FAMILY_ADDRESS_SIZE(i->probe_transaction->received->family)) < 0;
2fb3034c 542 if (we_lost)
4d91eec4 543 log_debug("Got a successful probe reply for an established RR, and we have a lexicographically larger IP address and thus lost.");
a4076574
LP
544 }
545
546 if (we_lost) {
547 dns_zone_item_conflict(i);
548 return;
549 }
550
551 log_debug("Got a successful probe reply, but peer has lexicographically lower IP address and thus lost.");
552 }
553
7b50eb2e 554 log_debug("Record %s successfully probed.", strna(dns_resource_record_to_string(i->rr)));
ec2c5e43 555
a4076574
LP
556 dns_zone_item_probe_stop(i);
557 i->state = DNS_ZONE_ITEM_ESTABLISHED;
558}
559
560static int dns_zone_item_verify(DnsZoneItem *i) {
561 int r;
562
563 assert(i);
564
565 if (i->state != DNS_ZONE_ITEM_ESTABLISHED)
566 return 0;
567
7b50eb2e 568 log_debug("Verifying RR %s", strna(dns_resource_record_to_string(i->rr)));
2fb3034c 569
a4076574
LP
570 i->state = DNS_ZONE_ITEM_VERIFYING;
571 r = dns_zone_item_probe_start(i);
572 if (r < 0) {
da927ba9 573 log_error_errno(r, "Failed to start probing for verifying RR: %m");
ec2c5e43 574 i->state = DNS_ZONE_ITEM_ESTABLISHED;
a4076574
LP
575 return r;
576 }
577
578 return 0;
579}
580
581int dns_zone_check_conflicts(DnsZone *zone, DnsResourceRecord *rr) {
582 DnsZoneItem *i, *first;
bf1594f5 583 int c = 0;
a4076574
LP
584
585 assert(zone);
586 assert(rr);
587
588 /* This checks whether a response RR we received from somebody
589 * else is one that we actually thought was uniquely ours. If
590 * so, we'll verify our RRs. */
591
592 /* No conflict if we don't have the name at all. */
1c02e7ba 593 first = hashmap_get(zone->by_name, dns_resource_key_name(rr->key));
a4076574
LP
594 if (!first)
595 return 0;
596
597 /* No conflict if we have the exact same RR */
598 if (dns_zone_get(zone, rr))
599 return 0;
600
d686f15c
DR
601 /* No conflict if it is DNS-SD RR used for service enumeration. */
602 if (dns_resource_key_is_dnssd_ptr(rr->key))
603 return 0;
604
a4076574
LP
605 /* OK, somebody else has RRs for the same name. Yuck! Let's
606 * start probing again */
607
608 LIST_FOREACH(by_name, i, first) {
609 if (dns_resource_record_equal(i->rr, rr))
610 continue;
611
612 dns_zone_item_verify(i);
613 c++;
614 }
615
616 return c;
617}
618
619int dns_zone_verify_conflicts(DnsZone *zone, DnsResourceKey *key) {
620 DnsZoneItem *i, *first;
bf1594f5 621 int c = 0;
a4076574
LP
622
623 assert(zone);
624
625 /* Somebody else notified us about a possible conflict. Let's
626 * verify if that's true. */
627
1c02e7ba 628 first = hashmap_get(zone->by_name, dns_resource_key_name(key));
a4076574
LP
629 if (!first)
630 return 0;
631
632 LIST_FOREACH(by_name, i, first) {
633 dns_zone_item_verify(i);
634 c++;
635 }
636
637 return c;
ec2c5e43 638}
902bb5d8
LP
639
640void dns_zone_verify_all(DnsZone *zone) {
641 DnsZoneItem *i;
642 Iterator iterator;
643
644 assert(zone);
645
646 HASHMAP_FOREACH(i, zone->by_key, iterator) {
647 DnsZoneItem *j;
648
649 LIST_FOREACH(by_key, j, i)
650 dns_zone_item_verify(j);
651 }
652}
4d506d6b
LP
653
654void dns_zone_dump(DnsZone *zone, FILE *f) {
655 Iterator iterator;
656 DnsZoneItem *i;
4d506d6b
LP
657
658 if (!zone)
659 return;
660
661 if (!f)
662 f = stdout;
663
664 HASHMAP_FOREACH(i, zone->by_key, iterator) {
665 DnsZoneItem *j;
666
667 LIST_FOREACH(by_key, j, i) {
7b50eb2e 668 const char *t;
4d506d6b 669
7b50eb2e
LP
670 t = dns_resource_record_to_string(j->rr);
671 if (!t) {
4d506d6b
LP
672 log_oom();
673 continue;
674 }
675
676 fputc('\t', f);
677 fputs(t, f);
678 fputc('\n', f);
679 }
680 }
681}
682
683bool dns_zone_is_empty(DnsZone *zone) {
684 if (!zone)
685 return true;
686
687 return hashmap_isempty(zone->by_key);
688}
a2bf8a19
DR
689
690bool dns_zone_contains_name(DnsZone *z, const char *name) {
691 DnsZoneItem *i, *first;
692
693 first = hashmap_get(z->by_name, name);
694 if (!first)
695 return false;
696
697 LIST_FOREACH(by_name, i, first) {
698 if (!IN_SET(i->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
699 continue;
700
701 return true;
702 }
703
704 return false;
705}