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