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