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