catz.c revision 1.4 1 /* $NetBSD: catz.c,v 1.4 2019/02/24 20:01:30 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 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 dns_catz_zones_t *catzs;
843
844 REQUIRE(catzsp != NULL && *catzsp != NULL);
845
846 catzs = *catzsp;
847 *catzsp = NULL;
848
849 if (isc_refcount_decrement(&catzs->refs) == 1) {
850 catzs->magic = 0;
851 isc_task_destroy(&catzs->updater);
852 isc_mutex_destroy(&catzs->lock);
853 if (catzs->zones != NULL) {
854 isc_ht_iter_t *iter = NULL;
855 isc_result_t result;
856 result = isc_ht_iter_create(catzs->zones, &iter);
857 INSIST(result == ISC_R_SUCCESS);
858 for (result = isc_ht_iter_first(iter);
859 result == ISC_R_SUCCESS;)
860 {
861 dns_catz_zone_t *zone = NULL;
862 isc_ht_iter_current(iter, (void **) &zone);
863 result = isc_ht_iter_delcurrent_next(iter);
864 dns_catz_zone_detach(&zone);
865 }
866 INSIST(result == ISC_R_NOMORE);
867 isc_ht_iter_destroy(&iter);
868 INSIST(isc_ht_count(catzs->zones) == 0);
869 isc_ht_destroy(&catzs->zones);
870 }
871 isc_refcount_destroy(&catzs->refs);
872 isc_mem_putanddetach(&catzs->mctx, catzs, sizeof(*catzs));
873 }
874 }
875
876 typedef enum {
877 CATZ_OPT_NONE,
878 CATZ_OPT_ZONES,
879 CATZ_OPT_MASTERS,
880 CATZ_OPT_ALLOW_QUERY,
881 CATZ_OPT_ALLOW_TRANSFER,
882 CATZ_OPT_VERSION,
883 } catz_opt_t;
884
885 static bool
886 catz_opt_cmp(const dns_label_t *option, const char *opt) {
887 unsigned int l = strlen(opt);
888 if (option->length - 1 == l &&
889 memcmp(opt, option->base + 1, l - 1) == 0)
890 return (true);
891 else
892 return (false);
893 }
894
895 static catz_opt_t
896 catz_get_option(const dns_label_t *option) {
897 if (catz_opt_cmp(option, "zones"))
898 return (CATZ_OPT_ZONES);
899 else if (catz_opt_cmp(option, "masters"))
900 return (CATZ_OPT_MASTERS);
901 else if (catz_opt_cmp(option, "allow-query"))
902 return (CATZ_OPT_ALLOW_QUERY);
903 else if (catz_opt_cmp(option, "allow-transfer"))
904 return (CATZ_OPT_ALLOW_TRANSFER);
905 else if (catz_opt_cmp(option, "version"))
906 return (CATZ_OPT_VERSION);
907 else
908 return (CATZ_OPT_NONE);
909 }
910
911 static isc_result_t
912 catz_process_zones(dns_catz_zone_t *zone, dns_rdataset_t *value,
913 dns_name_t *name)
914 {
915 dns_label_t mhash;
916 dns_name_t opt;
917
918 REQUIRE(DNS_CATZ_ZONE_VALID(zone));
919 REQUIRE(DNS_RDATASET_VALID(value));
920 REQUIRE(ISC_MAGIC_VALID(name, DNS_NAME_MAGIC));
921
922 if (value->rdclass != dns_rdataclass_in)
923 return (ISC_R_FAILURE);
924
925 if (name->labels == 0)
926 return (ISC_R_FAILURE);
927
928 dns_name_getlabel(name, name->labels-1, &mhash);
929
930 if (name->labels == 1)
931 return (catz_process_zones_entry(zone, value, &mhash));
932 else {
933 dns_name_init(&opt, NULL);
934 dns_name_split(name, 1, &opt, NULL);
935 return (catz_process_zones_suboption(zone, value, &mhash, &opt));
936 }
937 }
938
939 static isc_result_t
940 catz_process_zones_entry(dns_catz_zone_t *zone, dns_rdataset_t *value,
941 dns_label_t *mhash)
942 {
943 isc_result_t result;
944 dns_rdata_t rdata;
945 dns_rdata_ptr_t ptr;
946 dns_catz_entry_t *entry = NULL;
947
948 /*
949 * We only take -first- value, as mhash must be
950 * different.
951 */
952 if (value->type != dns_rdatatype_ptr)
953 return (ISC_R_FAILURE);
954
955 result = dns_rdataset_first(value);
956 if (result != ISC_R_SUCCESS)
957 return (ISC_R_FAILURE);
958
959 dns_rdata_init(&rdata);
960 dns_rdataset_current(value, &rdata);
961
962 result = dns_rdata_tostruct(&rdata, &ptr, NULL);
963 RUNTIME_CHECK(result == ISC_R_SUCCESS);
964
965 result = isc_ht_find(zone->entries, mhash->base,
966 mhash->length, (void **) &entry);
967 if (result == ISC_R_SUCCESS) {
968 if (dns_name_countlabels(&entry->name) != 0) {
969 /* We have a duplicate. */
970 dns_rdata_freestruct(&ptr);
971 return (ISC_R_FAILURE);
972 } else {
973 result = dns_name_dup(&ptr.ptr, zone->catzs->mctx,
974 &entry->name);
975 if (result != ISC_R_SUCCESS) {
976 dns_rdata_freestruct(&ptr);
977 return (result);
978 }
979 }
980 } else {
981 result = dns_catz_entry_new(zone->catzs->mctx, &ptr.ptr,
982 &entry);
983 if (result != ISC_R_SUCCESS) {
984 dns_rdata_freestruct(&ptr);
985 return (result);
986 }
987
988 result = isc_ht_add(zone->entries, mhash->base,
989 mhash->length, entry);
990 if (result != ISC_R_SUCCESS) {
991 dns_rdata_freestruct(&ptr);
992 dns_catz_entry_detach(zone, &entry);
993 return (result);
994 }
995 }
996
997 dns_rdata_freestruct(&ptr);
998
999 return (ISC_R_SUCCESS);
1000 }
1001
1002 static isc_result_t
1003 catz_process_version(dns_catz_zone_t *zone, dns_rdataset_t *value) {
1004 isc_result_t result;
1005 dns_rdata_t rdata;
1006 dns_rdata_txt_t rdatatxt;
1007 dns_rdata_txt_string_t rdatastr;
1008 uint32_t tversion;
1009 char t[16];
1010
1011 REQUIRE(DNS_CATZ_ZONE_VALID(zone));
1012 REQUIRE(DNS_RDATASET_VALID(value));
1013
1014 if (value->rdclass != dns_rdataclass_in ||
1015 value->type != dns_rdatatype_txt)
1016 return (ISC_R_FAILURE);
1017
1018 result = dns_rdataset_first(value);
1019 if (result != ISC_R_SUCCESS)
1020 return (result);
1021
1022 dns_rdata_init(&rdata);
1023 dns_rdataset_current(value, &rdata);
1024
1025 result = dns_rdata_tostruct(&rdata, &rdatatxt, NULL);
1026 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1027
1028 result = dns_rdata_txt_first(&rdatatxt);
1029 if (result != ISC_R_SUCCESS)
1030 goto cleanup;
1031
1032 result = dns_rdata_txt_current(&rdatatxt, &rdatastr);
1033 if (result != ISC_R_SUCCESS)
1034 goto cleanup;
1035
1036 result = dns_rdata_txt_next(&rdatatxt);
1037 if (result != ISC_R_NOMORE) {
1038 result = ISC_R_FAILURE;
1039 goto cleanup;
1040 }
1041 if (rdatastr.length > 15) {
1042 result = ISC_R_BADNUMBER;
1043 goto cleanup;
1044 }
1045 memmove(t, rdatastr.data, rdatastr.length);
1046 t[rdatastr.length] = 0;
1047 result = isc_parse_uint32(&tversion, t, 10);
1048 if (result != ISC_R_SUCCESS) {
1049 goto cleanup;
1050 }
1051 zone->version = tversion;
1052 result = ISC_R_SUCCESS;
1053
1054 cleanup:
1055 dns_rdata_freestruct(&rdatatxt);
1056 return (result);
1057 }
1058
1059 static isc_result_t
1060 catz_process_masters(dns_catz_zone_t *zone, dns_ipkeylist_t *ipkl,
1061 dns_rdataset_t *value, dns_name_t *name)
1062 {
1063 isc_result_t result;
1064 dns_rdata_t rdata;
1065 dns_rdata_in_a_t rdata_a;
1066 dns_rdata_in_aaaa_t rdata_aaaa;
1067 dns_rdata_txt_t rdata_txt;
1068 dns_rdata_txt_string_t rdatastr;
1069 dns_name_t *keyname = NULL;
1070 isc_mem_t *mctx;
1071 char keycbuf[DNS_NAME_FORMATSIZE];
1072 isc_buffer_t keybuf;
1073 unsigned int rcount;
1074 unsigned int i;
1075
1076 REQUIRE(DNS_CATZ_ZONE_VALID(zone));
1077 REQUIRE(ipkl != NULL);
1078 REQUIRE(DNS_RDATASET_VALID(value));
1079 REQUIRE(dns_rdataset_isassociated(value));
1080 REQUIRE(ISC_MAGIC_VALID(name, DNS_NAME_MAGIC));
1081
1082 mctx = zone->catzs->mctx;
1083 memset(&rdata_a, 0, sizeof(rdata_a));
1084 memset(&rdata_aaaa, 0, sizeof(rdata_aaaa));
1085 memset(&rdata_txt, 0, sizeof(rdata_txt));
1086 isc_buffer_init(&keybuf, keycbuf, sizeof(keycbuf));
1087
1088 /*
1089 * We have three possibilities here:
1090 * - either empty name and IN A/IN AAAA record
1091 * - label and IN A/IN AAAA
1092 * - label and IN TXT - TSIG key name
1093 */
1094 if (value->rdclass != dns_rdataclass_in)
1095 return (ISC_R_FAILURE);
1096
1097 if (name->labels > 0) {
1098 isc_sockaddr_t sockaddr;
1099
1100 /*
1101 * We're pre-preparing the data once, we'll put it into
1102 * the right spot in the masters array once we find it.
1103 */
1104 result = dns_rdataset_first(value);
1105 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1106 dns_rdata_init(&rdata);
1107 dns_rdataset_current(value, &rdata);
1108 switch (value->type) {
1109 case dns_rdatatype_a:
1110 result = dns_rdata_tostruct(&rdata, &rdata_a, NULL);
1111 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1112 isc_sockaddr_fromin(&sockaddr, &rdata_a.in_addr, 0);
1113 break;
1114 case dns_rdatatype_aaaa:
1115 result = dns_rdata_tostruct(&rdata, &rdata_aaaa, NULL);
1116 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1117 isc_sockaddr_fromin6(&sockaddr, &rdata_aaaa.in6_addr, 0);
1118 break;
1119 case dns_rdatatype_txt:
1120 result = dns_rdata_tostruct(&rdata, &rdata_txt, NULL);
1121 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1122
1123 result = dns_rdata_txt_first(&rdata_txt);
1124 if (result != ISC_R_SUCCESS)
1125 return (result);
1126
1127 result = dns_rdata_txt_current(&rdata_txt, &rdatastr);
1128 if (result != ISC_R_SUCCESS)
1129 return (result);
1130
1131 result = dns_rdata_txt_next(&rdata_txt);
1132 if (result != ISC_R_NOMORE)
1133 return (ISC_R_FAILURE);
1134
1135 /* rdatastr.length < DNS_NAME_MAXTEXT */
1136 keyname = isc_mem_get(mctx, sizeof(dns_name_t));
1137 if (keyname == NULL)
1138 return (ISC_R_NOMEMORY);
1139 dns_name_init(keyname, 0);
1140 memmove(keycbuf, rdatastr.data, rdatastr.length);
1141 keycbuf[rdatastr.length] = 0;
1142 result = dns_name_fromstring(keyname, keycbuf, 0, mctx);
1143 if (result != ISC_R_SUCCESS) {
1144 dns_name_free(keyname, mctx);
1145 isc_mem_put(mctx, keyname, sizeof(dns_name_t));
1146 return (result);
1147 }
1148 break;
1149 default:
1150 return (ISC_R_FAILURE);
1151 }
1152
1153 /*
1154 * We have to find the appropriate labeled record in masters
1155 * if it exists.
1156 * In common case we'll have no more than 3-4 records here so
1157 * no optimization.
1158 */
1159 for (i = 0; i < ipkl->count; i++) {
1160 if (ipkl->labels[i] != NULL &&
1161 !dns_name_compare(name, ipkl->labels[i]))
1162 break;
1163 }
1164
1165 if (i < ipkl->count) { /* we have this record already */
1166 if (value->type == dns_rdatatype_txt)
1167 ipkl->keys[i] = keyname;
1168 else /* A/AAAA */
1169 memmove(&ipkl->addrs[i], &sockaddr,
1170 sizeof(isc_sockaddr_t));
1171 } else {
1172 result = dns_ipkeylist_resize(mctx, ipkl,
1173 i+1);
1174 if (result != ISC_R_SUCCESS) {
1175 return (result);
1176 }
1177
1178 ipkl->labels[i] = isc_mem_get(mctx, sizeof(dns_name_t));
1179 if (ipkl->labels[i] == NULL) {
1180 if (keyname != NULL) {
1181 dns_name_free(keyname, mctx);
1182 isc_mem_put(mctx, keyname,
1183 sizeof(dns_name_t));
1184 }
1185 return (ISC_R_NOMEMORY);
1186 }
1187 dns_name_init(ipkl->labels[i], NULL);
1188 result = dns_name_dup(name, mctx, ipkl->labels[i]);
1189 if (result != ISC_R_SUCCESS) {
1190 if (keyname != NULL) {
1191 dns_name_free(keyname, mctx);
1192 isc_mem_put(mctx, keyname,
1193 sizeof(dns_name_t));
1194 }
1195 return (result);
1196 }
1197
1198 if (value->type == dns_rdatatype_txt)
1199 ipkl->keys[i] = keyname;
1200 else /* A/AAAA */
1201 memmove(&ipkl->addrs[i], &sockaddr,
1202 sizeof(isc_sockaddr_t));
1203 ipkl->count++;
1204 }
1205 return (ISC_R_SUCCESS);
1206 }
1207 /* else - 'simple' case - without labels */
1208
1209 if (value->type != dns_rdatatype_a &&
1210 value->type != dns_rdatatype_aaaa)
1211 return (ISC_R_FAILURE);
1212
1213 rcount = dns_rdataset_count(value) + ipkl->count;
1214
1215 result = dns_ipkeylist_resize(mctx, ipkl, rcount);
1216 if (result != ISC_R_SUCCESS) {
1217 return (result);
1218 }
1219
1220 for (result = dns_rdataset_first(value);
1221 result == ISC_R_SUCCESS;
1222 result = dns_rdataset_next(value))
1223 {
1224 dns_rdata_init(&rdata);
1225 dns_rdataset_current(value, &rdata);
1226 /*
1227 * port 0 == take the default
1228 */
1229 if (value->type == dns_rdatatype_a) {
1230 result = dns_rdata_tostruct(&rdata, &rdata_a, NULL);
1231 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1232 isc_sockaddr_fromin(&ipkl->addrs[ipkl->count],
1233 &rdata_a.in_addr, 0);
1234 } else {
1235 result = dns_rdata_tostruct(&rdata, &rdata_aaaa, NULL);
1236 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1237 isc_sockaddr_fromin6(&ipkl->addrs[ipkl->count],
1238 &rdata_aaaa.in6_addr, 0);
1239 }
1240 ipkl->keys[ipkl->count] = NULL;
1241 ipkl->labels[ipkl->count] = NULL;
1242 ipkl->count++;
1243 dns_rdata_freestruct(&rdata_a);
1244 }
1245 return (ISC_R_SUCCESS);
1246 }
1247
1248 static isc_result_t
1249 catz_process_apl(dns_catz_zone_t *zone, isc_buffer_t **aclbp,
1250 dns_rdataset_t *value)
1251 {
1252 isc_result_t result = ISC_R_SUCCESS;
1253 dns_rdata_t rdata;
1254 dns_rdata_in_apl_t rdata_apl;
1255 dns_rdata_apl_ent_t apl_ent;
1256 isc_netaddr_t addr;
1257 isc_buffer_t *aclb = NULL;
1258 unsigned char buf[256]; /* larger than INET6_ADDRSTRLEN */
1259
1260 REQUIRE(DNS_CATZ_ZONE_VALID(zone));
1261 REQUIRE(aclbp != NULL);
1262 REQUIRE(*aclbp == NULL);
1263 REQUIRE(DNS_RDATASET_VALID(value));
1264 REQUIRE(dns_rdataset_isassociated(value));
1265
1266 if (value->rdclass != dns_rdataclass_in ||
1267 value->type != dns_rdatatype_apl)
1268 return (ISC_R_FAILURE);
1269
1270
1271 if (dns_rdataset_count(value) > 1) {
1272 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1273 DNS_LOGMODULE_MASTER, ISC_LOG_WARNING,
1274 "catz: more than one APL entry for member zone, "
1275 "result is undefined");
1276 }
1277 result = dns_rdataset_first(value);
1278 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1279 dns_rdata_init(&rdata);
1280 dns_rdataset_current(value, &rdata);
1281 result = dns_rdata_tostruct(&rdata, &rdata_apl, zone->catzs->mctx);
1282 if (result != ISC_R_SUCCESS)
1283 return (result);
1284 result = isc_buffer_allocate(zone->catzs->mctx, &aclb, 16);
1285 isc_buffer_setautorealloc(aclb, true);
1286 if (result != ISC_R_SUCCESS)
1287 goto cleanup;
1288 for (result = dns_rdata_apl_first(&rdata_apl);
1289 result == ISC_R_SUCCESS;
1290 result = dns_rdata_apl_next(&rdata_apl)) {
1291 result = dns_rdata_apl_current(&rdata_apl, &apl_ent);
1292 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1293 memset(buf, 0, sizeof(buf));
1294 if (apl_ent.data != NULL && apl_ent.length > 0)
1295 memmove(buf, apl_ent.data, apl_ent.length);
1296 if (apl_ent.family == 1)
1297 isc_netaddr_fromin(&addr, (struct in_addr*) buf);
1298 else if (apl_ent.family == 2)
1299 isc_netaddr_fromin6(&addr, (struct in6_addr*) buf);
1300 else
1301 continue; /* xxxwpk log it or simply ignore? */
1302 if (apl_ent.negative)
1303 isc_buffer_putuint8(aclb, '!');
1304 isc_buffer_reserve(&aclb, INET6_ADDRSTRLEN);
1305 result = isc_netaddr_totext(&addr, aclb);
1306 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1307 if ((apl_ent.family == 1 && apl_ent.prefix < 32) ||
1308 (apl_ent.family == 2 && apl_ent.prefix < 128)) {
1309 isc_buffer_putuint8(aclb, '/');
1310 isc_buffer_putdecint(aclb, apl_ent.prefix);
1311 }
1312 isc_buffer_putstr(aclb, "; ");
1313 }
1314 if (result == ISC_R_NOMORE)
1315 result = ISC_R_SUCCESS;
1316 else
1317 goto cleanup;
1318 *aclbp = aclb;
1319 aclb = NULL;
1320 cleanup:
1321 if (aclb != NULL)
1322 isc_buffer_free(&aclb);
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 {
1331 isc_result_t result;
1332 dns_catz_entry_t *entry = NULL;
1333 dns_label_t option;
1334 dns_name_t prefix;
1335 catz_opt_t opt;
1336
1337 REQUIRE(DNS_CATZ_ZONE_VALID(zone));
1338 REQUIRE(mhash != NULL);
1339 REQUIRE(DNS_RDATASET_VALID(value));
1340 REQUIRE(ISC_MAGIC_VALID(name, DNS_NAME_MAGIC));
1341
1342 if (name->labels == 0)
1343 return (ISC_R_FAILURE);
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 result = isc_ht_add(zone->entries, mhash->base, mhash->length,
1358 entry);
1359 if (result != ISC_R_SUCCESS) {
1360 dns_catz_entry_detach(zone, &entry);
1361 return (result);
1362 }
1363 }
1364
1365 dns_name_init(&prefix, NULL);
1366 dns_name_split(name, 1, &prefix, NULL);
1367 switch (opt) {
1368 case CATZ_OPT_MASTERS:
1369 return (catz_process_masters(zone, &entry->opts.masters, value,
1370 &prefix));
1371 case CATZ_OPT_ALLOW_QUERY:
1372 if (prefix.labels != 0)
1373 return (ISC_R_FAILURE);
1374 return (catz_process_apl(zone, &entry->opts.allow_query,
1375 value));
1376 case CATZ_OPT_ALLOW_TRANSFER:
1377 if (prefix.labels != 0)
1378 return (ISC_R_FAILURE);
1379 return (catz_process_apl(zone, &entry->opts.allow_transfer,
1380 value));
1381 default:
1382 return (ISC_R_FAILURE);
1383 }
1384
1385 return (ISC_R_FAILURE);
1386 }
1387
1388 static isc_result_t
1389 catz_process_value(dns_catz_zone_t *zone, dns_name_t *name,
1390 dns_rdataset_t *rdataset)
1391 {
1392 dns_label_t option;
1393 dns_name_t prefix;
1394 catz_opt_t opt;
1395
1396 REQUIRE(DNS_CATZ_ZONE_VALID(zone));
1397 REQUIRE(ISC_MAGIC_VALID(name, DNS_NAME_MAGIC));
1398 REQUIRE(DNS_RDATASET_VALID(rdataset));
1399
1400 dns_name_getlabel(name, name->labels - 1, &option);
1401 opt = catz_get_option(&option);
1402 dns_name_init(&prefix, NULL);
1403 dns_name_split(name, 1, &prefix, NULL);
1404 switch (opt) {
1405 case CATZ_OPT_ZONES:
1406 return (catz_process_zones(zone, rdataset, &prefix));
1407 case CATZ_OPT_MASTERS:
1408 return (catz_process_masters(zone, &zone->zoneoptions.masters,
1409 rdataset, &prefix));
1410 case CATZ_OPT_ALLOW_QUERY:
1411 if (prefix.labels != 0)
1412 return (ISC_R_FAILURE);
1413 return (catz_process_apl(zone, &zone->zoneoptions.allow_query,
1414 rdataset));
1415 case CATZ_OPT_ALLOW_TRANSFER:
1416 if (prefix.labels != 0)
1417 return (ISC_R_FAILURE);
1418 return (catz_process_apl(zone,
1419 &zone->zoneoptions.allow_transfer,
1420 rdataset));
1421 case CATZ_OPT_VERSION:
1422 if (prefix.labels != 0)
1423 return (ISC_R_FAILURE);
1424 return (catz_process_version(zone, rdataset));
1425 default:
1426 return (ISC_R_FAILURE);
1427 }
1428 }
1429
1430 isc_result_t
1431 dns_catz_update_process(dns_catz_zones_t *catzs, dns_catz_zone_t *zone,
1432 const dns_name_t *src_name, dns_rdataset_t *rdataset)
1433 {
1434 isc_result_t result;
1435 int order;
1436 unsigned int nlabels;
1437 dns_namereln_t nrres;
1438 dns_rdata_t rdata = DNS_RDATA_INIT;
1439 dns_rdata_soa_t soa;
1440 dns_name_t prefix;
1441
1442 REQUIRE(DNS_CATZ_ZONES_VALID(catzs));
1443 REQUIRE(DNS_CATZ_ZONE_VALID(zone));
1444 REQUIRE(ISC_MAGIC_VALID(src_name, DNS_NAME_MAGIC));
1445
1446 nrres = dns_name_fullcompare(src_name, &zone->name, &order, &nlabels);
1447 if (nrres == dns_namereln_equal) {
1448 if (rdataset->type == dns_rdatatype_soa) {
1449 result = dns_rdataset_first(rdataset);
1450 if (result != ISC_R_SUCCESS)
1451 return (result);
1452
1453 dns_rdataset_current(rdataset, &rdata);
1454 result = dns_rdata_tostruct(&rdata, &soa, NULL);
1455 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1456
1457 /*
1458 * xxxwpk TODO do we want to save something from SOA?
1459 */
1460 return (result);
1461
1462 } else if (rdataset->type == dns_rdatatype_ns) {
1463 return (ISC_R_SUCCESS);
1464 } else {
1465 return (ISC_R_UNEXPECTED);
1466 }
1467 } else if (nrres != dns_namereln_subdomain) {
1468 return (ISC_R_UNEXPECTED);
1469 }
1470
1471 dns_name_init(&prefix, NULL);
1472 dns_name_split(src_name, zone->name.labels, &prefix, NULL);
1473 result = catz_process_value(zone, &prefix, rdataset);
1474
1475 return (result);
1476 }
1477
1478 static isc_result_t
1479 digest2hex(unsigned char *digest, unsigned int digestlen,
1480 char *hash, size_t hashlen)
1481 {
1482 unsigned int i;
1483 int ret;
1484 for (i = 0; i < digestlen; i++) {
1485 size_t left = hashlen - i * 2;
1486 ret = snprintf(hash + i * 2, left, "%02x", digest[i]);
1487 if (ret < 0 || (size_t)ret >= left) {
1488 return (ISC_R_NOSPACE);
1489 }
1490 }
1491 return (ISC_R_SUCCESS);
1492 }
1493
1494 isc_result_t
1495 dns_catz_generate_masterfilename(dns_catz_zone_t *zone, dns_catz_entry_t *entry,
1496 isc_buffer_t **buffer)
1497 {
1498 isc_buffer_t *tbuf = NULL;
1499 isc_region_t r;
1500 isc_result_t result;
1501 size_t rlen;
1502
1503 REQUIRE(DNS_CATZ_ZONE_VALID(zone));
1504 REQUIRE(entry != NULL);
1505 REQUIRE(buffer != NULL && *buffer != NULL);
1506
1507 result = isc_buffer_allocate(zone->catzs->mctx, &tbuf,
1508 strlen(zone->catzs->view->name) +
1509 2 * DNS_NAME_FORMATSIZE + 2);
1510 if (result != ISC_R_SUCCESS)
1511 return (result);
1512 INSIST(tbuf != NULL);
1513
1514 isc_buffer_putstr(tbuf, zone->catzs->view->name);
1515 isc_buffer_putstr(tbuf, "_");
1516 result = dns_name_totext(&zone->name, true, tbuf);
1517 if (result != ISC_R_SUCCESS)
1518 goto cleanup;
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 /* __catz__<digest>.db */
1526 rlen = (isc_md_type_get_size(ISC_MD_SHA256) * 2 + 1) + 12;
1527
1528 /* optionally prepend with <zonedir>/ */
1529 if (entry->opts.zonedir != NULL)
1530 rlen += strlen(entry->opts.zonedir) + 1;
1531
1532 result = isc_buffer_reserve(buffer, (unsigned int)rlen);
1533 if (result != ISC_R_SUCCESS)
1534 goto cleanup;
1535
1536 if (entry->opts.zonedir != NULL) {
1537 isc_buffer_putstr(*buffer, entry->opts.zonedir);
1538 isc_buffer_putstr(*buffer, "/");
1539 }
1540
1541 isc_buffer_usedregion(tbuf, &r);
1542 isc_buffer_putstr(*buffer, "__catz__");
1543 if (tbuf->used > ISC_SHA256_DIGESTLENGTH * 2 + 1) {
1544 unsigned char digest[ISC_MAX_MD_SIZE];
1545 unsigned int digestlen;
1546 /* we can do that because digest string < 2 * DNS_NAME */
1547 result = isc_md(ISC_MD_SHA256, r.base, r.length,
1548 digest, &digestlen);
1549 if (result != ISC_R_SUCCESS) {
1550 goto cleanup;
1551 }
1552 result = digest2hex(digest, digestlen, (char *)r.base,
1553 ISC_SHA256_DIGESTLENGTH * 2 + 1);
1554 if (result != ISC_R_SUCCESS) {
1555 goto cleanup;
1556 }
1557 isc_buffer_putstr(*buffer, (char *) r.base);
1558 } else {
1559 isc_buffer_copyregion(*buffer, &r);
1560 }
1561
1562 isc_buffer_putstr(*buffer, ".db");
1563 result = ISC_R_SUCCESS;
1564
1565 cleanup:
1566 isc_buffer_free(&tbuf);
1567 return (result);
1568 }
1569
1570 isc_result_t
1571 dns_catz_generate_zonecfg(dns_catz_zone_t *zone, dns_catz_entry_t *entry,
1572 isc_buffer_t **buf)
1573 {
1574 /*
1575 * We have to generate a text buffer with regular zone config:
1576 * zone foo.bar {
1577 * type slave;
1578 * masters [ dscp X ] { ip1 port port1; ip2 port port2; };
1579 * }
1580 */
1581 isc_buffer_t *buffer = NULL;
1582 isc_region_t region;
1583 isc_result_t result;
1584 uint32_t i;
1585 isc_netaddr_t netaddr;
1586 char pbuf[sizeof("65535")]; /* used both for port number and DSCP */
1587 char zname[DNS_NAME_FORMATSIZE];
1588
1589 REQUIRE(DNS_CATZ_ZONE_VALID(zone));
1590 REQUIRE(entry != NULL);
1591 REQUIRE(buf != NULL && *buf == NULL);
1592
1593 /*
1594 * The buffer will be reallocated if something won't fit,
1595 * ISC_BUFFER_INCR seems like a good start.
1596 */
1597 result = isc_buffer_allocate(zone->catzs->mctx, &buffer,
1598 ISC_BUFFER_INCR);
1599 if (result != ISC_R_SUCCESS) {
1600 goto cleanup;
1601 }
1602
1603 isc_buffer_setautorealloc(buffer, true);
1604 isc_buffer_putstr(buffer, "zone ");
1605 dns_name_totext(&entry->name, true, buffer);
1606 isc_buffer_putstr(buffer, " { type slave; masters");
1607
1608 /*
1609 * DSCP value has no default, but when it is specified, it is identical
1610 * for all masters and cannot be overriden for a specific master IP, so
1611 * use the DSCP value set for the first master
1612 */
1613 if (entry->opts.masters.count > 0 &&
1614 entry->opts.masters.dscps[0] >= 0) {
1615 isc_buffer_putstr(buffer, " dscp ");
1616 snprintf(pbuf, sizeof(pbuf), "%hd",
1617 entry->opts.masters.dscps[0]);
1618 isc_buffer_putstr(buffer, pbuf);
1619 }
1620
1621 isc_buffer_putstr(buffer, " { ");
1622 for (i = 0; i < entry->opts.masters.count; i++) {
1623 /*
1624 * Every master must have an IP address assigned.
1625 */
1626 switch (entry->opts.masters.addrs[i].type.sa.sa_family) {
1627 case AF_INET:
1628 case AF_INET6:
1629 break;
1630 default:
1631 dns_name_format(&entry->name, zname,
1632 DNS_NAME_FORMATSIZE);
1633 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1634 DNS_LOGMODULE_MASTER, ISC_LOG_ERROR,
1635 "catz: zone '%s' uses an invalid master "
1636 "(no IP address assigned)",
1637 zname);
1638 result = ISC_R_FAILURE;
1639 goto cleanup;
1640 }
1641 isc_netaddr_fromsockaddr(&netaddr,
1642 &entry->opts.masters.addrs[i]);
1643 isc_buffer_reserve(&buffer, INET6_ADDRSTRLEN);
1644 result = isc_netaddr_totext(&netaddr, buffer);
1645 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1646
1647 isc_buffer_putstr(buffer, " port ");
1648 snprintf(pbuf, sizeof(pbuf), "%u",
1649 isc_sockaddr_getport(&entry->opts.masters.addrs[i]));
1650 isc_buffer_putstr(buffer, pbuf);
1651
1652 if (entry->opts.masters.keys[i] != NULL) {
1653 isc_buffer_putstr(buffer, " key ");
1654 result = dns_name_totext(entry->opts.masters.keys[i],
1655 true, buffer);
1656 if (result != ISC_R_SUCCESS)
1657 goto cleanup;
1658 }
1659 isc_buffer_putstr(buffer, "; ");
1660 }
1661 isc_buffer_putstr(buffer, "}; ");
1662 if (entry->opts.in_memory == false) {
1663 isc_buffer_putstr(buffer, "file \"");
1664 result = dns_catz_generate_masterfilename(zone, entry, &buffer);
1665 if (result != ISC_R_SUCCESS)
1666 goto cleanup;
1667 isc_buffer_putstr(buffer, "\"; ");
1668
1669 }
1670 if (entry->opts.allow_query != NULL) {
1671 isc_buffer_putstr(buffer, "allow-query { ");
1672 isc_buffer_usedregion(entry->opts.allow_query, ®ion);
1673 isc_buffer_copyregion(buffer, ®ion);
1674 isc_buffer_putstr(buffer, "}; ");
1675 }
1676 if (entry->opts.allow_transfer != NULL) {
1677 isc_buffer_putstr(buffer, "allow-transfer { ");
1678 isc_buffer_usedregion(entry->opts.allow_transfer, ®ion);
1679 isc_buffer_copyregion(buffer, ®ion);
1680 isc_buffer_putstr(buffer, "}; ");
1681 }
1682
1683 isc_buffer_putstr(buffer, "};");
1684 *buf = buffer;
1685 return (ISC_R_SUCCESS);
1686
1687 cleanup:
1688 if (buffer != NULL)
1689 isc_buffer_free(&buffer);
1690 return (result);
1691 }
1692
1693 void
1694 dns_catz_update_taskaction(isc_task_t *task, isc_event_t *event) {
1695 isc_result_t result;
1696 dns_catz_zone_t * zone;
1697 (void) task;
1698
1699 REQUIRE(event != NULL);
1700 zone = event->ev_arg;
1701 REQUIRE(DNS_CATZ_ZONE_VALID(zone));
1702
1703 LOCK(&zone->catzs->lock);
1704 zone->updatepending = false;
1705 dns_catz_update_from_db(zone->db, zone->catzs);
1706 result = isc_timer_reset(zone->updatetimer, isc_timertype_inactive,
1707 NULL, NULL, true);
1708 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1709 isc_event_free(&event);
1710 result = isc_time_now(&zone->lastupdated);
1711 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1712 UNLOCK(&zone->catzs->lock);
1713 }
1714
1715 isc_result_t
1716 dns_catz_dbupdate_callback(dns_db_t *db, void *fn_arg) {
1717 dns_catz_zones_t *catzs;
1718 dns_catz_zone_t *zone = NULL;
1719 isc_time_t now;
1720 uint64_t tdiff;
1721 isc_result_t result = ISC_R_SUCCESS;
1722 isc_region_t r;
1723
1724 REQUIRE(DNS_DB_VALID(db));
1725 REQUIRE(fn_arg != NULL);
1726 catzs = (dns_catz_zones_t *) fn_arg;
1727
1728 dns_name_toregion(&db->origin, &r);
1729
1730 LOCK(&catzs->lock);
1731 result = isc_ht_find(catzs->zones, r.base, r.length, (void **) &zone);
1732 if (result != ISC_R_SUCCESS)
1733 goto cleanup;
1734
1735 /* New zone came as AXFR */
1736 if (zone->db != NULL && zone->db != db) {
1737 if (zone->dbversion != NULL)
1738 dns_db_closeversion(zone->db, &zone->dbversion,
1739 false);
1740 dns_db_detach(&zone->db);
1741 /*
1742 * We're not registering db update callback, it will be
1743 * registered at the end of update_from_db
1744 */
1745 zone->db_registered = false;
1746 }
1747 if (zone->db == NULL)
1748 dns_db_attach(db, &zone->db);
1749
1750 if (zone->updatepending == false) {
1751 zone->updatepending = true;
1752 isc_time_now(&now);
1753 tdiff = isc_time_microdiff(&now, &zone->lastupdated)/1000000;
1754 if (tdiff < zone->defoptions.min_update_interval) {
1755 isc_interval_t interval;
1756 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1757 DNS_LOGMODULE_MASTER, ISC_LOG_INFO,
1758 "catz: new zone version came too soon, "
1759 "deferring update");
1760 isc_interval_set(&interval,
1761 zone->defoptions.min_update_interval -
1762 (unsigned int)tdiff, 0);
1763 dns_db_currentversion(db, &zone->dbversion);
1764 result = isc_timer_reset(zone->updatetimer,
1765 isc_timertype_once,
1766 NULL, &interval, true);
1767 if (result != ISC_R_SUCCESS)
1768 goto cleanup;
1769 } else {
1770 isc_event_t *event;
1771
1772 dns_db_currentversion(db, &zone->dbversion);
1773 ISC_EVENT_INIT(&zone->updateevent,
1774 sizeof(zone->updateevent), 0, NULL,
1775 DNS_EVENT_CATZUPDATED,
1776 dns_catz_update_taskaction,
1777 zone, zone, NULL, NULL);
1778 event = &zone->updateevent;
1779 isc_task_send(catzs->updater, &event);
1780 }
1781 } else {
1782 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1783 DNS_LOGMODULE_MASTER, ISC_LOG_DEBUG(3),
1784 "catz: update already queued");
1785 if (zone->dbversion != NULL)
1786 dns_db_closeversion(zone->db, &zone->dbversion,
1787 false);
1788 dns_db_currentversion(zone->db, &zone->dbversion);
1789 }
1790
1791 cleanup:
1792 UNLOCK(&catzs->lock);
1793
1794 return (result);
1795 }
1796
1797 void
1798 dns_catz_update_from_db(dns_db_t *db, dns_catz_zones_t *catzs) {
1799 dns_catz_zone_t *oldzone = NULL, *newzone = NULL;
1800 isc_result_t result;
1801 isc_region_t r;
1802 dns_dbnode_t *node = NULL;
1803 dns_dbiterator_t *it = NULL;
1804 dns_fixedname_t fixname;
1805 dns_name_t *name;
1806 dns_rdatasetiter_t *rdsiter = NULL;
1807 dns_rdataset_t rdataset;
1808 char bname[DNS_NAME_FORMATSIZE];
1809 isc_buffer_t ibname;
1810 uint32_t vers;
1811
1812 REQUIRE(DNS_DB_VALID(db));
1813 REQUIRE(DNS_CATZ_ZONES_VALID(catzs));
1814
1815 /*
1816 * Create a new catz in the same context as current catz.
1817 */
1818 dns_name_toregion(&db->origin, &r);
1819 result = isc_ht_find(catzs->zones, r.base, r.length, (void **)&oldzone);
1820 if (result != ISC_R_SUCCESS) {
1821 /* This can happen if we remove the zone in the meantime. */
1822 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1823 DNS_LOGMODULE_MASTER, ISC_LOG_ERROR,
1824 "catz: zone '%s' not in config",
1825 bname);
1826 return;
1827 }
1828
1829 isc_buffer_init(&ibname, bname, DNS_NAME_FORMATSIZE);
1830 result = dns_name_totext(&db->origin, true, &ibname);
1831 INSIST(result == ISC_R_SUCCESS);
1832
1833 result = dns_db_getsoaserial(db, oldzone->dbversion, &vers);
1834 if (result != ISC_R_SUCCESS) {
1835 /* A zone without SOA record?!? */
1836 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1837 DNS_LOGMODULE_MASTER, ISC_LOG_ERROR,
1838 "catz: zone '%s' has no SOA record (%s)",
1839 bname, isc_result_totext(result));
1840 return;
1841 }
1842
1843 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1844 DNS_LOGMODULE_MASTER, ISC_LOG_INFO,
1845 "catz: updating catalog zone '%s' with serial %d",
1846 bname, vers);
1847
1848 result = dns_catz_new_zone(catzs, &newzone, &db->origin);
1849 if (result != ISC_R_SUCCESS) {
1850 dns_db_closeversion(db, &oldzone->dbversion, false);
1851 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1852 DNS_LOGMODULE_MASTER, ISC_LOG_ERROR,
1853 "catz: failed to create new zone - %s",
1854 isc_result_totext(result));
1855 return;
1856 }
1857
1858 result = dns_db_createiterator(db, DNS_DB_NONSEC3, &it);
1859 if (result != ISC_R_SUCCESS) {
1860 dns_catz_zone_detach(&newzone);
1861 dns_db_closeversion(db, &oldzone->dbversion, false);
1862 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1863 DNS_LOGMODULE_MASTER, ISC_LOG_ERROR,
1864 "catz: failed to create DB iterator - %s",
1865 isc_result_totext(result));
1866 return;
1867 }
1868
1869 name = dns_fixedname_initname(&fixname);
1870
1871 /*
1872 * Iterate over database to fill the new zone.
1873 */
1874 result = dns_dbiterator_first(it);
1875 if (result != ISC_R_SUCCESS) {
1876 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1877 DNS_LOGMODULE_MASTER, ISC_LOG_ERROR,
1878 "catz: failed to get db iterator - %s",
1879 isc_result_totext(result));
1880 }
1881
1882 while (result == ISC_R_SUCCESS) {
1883 result = dns_dbiterator_current(it, &node, name);
1884 if (result != ISC_R_SUCCESS) {
1885 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1886 DNS_LOGMODULE_MASTER, ISC_LOG_ERROR,
1887 "catz: failed to get db iterator - %s",
1888 isc_result_totext(result));
1889 break;
1890 }
1891
1892 result = dns_db_allrdatasets(db, node, oldzone->dbversion, 0,
1893 &rdsiter);
1894 if (result != ISC_R_SUCCESS) {
1895 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1896 DNS_LOGMODULE_MASTER, ISC_LOG_ERROR,
1897 "catz: failed to fetch rrdatasets - %s",
1898 isc_result_totext(result));
1899 dns_db_detachnode(db, &node);
1900 break;
1901 }
1902
1903 dns_rdataset_init(&rdataset);
1904 result = dns_rdatasetiter_first(rdsiter);
1905 while (result == ISC_R_SUCCESS) {
1906 dns_rdatasetiter_current(rdsiter, &rdataset);
1907 result = dns_catz_update_process(catzs, newzone, name,
1908 &rdataset);
1909 if (result != ISC_R_SUCCESS) {
1910 char cname[DNS_NAME_FORMATSIZE];
1911 char typebuf[DNS_RDATATYPE_FORMATSIZE];
1912 char classbuf[DNS_RDATACLASS_FORMATSIZE];
1913
1914 dns_name_format(name, cname,
1915 DNS_NAME_FORMATSIZE);
1916 dns_rdataclass_format(rdataset.rdclass,
1917 classbuf,
1918 sizeof(classbuf));
1919 dns_rdatatype_format(rdataset.type, typebuf,
1920 sizeof(typebuf));
1921 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1922 DNS_LOGMODULE_MASTER,
1923 ISC_LOG_WARNING,
1924 "catz: unknown record in catalog "
1925 "zone - %s %s %s(%s) - ignoring",
1926 cname, classbuf, typebuf,
1927 isc_result_totext(result));
1928 }
1929 dns_rdataset_disassociate(&rdataset);
1930 if (result != ISC_R_SUCCESS) {
1931 break;
1932 }
1933 result = dns_rdatasetiter_next(rdsiter);
1934 }
1935
1936 dns_rdatasetiter_destroy(&rdsiter);
1937
1938 dns_db_detachnode(db, &node);
1939 result = dns_dbiterator_next(it);
1940 }
1941
1942 dns_dbiterator_destroy(&it);
1943 dns_db_closeversion(db, &oldzone->dbversion, false);
1944 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1945 DNS_LOGMODULE_MASTER, ISC_LOG_DEBUG(3),
1946 "catz: update_from_db: iteration finished");
1947
1948 /*
1949 * Finally merge new zone into old zone.
1950 */
1951 result = dns_catz_zones_merge(oldzone, newzone);
1952 dns_catz_zone_detach(&newzone);
1953 if (result != ISC_R_SUCCESS) {
1954 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1955 DNS_LOGMODULE_MASTER,
1956 ISC_LOG_ERROR,
1957 "catz: failed merging zones: %s",
1958 isc_result_totext(result));
1959
1960 return;
1961 }
1962
1963 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1964 DNS_LOGMODULE_MASTER, ISC_LOG_DEBUG(3),
1965 "catz: update_from_db: new zone merged");
1966
1967 /*
1968 * When we're doing reconfig and setting a new catalog zone
1969 * from an existing zone we won't have a chance to set up
1970 * update callback in zone_startload or axfr_makedb, but we will
1971 * call onupdate() artificially so we can register the callback here.
1972 */
1973 if (oldzone->db_registered == false) {
1974 result = dns_db_updatenotify_register(db,
1975 dns_catz_dbupdate_callback,
1976 oldzone->catzs);
1977 if (result == ISC_R_SUCCESS)
1978 oldzone->db_registered = true;
1979 }
1980 }
1981
1982 void
1983 dns_catz_prereconfig(dns_catz_zones_t *catzs) {
1984 isc_result_t result;
1985 isc_ht_iter_t *iter = NULL;
1986
1987 REQUIRE(DNS_CATZ_ZONES_VALID(catzs));
1988
1989 result = isc_ht_iter_create(catzs->zones, &iter);
1990 INSIST(result == ISC_R_SUCCESS);
1991 for (result = isc_ht_iter_first(iter);
1992 result == ISC_R_SUCCESS;
1993 result = isc_ht_iter_next(iter))
1994 {
1995 dns_catz_zone_t *zone = NULL;
1996 isc_ht_iter_current(iter, (void **) &zone);
1997 zone->active = false;
1998 }
1999 INSIST(result == ISC_R_NOMORE);
2000 isc_ht_iter_destroy(&iter);
2001 }
2002
2003 void
2004 dns_catz_postreconfig(dns_catz_zones_t *catzs) {
2005 isc_result_t result;
2006 dns_catz_zone_t *newzone = NULL;
2007 isc_ht_iter_t *iter = NULL;
2008
2009 REQUIRE(DNS_CATZ_ZONES_VALID(catzs));
2010
2011 LOCK(&catzs->lock);
2012 result = isc_ht_iter_create(catzs->zones, &iter);
2013 INSIST(result == ISC_R_SUCCESS);
2014 for (result = isc_ht_iter_first(iter);
2015 result == ISC_R_SUCCESS;)
2016 {
2017 dns_catz_zone_t *zone = NULL;
2018
2019 isc_ht_iter_current(iter, (void **) &zone);
2020 if (zone->active == false) {
2021 char cname[DNS_NAME_FORMATSIZE];
2022 dns_name_format(&zone->name, cname,
2023 DNS_NAME_FORMATSIZE);
2024 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
2025 DNS_LOGMODULE_MASTER,
2026 ISC_LOG_WARNING,
2027 "catz: removing catalog zone %s", cname);
2028
2029 /*
2030 * Merge the old zone with an empty one to remove
2031 * all members.
2032 */
2033 result = dns_catz_new_zone(catzs, &newzone,
2034 &zone->name);
2035 INSIST(result == ISC_R_SUCCESS);
2036 dns_catz_zones_merge(zone, newzone);
2037 dns_catz_zone_detach(&newzone);
2038
2039 /* Make sure that we have an empty catalog zone. */
2040 INSIST(isc_ht_count(zone->entries) == 0);
2041 result = isc_ht_iter_delcurrent_next(iter);
2042 dns_catz_zone_detach(&zone);
2043 } else {
2044 result = isc_ht_iter_next(iter);
2045 }
2046 }
2047 UNLOCK(&catzs->lock);
2048 RUNTIME_CHECK(result == ISC_R_NOMORE);
2049 isc_ht_iter_destroy(&iter);
2050 }
2051
2052 isc_result_t
2053 dns_catz_get_iterator(dns_catz_zone_t *catz, isc_ht_iter_t **itp) {
2054 REQUIRE(DNS_CATZ_ZONE_VALID(catz));
2055 return (isc_ht_iter_create(catz->entries, itp));
2056 }
2057