]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-zone.c
basic/set: add set_ensure_put()
[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) {
29bd6012 165 _cleanup_(dns_transaction_gcp) DnsTransaction *t = NULL;
ec2c5e43
LP
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 187 if (r < 0)
29bd6012 188 return r;
ec2c5e43 189
35aa04e9
LP
190 r = set_ensure_allocated(&t->notify_zone_items_done, NULL);
191 if (r < 0)
29bd6012 192 return r;
35aa04e9 193
547973de 194 r = set_put(t->notify_zone_items, i);
ec2c5e43 195 if (r < 0)
29bd6012 196 return r;
ec2c5e43 197
53fda2bb 198 t->probing = true;
29bd6012 199 i->probe_transaction = TAKE_PTR(t);
ec2c5e43 200
29bd6012 201 if (i->probe_transaction->state == DNS_TRANSACTION_NULL) {
ec2c5e43 202 i->block_ready++;
29bd6012 203 r = dns_transaction_go(i->probe_transaction);
ec2c5e43
LP
204 i->block_ready--;
205
206 if (r < 0) {
207 dns_zone_item_probe_stop(i);
208 return r;
209 }
210 }
211
547973de 212 dns_zone_item_notify(i);
ec2c5e43 213 return 0;
ec2c5e43
LP
214}
215
216int dns_zone_put(DnsZone *z, DnsScope *s, DnsResourceRecord *rr, bool probe) {
623a4c97
LP
217 _cleanup_(dns_zone_item_freep) DnsZoneItem *i = NULL;
218 DnsZoneItem *existing;
219 int r;
220
221 assert(z);
ec2c5e43 222 assert(s);
623a4c97
LP
223 assert(rr);
224
222148b6 225 if (dns_class_is_pseudo(rr->key->class))
1d3b690f 226 return -EINVAL;
222148b6 227 if (dns_type_is_pseudo(rr->key->type))
1d3b690f
LP
228 return -EINVAL;
229
623a4c97
LP
230 existing = dns_zone_get(z, rr);
231 if (existing)
232 return 0;
233
234 r = dns_zone_init(z);
235 if (r < 0)
236 return r;
237
238 i = new0(DnsZoneItem, 1);
239 if (!i)
240 return -ENOMEM;
241
ec2c5e43 242 i->scope = s;
623a4c97 243 i->rr = dns_resource_record_ref(rr);
ec2c5e43 244 i->probing_enabled = probe;
623a4c97
LP
245
246 r = dns_zone_link_item(z, i);
247 if (r < 0)
248 return r;
249
ec2c5e43 250 if (probe) {
cd1b20f9
LP
251 DnsZoneItem *first, *j;
252 bool established = false;
253
254 /* Check if there's already an RR with the same name
255 * established. If so, it has been probed already, and
5238e957 256 * we don't need to probe again. */
cd1b20f9
LP
257
258 LIST_FIND_HEAD(by_name, i, first);
259 LIST_FOREACH(by_name, j, first) {
260 if (i == j)
261 continue;
262
263 if (j->state == DNS_ZONE_ITEM_ESTABLISHED)
264 established = true;
ec2c5e43
LP
265 }
266
cd1b20f9
LP
267 if (established)
268 i->state = DNS_ZONE_ITEM_ESTABLISHED;
269 else {
60eb3f7c
LP
270 i->state = DNS_ZONE_ITEM_PROBING;
271
cd1b20f9
LP
272 r = dns_zone_item_probe_start(i);
273 if (r < 0) {
274 dns_zone_item_remove_and_free(z, i);
275 i = NULL;
276 return r;
277 }
cd1b20f9 278 }
ec2c5e43
LP
279 } else
280 i->state = DNS_ZONE_ITEM_ESTABLISHED;
281
623a4c97
LP
282 i = NULL;
283 return 0;
284}
285
748a548e
DR
286static int dns_zone_add_authenticated_answer(DnsAnswer *a, DnsZoneItem *i, int ifindex) {
287 DnsAnswerFlags flags;
288
289 /* From RFC 6762, Section 10.2
290 * "They (the rules about when to set the cache-flush bit) apply to
291 * startup announcements as described in Section 8.3, "Announcing",
292 * and to responses generated as a result of receiving query messages."
293 * So, set the cache-flush bit for mDNS answers except for DNS-SD
294 * service enumeration PTRs described in RFC 6763, Section 4.1. */
295 if (i->scope->protocol == DNS_PROTOCOL_MDNS &&
296 !dns_resource_key_is_dnssd_ptr(i->rr->key))
297 flags = DNS_ANSWER_AUTHENTICATED|DNS_ANSWER_CACHE_FLUSH;
298 else
299 flags = DNS_ANSWER_AUTHENTICATED;
300
301 return dns_answer_add(a, i->rr, ifindex, flags);
302}
303
97ebebbc 304int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, int ifindex, DnsAnswer **ret_answer, DnsAnswer **ret_soa, bool *ret_tentative) {
8bf52d3d 305 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL;
5032b16d
LP
306 unsigned n_answer = 0;
307 DnsZoneItem *j, *first;
308 bool tentative = true, need_soa = false;
d5323661 309 int r;
623a4c97 310
97ebebbc
LP
311 /* Note that we don't actually need the ifindex for anything. However when it is passed we'll initialize the
312 * ifindex field in the answer with it */
313
623a4c97 314 assert(z);
5032b16d 315 assert(key);
8bf52d3d 316 assert(ret_answer);
623a4c97 317
5032b16d 318 /* First iteration, count what we have */
ec2c5e43 319
5032b16d
LP
320 if (key->type == DNS_TYPE_ANY || key->class == DNS_CLASS_ANY) {
321 bool found = false, added = false;
322 int k;
623a4c97 323
5032b16d
LP
324 /* If this is a generic match, then we have to
325 * go through the list by the name and look
326 * for everything manually */
623a4c97 327
1c02e7ba 328 first = hashmap_get(z->by_name, dns_resource_key_name(key));
5032b16d
LP
329 LIST_FOREACH(by_name, j, first) {
330 if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
331 continue;
d5323661 332
5032b16d 333 found = true;
d5323661 334
801ad6a6 335 k = dns_resource_key_match_rr(key, j->rr, NULL);
5032b16d
LP
336 if (k < 0)
337 return k;
338 if (k > 0) {
339 n_answer++;
340 added = true;
341 }
ec2c5e43 342
5032b16d 343 }
ec2c5e43 344
5032b16d
LP
345 if (found && !added)
346 need_soa = true;
ec2c5e43 347
5032b16d
LP
348 } else {
349 bool found = false;
d5323661 350
5032b16d
LP
351 /* If this is a specific match, then look for
352 * the right key immediately */
ec2c5e43 353
5032b16d
LP
354 first = hashmap_get(z->by_key, key);
355 LIST_FOREACH(by_key, j, first) {
356 if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
357 continue;
ec2c5e43 358
5032b16d
LP
359 found = true;
360 n_answer++;
361 }
ec2c5e43 362
5032b16d 363 if (!found) {
1c02e7ba 364 first = hashmap_get(z->by_name, dns_resource_key_name(key));
5032b16d 365 LIST_FOREACH(by_name, j, first) {
ec2c5e43
LP
366 if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
367 continue;
368
5032b16d
LP
369 need_soa = true;
370 break;
d5323661 371 }
d5323661 372 }
623a4c97
LP
373 }
374
5032b16d
LP
375 if (n_answer <= 0 && !need_soa)
376 goto return_empty;
623a4c97 377
8bf52d3d
LP
378 if (n_answer > 0) {
379 answer = dns_answer_new(n_answer);
380 if (!answer)
381 return -ENOMEM;
382 }
623a4c97 383
5032b16d
LP
384 if (need_soa) {
385 soa = dns_answer_new(1);
8bf52d3d
LP
386 if (!soa)
387 return -ENOMEM;
388 }
389
390 /* Second iteration, actually add the RRs to the answers */
5032b16d
LP
391 if (key->type == DNS_TYPE_ANY || key->class == DNS_CLASS_ANY) {
392 bool found = false, added = false;
393 int k;
d5323661 394
1c02e7ba 395 first = hashmap_get(z->by_name, dns_resource_key_name(key));
5032b16d
LP
396 LIST_FOREACH(by_name, j, first) {
397 if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
398 continue;
ec2c5e43 399
5032b16d 400 found = true;
ec2c5e43 401
5032b16d
LP
402 if (j->state != DNS_ZONE_ITEM_PROBING)
403 tentative = false;
ec2c5e43 404
801ad6a6 405 k = dns_resource_key_match_rr(key, j->rr, NULL);
5032b16d
LP
406 if (k < 0)
407 return k;
408 if (k > 0) {
748a548e 409 r = dns_zone_add_authenticated_answer(answer, j, ifindex);
d5323661
LP
410 if (r < 0)
411 return r;
5032b16d
LP
412
413 added = true;
d5323661 414 }
5032b16d 415 }
d5323661 416
5032b16d 417 if (found && !added) {
97ebebbc 418 r = dns_answer_add_soa(soa, dns_resource_key_name(key), LLMNR_DEFAULT_TTL, ifindex);
5032b16d
LP
419 if (r < 0)
420 return r;
421 }
422 } else {
423 bool found = false;
ec2c5e43 424
5032b16d
LP
425 first = hashmap_get(z->by_key, key);
426 LIST_FOREACH(by_key, j, first) {
427 if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
428 continue;
ec2c5e43 429
5032b16d 430 found = true;
ec2c5e43 431
5032b16d
LP
432 if (j->state != DNS_ZONE_ITEM_PROBING)
433 tentative = false;
ec2c5e43 434
748a548e 435 r = dns_zone_add_authenticated_answer(answer, j, ifindex);
5032b16d
LP
436 if (r < 0)
437 return r;
438 }
ec2c5e43 439
5032b16d
LP
440 if (!found) {
441 bool add_soa = false;
ec2c5e43 442
1c02e7ba 443 first = hashmap_get(z->by_name, dns_resource_key_name(key));
5032b16d
LP
444 LIST_FOREACH(by_name, j, first) {
445 if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
446 continue;
ec2c5e43 447
5032b16d
LP
448 if (j->state != DNS_ZONE_ITEM_PROBING)
449 tentative = false;
ec2c5e43 450
5032b16d
LP
451 add_soa = true;
452 }
453
454 if (add_soa) {
97ebebbc 455 r = dns_answer_add_soa(soa, dns_resource_key_name(key), LLMNR_DEFAULT_TTL, ifindex);
5032b16d
LP
456 if (r < 0)
457 return r;
d5323661 458 }
623a4c97
LP
459 }
460 }
461
5032b16d
LP
462 /* If the caller sets ret_tentative to NULL, then use this as
463 * indication to not return tentative entries */
464
465 if (!ret_tentative && tentative)
466 goto return_empty;
467
1cc6c93a 468 *ret_answer = TAKE_PTR(answer);
623a4c97 469
1cc6c93a
YW
470 if (ret_soa)
471 *ret_soa = TAKE_PTR(soa);
8bf52d3d 472
ec2c5e43
LP
473 if (ret_tentative)
474 *ret_tentative = tentative;
475
623a4c97 476 return 1;
5032b16d
LP
477
478return_empty:
479 *ret_answer = NULL;
480
481 if (ret_soa)
482 *ret_soa = NULL;
483
484 if (ret_tentative)
485 *ret_tentative = false;
486
487 return 0;
623a4c97 488}
ec2c5e43
LP
489
490void dns_zone_item_conflict(DnsZoneItem *i) {
ec2c5e43
LP
491 assert(i);
492
a4076574
LP
493 if (!IN_SET(i->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_VERIFYING, DNS_ZONE_ITEM_ESTABLISHED))
494 return;
495
7b50eb2e 496 log_info("Detected conflict on %s", strna(dns_resource_record_to_string(i->rr)));
ec2c5e43 497
d84b686f
LP
498 dns_zone_item_probe_stop(i);
499
ec2c5e43
LP
500 /* Withdraw the conflict item */
501 i->state = DNS_ZONE_ITEM_WITHDRAWN;
502
c3036641
DR
503 dnssd_signal_conflict(i->scope->manager, dns_resource_key_name(i->rr->key));
504
ec2c5e43 505 /* Maybe change the hostname */
1c02e7ba 506 if (manager_is_own_hostname(i->scope->manager, dns_resource_key_name(i->rr->key)) > 0)
ec2c5e43
LP
507 manager_next_hostname(i->scope->manager);
508}
509
547973de 510void dns_zone_item_notify(DnsZoneItem *i) {
ec2c5e43
LP
511 assert(i);
512 assert(i->probe_transaction);
513
514 if (i->block_ready > 0)
515 return;
516
547973de 517 if (IN_SET(i->probe_transaction->state, DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING, DNS_TRANSACTION_VALIDATING))
ec2c5e43
LP
518 return;
519
a4076574
LP
520 if (i->probe_transaction->state == DNS_TRANSACTION_SUCCESS) {
521 bool we_lost = false;
ec2c5e43 522
a4076574 523 /* The probe got a successful reply. If we so far
008d4ab7
DR
524 * weren't established we just give up.
525 *
526 * In LLMNR case if we already
a4076574 527 * were established, and the peer has the
4d91eec4 528 * lexicographically larger IP address we continue
a4076574
LP
529 * and defend it. */
530
2fb3034c
LP
531 if (!IN_SET(i->state, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING)) {
532 log_debug("Got a successful probe for not yet established RR, we lost.");
a4076574 533 we_lost = true;
008d4ab7 534 } else if (i->probe_transaction->scope->protocol == DNS_PROTOCOL_LLMNR) {
a4076574 535 assert(i->probe_transaction->received);
4d91eec4 536 we_lost = memcmp(&i->probe_transaction->received->sender, &i->probe_transaction->received->destination, FAMILY_ADDRESS_SIZE(i->probe_transaction->received->family)) < 0;
2fb3034c 537 if (we_lost)
4d91eec4 538 log_debug("Got a successful probe reply for an established RR, and we have a lexicographically larger IP address and thus lost.");
a4076574
LP
539 }
540
541 if (we_lost) {
542 dns_zone_item_conflict(i);
543 return;
544 }
545
546 log_debug("Got a successful probe reply, but peer has lexicographically lower IP address and thus lost.");
547 }
548
7b50eb2e 549 log_debug("Record %s successfully probed.", strna(dns_resource_record_to_string(i->rr)));
ec2c5e43 550
a4076574
LP
551 dns_zone_item_probe_stop(i);
552 i->state = DNS_ZONE_ITEM_ESTABLISHED;
553}
554
555static int dns_zone_item_verify(DnsZoneItem *i) {
556 int r;
557
558 assert(i);
559
560 if (i->state != DNS_ZONE_ITEM_ESTABLISHED)
561 return 0;
562
7b50eb2e 563 log_debug("Verifying RR %s", strna(dns_resource_record_to_string(i->rr)));
2fb3034c 564
a4076574
LP
565 i->state = DNS_ZONE_ITEM_VERIFYING;
566 r = dns_zone_item_probe_start(i);
567 if (r < 0) {
da927ba9 568 log_error_errno(r, "Failed to start probing for verifying RR: %m");
ec2c5e43 569 i->state = DNS_ZONE_ITEM_ESTABLISHED;
a4076574
LP
570 return r;
571 }
572
573 return 0;
574}
575
576int dns_zone_check_conflicts(DnsZone *zone, DnsResourceRecord *rr) {
577 DnsZoneItem *i, *first;
bf1594f5 578 int c = 0;
a4076574
LP
579
580 assert(zone);
581 assert(rr);
582
583 /* This checks whether a response RR we received from somebody
584 * else is one that we actually thought was uniquely ours. If
585 * so, we'll verify our RRs. */
586
587 /* No conflict if we don't have the name at all. */
1c02e7ba 588 first = hashmap_get(zone->by_name, dns_resource_key_name(rr->key));
a4076574
LP
589 if (!first)
590 return 0;
591
592 /* No conflict if we have the exact same RR */
593 if (dns_zone_get(zone, rr))
594 return 0;
595
d686f15c
DR
596 /* No conflict if it is DNS-SD RR used for service enumeration. */
597 if (dns_resource_key_is_dnssd_ptr(rr->key))
598 return 0;
599
a4076574
LP
600 /* OK, somebody else has RRs for the same name. Yuck! Let's
601 * start probing again */
602
603 LIST_FOREACH(by_name, i, first) {
604 if (dns_resource_record_equal(i->rr, rr))
605 continue;
606
607 dns_zone_item_verify(i);
608 c++;
609 }
610
611 return c;
612}
613
614int dns_zone_verify_conflicts(DnsZone *zone, DnsResourceKey *key) {
615 DnsZoneItem *i, *first;
bf1594f5 616 int c = 0;
a4076574
LP
617
618 assert(zone);
619
620 /* Somebody else notified us about a possible conflict. Let's
621 * verify if that's true. */
622
1c02e7ba 623 first = hashmap_get(zone->by_name, dns_resource_key_name(key));
a4076574
LP
624 if (!first)
625 return 0;
626
627 LIST_FOREACH(by_name, i, first) {
628 dns_zone_item_verify(i);
629 c++;
630 }
631
632 return c;
ec2c5e43 633}
902bb5d8
LP
634
635void dns_zone_verify_all(DnsZone *zone) {
636 DnsZoneItem *i;
637 Iterator iterator;
638
639 assert(zone);
640
641 HASHMAP_FOREACH(i, zone->by_key, iterator) {
642 DnsZoneItem *j;
643
644 LIST_FOREACH(by_key, j, i)
645 dns_zone_item_verify(j);
646 }
647}
4d506d6b
LP
648
649void dns_zone_dump(DnsZone *zone, FILE *f) {
650 Iterator iterator;
651 DnsZoneItem *i;
4d506d6b
LP
652
653 if (!zone)
654 return;
655
656 if (!f)
657 f = stdout;
658
659 HASHMAP_FOREACH(i, zone->by_key, iterator) {
660 DnsZoneItem *j;
661
662 LIST_FOREACH(by_key, j, i) {
7b50eb2e 663 const char *t;
4d506d6b 664
7b50eb2e
LP
665 t = dns_resource_record_to_string(j->rr);
666 if (!t) {
4d506d6b
LP
667 log_oom();
668 continue;
669 }
670
671 fputc('\t', f);
672 fputs(t, f);
673 fputc('\n', f);
674 }
675 }
676}
677
678bool dns_zone_is_empty(DnsZone *zone) {
679 if (!zone)
680 return true;
681
682 return hashmap_isempty(zone->by_key);
683}
a2bf8a19
DR
684
685bool dns_zone_contains_name(DnsZone *z, const char *name) {
686 DnsZoneItem *i, *first;
687
688 first = hashmap_get(z->by_name, name);
689 if (!first)
690 return false;
691
692 LIST_FOREACH(by_name, i, first) {
693 if (!IN_SET(i->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
694 continue;
695
696 return true;
697 }
698
699 return false;
700}