catz.c revision 1.8 1 /* $NetBSD: catz.c,v 1.8 2022/09/23 12:15:29 christos Exp $ */
2
3 /*
4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 *
6 * SPDX-License-Identifier: MPL-2.0
7 *
8 * This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0. If a copy of the MPL was not distributed with this
10 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11 *
12 * See the COPYRIGHT file distributed with this work for additional
13 * information regarding copyright ownership.
14 */
15
16 /*! \file */
17
18 #include <inttypes.h>
19 #include <stdbool.h>
20
21 #include <isc/hex.h>
22 #include <isc/md.h>
23 #include <isc/mem.h>
24 #include <isc/parseint.h>
25 #include <isc/print.h>
26 #include <isc/result.h>
27 #include <isc/task.h>
28 #include <isc/util.h>
29
30 #include <dns/catz.h>
31 #include <dns/dbiterator.h>
32 #include <dns/events.h>
33 #include <dns/rdatasetiter.h>
34 #include <dns/view.h>
35 #include <dns/zone.h>
36
37 #define DNS_CATZ_ZONE_MAGIC ISC_MAGIC('c', 'a', 't', 'z')
38 #define DNS_CATZ_ZONES_MAGIC ISC_MAGIC('c', 'a', 't', 's')
39 #define DNS_CATZ_ENTRY_MAGIC ISC_MAGIC('c', 'a', 't', 'e')
40
41 #define DNS_CATZ_ZONE_VALID(catz) ISC_MAGIC_VALID(catz, DNS_CATZ_ZONE_MAGIC)
42 #define DNS_CATZ_ZONES_VALID(catzs) ISC_MAGIC_VALID(catzs, DNS_CATZ_ZONES_MAGIC)
43 #define DNS_CATZ_ENTRY_VALID(entry) ISC_MAGIC_VALID(entry, DNS_CATZ_ENTRY_MAGIC)
44
45 /*%
46 * Single member zone in a catalog
47 */
48 struct dns_catz_entry {
49 unsigned int magic;
50 dns_name_t name;
51 dns_catz_options_t opts;
52 isc_refcount_t refs;
53 };
54
55 /*%
56 * Catalog zone
57 */
58 struct dns_catz_zone {
59 unsigned int magic;
60 dns_name_t name;
61 dns_catz_zones_t *catzs;
62 dns_rdata_t soa;
63 /* key in entries is 'mhash', not domain name! */
64 isc_ht_t *entries;
65 /*
66 * defoptions are taken from named.conf
67 * zoneoptions are global options from zone
68 */
69 dns_catz_options_t defoptions;
70 dns_catz_options_t zoneoptions;
71 isc_time_t lastupdated;
72 bool updatepending;
73 uint32_t version;
74
75 dns_db_t *db;
76 dns_dbversion_t *dbversion;
77
78 isc_timer_t *updatetimer;
79 isc_event_t updateevent;
80
81 bool active;
82 bool db_registered;
83
84 isc_refcount_t refs;
85 };
86
87 static isc_result_t
88 catz_process_zones_entry(dns_catz_zone_t *zone, dns_rdataset_t *value,
89 dns_label_t *mhash);
90 static isc_result_t
91 catz_process_zones_suboption(dns_catz_zone_t *zone, dns_rdataset_t *value,
92 dns_label_t *mhash, dns_name_t *name);
93 static void
94 catz_entry_add_or_mod(dns_catz_zone_t *target, isc_ht_t *ht, unsigned char *key,
95 size_t keysize, dns_catz_entry_t *nentry,
96 dns_catz_entry_t *oentry, const char *msg,
97 const char *zname, const char *czname);
98
99 /*%
100 * Collection of catalog zones for a view
101 */
102 struct dns_catz_zones {
103 unsigned int magic;
104 isc_ht_t *zones;
105 isc_mem_t *mctx;
106 isc_refcount_t refs;
107 isc_mutex_t lock;
108 dns_catz_zonemodmethods_t *zmm;
109 isc_taskmgr_t *taskmgr;
110 isc_timermgr_t *timermgr;
111 dns_view_t *view;
112 isc_task_t *updater;
113 };
114
115 void
116 dns_catz_options_init(dns_catz_options_t *options) {
117 REQUIRE(options != NULL);
118
119 dns_ipkeylist_init(&options->masters);
120
121 options->allow_query = NULL;
122 options->allow_transfer = NULL;
123
124 options->allow_query = NULL;
125 options->allow_transfer = NULL;
126
127 options->in_memory = false;
128 options->min_update_interval = 5;
129 options->zonedir = NULL;
130 }
131
132 void
133 dns_catz_options_free(dns_catz_options_t *options, isc_mem_t *mctx) {
134 REQUIRE(options != NULL);
135 REQUIRE(mctx != NULL);
136
137 if (options->masters.count != 0) {
138 dns_ipkeylist_clear(mctx, &options->masters);
139 }
140 if (options->zonedir != NULL) {
141 isc_mem_free(mctx, options->zonedir);
142 options->zonedir = NULL;
143 }
144 if (options->allow_query != NULL) {
145 isc_buffer_free(&options->allow_query);
146 }
147 if (options->allow_transfer != NULL) {
148 isc_buffer_free(&options->allow_transfer);
149 }
150 }
151
152 isc_result_t
153 dns_catz_options_copy(isc_mem_t *mctx, const dns_catz_options_t *src,
154 dns_catz_options_t *dst) {
155 REQUIRE(mctx != NULL);
156 REQUIRE(src != NULL);
157 REQUIRE(dst != NULL);
158 REQUIRE(dst->masters.count == 0);
159 REQUIRE(dst->allow_query == NULL);
160 REQUIRE(dst->allow_transfer == NULL);
161
162 if (src->masters.count != 0) {
163 dns_ipkeylist_copy(mctx, &src->masters, &dst->masters);
164 }
165
166 if (dst->zonedir != NULL) {
167 isc_mem_free(mctx, dst->zonedir);
168 dst->zonedir = NULL;
169 }
170
171 if (src->zonedir != NULL) {
172 dst->zonedir = isc_mem_strdup(mctx, src->zonedir);
173 }
174
175 if (src->allow_query != NULL) {
176 isc_buffer_dup(mctx, &dst->allow_query, src->allow_query);
177 }
178
179 if (src->allow_transfer != NULL) {
180 isc_buffer_dup(mctx, &dst->allow_transfer, src->allow_transfer);
181 }
182
183 return (ISC_R_SUCCESS);
184 }
185
186 isc_result_t
187 dns_catz_options_setdefault(isc_mem_t *mctx, const dns_catz_options_t *defaults,
188 dns_catz_options_t *opts) {
189 REQUIRE(mctx != NULL);
190 REQUIRE(defaults != NULL);
191 REQUIRE(opts != NULL);
192
193 if (opts->masters.count == 0 && defaults->masters.count != 0) {
194 dns_ipkeylist_copy(mctx, &defaults->masters, &opts->masters);
195 }
196
197 if (defaults->zonedir != NULL) {
198 opts->zonedir = isc_mem_strdup(mctx, defaults->zonedir);
199 }
200
201 if (opts->allow_query == NULL && defaults->allow_query != NULL) {
202 isc_buffer_dup(mctx, &opts->allow_query, defaults->allow_query);
203 }
204 if (opts->allow_transfer == NULL && defaults->allow_transfer != NULL) {
205 isc_buffer_dup(mctx, &opts->allow_transfer,
206 defaults->allow_transfer);
207 }
208
209 /* This option is always taken from config, so it's always 'default' */
210 opts->in_memory = defaults->in_memory;
211 return (ISC_R_SUCCESS);
212 }
213
214 isc_result_t
215 dns_catz_entry_new(isc_mem_t *mctx, const dns_name_t *domain,
216 dns_catz_entry_t **nentryp) {
217 dns_catz_entry_t *nentry;
218
219 REQUIRE(mctx != NULL);
220 REQUIRE(nentryp != NULL && *nentryp == NULL);
221
222 nentry = isc_mem_get(mctx, sizeof(dns_catz_entry_t));
223
224 dns_name_init(&nentry->name, NULL);
225 if (domain != NULL) {
226 dns_name_dup(domain, mctx, &nentry->name);
227 }
228
229 dns_catz_options_init(&nentry->opts);
230 isc_refcount_init(&nentry->refs, 1);
231 nentry->magic = DNS_CATZ_ENTRY_MAGIC;
232 *nentryp = nentry;
233 return (ISC_R_SUCCESS);
234 }
235
236 dns_name_t *
237 dns_catz_entry_getname(dns_catz_entry_t *entry) {
238 REQUIRE(DNS_CATZ_ENTRY_VALID(entry));
239 return (&entry->name);
240 }
241
242 isc_result_t
243 dns_catz_entry_copy(dns_catz_zone_t *zone, const dns_catz_entry_t *entry,
244 dns_catz_entry_t **nentryp) {
245 isc_result_t result;
246 dns_catz_entry_t *nentry = NULL;
247
248 REQUIRE(DNS_CATZ_ZONE_VALID(zone));
249 REQUIRE(DNS_CATZ_ENTRY_VALID(entry));
250 REQUIRE(nentryp != NULL && *nentryp == NULL);
251
252 result = dns_catz_entry_new(zone->catzs->mctx, &entry->name, &nentry);
253 if (result != ISC_R_SUCCESS) {
254 return (result);
255 }
256
257 result = dns_catz_options_copy(zone->catzs->mctx, &entry->opts,
258 &nentry->opts);
259 if (result != ISC_R_SUCCESS) {
260 dns_catz_entry_detach(zone, &nentry);
261 }
262
263 *nentryp = nentry;
264 return (result);
265 }
266
267 void
268 dns_catz_entry_attach(dns_catz_entry_t *entry, dns_catz_entry_t **entryp) {
269 REQUIRE(DNS_CATZ_ENTRY_VALID(entry));
270 REQUIRE(entryp != NULL && *entryp == NULL);
271
272 isc_refcount_increment(&entry->refs);
273 *entryp = entry;
274 }
275
276 void
277 dns_catz_entry_detach(dns_catz_zone_t *zone, dns_catz_entry_t **entryp) {
278 dns_catz_entry_t *entry;
279
280 REQUIRE(DNS_CATZ_ZONE_VALID(zone));
281 REQUIRE(entryp != NULL);
282 entry = *entryp;
283 *entryp = NULL;
284 REQUIRE(DNS_CATZ_ENTRY_VALID(entry));
285
286 if (isc_refcount_decrement(&entry->refs) == 1) {
287 isc_mem_t *mctx = zone->catzs->mctx;
288 entry->magic = 0;
289 isc_refcount_destroy(&entry->refs);
290 dns_catz_options_free(&entry->opts, mctx);
291 if (dns_name_dynamic(&entry->name)) {
292 dns_name_free(&entry->name, mctx);
293 }
294 isc_mem_put(mctx, entry, sizeof(dns_catz_entry_t));
295 }
296 }
297
298 bool
299 dns_catz_entry_validate(const dns_catz_entry_t *entry) {
300 REQUIRE(DNS_CATZ_ENTRY_VALID(entry));
301 UNUSED(entry);
302
303 return (true);
304 }
305
306 bool
307 dns_catz_entry_cmp(const dns_catz_entry_t *ea, const dns_catz_entry_t *eb) {
308 isc_region_t ra, rb;
309
310 REQUIRE(DNS_CATZ_ENTRY_VALID(ea));
311 REQUIRE(DNS_CATZ_ENTRY_VALID(eb));
312
313 if (ea == eb) {
314 return (true);
315 }
316
317 if (ea->opts.masters.count != eb->opts.masters.count) {
318 return (false);
319 }
320
321 if (memcmp(ea->opts.masters.addrs, eb->opts.masters.addrs,
322 ea->opts.masters.count * sizeof(isc_sockaddr_t)))
323 {
324 return (false);
325 }
326
327 /* If one is NULL and the other isn't, the entries don't match */
328 if ((ea->opts.allow_query == NULL) != (eb->opts.allow_query == NULL)) {
329 return (false);
330 }
331
332 /* If one is non-NULL, then they both are */
333 if (ea->opts.allow_query != NULL) {
334 isc_buffer_usedregion(ea->opts.allow_query, &ra);
335 isc_buffer_usedregion(eb->opts.allow_query, &rb);
336 if (isc_region_compare(&ra, &rb)) {
337 return (false);
338 }
339 }
340
341 /* Repeat the above checks with allow_transfer */
342 if ((ea->opts.allow_transfer == NULL) !=
343 (eb->opts.allow_transfer == NULL)) {
344 return (false);
345 }
346
347 if (ea->opts.allow_transfer != NULL) {
348 isc_buffer_usedregion(ea->opts.allow_transfer, &ra);
349 isc_buffer_usedregion(eb->opts.allow_transfer, &rb);
350 if (isc_region_compare(&ra, &rb)) {
351 return (false);
352 }
353 }
354
355 /* xxxwpk TODO compare dscps/keys! */
356 return (true);
357 }
358
359 dns_name_t *
360 dns_catz_zone_getname(dns_catz_zone_t *zone) {
361 REQUIRE(DNS_CATZ_ZONE_VALID(zone));
362
363 return (&zone->name);
364 }
365
366 dns_catz_options_t *
367 dns_catz_zone_getdefoptions(dns_catz_zone_t *zone) {
368 REQUIRE(DNS_CATZ_ZONE_VALID(zone));
369
370 return (&zone->defoptions);
371 }
372
373 void
374 dns_catz_zone_resetdefoptions(dns_catz_zone_t *zone) {
375 REQUIRE(DNS_CATZ_ZONE_VALID(zone));
376
377 dns_catz_options_free(&zone->defoptions, zone->catzs->mctx);
378 dns_catz_options_init(&zone->defoptions);
379 }
380
381 isc_result_t
382 dns_catz_zones_merge(dns_catz_zone_t *target, dns_catz_zone_t *newzone) {
383 isc_result_t result;
384 isc_ht_iter_t *iter1 = NULL, *iter2 = NULL;
385 isc_ht_iter_t *iteradd = NULL, *itermod = NULL;
386 isc_ht_t *toadd = NULL, *tomod = NULL;
387 bool delcur = false;
388 char czname[DNS_NAME_FORMATSIZE];
389 char zname[DNS_NAME_FORMATSIZE];
390 dns_catz_zoneop_fn_t addzone, modzone, delzone;
391
392 REQUIRE(DNS_CATZ_ZONE_VALID(newzone));
393 REQUIRE(DNS_CATZ_ZONE_VALID(target));
394
395 /* TODO verify the new zone first! */
396
397 addzone = target->catzs->zmm->addzone;
398 modzone = target->catzs->zmm->modzone;
399 delzone = target->catzs->zmm->delzone;
400
401 /* Copy zoneoptions from newzone into target. */
402
403 dns_catz_options_free(&target->zoneoptions, target->catzs->mctx);
404 dns_catz_options_copy(target->catzs->mctx, &newzone->zoneoptions,
405 &target->zoneoptions);
406 dns_catz_options_setdefault(target->catzs->mctx, &target->defoptions,
407 &target->zoneoptions);
408
409 dns_name_format(&target->name, czname, DNS_NAME_FORMATSIZE);
410
411 isc_ht_init(&toadd, target->catzs->mctx, 16);
412
413 isc_ht_init(&tomod, target->catzs->mctx, 16);
414
415 isc_ht_iter_create(newzone->entries, &iter1);
416
417 isc_ht_iter_create(target->entries, &iter2);
418
419 /*
420 * We can create those iterators now, even though toadd and tomod are
421 * empty
422 */
423 isc_ht_iter_create(toadd, &iteradd);
424
425 isc_ht_iter_create(tomod, &itermod);
426
427 /*
428 * First - walk the new zone and find all nodes that are not in the
429 * old zone, or are in both zones and are modified.
430 */
431 for (result = isc_ht_iter_first(iter1); result == ISC_R_SUCCESS;
432 result = delcur ? isc_ht_iter_delcurrent_next(iter1)
433 : isc_ht_iter_next(iter1))
434 {
435 dns_catz_entry_t *nentry = NULL;
436 dns_catz_entry_t *oentry = NULL;
437 dns_zone_t *zone = NULL;
438 unsigned char *key = NULL;
439 size_t keysize;
440 delcur = false;
441
442 isc_ht_iter_current(iter1, (void **)&nentry);
443 isc_ht_iter_currentkey(iter1, &key, &keysize);
444
445 /*
446 * Spurious record that came from suboption without main
447 * record, removed.
448 * xxxwpk: make it a separate verification phase?
449 */
450 if (dns_name_countlabels(&nentry->name) == 0) {
451 dns_catz_entry_detach(newzone, &nentry);
452 delcur = true;
453 continue;
454 }
455
456 dns_name_format(&nentry->name, zname, DNS_NAME_FORMATSIZE);
457
458 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
459 DNS_LOGMODULE_MASTER, ISC_LOG_DEBUG(3),
460 "catz: iterating over '%s' from catalog '%s'",
461 zname, czname);
462 dns_catz_options_setdefault(target->catzs->mctx,
463 &target->zoneoptions,
464 &nentry->opts);
465
466 result = isc_ht_find(target->entries, key, (uint32_t)keysize,
467 (void **)&oentry);
468 if (result != ISC_R_SUCCESS) {
469 catz_entry_add_or_mod(target, toadd, key, keysize,
470 nentry, NULL, "adding", zname,
471 czname);
472 continue;
473 }
474
475 result = dns_zt_find(target->catzs->view->zonetable,
476 dns_catz_entry_getname(nentry), 0, NULL,
477 &zone);
478 if (result != ISC_R_SUCCESS) {
479 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
480 DNS_LOGMODULE_MASTER, ISC_LOG_DEBUG(3),
481 "catz: zone '%s' was expected to exist "
482 "but can not be found, will be restored",
483 zname);
484 catz_entry_add_or_mod(target, toadd, key, keysize,
485 nentry, oentry, "adding", zname,
486 czname);
487 continue;
488 }
489 dns_zone_detach(&zone);
490
491 if (dns_catz_entry_cmp(oentry, nentry) != true) {
492 catz_entry_add_or_mod(target, tomod, key, keysize,
493 nentry, oentry, "modifying",
494 zname, czname);
495 continue;
496 }
497
498 /*
499 * Delete the old entry so that it won't accidentally be
500 * removed as a non-existing entry below.
501 */
502 dns_catz_entry_detach(target, &oentry);
503 result = isc_ht_delete(target->entries, key, (uint32_t)keysize);
504 RUNTIME_CHECK(result == ISC_R_SUCCESS);
505 }
506 RUNTIME_CHECK(result == ISC_R_NOMORE);
507 isc_ht_iter_destroy(&iter1);
508
509 /*
510 * Then - walk the old zone; only deleted entries should remain.
511 */
512 for (result = isc_ht_iter_first(iter2); result == ISC_R_SUCCESS;
513 result = isc_ht_iter_delcurrent_next(iter2))
514 {
515 dns_catz_entry_t *entry = NULL;
516 isc_ht_iter_current(iter2, (void **)&entry);
517
518 dns_name_format(&entry->name, zname, DNS_NAME_FORMATSIZE);
519 result = delzone(entry, target, target->catzs->view,
520 target->catzs->taskmgr,
521 target->catzs->zmm->udata);
522 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
523 DNS_LOGMODULE_MASTER, ISC_LOG_INFO,
524 "catz: deleting zone '%s' from catalog '%s' - %s",
525 zname, czname, isc_result_totext(result));
526 dns_catz_entry_detach(target, &entry);
527 }
528 RUNTIME_CHECK(result == ISC_R_NOMORE);
529 isc_ht_iter_destroy(&iter2);
530 /* At this moment target->entries has to be be empty. */
531 INSIST(isc_ht_count(target->entries) == 0);
532 isc_ht_destroy(&target->entries);
533
534 for (result = isc_ht_iter_first(iteradd); result == ISC_R_SUCCESS;
535 result = isc_ht_iter_delcurrent_next(iteradd))
536 {
537 dns_catz_entry_t *entry = NULL;
538 isc_ht_iter_current(iteradd, (void **)&entry);
539
540 dns_name_format(&entry->name, zname, DNS_NAME_FORMATSIZE);
541 result = addzone(entry, target, target->catzs->view,
542 target->catzs->taskmgr,
543 target->catzs->zmm->udata);
544 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
545 DNS_LOGMODULE_MASTER, ISC_LOG_INFO,
546 "catz: adding zone '%s' from catalog "
547 "'%s' - %s",
548 zname, czname, isc_result_totext(result));
549 }
550
551 for (result = isc_ht_iter_first(itermod); result == ISC_R_SUCCESS;
552 result = isc_ht_iter_delcurrent_next(itermod))
553 {
554 dns_catz_entry_t *entry = NULL;
555 isc_ht_iter_current(itermod, (void **)&entry);
556
557 dns_name_format(&entry->name, zname, DNS_NAME_FORMATSIZE);
558 result = modzone(entry, target, target->catzs->view,
559 target->catzs->taskmgr,
560 target->catzs->zmm->udata);
561 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
562 DNS_LOGMODULE_MASTER, ISC_LOG_INFO,
563 "catz: modifying zone '%s' from catalog "
564 "'%s' - %s",
565 zname, czname, isc_result_totext(result));
566 }
567
568 target->entries = newzone->entries;
569 newzone->entries = NULL;
570
571 result = ISC_R_SUCCESS;
572
573 isc_ht_iter_destroy(&iteradd);
574 isc_ht_iter_destroy(&itermod);
575 isc_ht_destroy(&toadd);
576 isc_ht_destroy(&tomod);
577
578 return (result);
579 }
580
581 isc_result_t
582 dns_catz_new_zones(dns_catz_zones_t **catzsp, dns_catz_zonemodmethods_t *zmm,
583 isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
584 isc_timermgr_t *timermgr) {
585 dns_catz_zones_t *new_zones;
586 isc_result_t result;
587
588 REQUIRE(catzsp != NULL && *catzsp == NULL);
589 REQUIRE(zmm != NULL);
590
591 new_zones = isc_mem_get(mctx, sizeof(*new_zones));
592 memset(new_zones, 0, sizeof(*new_zones));
593
594 isc_mutex_init(&new_zones->lock);
595
596 isc_refcount_init(&new_zones->refs, 1);
597
598 isc_ht_init(&new_zones->zones, mctx, 4);
599
600 isc_mem_attach(mctx, &new_zones->mctx);
601 new_zones->zmm = zmm;
602 new_zones->timermgr = timermgr;
603 new_zones->taskmgr = taskmgr;
604
605 result = isc_task_create(taskmgr, 0, &new_zones->updater);
606 if (result != ISC_R_SUCCESS) {
607 goto cleanup_ht;
608 }
609 new_zones->magic = DNS_CATZ_ZONES_MAGIC;
610
611 *catzsp = new_zones;
612 return (ISC_R_SUCCESS);
613
614 cleanup_ht:
615 isc_ht_destroy(&new_zones->zones);
616 isc_refcount_destroy(&new_zones->refs);
617 isc_mutex_destroy(&new_zones->lock);
618 isc_mem_put(mctx, new_zones, sizeof(*new_zones));
619
620 return (result);
621 }
622
623 void
624 dns_catz_catzs_set_view(dns_catz_zones_t *catzs, dns_view_t *view) {
625 REQUIRE(DNS_CATZ_ZONES_VALID(catzs));
626 REQUIRE(view != NULL);
627 /* Either it's a new one or it's being reconfigured. */
628 REQUIRE(catzs->view == NULL || !strcmp(catzs->view->name, view->name));
629
630 catzs->view = view;
631 }
632
633 isc_result_t
634 dns_catz_new_zone(dns_catz_zones_t *catzs, dns_catz_zone_t **zonep,
635 const dns_name_t *name) {
636 isc_result_t result;
637 dns_catz_zone_t *new_zone;
638
639 REQUIRE(DNS_CATZ_ZONES_VALID(catzs));
640 REQUIRE(zonep != NULL && *zonep == NULL);
641 REQUIRE(ISC_MAGIC_VALID(name, DNS_NAME_MAGIC));
642
643 new_zone = isc_mem_get(catzs->mctx, sizeof(*new_zone));
644
645 memset(new_zone, 0, sizeof(*new_zone));
646
647 dns_name_init(&new_zone->name, NULL);
648 dns_name_dup(name, catzs->mctx, &new_zone->name);
649
650 isc_ht_init(&new_zone->entries, catzs->mctx, 4);
651
652 new_zone->updatetimer = NULL;
653 result = isc_timer_create(catzs->timermgr, isc_timertype_inactive, NULL,
654 NULL, catzs->updater,
655 dns_catz_update_taskaction, new_zone,
656 &new_zone->updatetimer);
657 if (result != ISC_R_SUCCESS) {
658 goto cleanup_ht;
659 }
660
661 isc_time_settoepoch(&new_zone->lastupdated);
662 new_zone->updatepending = false;
663 new_zone->db = NULL;
664 new_zone->dbversion = NULL;
665 new_zone->catzs = catzs;
666 dns_catz_options_init(&new_zone->defoptions);
667 dns_catz_options_init(&new_zone->zoneoptions);
668 new_zone->active = true;
669 new_zone->db_registered = false;
670 new_zone->version = (uint32_t)(-1);
671 isc_refcount_init(&new_zone->refs, 1);
672 new_zone->magic = DNS_CATZ_ZONE_MAGIC;
673
674 *zonep = new_zone;
675
676 return (ISC_R_SUCCESS);
677
678 cleanup_ht:
679 isc_ht_destroy(&new_zone->entries);
680 dns_name_free(&new_zone->name, catzs->mctx);
681 isc_mem_put(catzs->mctx, new_zone, sizeof(*new_zone));
682
683 return (result);
684 }
685
686 isc_result_t
687 dns_catz_add_zone(dns_catz_zones_t *catzs, const dns_name_t *name,
688 dns_catz_zone_t **zonep) {
689 dns_catz_zone_t *new_zone = NULL;
690 isc_result_t result, tresult;
691 char zname[DNS_NAME_FORMATSIZE];
692
693 REQUIRE(DNS_CATZ_ZONES_VALID(catzs));
694 REQUIRE(ISC_MAGIC_VALID(name, DNS_NAME_MAGIC));
695 REQUIRE(zonep != NULL && *zonep == NULL);
696
697 dns_name_format(name, zname, DNS_NAME_FORMATSIZE);
698 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_MASTER,
699 ISC_LOG_DEBUG(3), "catz: dns_catz_add_zone %s", zname);
700
701 LOCK(&catzs->lock);
702
703 result = dns_catz_new_zone(catzs, &new_zone, name);
704 if (result != ISC_R_SUCCESS) {
705 goto cleanup;
706 }
707
708 result = isc_ht_add(catzs->zones, new_zone->name.ndata,
709 new_zone->name.length, new_zone);
710 if (result != ISC_R_SUCCESS) {
711 dns_catz_zone_detach(&new_zone);
712 if (result != ISC_R_EXISTS) {
713 goto cleanup;
714 }
715 }
716
717 if (result == ISC_R_EXISTS) {
718 tresult = isc_ht_find(catzs->zones, name->ndata, name->length,
719 (void **)&new_zone);
720 INSIST(tresult == ISC_R_SUCCESS && !new_zone->active);
721 new_zone->active = true;
722 }
723
724 *zonep = new_zone;
725
726 cleanup:
727 UNLOCK(&catzs->lock);
728
729 return (result);
730 }
731
732 dns_catz_zone_t *
733 dns_catz_get_zone(dns_catz_zones_t *catzs, const dns_name_t *name) {
734 isc_result_t result;
735 dns_catz_zone_t *found = NULL;
736
737 REQUIRE(DNS_CATZ_ZONES_VALID(catzs));
738 REQUIRE(ISC_MAGIC_VALID(name, DNS_NAME_MAGIC));
739
740 result = isc_ht_find(catzs->zones, name->ndata, name->length,
741 (void **)&found);
742 if (result != ISC_R_SUCCESS) {
743 return (NULL);
744 }
745
746 return (found);
747 }
748
749 void
750 dns_catz_catzs_attach(dns_catz_zones_t *catzs, dns_catz_zones_t **catzsp) {
751 REQUIRE(DNS_CATZ_ZONES_VALID(catzs));
752 REQUIRE(catzsp != NULL && *catzsp == NULL);
753
754 isc_refcount_increment(&catzs->refs);
755 *catzsp = catzs;
756 }
757
758 void
759 dns_catz_zone_attach(dns_catz_zone_t *zone, dns_catz_zone_t **zonep) {
760 REQUIRE(zonep != NULL && *zonep == NULL);
761
762 isc_refcount_increment(&zone->refs);
763 *zonep = zone;
764 }
765
766 void
767 dns_catz_zone_detach(dns_catz_zone_t **zonep) {
768 REQUIRE(zonep != NULL && *zonep != NULL);
769 dns_catz_zone_t *zone = *zonep;
770 *zonep = NULL;
771
772 if (isc_refcount_decrement(&zone->refs) == 1) {
773 isc_mem_t *mctx = zone->catzs->mctx;
774 isc_refcount_destroy(&zone->refs);
775 if (zone->entries != NULL) {
776 isc_ht_iter_t *iter = NULL;
777 isc_result_t result;
778 isc_ht_iter_create(zone->entries, &iter);
779 for (result = isc_ht_iter_first(iter);
780 result == ISC_R_SUCCESS;
781 result = isc_ht_iter_delcurrent_next(iter))
782 {
783 dns_catz_entry_t *entry = NULL;
784
785 isc_ht_iter_current(iter, (void **)&entry);
786 dns_catz_entry_detach(zone, &entry);
787 }
788 INSIST(result == ISC_R_NOMORE);
789 isc_ht_iter_destroy(&iter);
790
791 /* The hashtable has to be empty now. */
792 INSIST(isc_ht_count(zone->entries) == 0);
793 isc_ht_destroy(&zone->entries);
794 }
795 zone->magic = 0;
796 isc_timer_detach(&zone->updatetimer);
797 if (zone->db_registered) {
798 INSIST(dns_db_updatenotify_unregister(
799 zone->db, dns_catz_dbupdate_callback,
800 zone->catzs) == ISC_R_SUCCESS);
801 }
802 if (zone->dbversion) {
803 dns_db_closeversion(zone->db, &zone->dbversion, false);
804 }
805 if (zone->db != NULL) {
806 dns_db_detach(&zone->db);
807 }
808
809 dns_name_free(&zone->name, mctx);
810 dns_catz_options_free(&zone->defoptions, mctx);
811 dns_catz_options_free(&zone->zoneoptions, mctx);
812
813 zone->catzs = NULL;
814 isc_mem_put(mctx, zone, sizeof(dns_catz_zone_t));
815 }
816 }
817
818 void
819 dns_catz_catzs_detach(dns_catz_zones_t **catzsp) {
820 dns_catz_zones_t *catzs;
821
822 REQUIRE(catzsp != NULL && *catzsp != NULL);
823
824 catzs = *catzsp;
825 *catzsp = NULL;
826
827 if (isc_refcount_decrement(&catzs->refs) == 1) {
828 catzs->magic = 0;
829 isc_task_destroy(&catzs->updater);
830 isc_mutex_destroy(&catzs->lock);
831 if (catzs->zones != NULL) {
832 isc_ht_iter_t *iter = NULL;
833 isc_result_t result;
834 isc_ht_iter_create(catzs->zones, &iter);
835 for (result = isc_ht_iter_first(iter);
836 result == ISC_R_SUCCESS;) {
837 dns_catz_zone_t *zone = NULL;
838 isc_ht_iter_current(iter, (void **)&zone);
839 result = isc_ht_iter_delcurrent_next(iter);
840 dns_catz_zone_detach(&zone);
841 }
842 INSIST(result == ISC_R_NOMORE);
843 isc_ht_iter_destroy(&iter);
844 INSIST(isc_ht_count(catzs->zones) == 0);
845 isc_ht_destroy(&catzs->zones);
846 }
847 isc_refcount_destroy(&catzs->refs);
848 isc_mem_putanddetach(&catzs->mctx, catzs, sizeof(*catzs));
849 }
850 }
851
852 typedef enum {
853 CATZ_OPT_NONE,
854 CATZ_OPT_ZONES,
855 CATZ_OPT_MASTERS,
856 CATZ_OPT_ALLOW_QUERY,
857 CATZ_OPT_ALLOW_TRANSFER,
858 CATZ_OPT_VERSION,
859 } catz_opt_t;
860
861 static bool
862 catz_opt_cmp(const dns_label_t *option, const char *opt) {
863 unsigned int l = strlen(opt);
864 if (option->length - 1 == l &&
865 memcmp(opt, option->base + 1, l - 1) == 0) {
866 return (true);
867 } else {
868 return (false);
869 }
870 }
871
872 static catz_opt_t
873 catz_get_option(const dns_label_t *option) {
874 if (catz_opt_cmp(option, "zones")) {
875 return (CATZ_OPT_ZONES);
876 } else if (catz_opt_cmp(option, "masters")) {
877 return (CATZ_OPT_MASTERS);
878 } else if (catz_opt_cmp(option, "allow-query")) {
879 return (CATZ_OPT_ALLOW_QUERY);
880 } else if (catz_opt_cmp(option, "allow-transfer")) {
881 return (CATZ_OPT_ALLOW_TRANSFER);
882 } else if (catz_opt_cmp(option, "version")) {
883 return (CATZ_OPT_VERSION);
884 } else {
885 return (CATZ_OPT_NONE);
886 }
887 }
888
889 static isc_result_t
890 catz_process_zones(dns_catz_zone_t *zone, dns_rdataset_t *value,
891 dns_name_t *name) {
892 dns_label_t mhash;
893 dns_name_t opt;
894
895 REQUIRE(DNS_CATZ_ZONE_VALID(zone));
896 REQUIRE(DNS_RDATASET_VALID(value));
897 REQUIRE(ISC_MAGIC_VALID(name, DNS_NAME_MAGIC));
898
899 if (value->rdclass != dns_rdataclass_in) {
900 return (ISC_R_FAILURE);
901 }
902
903 if (name->labels == 0) {
904 return (ISC_R_FAILURE);
905 }
906
907 dns_name_getlabel(name, name->labels - 1, &mhash);
908
909 if (name->labels == 1) {
910 return (catz_process_zones_entry(zone, value, &mhash));
911 } else {
912 dns_name_init(&opt, NULL);
913 dns_name_split(name, 1, &opt, NULL);
914 return (catz_process_zones_suboption(zone, value, &mhash,
915 &opt));
916 }
917 }
918
919 static isc_result_t
920 catz_process_zones_entry(dns_catz_zone_t *zone, dns_rdataset_t *value,
921 dns_label_t *mhash) {
922 isc_result_t result;
923 dns_rdata_t rdata;
924 dns_rdata_ptr_t ptr;
925 dns_catz_entry_t *entry = NULL;
926
927 /*
928 * We only take -first- value, as mhash must be
929 * different.
930 */
931 if (value->type != dns_rdatatype_ptr) {
932 return (ISC_R_FAILURE);
933 }
934
935 result = dns_rdataset_first(value);
936 if (result != ISC_R_SUCCESS) {
937 return (ISC_R_FAILURE);
938 }
939
940 dns_rdata_init(&rdata);
941 dns_rdataset_current(value, &rdata);
942
943 result = dns_rdata_tostruct(&rdata, &ptr, NULL);
944 RUNTIME_CHECK(result == ISC_R_SUCCESS);
945
946 result = isc_ht_find(zone->entries, mhash->base, mhash->length,
947 (void **)&entry);
948 if (result == ISC_R_SUCCESS) {
949 if (dns_name_countlabels(&entry->name) != 0) {
950 /* We have a duplicate. */
951 dns_rdata_freestruct(&ptr);
952 return (ISC_R_FAILURE);
953 } else {
954 dns_name_dup(&ptr.ptr, zone->catzs->mctx, &entry->name);
955 }
956 } else {
957 result = dns_catz_entry_new(zone->catzs->mctx, &ptr.ptr,
958 &entry);
959 if (result != ISC_R_SUCCESS) {
960 dns_rdata_freestruct(&ptr);
961 return (result);
962 }
963
964 result = isc_ht_add(zone->entries, mhash->base, mhash->length,
965 entry);
966 if (result != ISC_R_SUCCESS) {
967 dns_rdata_freestruct(&ptr);
968 dns_catz_entry_detach(zone, &entry);
969 return (result);
970 }
971 }
972
973 dns_rdata_freestruct(&ptr);
974
975 return (ISC_R_SUCCESS);
976 }
977
978 static isc_result_t
979 catz_process_version(dns_catz_zone_t *zone, dns_rdataset_t *value) {
980 isc_result_t result;
981 dns_rdata_t rdata;
982 dns_rdata_txt_t rdatatxt;
983 dns_rdata_txt_string_t rdatastr;
984 uint32_t tversion;
985 char t[16];
986
987 REQUIRE(DNS_CATZ_ZONE_VALID(zone));
988 REQUIRE(DNS_RDATASET_VALID(value));
989
990 if (value->rdclass != dns_rdataclass_in ||
991 value->type != dns_rdatatype_txt) {
992 return (ISC_R_FAILURE);
993 }
994
995 result = dns_rdataset_first(value);
996 if (result != ISC_R_SUCCESS) {
997 return (result);
998 }
999
1000 dns_rdata_init(&rdata);
1001 dns_rdataset_current(value, &rdata);
1002
1003 result = dns_rdata_tostruct(&rdata, &rdatatxt, NULL);
1004 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1005
1006 result = dns_rdata_txt_first(&rdatatxt);
1007 if (result != ISC_R_SUCCESS) {
1008 goto cleanup;
1009 }
1010
1011 result = dns_rdata_txt_current(&rdatatxt, &rdatastr);
1012 if (result != ISC_R_SUCCESS) {
1013 goto cleanup;
1014 }
1015
1016 result = dns_rdata_txt_next(&rdatatxt);
1017 if (result != ISC_R_NOMORE) {
1018 result = ISC_R_FAILURE;
1019 goto cleanup;
1020 }
1021 if (rdatastr.length > 15) {
1022 result = ISC_R_BADNUMBER;
1023 goto cleanup;
1024 }
1025 memmove(t, rdatastr.data, rdatastr.length);
1026 t[rdatastr.length] = 0;
1027 result = isc_parse_uint32(&tversion, t, 10);
1028 if (result != ISC_R_SUCCESS) {
1029 goto cleanup;
1030 }
1031 zone->version = tversion;
1032 result = ISC_R_SUCCESS;
1033
1034 cleanup:
1035 dns_rdata_freestruct(&rdatatxt);
1036 return (result);
1037 }
1038
1039 static isc_result_t
1040 catz_process_masters(dns_catz_zone_t *zone, dns_ipkeylist_t *ipkl,
1041 dns_rdataset_t *value, dns_name_t *name) {
1042 isc_result_t result;
1043 dns_rdata_t rdata;
1044 dns_rdata_in_a_t rdata_a;
1045 dns_rdata_in_aaaa_t rdata_aaaa;
1046 dns_rdata_txt_t rdata_txt;
1047 dns_rdata_txt_string_t rdatastr;
1048 dns_name_t *keyname = NULL;
1049 isc_mem_t *mctx;
1050 char keycbuf[DNS_NAME_FORMATSIZE];
1051 isc_buffer_t keybuf;
1052 unsigned int rcount;
1053 unsigned int i;
1054
1055 REQUIRE(DNS_CATZ_ZONE_VALID(zone));
1056 REQUIRE(ipkl != NULL);
1057 REQUIRE(DNS_RDATASET_VALID(value));
1058 REQUIRE(dns_rdataset_isassociated(value));
1059 REQUIRE(ISC_MAGIC_VALID(name, DNS_NAME_MAGIC));
1060
1061 mctx = zone->catzs->mctx;
1062 memset(&rdata_a, 0, sizeof(rdata_a));
1063 memset(&rdata_aaaa, 0, sizeof(rdata_aaaa));
1064 memset(&rdata_txt, 0, sizeof(rdata_txt));
1065 isc_buffer_init(&keybuf, keycbuf, sizeof(keycbuf));
1066
1067 /*
1068 * We have three possibilities here:
1069 * - either empty name and IN A/IN AAAA record
1070 * - label and IN A/IN AAAA
1071 * - label and IN TXT - TSIG key name
1072 */
1073 if (value->rdclass != dns_rdataclass_in) {
1074 return (ISC_R_FAILURE);
1075 }
1076
1077 if (name->labels > 0) {
1078 isc_sockaddr_t sockaddr;
1079
1080 /*
1081 * We're pre-preparing the data once, we'll put it into
1082 * the right spot in the masters array once we find it.
1083 */
1084 result = dns_rdataset_first(value);
1085 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1086 dns_rdata_init(&rdata);
1087 dns_rdataset_current(value, &rdata);
1088 switch (value->type) {
1089 case dns_rdatatype_a:
1090 result = dns_rdata_tostruct(&rdata, &rdata_a, NULL);
1091 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1092 isc_sockaddr_fromin(&sockaddr, &rdata_a.in_addr, 0);
1093 break;
1094 case dns_rdatatype_aaaa:
1095 result = dns_rdata_tostruct(&rdata, &rdata_aaaa, NULL);
1096 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1097 isc_sockaddr_fromin6(&sockaddr, &rdata_aaaa.in6_addr,
1098 0);
1099 break;
1100 case dns_rdatatype_txt:
1101 result = dns_rdata_tostruct(&rdata, &rdata_txt, NULL);
1102 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1103
1104 result = dns_rdata_txt_first(&rdata_txt);
1105 if (result != ISC_R_SUCCESS) {
1106 return (result);
1107 }
1108
1109 result = dns_rdata_txt_current(&rdata_txt, &rdatastr);
1110 if (result != ISC_R_SUCCESS) {
1111 return (result);
1112 }
1113
1114 result = dns_rdata_txt_next(&rdata_txt);
1115 if (result != ISC_R_NOMORE) {
1116 return (ISC_R_FAILURE);
1117 }
1118
1119 /* rdatastr.length < DNS_NAME_MAXTEXT */
1120 keyname = isc_mem_get(mctx, sizeof(dns_name_t));
1121 dns_name_init(keyname, 0);
1122 memmove(keycbuf, rdatastr.data, rdatastr.length);
1123 keycbuf[rdatastr.length] = 0;
1124 result = dns_name_fromstring(keyname, keycbuf, 0, mctx);
1125 if (result != ISC_R_SUCCESS) {
1126 dns_name_free(keyname, mctx);
1127 isc_mem_put(mctx, keyname, sizeof(dns_name_t));
1128 return (result);
1129 }
1130 break;
1131 default:
1132 return (ISC_R_FAILURE);
1133 }
1134
1135 /*
1136 * We have to find the appropriate labeled record in masters
1137 * if it exists.
1138 * In common case we'll have no more than 3-4 records here so
1139 * no optimization.
1140 */
1141 for (i = 0; i < ipkl->count; i++) {
1142 if (ipkl->labels[i] != NULL &&
1143 !dns_name_compare(name, ipkl->labels[i])) {
1144 break;
1145 }
1146 }
1147
1148 if (i < ipkl->count) { /* we have this record already */
1149 if (value->type == dns_rdatatype_txt) {
1150 ipkl->keys[i] = keyname;
1151 } else { /* A/AAAA */
1152 memmove(&ipkl->addrs[i], &sockaddr,
1153 sizeof(isc_sockaddr_t));
1154 }
1155 } else {
1156 result = dns_ipkeylist_resize(mctx, ipkl, i + 1);
1157 if (result != ISC_R_SUCCESS) {
1158 return (result);
1159 }
1160
1161 ipkl->labels[i] = isc_mem_get(mctx, sizeof(dns_name_t));
1162 dns_name_init(ipkl->labels[i], NULL);
1163 dns_name_dup(name, mctx, ipkl->labels[i]);
1164
1165 if (value->type == dns_rdatatype_txt) {
1166 ipkl->keys[i] = keyname;
1167 } else { /* A/AAAA */
1168 memmove(&ipkl->addrs[i], &sockaddr,
1169 sizeof(isc_sockaddr_t));
1170 }
1171 ipkl->count++;
1172 }
1173 return (ISC_R_SUCCESS);
1174 }
1175 /* else - 'simple' case - without labels */
1176
1177 if (value->type != dns_rdatatype_a && value->type != dns_rdatatype_aaaa)
1178 {
1179 return (ISC_R_FAILURE);
1180 }
1181
1182 rcount = dns_rdataset_count(value) + ipkl->count;
1183
1184 result = dns_ipkeylist_resize(mctx, ipkl, rcount);
1185 if (result != ISC_R_SUCCESS) {
1186 return (result);
1187 }
1188
1189 for (result = dns_rdataset_first(value); result == ISC_R_SUCCESS;
1190 result = dns_rdataset_next(value))
1191 {
1192 dns_rdata_init(&rdata);
1193 dns_rdataset_current(value, &rdata);
1194 /*
1195 * port 0 == take the default
1196 */
1197 if (value->type == dns_rdatatype_a) {
1198 result = dns_rdata_tostruct(&rdata, &rdata_a, NULL);
1199 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1200 isc_sockaddr_fromin(&ipkl->addrs[ipkl->count],
1201 &rdata_a.in_addr, 0);
1202 } else {
1203 result = dns_rdata_tostruct(&rdata, &rdata_aaaa, NULL);
1204 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1205 isc_sockaddr_fromin6(&ipkl->addrs[ipkl->count],
1206 &rdata_aaaa.in6_addr, 0);
1207 }
1208 ipkl->keys[ipkl->count] = NULL;
1209 ipkl->labels[ipkl->count] = NULL;
1210 ipkl->count++;
1211 dns_rdata_freestruct(&rdata_a);
1212 }
1213 return (ISC_R_SUCCESS);
1214 }
1215
1216 static isc_result_t
1217 catz_process_apl(dns_catz_zone_t *zone, isc_buffer_t **aclbp,
1218 dns_rdataset_t *value) {
1219 isc_result_t result = ISC_R_SUCCESS;
1220 dns_rdata_t rdata;
1221 dns_rdata_in_apl_t rdata_apl;
1222 dns_rdata_apl_ent_t apl_ent;
1223 isc_netaddr_t addr;
1224 isc_buffer_t *aclb = NULL;
1225 unsigned char buf[256]; /* larger than INET6_ADDRSTRLEN */
1226
1227 REQUIRE(DNS_CATZ_ZONE_VALID(zone));
1228 REQUIRE(aclbp != NULL);
1229 REQUIRE(*aclbp == NULL);
1230 REQUIRE(DNS_RDATASET_VALID(value));
1231 REQUIRE(dns_rdataset_isassociated(value));
1232
1233 if (value->rdclass != dns_rdataclass_in ||
1234 value->type != dns_rdatatype_apl) {
1235 return (ISC_R_FAILURE);
1236 }
1237
1238 if (dns_rdataset_count(value) > 1) {
1239 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1240 DNS_LOGMODULE_MASTER, ISC_LOG_WARNING,
1241 "catz: more than one APL entry for member zone, "
1242 "result is undefined");
1243 }
1244 result = dns_rdataset_first(value);
1245 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1246 dns_rdata_init(&rdata);
1247 dns_rdataset_current(value, &rdata);
1248 result = dns_rdata_tostruct(&rdata, &rdata_apl, zone->catzs->mctx);
1249 if (result != ISC_R_SUCCESS) {
1250 return (result);
1251 }
1252 isc_buffer_allocate(zone->catzs->mctx, &aclb, 16);
1253 isc_buffer_setautorealloc(aclb, true);
1254 for (result = dns_rdata_apl_first(&rdata_apl); result == ISC_R_SUCCESS;
1255 result = dns_rdata_apl_next(&rdata_apl))
1256 {
1257 result = dns_rdata_apl_current(&rdata_apl, &apl_ent);
1258 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1259 memset(buf, 0, sizeof(buf));
1260 if (apl_ent.data != NULL && apl_ent.length > 0) {
1261 memmove(buf, apl_ent.data, apl_ent.length);
1262 }
1263 if (apl_ent.family == 1) {
1264 isc_netaddr_fromin(&addr, (struct in_addr *)buf);
1265 } else if (apl_ent.family == 2) {
1266 isc_netaddr_fromin6(&addr, (struct in6_addr *)buf);
1267 } else {
1268 continue; /* xxxwpk log it or simply ignore? */
1269 }
1270 if (apl_ent.negative) {
1271 isc_buffer_putuint8(aclb, '!');
1272 }
1273 isc_buffer_reserve(&aclb, INET6_ADDRSTRLEN);
1274 result = isc_netaddr_totext(&addr, aclb);
1275 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1276 if ((apl_ent.family == 1 && apl_ent.prefix < 32) ||
1277 (apl_ent.family == 2 && apl_ent.prefix < 128))
1278 {
1279 isc_buffer_putuint8(aclb, '/');
1280 isc_buffer_putdecint(aclb, apl_ent.prefix);
1281 }
1282 isc_buffer_putstr(aclb, "; ");
1283 }
1284 if (result == ISC_R_NOMORE) {
1285 result = ISC_R_SUCCESS;
1286 } else {
1287 goto cleanup;
1288 }
1289 *aclbp = aclb;
1290 aclb = NULL;
1291 cleanup:
1292 if (aclb != NULL) {
1293 isc_buffer_free(&aclb);
1294 }
1295 dns_rdata_freestruct(&rdata_apl);
1296 return (result);
1297 }
1298
1299 static isc_result_t
1300 catz_process_zones_suboption(dns_catz_zone_t *zone, dns_rdataset_t *value,
1301 dns_label_t *mhash, dns_name_t *name) {
1302 isc_result_t result;
1303 dns_catz_entry_t *entry = NULL;
1304 dns_label_t option;
1305 dns_name_t prefix;
1306 catz_opt_t opt;
1307
1308 REQUIRE(DNS_CATZ_ZONE_VALID(zone));
1309 REQUIRE(mhash != NULL);
1310 REQUIRE(DNS_RDATASET_VALID(value));
1311 REQUIRE(ISC_MAGIC_VALID(name, DNS_NAME_MAGIC));
1312
1313 if (name->labels == 0) {
1314 return (ISC_R_FAILURE);
1315 }
1316 dns_name_getlabel(name, name->labels - 1, &option);
1317 opt = catz_get_option(&option);
1318
1319 /*
1320 * We're adding this entry now, in case the option is invalid we'll get
1321 * rid of it in verification phase.
1322 */
1323 result = isc_ht_find(zone->entries, mhash->base, mhash->length,
1324 (void **)&entry);
1325 if (result != ISC_R_SUCCESS) {
1326 result = dns_catz_entry_new(zone->catzs->mctx, NULL, &entry);
1327 if (result != ISC_R_SUCCESS) {
1328 return (result);
1329 }
1330 result = isc_ht_add(zone->entries, mhash->base, mhash->length,
1331 entry);
1332 if (result != ISC_R_SUCCESS) {
1333 dns_catz_entry_detach(zone, &entry);
1334 return (result);
1335 }
1336 }
1337
1338 dns_name_init(&prefix, NULL);
1339 dns_name_split(name, 1, &prefix, NULL);
1340 switch (opt) {
1341 case CATZ_OPT_MASTERS:
1342 return (catz_process_masters(zone, &entry->opts.masters, value,
1343 &prefix));
1344 case CATZ_OPT_ALLOW_QUERY:
1345 if (prefix.labels != 0) {
1346 return (ISC_R_FAILURE);
1347 }
1348 return (catz_process_apl(zone, &entry->opts.allow_query,
1349 value));
1350 case CATZ_OPT_ALLOW_TRANSFER:
1351 if (prefix.labels != 0) {
1352 return (ISC_R_FAILURE);
1353 }
1354 return (catz_process_apl(zone, &entry->opts.allow_transfer,
1355 value));
1356 default:
1357 return (ISC_R_FAILURE);
1358 }
1359
1360 return (ISC_R_FAILURE);
1361 }
1362
1363 static void
1364 catz_entry_add_or_mod(dns_catz_zone_t *target, isc_ht_t *ht, unsigned char *key,
1365 size_t keysize, dns_catz_entry_t *nentry,
1366 dns_catz_entry_t *oentry, const char *msg,
1367 const char *zname, const char *czname) {
1368 isc_result_t result = isc_ht_add(ht, key, (uint32_t)keysize, nentry);
1369
1370 if (result != ISC_R_SUCCESS) {
1371 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1372 DNS_LOGMODULE_MASTER, ISC_LOG_ERROR,
1373 "catz: error %s zone '%s' from catalog '%s' - %s",
1374 msg, zname, czname, isc_result_totext(result));
1375 }
1376 if (oentry != NULL) {
1377 dns_catz_entry_detach(target, &oentry);
1378 result = isc_ht_delete(target->entries, key, (uint32_t)keysize);
1379 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1380 }
1381 }
1382
1383 static isc_result_t
1384 catz_process_value(dns_catz_zone_t *zone, dns_name_t *name,
1385 dns_rdataset_t *rdataset) {
1386 dns_label_t option;
1387 dns_name_t prefix;
1388 catz_opt_t opt;
1389
1390 REQUIRE(DNS_CATZ_ZONE_VALID(zone));
1391 REQUIRE(ISC_MAGIC_VALID(name, DNS_NAME_MAGIC));
1392 REQUIRE(DNS_RDATASET_VALID(rdataset));
1393
1394 dns_name_getlabel(name, name->labels - 1, &option);
1395 opt = catz_get_option(&option);
1396 dns_name_init(&prefix, NULL);
1397 dns_name_split(name, 1, &prefix, NULL);
1398 switch (opt) {
1399 case CATZ_OPT_ZONES:
1400 return (catz_process_zones(zone, rdataset, &prefix));
1401 case CATZ_OPT_MASTERS:
1402 return (catz_process_masters(zone, &zone->zoneoptions.masters,
1403 rdataset, &prefix));
1404 case CATZ_OPT_ALLOW_QUERY:
1405 if (prefix.labels != 0) {
1406 return (ISC_R_FAILURE);
1407 }
1408 return (catz_process_apl(zone, &zone->zoneoptions.allow_query,
1409 rdataset));
1410 case CATZ_OPT_ALLOW_TRANSFER:
1411 if (prefix.labels != 0) {
1412 return (ISC_R_FAILURE);
1413 }
1414 return (catz_process_apl(
1415 zone, &zone->zoneoptions.allow_transfer, rdataset));
1416 case CATZ_OPT_VERSION:
1417 if (prefix.labels != 0) {
1418 return (ISC_R_FAILURE);
1419 }
1420 return (catz_process_version(zone, rdataset));
1421 default:
1422 return (ISC_R_FAILURE);
1423 }
1424 }
1425
1426 isc_result_t
1427 dns_catz_update_process(dns_catz_zones_t *catzs, dns_catz_zone_t *zone,
1428 const dns_name_t *src_name, dns_rdataset_t *rdataset) {
1429 isc_result_t result;
1430 int order;
1431 unsigned int nlabels;
1432 dns_namereln_t nrres;
1433 dns_rdata_t rdata = DNS_RDATA_INIT;
1434 dns_rdata_soa_t soa;
1435 dns_name_t prefix;
1436
1437 REQUIRE(DNS_CATZ_ZONES_VALID(catzs));
1438 REQUIRE(DNS_CATZ_ZONE_VALID(zone));
1439 REQUIRE(ISC_MAGIC_VALID(src_name, DNS_NAME_MAGIC));
1440
1441 nrres = dns_name_fullcompare(src_name, &zone->name, &order, &nlabels);
1442 if (nrres == dns_namereln_equal) {
1443 if (rdataset->type == dns_rdatatype_soa) {
1444 result = dns_rdataset_first(rdataset);
1445 if (result != ISC_R_SUCCESS) {
1446 return (result);
1447 }
1448
1449 dns_rdataset_current(rdataset, &rdata);
1450 result = dns_rdata_tostruct(&rdata, &soa, NULL);
1451 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1452
1453 /*
1454 * xxxwpk TODO do we want to save something from SOA?
1455 */
1456 return (result);
1457 } else if (rdataset->type == dns_rdatatype_ns) {
1458 return (ISC_R_SUCCESS);
1459 } else {
1460 return (ISC_R_UNEXPECTED);
1461 }
1462 } else if (nrres != dns_namereln_subdomain) {
1463 return (ISC_R_UNEXPECTED);
1464 }
1465
1466 dns_name_init(&prefix, NULL);
1467 dns_name_split(src_name, zone->name.labels, &prefix, NULL);
1468 result = catz_process_value(zone, &prefix, rdataset);
1469
1470 return (result);
1471 }
1472
1473 static isc_result_t
1474 digest2hex(unsigned char *digest, unsigned int digestlen, char *hash,
1475 size_t hashlen) {
1476 unsigned int i;
1477 int ret;
1478 for (i = 0; i < digestlen; i++) {
1479 size_t left = hashlen - i * 2;
1480 ret = snprintf(hash + i * 2, left, "%02x", digest[i]);
1481 if (ret < 0 || (size_t)ret >= left) {
1482 return (ISC_R_NOSPACE);
1483 }
1484 }
1485 return (ISC_R_SUCCESS);
1486 }
1487
1488 isc_result_t
1489 dns_catz_generate_masterfilename(dns_catz_zone_t *zone, dns_catz_entry_t *entry,
1490 isc_buffer_t **buffer) {
1491 isc_buffer_t *tbuf = NULL;
1492 isc_region_t r;
1493 isc_result_t result;
1494 size_t rlen;
1495 bool special = false;
1496
1497 REQUIRE(DNS_CATZ_ZONE_VALID(zone));
1498 REQUIRE(entry != NULL);
1499 REQUIRE(buffer != NULL && *buffer != NULL);
1500
1501 isc_buffer_allocate(zone->catzs->mctx, &tbuf,
1502 strlen(zone->catzs->view->name) +
1503 2 * DNS_NAME_FORMATSIZE + 2);
1504
1505 isc_buffer_putstr(tbuf, zone->catzs->view->name);
1506 isc_buffer_putstr(tbuf, "_");
1507 result = dns_name_totext(&zone->name, true, tbuf);
1508 if (result != ISC_R_SUCCESS) {
1509 goto cleanup;
1510 }
1511
1512 isc_buffer_putstr(tbuf, "_");
1513 result = dns_name_totext(&entry->name, true, tbuf);
1514 if (result != ISC_R_SUCCESS) {
1515 goto cleanup;
1516 }
1517
1518 /*
1519 * Search for slash and other special characters in the view and
1520 * zone names. Add a null terminator so we can use strpbrk(), then
1521 * remove it.
1522 */
1523 isc_buffer_putuint8(tbuf, 0);
1524 if (strpbrk(isc_buffer_base(tbuf), "\\/:") != NULL) {
1525 special = true;
1526 }
1527 isc_buffer_subtract(tbuf, 1);
1528
1529 /* __catz__<digest>.db */
1530 rlen = (isc_md_type_get_size(ISC_MD_SHA256) * 2 + 1) + 12;
1531
1532 /* optionally prepend with <zonedir>/ */
1533 if (entry->opts.zonedir != NULL) {
1534 rlen += strlen(entry->opts.zonedir) + 1;
1535 }
1536
1537 result = isc_buffer_reserve(buffer, (unsigned int)rlen);
1538 if (result != ISC_R_SUCCESS) {
1539 goto cleanup;
1540 }
1541
1542 if (entry->opts.zonedir != NULL) {
1543 isc_buffer_putstr(*buffer, entry->opts.zonedir);
1544 isc_buffer_putstr(*buffer, "/");
1545 }
1546
1547 isc_buffer_usedregion(tbuf, &r);
1548 isc_buffer_putstr(*buffer, "__catz__");
1549 if (special || tbuf->used > ISC_SHA256_DIGESTLENGTH * 2 + 1) {
1550 unsigned char digest[ISC_MAX_MD_SIZE];
1551 unsigned int digestlen;
1552
1553 /* we can do that because digest string < 2 * DNS_NAME */
1554 result = isc_md(ISC_MD_SHA256, r.base, r.length, digest,
1555 &digestlen);
1556 if (result != ISC_R_SUCCESS) {
1557 goto cleanup;
1558 }
1559 result = digest2hex(digest, digestlen, (char *)r.base,
1560 ISC_SHA256_DIGESTLENGTH * 2 + 1);
1561 if (result != ISC_R_SUCCESS) {
1562 goto cleanup;
1563 }
1564 isc_buffer_putstr(*buffer, (char *)r.base);
1565 } else {
1566 isc_buffer_copyregion(*buffer, &r);
1567 }
1568
1569 isc_buffer_putstr(*buffer, ".db");
1570 result = ISC_R_SUCCESS;
1571
1572 cleanup:
1573 isc_buffer_free(&tbuf);
1574 return (result);
1575 }
1576
1577 isc_result_t
1578 dns_catz_generate_zonecfg(dns_catz_zone_t *zone, dns_catz_entry_t *entry,
1579 isc_buffer_t **buf) {
1580 /*
1581 * We have to generate a text buffer with regular zone config:
1582 * zone "foo.bar" {
1583 * type slave;
1584 * masters [ dscp X ] { ip1 port port1; ip2 port port2; };
1585 * }
1586 */
1587 isc_buffer_t *buffer = NULL;
1588 isc_region_t region;
1589 isc_result_t result;
1590 uint32_t i;
1591 isc_netaddr_t netaddr;
1592 char pbuf[sizeof("65535")]; /* used both for port number and DSCP */
1593 char zname[DNS_NAME_FORMATSIZE];
1594
1595 REQUIRE(DNS_CATZ_ZONE_VALID(zone));
1596 REQUIRE(entry != NULL);
1597 REQUIRE(buf != NULL && *buf == NULL);
1598
1599 /*
1600 * The buffer will be reallocated if something won't fit,
1601 * ISC_BUFFER_INCR seems like a good start.
1602 */
1603 isc_buffer_allocate(zone->catzs->mctx, &buffer, ISC_BUFFER_INCR);
1604
1605 isc_buffer_setautorealloc(buffer, true);
1606 isc_buffer_putstr(buffer, "zone \"");
1607 dns_name_totext(&entry->name, true, buffer);
1608 isc_buffer_putstr(buffer, "\" { type slave; masters");
1609
1610 /*
1611 * DSCP value has no default, but when it is specified, it is identical
1612 * for all masters and cannot be overridden for a specific master IP, so
1613 * use the DSCP value set for the first master
1614 */
1615 if (entry->opts.masters.count > 0 && entry->opts.masters.dscps[0] >= 0)
1616 {
1617 isc_buffer_putstr(buffer, " dscp ");
1618 snprintf(pbuf, sizeof(pbuf), "%hd",
1619 entry->opts.masters.dscps[0]);
1620 isc_buffer_putstr(buffer, pbuf);
1621 }
1622
1623 isc_buffer_putstr(buffer, " { ");
1624 for (i = 0; i < entry->opts.masters.count; i++) {
1625 /*
1626 * Every master must have an IP address assigned.
1627 */
1628 switch (entry->opts.masters.addrs[i].type.sa.sa_family) {
1629 case AF_INET:
1630 case AF_INET6:
1631 break;
1632 default:
1633 dns_name_format(&entry->name, zname,
1634 DNS_NAME_FORMATSIZE);
1635 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1636 DNS_LOGMODULE_MASTER, ISC_LOG_ERROR,
1637 "catz: zone '%s' uses an invalid master "
1638 "(no IP address assigned)",
1639 zname);
1640 result = ISC_R_FAILURE;
1641 goto cleanup;
1642 }
1643 isc_netaddr_fromsockaddr(&netaddr,
1644 &entry->opts.masters.addrs[i]);
1645 isc_buffer_reserve(&buffer, INET6_ADDRSTRLEN);
1646 result = isc_netaddr_totext(&netaddr, buffer);
1647 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1648
1649 isc_buffer_putstr(buffer, " port ");
1650 snprintf(pbuf, sizeof(pbuf), "%u",
1651 isc_sockaddr_getport(&entry->opts.masters.addrs[i]));
1652 isc_buffer_putstr(buffer, pbuf);
1653
1654 if (entry->opts.masters.keys[i] != NULL) {
1655 isc_buffer_putstr(buffer, " key ");
1656 result = dns_name_totext(entry->opts.masters.keys[i],
1657 true, buffer);
1658 if (result != ISC_R_SUCCESS) {
1659 goto cleanup;
1660 }
1661 }
1662 isc_buffer_putstr(buffer, "; ");
1663 }
1664 isc_buffer_putstr(buffer, "}; ");
1665 if (!entry->opts.in_memory) {
1666 isc_buffer_putstr(buffer, "file \"");
1667 result = dns_catz_generate_masterfilename(zone, entry, &buffer);
1668 if (result != ISC_R_SUCCESS) {
1669 goto cleanup;
1670 }
1671 isc_buffer_putstr(buffer, "\"; ");
1672 }
1673 if (entry->opts.allow_query != NULL) {
1674 isc_buffer_putstr(buffer, "allow-query { ");
1675 isc_buffer_usedregion(entry->opts.allow_query, ®ion);
1676 isc_buffer_copyregion(buffer, ®ion);
1677 isc_buffer_putstr(buffer, "}; ");
1678 }
1679 if (entry->opts.allow_transfer != NULL) {
1680 isc_buffer_putstr(buffer, "allow-transfer { ");
1681 isc_buffer_usedregion(entry->opts.allow_transfer, ®ion);
1682 isc_buffer_copyregion(buffer, ®ion);
1683 isc_buffer_putstr(buffer, "}; ");
1684 }
1685
1686 isc_buffer_putstr(buffer, "};");
1687 *buf = buffer;
1688
1689 return (ISC_R_SUCCESS);
1690
1691 cleanup:
1692 isc_buffer_free(&buffer);
1693 return (result);
1694 }
1695
1696 void
1697 dns_catz_update_taskaction(isc_task_t *task, isc_event_t *event) {
1698 isc_result_t result;
1699 dns_catz_zone_t *zone;
1700 (void)task;
1701
1702 REQUIRE(event != NULL);
1703 zone = event->ev_arg;
1704 REQUIRE(DNS_CATZ_ZONE_VALID(zone));
1705
1706 LOCK(&zone->catzs->lock);
1707 zone->updatepending = false;
1708 dns_catz_update_from_db(zone->db, zone->catzs);
1709 result = isc_timer_reset(zone->updatetimer, isc_timertype_inactive,
1710 NULL, NULL, true);
1711 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1712 isc_event_free(&event);
1713 result = isc_time_now(&zone->lastupdated);
1714 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1715 UNLOCK(&zone->catzs->lock);
1716 }
1717
1718 isc_result_t
1719 dns_catz_dbupdate_callback(dns_db_t *db, void *fn_arg) {
1720 dns_catz_zones_t *catzs;
1721 dns_catz_zone_t *zone = NULL;
1722 isc_time_t now;
1723 uint64_t tdiff;
1724 isc_result_t result = ISC_R_SUCCESS;
1725 isc_region_t r;
1726
1727 REQUIRE(DNS_DB_VALID(db));
1728 REQUIRE(fn_arg != NULL);
1729 catzs = (dns_catz_zones_t *)fn_arg;
1730
1731 dns_name_toregion(&db->origin, &r);
1732
1733 LOCK(&catzs->lock);
1734 result = isc_ht_find(catzs->zones, r.base, r.length, (void **)&zone);
1735 if (result != ISC_R_SUCCESS) {
1736 goto cleanup;
1737 }
1738
1739 /* New zone came as AXFR */
1740 if (zone->db != NULL && zone->db != db) {
1741 if (zone->dbversion != NULL) {
1742 dns_db_closeversion(zone->db, &zone->dbversion, false);
1743 }
1744 dns_db_detach(&zone->db);
1745 /*
1746 * We're not registering db update callback, it will be
1747 * registered at the end of update_from_db
1748 */
1749 zone->db_registered = false;
1750 }
1751 if (zone->db == NULL) {
1752 dns_db_attach(db, &zone->db);
1753 }
1754
1755 if (!zone->updatepending) {
1756 zone->updatepending = true;
1757 isc_time_now(&now);
1758 tdiff = isc_time_microdiff(&now, &zone->lastupdated) / 1000000;
1759 if (tdiff < zone->defoptions.min_update_interval) {
1760 isc_interval_t interval;
1761 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1762 DNS_LOGMODULE_MASTER, ISC_LOG_INFO,
1763 "catz: new zone version came too soon, "
1764 "deferring update");
1765 isc_interval_set(&interval,
1766 zone->defoptions.min_update_interval -
1767 (unsigned int)tdiff,
1768 0);
1769 dns_db_currentversion(db, &zone->dbversion);
1770 result = isc_timer_reset(zone->updatetimer,
1771 isc_timertype_once, NULL,
1772 &interval, true);
1773 if (result != ISC_R_SUCCESS) {
1774 goto cleanup;
1775 }
1776 } else {
1777 isc_event_t *event;
1778
1779 dns_db_currentversion(db, &zone->dbversion);
1780 ISC_EVENT_INIT(&zone->updateevent,
1781 sizeof(zone->updateevent), 0, NULL,
1782 DNS_EVENT_CATZUPDATED,
1783 dns_catz_update_taskaction, zone, zone,
1784 NULL, NULL);
1785 event = &zone->updateevent;
1786 isc_task_send(catzs->updater, &event);
1787 }
1788 } else {
1789 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1790 DNS_LOGMODULE_MASTER, ISC_LOG_DEBUG(3),
1791 "catz: update already queued");
1792 if (zone->dbversion != NULL) {
1793 dns_db_closeversion(zone->db, &zone->dbversion, false);
1794 }
1795 dns_db_currentversion(zone->db, &zone->dbversion);
1796 }
1797
1798 cleanup:
1799 UNLOCK(&catzs->lock);
1800
1801 return (result);
1802 }
1803
1804 static bool
1805 catz_rdatatype_is_processable(const dns_rdatatype_t type) {
1806 return (!dns_rdatatype_isdnssec(type) && type != dns_rdatatype_cds &&
1807 type != dns_rdatatype_cdnskey && type != dns_rdatatype_zonemd);
1808 }
1809
1810 void
1811 dns_catz_update_from_db(dns_db_t *db, dns_catz_zones_t *catzs) {
1812 dns_catz_zone_t *oldzone = NULL, *newzone = NULL;
1813 isc_result_t result;
1814 isc_region_t r;
1815 dns_dbnode_t *node = NULL;
1816 dns_dbiterator_t *it = NULL;
1817 dns_fixedname_t fixname;
1818 dns_name_t *name;
1819 dns_rdatasetiter_t *rdsiter = NULL;
1820 dns_rdataset_t rdataset;
1821 char bname[DNS_NAME_FORMATSIZE];
1822 isc_buffer_t ibname;
1823 uint32_t vers;
1824
1825 REQUIRE(DNS_DB_VALID(db));
1826 REQUIRE(DNS_CATZ_ZONES_VALID(catzs));
1827
1828 /*
1829 * Create a new catz in the same context as current catz.
1830 */
1831 dns_name_toregion(&db->origin, &r);
1832 result = isc_ht_find(catzs->zones, r.base, r.length, (void **)&oldzone);
1833 if (result != ISC_R_SUCCESS) {
1834 /* This can happen if we remove the zone in the meantime. */
1835 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1836 DNS_LOGMODULE_MASTER, ISC_LOG_ERROR,
1837 "catz: zone '%s' not in config", bname);
1838 return;
1839 }
1840
1841 isc_buffer_init(&ibname, bname, DNS_NAME_FORMATSIZE);
1842 result = dns_name_totext(&db->origin, true, &ibname);
1843 INSIST(result == ISC_R_SUCCESS);
1844
1845 result = dns_db_getsoaserial(db, oldzone->dbversion, &vers);
1846 if (result != ISC_R_SUCCESS) {
1847 /* A zone without SOA record?!? */
1848 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1849 DNS_LOGMODULE_MASTER, ISC_LOG_ERROR,
1850 "catz: zone '%s' has no SOA record (%s)", bname,
1851 isc_result_totext(result));
1852 return;
1853 }
1854
1855 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_MASTER,
1856 ISC_LOG_INFO,
1857 "catz: updating catalog zone '%s' with serial %d", bname,
1858 vers);
1859
1860 result = dns_catz_new_zone(catzs, &newzone, &db->origin);
1861 if (result != ISC_R_SUCCESS) {
1862 dns_db_closeversion(db, &oldzone->dbversion, false);
1863 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1864 DNS_LOGMODULE_MASTER, ISC_LOG_ERROR,
1865 "catz: failed to create new zone - %s",
1866 isc_result_totext(result));
1867 return;
1868 }
1869
1870 result = dns_db_createiterator(db, DNS_DB_NONSEC3, &it);
1871 if (result != ISC_R_SUCCESS) {
1872 dns_catz_zone_detach(&newzone);
1873 dns_db_closeversion(db, &oldzone->dbversion, false);
1874 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1875 DNS_LOGMODULE_MASTER, ISC_LOG_ERROR,
1876 "catz: failed to create DB iterator - %s",
1877 isc_result_totext(result));
1878 return;
1879 }
1880
1881 name = dns_fixedname_initname(&fixname);
1882
1883 /*
1884 * Iterate over database to fill the new zone.
1885 */
1886 result = dns_dbiterator_first(it);
1887 if (result != ISC_R_SUCCESS) {
1888 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1889 DNS_LOGMODULE_MASTER, ISC_LOG_ERROR,
1890 "catz: failed to get db iterator - %s",
1891 isc_result_totext(result));
1892 }
1893
1894 while (result == ISC_R_SUCCESS) {
1895 result = dns_dbiterator_current(it, &node, name);
1896 if (result != ISC_R_SUCCESS) {
1897 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1898 DNS_LOGMODULE_MASTER, ISC_LOG_ERROR,
1899 "catz: failed to get db iterator - %s",
1900 isc_result_totext(result));
1901 break;
1902 }
1903
1904 result = dns_db_allrdatasets(db, node, oldzone->dbversion, 0,
1905 &rdsiter);
1906 if (result != ISC_R_SUCCESS) {
1907 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1908 DNS_LOGMODULE_MASTER, ISC_LOG_ERROR,
1909 "catz: failed to fetch rrdatasets - %s",
1910 isc_result_totext(result));
1911 dns_db_detachnode(db, &node);
1912 break;
1913 }
1914
1915 dns_rdataset_init(&rdataset);
1916 result = dns_rdatasetiter_first(rdsiter);
1917 while (result == ISC_R_SUCCESS) {
1918 dns_rdatasetiter_current(rdsiter, &rdataset);
1919
1920 /*
1921 * Skip processing DNSSEC-related and ZONEMD types,
1922 * because we are not interested in them in the context
1923 * of a catalog zone, and processing them will fail
1924 * and produce an unnecessary warning message.
1925 */
1926 if (!catz_rdatatype_is_processable(rdataset.type)) {
1927 goto next;
1928 }
1929
1930 result = dns_catz_update_process(catzs, newzone, name,
1931 &rdataset);
1932 if (result != ISC_R_SUCCESS) {
1933 char cname[DNS_NAME_FORMATSIZE];
1934 char typebuf[DNS_RDATATYPE_FORMATSIZE];
1935 char classbuf[DNS_RDATACLASS_FORMATSIZE];
1936
1937 dns_name_format(name, cname,
1938 DNS_NAME_FORMATSIZE);
1939 dns_rdataclass_format(rdataset.rdclass,
1940 classbuf,
1941 sizeof(classbuf));
1942 dns_rdatatype_format(rdataset.type, typebuf,
1943 sizeof(typebuf));
1944 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1945 DNS_LOGMODULE_MASTER,
1946 ISC_LOG_WARNING,
1947 "catz: unknown record in catalog "
1948 "zone - %s %s %s(%s) - ignoring",
1949 cname, classbuf, typebuf,
1950 isc_result_totext(result));
1951 }
1952 next:
1953 dns_rdataset_disassociate(&rdataset);
1954 result = dns_rdatasetiter_next(rdsiter);
1955 }
1956
1957 dns_rdatasetiter_destroy(&rdsiter);
1958
1959 dns_db_detachnode(db, &node);
1960 result = dns_dbiterator_next(it);
1961 }
1962
1963 dns_dbiterator_destroy(&it);
1964 dns_db_closeversion(db, &oldzone->dbversion, false);
1965 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_MASTER,
1966 ISC_LOG_DEBUG(3),
1967 "catz: update_from_db: iteration finished");
1968
1969 /*
1970 * Finally merge new zone into old zone.
1971 */
1972 result = dns_catz_zones_merge(oldzone, newzone);
1973 dns_catz_zone_detach(&newzone);
1974 if (result != ISC_R_SUCCESS) {
1975 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1976 DNS_LOGMODULE_MASTER, ISC_LOG_ERROR,
1977 "catz: failed merging zones: %s",
1978 isc_result_totext(result));
1979
1980 return;
1981 }
1982
1983 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_MASTER,
1984 ISC_LOG_DEBUG(3),
1985 "catz: update_from_db: new zone merged");
1986
1987 /*
1988 * When we're doing reconfig and setting a new catalog zone
1989 * from an existing zone we won't have a chance to set up
1990 * update callback in zone_startload or axfr_makedb, but we will
1991 * call onupdate() artificially so we can register the callback here.
1992 */
1993 if (!oldzone->db_registered) {
1994 result = dns_db_updatenotify_register(
1995 db, dns_catz_dbupdate_callback, oldzone->catzs);
1996 if (result == ISC_R_SUCCESS) {
1997 oldzone->db_registered = true;
1998 }
1999 }
2000 }
2001
2002 void
2003 dns_catz_prereconfig(dns_catz_zones_t *catzs) {
2004 isc_result_t result;
2005 isc_ht_iter_t *iter = NULL;
2006
2007 REQUIRE(DNS_CATZ_ZONES_VALID(catzs));
2008
2009 isc_ht_iter_create(catzs->zones, &iter);
2010 for (result = isc_ht_iter_first(iter); result == ISC_R_SUCCESS;
2011 result = isc_ht_iter_next(iter))
2012 {
2013 dns_catz_zone_t *zone = NULL;
2014 isc_ht_iter_current(iter, (void **)&zone);
2015 zone->active = false;
2016 }
2017 INSIST(result == ISC_R_NOMORE);
2018 isc_ht_iter_destroy(&iter);
2019 }
2020
2021 void
2022 dns_catz_postreconfig(dns_catz_zones_t *catzs) {
2023 isc_result_t result;
2024 dns_catz_zone_t *newzone = NULL;
2025 isc_ht_iter_t *iter = NULL;
2026
2027 REQUIRE(DNS_CATZ_ZONES_VALID(catzs));
2028
2029 LOCK(&catzs->lock);
2030 isc_ht_iter_create(catzs->zones, &iter);
2031 for (result = isc_ht_iter_first(iter); result == ISC_R_SUCCESS;) {
2032 dns_catz_zone_t *zone = NULL;
2033
2034 isc_ht_iter_current(iter, (void **)&zone);
2035 if (!zone->active) {
2036 char cname[DNS_NAME_FORMATSIZE];
2037 dns_name_format(&zone->name, cname,
2038 DNS_NAME_FORMATSIZE);
2039 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
2040 DNS_LOGMODULE_MASTER, ISC_LOG_WARNING,
2041 "catz: removing catalog zone %s", cname);
2042
2043 /*
2044 * Merge the old zone with an empty one to remove
2045 * all members.
2046 */
2047 result = dns_catz_new_zone(catzs, &newzone,
2048 &zone->name);
2049 INSIST(result == ISC_R_SUCCESS);
2050 dns_catz_zones_merge(zone, newzone);
2051 dns_catz_zone_detach(&newzone);
2052
2053 /* Make sure that we have an empty catalog zone. */
2054 INSIST(isc_ht_count(zone->entries) == 0);
2055 result = isc_ht_iter_delcurrent_next(iter);
2056 dns_catz_zone_detach(&zone);
2057 } else {
2058 result = isc_ht_iter_next(iter);
2059 }
2060 }
2061 UNLOCK(&catzs->lock);
2062 RUNTIME_CHECK(result == ISC_R_NOMORE);
2063 isc_ht_iter_destroy(&iter);
2064 }
2065
2066 void
2067 dns_catz_get_iterator(dns_catz_zone_t *catz, isc_ht_iter_t **itp) {
2068 REQUIRE(DNS_CATZ_ZONE_VALID(catz));
2069
2070 isc_ht_iter_create(catz->entries, itp);
2071 }
2072