/src/bind9/lib/dns/zone.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) Internet Systems Consortium, Inc. ("ISC") |
3 | | * |
4 | | * SPDX-License-Identifier: MPL-2.0 |
5 | | * |
6 | | * This Source Code Form is subject to the terms of the Mozilla Public |
7 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
8 | | * file, you can obtain one at https://mozilla.org/MPL/2.0/. |
9 | | * |
10 | | * See the COPYRIGHT file distributed with this work for additional |
11 | | * information regarding copyright ownership. |
12 | | */ |
13 | | |
14 | | /*! \file */ |
15 | | |
16 | | #include <errno.h> |
17 | | #include <inttypes.h> |
18 | | #include <stdbool.h> |
19 | | |
20 | | #include <isc/async.h> |
21 | | #include <isc/atomic.h> |
22 | | #include <isc/file.h> |
23 | | #include <isc/hash.h> |
24 | | #include <isc/hashmap.h> |
25 | | #include <isc/hex.h> |
26 | | #include <isc/loop.h> |
27 | | #include <isc/md.h> |
28 | | #include <isc/mutex.h> |
29 | | #include <isc/overflow.h> |
30 | | #include <isc/random.h> |
31 | | #include <isc/ratelimiter.h> |
32 | | #include <isc/refcount.h> |
33 | | #include <isc/result.h> |
34 | | #include <isc/rwlock.h> |
35 | | #include <isc/serial.h> |
36 | | #include <isc/stats.h> |
37 | | #include <isc/stdtime.h> |
38 | | #include <isc/strerr.h> |
39 | | #include <isc/string.h> |
40 | | #include <isc/thread.h> |
41 | | #include <isc/tid.h> |
42 | | #include <isc/timer.h> |
43 | | #include <isc/tls.h> |
44 | | #include <isc/util.h> |
45 | | |
46 | | #include <dns/acl.h> |
47 | | #include <dns/adb.h> |
48 | | #include <dns/callbacks.h> |
49 | | #include <dns/catz.h> |
50 | | #include <dns/db.h> |
51 | | #include <dns/dbiterator.h> |
52 | | #include <dns/dlz.h> |
53 | | #include <dns/dnssec.h> |
54 | | #include <dns/journal.h> |
55 | | #include <dns/kasp.h> |
56 | | #include <dns/keydata.h> |
57 | | #include <dns/keymgr.h> |
58 | | #include <dns/keytable.h> |
59 | | #include <dns/keyvalues.h> |
60 | | #include <dns/log.h> |
61 | | #include <dns/master.h> |
62 | | #include <dns/masterdump.h> |
63 | | #include <dns/message.h> |
64 | | #include <dns/name.h> |
65 | | #include <dns/nsec.h> |
66 | | #include <dns/nsec3.h> |
67 | | #include <dns/opcode.h> |
68 | | #include <dns/peer.h> |
69 | | #include <dns/private.h> |
70 | | #include <dns/rcode.h> |
71 | | #include <dns/rdata.h> |
72 | | #include <dns/rdataclass.h> |
73 | | #include <dns/rdatalist.h> |
74 | | #include <dns/rdataset.h> |
75 | | #include <dns/rdatasetiter.h> |
76 | | #include <dns/rdatastruct.h> |
77 | | #include <dns/rdatatype.h> |
78 | | #include <dns/remote.h> |
79 | | #include <dns/request.h> |
80 | | #include <dns/resolver.h> |
81 | | #include <dns/rriterator.h> |
82 | | #include <dns/soa.h> |
83 | | #include <dns/ssu.h> |
84 | | #include <dns/stats.h> |
85 | | #include <dns/time.h> |
86 | | #include <dns/tsig.h> |
87 | | #include <dns/update.h> |
88 | | #include <dns/xfrin.h> |
89 | | #include <dns/zone.h> |
90 | | #include <dns/zoneverify.h> |
91 | | #include <dns/zt.h> |
92 | | |
93 | | #include <dst/dst.h> |
94 | | |
95 | | #include "zone_p.h" |
96 | | |
97 | 2 | #define ZONE_MAGIC ISC_MAGIC('Z', 'O', 'N', 'E') |
98 | | #define DNS_ZONE_VALID(zone) ISC_MAGIC_VALID(zone, ZONE_MAGIC) |
99 | | |
100 | 0 | #define NOTIFY_MAGIC ISC_MAGIC('N', 't', 'f', 'y') |
101 | | #define DNS_NOTIFY_VALID(notify) ISC_MAGIC_VALID(notify, NOTIFY_MAGIC) |
102 | | |
103 | 0 | #define CHECKDS_MAGIC ISC_MAGIC('C', 'h', 'D', 'S') |
104 | | #define DNS_CHECKDS_VALID(checkds) ISC_MAGIC_VALID(checkds, CHECKDS_MAGIC) |
105 | | |
106 | 0 | #define STUB_MAGIC ISC_MAGIC('S', 't', 'u', 'b') |
107 | | #define DNS_STUB_VALID(stub) ISC_MAGIC_VALID(stub, STUB_MAGIC) |
108 | | |
109 | 0 | #define ZONEMGR_MAGIC ISC_MAGIC('Z', 'm', 'g', 'r') |
110 | | #define DNS_ZONEMGR_VALID(stub) ISC_MAGIC_VALID(stub, ZONEMGR_MAGIC) |
111 | | |
112 | 0 | #define FORWARD_MAGIC ISC_MAGIC('F', 'o', 'r', 'w') |
113 | | #define DNS_FORWARD_VALID(load) ISC_MAGIC_VALID(load, FORWARD_MAGIC) |
114 | | |
115 | | #define IO_MAGIC ISC_MAGIC('Z', 'm', 'I', 'O') |
116 | | #define DNS_IO_VALID(load) ISC_MAGIC_VALID(load, IO_MAGIC) |
117 | | |
118 | 0 | #define KEYMGMT_MAGIC ISC_MAGIC('M', 'g', 'm', 't') |
119 | | #define DNS_KEYMGMT_VALID(load) ISC_MAGIC_VALID(load, KEYMGMT_MAGIC) |
120 | | |
121 | 0 | #define KEYFILEIO_MAGIC ISC_MAGIC('K', 'y', 'I', 'O') |
122 | | #define DNS_KEYFILEIO_VALID(kfio) ISC_MAGIC_VALID(kfio, KEYFILEIO_MAGIC) |
123 | | |
124 | | /*% |
125 | | * Ensure 'a' is at least 'min' but not more than 'max'. |
126 | | */ |
127 | 6 | #define RANGE(a, min, max) (((a) < (min)) ? (min) : ((a) < (max) ? (a) : (max))) |
128 | | |
129 | 0 | #define NSEC3REMOVE(x) (((x) & DNS_NSEC3FLAG_REMOVE) != 0) |
130 | | |
131 | | /*% |
132 | | * Key flags |
133 | | */ |
134 | 0 | #define REVOKE(x) ((dst_key_flags(x) & DNS_KEYFLAG_REVOKE) != 0) |
135 | 0 | #define KSK(x) ((dst_key_flags(x) & DNS_KEYFLAG_KSK) != 0) |
136 | 0 | #define ID(x) dst_key_id(x) |
137 | 0 | #define ALG(x) dst_key_alg(x) |
138 | | |
139 | | /*% |
140 | | * KASP flags |
141 | | */ |
142 | | #define KASP_LOCK(k) \ |
143 | 0 | if ((k) != NULL) { \ |
144 | 0 | LOCK((&((k)->lock))); \ |
145 | 0 | } |
146 | | |
147 | | #define KASP_UNLOCK(k) \ |
148 | 0 | if ((k) != NULL) { \ |
149 | 0 | UNLOCK((&((k)->lock))); \ |
150 | 0 | } |
151 | | |
152 | | /* |
153 | | * Default values. |
154 | | */ |
155 | 2 | #define DNS_DEFAULT_IDLEIN 3600 /*%< 1 hour */ |
156 | 2 | #define DNS_DEFAULT_IDLEOUT 3600 /*%< 1 hour */ |
157 | 4 | #define MAX_XFER_TIME (2 * 3600) /*%< Documented default is 2 hours */ |
158 | | #define RESIGN_DELAY 3600 /*%< 1 hour */ |
159 | | |
160 | | #ifndef DNS_MAX_EXPIRE |
161 | | #define DNS_MAX_EXPIRE 14515200 /*%< 24 weeks */ |
162 | | #endif /* ifndef DNS_MAX_EXPIRE */ |
163 | | |
164 | | #ifndef DNS_DUMP_DELAY |
165 | 0 | #define DNS_DUMP_DELAY 900 /*%< 15 minutes */ |
166 | | #endif /* ifndef DNS_DUMP_DELAY */ |
167 | | |
168 | | typedef struct dns_notify dns_notify_t; |
169 | | typedef struct dns_checkds dns_checkds_t; |
170 | | typedef struct dns_stub dns_stub_t; |
171 | | typedef struct dns_load dns_load_t; |
172 | | typedef struct dns_forward dns_forward_t; |
173 | | typedef ISC_LIST(dns_forward_t) dns_forwardlist_t; |
174 | | typedef struct dns_keymgmt dns_keymgmt_t; |
175 | | typedef struct dns_signing dns_signing_t; |
176 | | typedef ISC_LIST(dns_signing_t) dns_signinglist_t; |
177 | | typedef struct dns_nsec3chain dns_nsec3chain_t; |
178 | | typedef ISC_LIST(dns_nsec3chain_t) dns_nsec3chainlist_t; |
179 | | typedef struct dns_nsfetch dns_nsfetch_t; |
180 | | typedef struct dns_keyfetch dns_keyfetch_t; |
181 | | typedef struct dns_asyncload dns_asyncload_t; |
182 | | typedef struct dns_include dns_include_t; |
183 | | |
184 | | #define DNS_ZONE_CHECKLOCK |
185 | | #ifdef DNS_ZONE_CHECKLOCK |
186 | | #define LOCK_ZONE(z) \ |
187 | 16 | do { \ |
188 | 16 | LOCK(&(z)->lock); \ |
189 | 16 | INSIST(!(z)->locked); \ |
190 | 16 | (z)->locked = true; \ |
191 | 16 | } while (0) |
192 | | #define UNLOCK_ZONE(z) \ |
193 | 16 | do { \ |
194 | 16 | (z)->locked = false; \ |
195 | 16 | UNLOCK(&(z)->lock); \ |
196 | 16 | } while (0) |
197 | | #define LOCKED_ZONE(z) ((z)->locked) |
198 | | #define TRYLOCK_ZONE(result, z) \ |
199 | 0 | do { \ |
200 | 0 | result = isc_mutex_trylock(&(z)->lock); \ |
201 | 0 | if (result == ISC_R_SUCCESS) { \ |
202 | 0 | INSIST(!(z)->locked); \ |
203 | 0 | (z)->locked = true; \ |
204 | 0 | } \ |
205 | 0 | } while (0) |
206 | | #else /* ifdef DNS_ZONE_CHECKLOCK */ |
207 | | #define LOCK_ZONE(z) LOCK(&(z)->lock) |
208 | | #define UNLOCK_ZONE(z) UNLOCK(&(z)->lock) |
209 | | #define LOCKED_ZONE(z) true |
210 | | #define TRYLOCK_ZONE(result, z) \ |
211 | | do { \ |
212 | | result = isc_mutex_trylock(&(z)->lock); \ |
213 | | } while (0) |
214 | | #endif /* ifdef DNS_ZONE_CHECKLOCK */ |
215 | | |
216 | 2 | #define ZONEDB_INITLOCK(l) isc_rwlock_init((l)) |
217 | 0 | #define ZONEDB_DESTROYLOCK(l) isc_rwlock_destroy(l) |
218 | 188 | #define ZONEDB_LOCK(l, t) RWLOCK((l), (t)) |
219 | 188 | #define ZONEDB_UNLOCK(l, t) RWUNLOCK((l), (t)) |
220 | | |
221 | | #ifdef ENABLE_AFL |
222 | | extern bool dns_fuzzing_resolver; |
223 | | #endif /* ifdef ENABLE_AFL */ |
224 | | |
225 | | /*% |
226 | | * Hold key file IO locks. |
227 | | */ |
228 | | typedef struct dns_keyfileio { |
229 | | unsigned int magic; |
230 | | isc_mutex_t lock; |
231 | | isc_refcount_t references; |
232 | | dns_name_t *name; |
233 | | dns_fixedname_t fname; |
234 | | } dns_keyfileio_t; |
235 | | |
236 | | struct dns_keymgmt { |
237 | | unsigned int magic; |
238 | | isc_rwlock_t lock; |
239 | | isc_mem_t *mctx; |
240 | | isc_hashmap_t *table; |
241 | | }; |
242 | | |
243 | | /* |
244 | | * Initial size of the keymgmt hash table. |
245 | | */ |
246 | 0 | #define DNS_KEYMGMT_HASH_BITS 12 |
247 | | |
248 | | struct dns_zone { |
249 | | /* Unlocked */ |
250 | | unsigned int magic; |
251 | | isc_mutex_t lock; |
252 | | #ifdef DNS_ZONE_CHECKLOCK |
253 | | bool locked; |
254 | | #endif /* ifdef DNS_ZONE_CHECKLOCK */ |
255 | | isc_mem_t *mctx; |
256 | | isc_refcount_t references; |
257 | | |
258 | | isc_rwlock_t dblock; |
259 | | dns_db_t *db; /* Locked by dblock */ |
260 | | |
261 | | unsigned int tid; |
262 | | |
263 | | /* Locked */ |
264 | | dns_zonemgr_t *zmgr; |
265 | | ISC_LINK(dns_zone_t) link; /* Used by zmgr. */ |
266 | | isc_loop_t *loop; |
267 | | isc_timer_t *timer; |
268 | | isc_refcount_t irefs; |
269 | | dns_name_t origin; |
270 | | char *masterfile; |
271 | | const FILE *stream; /* loading from a stream? */ |
272 | | ISC_LIST(dns_include_t) includes; /* Include files */ |
273 | | ISC_LIST(dns_include_t) newincludes; /* Loading */ |
274 | | unsigned int nincludes; |
275 | | dns_masterformat_t masterformat; |
276 | | const dns_master_style_t *masterstyle; |
277 | | char *journal; |
278 | | int32_t journalsize; |
279 | | dns_rdataclass_t rdclass; |
280 | | dns_zonetype_t type; |
281 | | atomic_uint_fast64_t flags; |
282 | | atomic_uint_fast64_t options; |
283 | | unsigned int db_argc; |
284 | | char **db_argv; |
285 | | isc_time_t expiretime; |
286 | | isc_time_t refreshtime; |
287 | | isc_time_t dumptime; |
288 | | isc_time_t loadtime; |
289 | | isc_time_t notifytime; |
290 | | isc_time_t resigntime; |
291 | | isc_time_t keywarntime; |
292 | | isc_time_t signingtime; |
293 | | isc_time_t nsec3chaintime; |
294 | | isc_time_t refreshkeytime; |
295 | | isc_time_t xfrintime; |
296 | | uint32_t refreshkeyinterval; |
297 | | uint32_t refreshkeycount; |
298 | | uint32_t refresh; |
299 | | uint32_t retry; |
300 | | uint32_t expire; |
301 | | uint32_t minimum; |
302 | | isc_stdtime_t key_expiry; |
303 | | isc_stdtime_t log_key_expired_timer; |
304 | | char *keydirectory; |
305 | | dns_keyfileio_t *kfio; |
306 | | |
307 | | uint32_t maxrefresh; |
308 | | uint32_t minrefresh; |
309 | | uint32_t maxretry; |
310 | | uint32_t minretry; |
311 | | |
312 | | uint32_t maxrecords; |
313 | | |
314 | | dns_remote_t primaries; |
315 | | |
316 | | dns_remote_t parentals; |
317 | | dns_dnsseckeylist_t checkds_ok; |
318 | | dns_checkdstype_t checkdstype; |
319 | | uint32_t nsfetchcount; |
320 | | uint32_t parent_nscount; |
321 | | |
322 | | dns_remote_t notify; |
323 | | dns_notifytype_t notifytype; |
324 | | isc_sockaddr_t notifyfrom; |
325 | | isc_sockaddr_t notifysrc4; |
326 | | isc_sockaddr_t notifysrc6; |
327 | | isc_sockaddr_t parentalsrc4; |
328 | | isc_sockaddr_t parentalsrc6; |
329 | | isc_sockaddr_t xfrsource4; |
330 | | isc_sockaddr_t xfrsource6; |
331 | | isc_sockaddr_t sourceaddr; |
332 | | dns_xfrin_t *xfr; /* loop locked */ |
333 | | dns_tsigkey_t *tsigkey; /* key used for xfr */ |
334 | | dns_transport_t *transport; /* transport used for xfr */ |
335 | | /* Access Control Lists */ |
336 | | dns_acl_t *update_acl; |
337 | | dns_acl_t *forward_acl; |
338 | | dns_acl_t *notify_acl; |
339 | | dns_acl_t *query_acl; |
340 | | dns_acl_t *queryon_acl; |
341 | | dns_acl_t *xfr_acl; |
342 | | bool update_disabled; |
343 | | bool zero_no_soa_ttl; |
344 | | dns_severity_t check_names; |
345 | | ISC_LIST(dns_notify_t) notifies; |
346 | | ISC_LIST(dns_checkds_t) checkds_requests; |
347 | | dns_request_t *request; |
348 | | dns_loadctx_t *loadctx; |
349 | | dns_dumpctx_t *dumpctx; |
350 | | uint32_t maxxfrin; |
351 | | uint32_t maxxfrout; |
352 | | uint32_t idlein; |
353 | | uint32_t idleout; |
354 | | dns_ssutable_t *ssutable; |
355 | | uint32_t sigvalidityinterval; |
356 | | uint32_t keyvalidityinterval; |
357 | | uint32_t sigresigninginterval; |
358 | | dns_view_t *view; |
359 | | dns_view_t *prev_view; |
360 | | dns_kasp_t *kasp; |
361 | | dns_kasp_t *defaultkasp; |
362 | | dns_checkmxfunc_t checkmx; |
363 | | dns_checksrvfunc_t checksrv; |
364 | | dns_checknsfunc_t checkns; |
365 | | /*% |
366 | | * Zones in certain states such as "waiting for zone transfer" |
367 | | * or "zone transfer in progress" are kept on per-state linked lists |
368 | | * in the zone manager using the 'statelink' field. The 'statelist' |
369 | | * field points at the list the zone is currently on. It the zone |
370 | | * is not on any such list, statelist is NULL. |
371 | | */ |
372 | | ISC_LINK(dns_zone_t) statelink; |
373 | | dns_zonelist_t *statelist; |
374 | | /*% |
375 | | * Statistics counters about zone management. |
376 | | */ |
377 | | isc_stats_t *stats; |
378 | | /*% |
379 | | * Optional per-zone statistics counters. Counted outside of this |
380 | | * module. |
381 | | */ |
382 | | dns_zonestat_level_t statlevel; |
383 | | bool requeststats_on; |
384 | | isc_stats_t *requeststats; |
385 | | dns_stats_t *rcvquerystats; |
386 | | dns_stats_t *dnssecsignstats; |
387 | | uint32_t notifydelay; |
388 | | dns_isselffunc_t isself; |
389 | | void *isselfarg; |
390 | | |
391 | | char *strnamerd; |
392 | | char *strname; |
393 | | char *strrdclass; |
394 | | char *strviewname; |
395 | | |
396 | | /*% |
397 | | * Serial number for deferred journal compaction. |
398 | | */ |
399 | | uint32_t compact_serial; |
400 | | /*% |
401 | | * Keys that are signing the zone for the first time. |
402 | | */ |
403 | | dns_signinglist_t signing; |
404 | | dns_nsec3chainlist_t nsec3chain; |
405 | | /*% |
406 | | * List of outstanding NSEC3PARAM change requests. |
407 | | */ |
408 | | ISC_LIST(struct np3) setnsec3param_queue; |
409 | | /*% |
410 | | * Signing / re-signing quantum stopping parameters. |
411 | | */ |
412 | | uint32_t signatures; |
413 | | uint32_t nodes; |
414 | | dns_rdatatype_t privatetype; |
415 | | |
416 | | /*% |
417 | | * Autosigning/key-maintenance options |
418 | | */ |
419 | | atomic_uint_fast64_t keyopts; |
420 | | |
421 | | /*% |
422 | | * True if added by "rndc addzone" |
423 | | */ |
424 | | bool added; |
425 | | |
426 | | /*% |
427 | | * True if added by automatically by named. |
428 | | */ |
429 | | bool automatic; |
430 | | |
431 | | /*% |
432 | | * response policy data to be relayed to the database |
433 | | */ |
434 | | dns_rpz_zones_t *rpzs; |
435 | | dns_rpz_num_t rpz_num; |
436 | | |
437 | | /*% |
438 | | * catalog zone data |
439 | | */ |
440 | | dns_catz_zones_t *catzs; |
441 | | |
442 | | /*% |
443 | | * parent catalog zone |
444 | | */ |
445 | | dns_catz_zone_t *parentcatz; |
446 | | |
447 | | /*% |
448 | | * Serial number update method. |
449 | | */ |
450 | | dns_updatemethod_t updatemethod; |
451 | | |
452 | | /*% |
453 | | * whether ixfr is requested |
454 | | */ |
455 | | bool requestixfr; |
456 | | uint32_t ixfr_ratio; |
457 | | |
458 | | /*% |
459 | | * whether EDNS EXPIRE is requested |
460 | | */ |
461 | | bool requestexpire; |
462 | | |
463 | | /*% |
464 | | * Outstanding forwarded UPDATE requests. |
465 | | */ |
466 | | dns_forwardlist_t forwards; |
467 | | |
468 | | dns_zone_t *raw; |
469 | | dns_zone_t *secure; |
470 | | |
471 | | bool sourceserialset; |
472 | | uint32_t sourceserial; |
473 | | |
474 | | /*% |
475 | | * soa and maximum zone ttl |
476 | | */ |
477 | | dns_ttl_t soattl; |
478 | | dns_ttl_t maxttl; |
479 | | |
480 | | /* |
481 | | * Inline zone signing state. |
482 | | */ |
483 | | dns_diff_t rss_diff; |
484 | | dns_dbversion_t *rss_newver; |
485 | | dns_dbversion_t *rss_oldver; |
486 | | dns_db_t *rss_db; |
487 | | dns_zone_t *rss_raw; |
488 | | struct rss *rss; |
489 | | dns_update_state_t *rss_state; |
490 | | |
491 | | isc_stats_t *gluecachestats; |
492 | | }; |
493 | | |
494 | | #define zonediff_init(z, d) \ |
495 | 0 | do { \ |
496 | 0 | dns__zonediff_t *_z = (z); \ |
497 | 0 | (_z)->diff = (d); \ |
498 | 0 | (_z)->offline = false; \ |
499 | 0 | } while (0) |
500 | | |
501 | 14 | #define DNS_ZONE_FLAG(z, f) ((atomic_load_relaxed(&(z)->flags) & (f)) != 0) |
502 | 4 | #define DNS_ZONE_SETFLAG(z, f) atomic_fetch_or(&(z)->flags, (f)) |
503 | 4 | #define DNS_ZONE_CLRFLAG(z, f) atomic_fetch_and(&(z)->flags, ~(f)) |
504 | | typedef enum { |
505 | | DNS_ZONEFLG_REFRESH = 0x00000001U, /*%< refresh check in progress */ |
506 | | DNS_ZONEFLG_NEEDDUMP = 0x00000002U, /*%< zone need consolidation */ |
507 | | DNS_ZONEFLG_USEVC = 0x00000004U, /*%< use tcp for refresh query */ |
508 | | DNS_ZONEFLG_DUMPING = 0x00000008U, /*%< a dump is in progress */ |
509 | | DNS_ZONEFLG_HASINCLUDE = 0x00000010U, /*%< $INCLUDE in zone file */ |
510 | | DNS_ZONEFLG_LOADED = 0x00000020U, /*%< database has loaded */ |
511 | | DNS_ZONEFLG_EXITING = 0x00000040U, /*%< zone is being destroyed */ |
512 | | DNS_ZONEFLG_EXPIRED = 0x00000080U, /*%< zone has expired */ |
513 | | DNS_ZONEFLG_NEEDREFRESH = 0x00000100U, /*%< refresh check needed */ |
514 | | DNS_ZONEFLG_UPTODATE = 0x00000200U, /*%< zone contents are |
515 | | * up-to-date */ |
516 | | DNS_ZONEFLG_NEEDNOTIFY = 0x00000400U, /*%< need to send out notify |
517 | | * messages */ |
518 | | DNS_ZONEFLG_FIXJOURNAL = 0x00000800U, /*%< journal file had |
519 | | * recoverable error, |
520 | | * needs rewriting */ |
521 | | DNS_ZONEFLG_NOPRIMARIES = 0x00001000U, /*%< an attempt to refresh a |
522 | | * zone with no primaries |
523 | | * occurred */ |
524 | | DNS_ZONEFLG_LOADING = 0x00002000U, /*%< load from disk in progress*/ |
525 | | DNS_ZONEFLG_HAVETIMERS = 0x00004000U, /*%< timer values have been set |
526 | | * from SOA (if not set, we |
527 | | * are still using |
528 | | * default timer values) */ |
529 | | DNS_ZONEFLG_FORCEXFER = 0x00008000U, /*%< Force a zone xfer */ |
530 | | DNS_ZONEFLG_NOREFRESH = 0x00010000U, |
531 | | DNS_ZONEFLG_DIALNOTIFY = 0x00020000U, |
532 | | DNS_ZONEFLG_DIALREFRESH = 0x00040000U, |
533 | | DNS_ZONEFLG_SHUTDOWN = 0x00080000U, |
534 | | DNS_ZONEFLG_NOIXFR = 0x00100000U, /*%< IXFR failed, force AXFR */ |
535 | | DNS_ZONEFLG_FLUSH = 0x00200000U, |
536 | | DNS_ZONEFLG_NOEDNS = 0x00400000U, |
537 | | DNS_ZONEFLG_USEALTXFRSRC = 0x00800000U, /*%< Obsoleted. */ |
538 | | DNS_ZONEFLG_SOABEFOREAXFR = 0x01000000U, |
539 | | DNS_ZONEFLG_NEEDCOMPACT = 0x02000000U, |
540 | | DNS_ZONEFLG_REFRESHING = 0x04000000U, /*%< Refreshing keydata */ |
541 | | DNS_ZONEFLG_THAW = 0x08000000U, |
542 | | DNS_ZONEFLG_LOADPENDING = 0x10000000U, /*%< Loading scheduled */ |
543 | | DNS_ZONEFLG_NODELAY = 0x20000000U, |
544 | | DNS_ZONEFLG_SENDSECURE = 0x40000000U, |
545 | | DNS_ZONEFLG_NEEDSTARTUPNOTIFY = 0x80000000U, /*%< need to send out |
546 | | * notify due to the zone |
547 | | * just being loaded for |
548 | | * the first time. */ |
549 | | DNS_ZONEFLG___MAX = UINT64_MAX, /* trick to make the ENUM 64-bit wide */ |
550 | | } dns_zoneflg_t; |
551 | | |
552 | 32 | #define DNS_ZONE_OPTION(z, o) ((atomic_load_relaxed(&(z)->options) & (o)) != 0) |
553 | 0 | #define DNS_ZONE_SETOPTION(z, o) atomic_fetch_or(&(z)->options, (o)) |
554 | 0 | #define DNS_ZONE_CLROPTION(z, o) atomic_fetch_and(&(z)->options, ~(o)) |
555 | | |
556 | | #define DNS_ZONEKEY_OPTION(z, o) \ |
557 | 2 | ((atomic_load_relaxed(&(z)->keyopts) & (o)) != 0) |
558 | 0 | #define DNS_ZONEKEY_SETOPTION(z, o) atomic_fetch_or(&(z)->keyopts, (o)) |
559 | 0 | #define DNS_ZONEKEY_CLROPTION(z, o) atomic_fetch_and(&(z)->keyopts, ~(o)) |
560 | | |
561 | | /* Flags for zone_load() */ |
562 | | typedef enum { |
563 | | DNS_ZONELOADFLAG_NOSTAT = 0x00000001U, /* Do not stat() master files */ |
564 | | DNS_ZONELOADFLAG_THAW = 0x00000002U, /* Thaw the zone on successful |
565 | | * load. */ |
566 | | } dns_zoneloadflag_t; |
567 | | |
568 | 0 | #define UNREACH_CACHE_SIZE 10U |
569 | | #define UNREACH_HOLD_TIME 600 /* 10 minutes */ |
570 | | |
571 | | #define CHECK(op) \ |
572 | 0 | do { \ |
573 | 0 | result = (op); \ |
574 | 0 | if (result != ISC_R_SUCCESS) \ |
575 | 0 | goto failure; \ |
576 | 0 | } while (0) |
577 | | |
578 | | struct dns_unreachable { |
579 | | isc_sockaddr_t remote; |
580 | | isc_sockaddr_t local; |
581 | | atomic_uint_fast32_t expire; |
582 | | atomic_uint_fast32_t last; |
583 | | uint32_t count; |
584 | | }; |
585 | | |
586 | | struct dns_zonemgr { |
587 | | unsigned int magic; |
588 | | isc_mem_t *mctx; |
589 | | isc_refcount_t refs; |
590 | | isc_loopmgr_t *loopmgr; |
591 | | isc_nm_t *netmgr; |
592 | | uint32_t workers; |
593 | | isc_mem_t **mctxpool; |
594 | | isc_ratelimiter_t *checkdsrl; |
595 | | isc_ratelimiter_t *notifyrl; |
596 | | isc_ratelimiter_t *refreshrl; |
597 | | isc_ratelimiter_t *startupnotifyrl; |
598 | | isc_ratelimiter_t *startuprefreshrl; |
599 | | isc_rwlock_t rwlock; |
600 | | isc_rwlock_t urlock; |
601 | | |
602 | | /* Locked by rwlock. */ |
603 | | dns_zonelist_t zones; |
604 | | dns_zonelist_t waiting_for_xfrin; |
605 | | dns_zonelist_t xfrin_in_progress; |
606 | | |
607 | | /* Configuration data. */ |
608 | | uint32_t transfersin; |
609 | | uint32_t transfersperns; |
610 | | unsigned int checkdsrate; |
611 | | unsigned int notifyrate; |
612 | | unsigned int startupnotifyrate; |
613 | | unsigned int serialqueryrate; |
614 | | unsigned int startupserialqueryrate; |
615 | | |
616 | | /* Locked by urlock. */ |
617 | | /* LRU cache */ |
618 | | struct dns_unreachable unreachable[UNREACH_CACHE_SIZE]; |
619 | | |
620 | | dns_keymgmt_t *keymgmt; |
621 | | |
622 | | isc_tlsctx_cache_t *tlsctx_cache; |
623 | | isc_rwlock_t tlsctx_cache_rwlock; |
624 | | }; |
625 | | |
626 | | /*% |
627 | | * Hold notify state. |
628 | | */ |
629 | | struct dns_notify { |
630 | | unsigned int magic; |
631 | | unsigned int flags; |
632 | | isc_mem_t *mctx; |
633 | | dns_zone_t *zone; |
634 | | dns_adbfind_t *find; |
635 | | dns_request_t *request; |
636 | | dns_name_t ns; |
637 | | isc_sockaddr_t src; |
638 | | isc_sockaddr_t dst; |
639 | | dns_tsigkey_t *key; |
640 | | dns_transport_t *transport; |
641 | | ISC_LINK(dns_notify_t) link; |
642 | | isc_rlevent_t *rlevent; |
643 | | }; |
644 | | |
645 | | typedef enum dns_notify_flags { |
646 | | DNS_NOTIFY_NOSOA = 1 << 0, |
647 | | DNS_NOTIFY_STARTUP = 1 << 1, |
648 | | DNS_NOTIFY_TCP = 1 << 2, |
649 | | } dns_notify_flags_t; |
650 | | |
651 | | /*% |
652 | | * Hold checkds state. |
653 | | */ |
654 | | struct dns_checkds { |
655 | | unsigned int magic; |
656 | | dns_notify_flags_t flags; |
657 | | isc_mem_t *mctx; |
658 | | dns_zone_t *zone; |
659 | | dns_adbfind_t *find; |
660 | | dns_request_t *request; |
661 | | dns_name_t ns; |
662 | | isc_sockaddr_t src; |
663 | | isc_sockaddr_t dst; |
664 | | dns_tsigkey_t *key; |
665 | | dns_transport_t *transport; |
666 | | ISC_LINK(dns_checkds_t) link; |
667 | | isc_rlevent_t *rlevent; |
668 | | }; |
669 | | |
670 | | /*% |
671 | | * dns_stub holds state while performing a 'stub' transfer. |
672 | | * 'db' is the zone's 'db' or a new one if this is the initial |
673 | | * transfer. |
674 | | */ |
675 | | |
676 | | struct dns_stub { |
677 | | unsigned int magic; |
678 | | isc_mem_t *mctx; |
679 | | dns_zone_t *zone; |
680 | | dns_db_t *db; |
681 | | dns_dbversion_t *version; |
682 | | atomic_uint_fast32_t pending_requests; |
683 | | }; |
684 | | |
685 | | /*% |
686 | | * Hold load state. |
687 | | */ |
688 | | struct dns_load { |
689 | | dns_zone_t *zone; |
690 | | dns_db_t *db; |
691 | | isc_time_t loadtime; |
692 | | dns_rdatacallbacks_t callbacks; |
693 | | }; |
694 | | |
695 | | /*% |
696 | | * Hold forward state. |
697 | | */ |
698 | | struct dns_forward { |
699 | | unsigned int magic; |
700 | | isc_mem_t *mctx; |
701 | | dns_zone_t *zone; |
702 | | isc_buffer_t *msgbuf; |
703 | | dns_request_t *request; |
704 | | uint32_t which; |
705 | | isc_sockaddr_t addr; |
706 | | dns_transport_t *transport; |
707 | | dns_updatecallback_t callback; |
708 | | void *callback_arg; |
709 | | unsigned int options; |
710 | | ISC_LINK(dns_forward_t) link; |
711 | | }; |
712 | | |
713 | | /*% |
714 | | * Hold state for when we are signing a zone with a new |
715 | | * DNSKEY as result of an update. |
716 | | */ |
717 | | struct dns_signing { |
718 | | unsigned int magic; |
719 | | dns_db_t *db; |
720 | | dns_dbiterator_t *dbiterator; |
721 | | dns_secalg_t algorithm; |
722 | | uint16_t keyid; |
723 | | bool deleteit; |
724 | | bool done; |
725 | | ISC_LINK(dns_signing_t) link; |
726 | | }; |
727 | | |
728 | | struct dns_nsec3chain { |
729 | | unsigned int magic; |
730 | | dns_db_t *db; |
731 | | dns_dbiterator_t *dbiterator; |
732 | | dns_rdata_nsec3param_t nsec3param; |
733 | | unsigned char salt[255]; |
734 | | bool done; |
735 | | bool seen_nsec; |
736 | | bool delete_nsec; |
737 | | bool save_delete_nsec; |
738 | | ISC_LINK(dns_nsec3chain_t) link; |
739 | | }; |
740 | | |
741 | | /*%< |
742 | | * 'dbiterator' contains a iterator for the database. If we are creating |
743 | | * a NSEC3 chain only the non-NSEC3 nodes will be iterated. If we are |
744 | | * removing a NSEC3 chain then both NSEC3 and non-NSEC3 nodes will be |
745 | | * iterated. |
746 | | * |
747 | | * 'nsec3param' contains the parameters of the NSEC3 chain being created |
748 | | * or removed. |
749 | | * |
750 | | * 'salt' is buffer space and is referenced via 'nsec3param.salt'. |
751 | | * |
752 | | * 'seen_nsec' will be set to true if, while iterating the zone to create a |
753 | | * NSEC3 chain, a NSEC record is seen. |
754 | | * |
755 | | * 'delete_nsec' will be set to true if, at the completion of the creation |
756 | | * of a NSEC3 chain, 'seen_nsec' is true. If 'delete_nsec' is true then we |
757 | | * are in the process of deleting the NSEC chain. |
758 | | * |
759 | | * 'save_delete_nsec' is used to store the initial state of 'delete_nsec' |
760 | | * so it can be recovered in the event of a error. |
761 | | */ |
762 | | |
763 | | struct dns_keyfetch { |
764 | | isc_mem_t *mctx; |
765 | | dns_fixedname_t name; |
766 | | dns_rdataset_t keydataset; |
767 | | dns_rdataset_t dnskeyset; |
768 | | dns_rdataset_t dnskeysigset; |
769 | | dns_zone_t *zone; |
770 | | dns_db_t *db; |
771 | | dns_fetch_t *fetch; |
772 | | }; |
773 | | |
774 | | struct dns_nsfetch { |
775 | | isc_mem_t *mctx; |
776 | | dns_fixedname_t name; |
777 | | dns_name_t pname; |
778 | | dns_rdataset_t nsrrset; |
779 | | dns_rdataset_t nssigset; |
780 | | dns_zone_t *zone; |
781 | | dns_fetch_t *fetch; |
782 | | }; |
783 | | |
784 | | /*% |
785 | | * Hold state for an asynchronous load |
786 | | */ |
787 | | struct dns_asyncload { |
788 | | dns_zone_t *zone; |
789 | | unsigned int flags; |
790 | | dns_zt_callback_t *loaded; |
791 | | void *loaded_arg; |
792 | | }; |
793 | | |
794 | | /*% |
795 | | * Reference to an include file encountered during loading |
796 | | */ |
797 | | struct dns_include { |
798 | | char *name; |
799 | | isc_time_t filetime; |
800 | | ISC_LINK(dns_include_t) link; |
801 | | }; |
802 | | |
803 | | /* |
804 | | * These can be overridden by the -T mkeytimers option on the command |
805 | | * line, so that we can test with shorter periods than specified in |
806 | | * RFC 5011. |
807 | | */ |
808 | | #define HOUR 3600 |
809 | | #define DAY (24 * HOUR) |
810 | | #define MONTH (30 * DAY) |
811 | | unsigned int dns_zone_mkey_hour = HOUR; |
812 | | unsigned int dns_zone_mkey_day = DAY; |
813 | | unsigned int dns_zone_mkey_month = MONTH; |
814 | | |
815 | 0 | #define SEND_BUFFER_SIZE 2048 |
816 | | |
817 | | static void |
818 | | zone_timer_set(dns_zone_t *zone, isc_time_t *next, isc_time_t *now); |
819 | | |
820 | | typedef struct zone_settimer { |
821 | | dns_zone_t *zone; |
822 | | isc_time_t now; |
823 | | } zone_settimer_t; |
824 | | |
825 | | static void |
826 | | zone_settimer(dns_zone_t *, isc_time_t *); |
827 | | static void |
828 | | cancel_refresh(dns_zone_t *); |
829 | | static void |
830 | | zone_debuglog(dns_zone_t *zone, const char *, int debuglevel, const char *msg, |
831 | | ...) ISC_FORMAT_PRINTF(4, 5); |
832 | | static void |
833 | | notify_log(dns_zone_t *zone, int level, const char *fmt, ...) |
834 | | ISC_FORMAT_PRINTF(3, 4); |
835 | | static void |
836 | | dnssec_log(dns_zone_t *zone, int level, const char *fmt, ...) |
837 | | ISC_FORMAT_PRINTF(3, 4); |
838 | | static void |
839 | | queue_xfrin(dns_zone_t *zone); |
840 | | static isc_result_t |
841 | | update_one_rr(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff, |
842 | | dns_diffop_t op, dns_name_t *name, dns_ttl_t ttl, |
843 | | dns_rdata_t *rdata); |
844 | | static void |
845 | | zone_unload(dns_zone_t *zone); |
846 | | static void |
847 | | zone_expire(dns_zone_t *zone); |
848 | | static void |
849 | | zone_refresh(dns_zone_t *zone); |
850 | | static void |
851 | | zone_iattach(dns_zone_t *source, dns_zone_t **target); |
852 | | static void |
853 | | zone_idetach(dns_zone_t **zonep); |
854 | | static isc_result_t |
855 | | zone_replacedb(dns_zone_t *zone, dns_db_t *db, bool dump); |
856 | | static void |
857 | | zone_attachdb(dns_zone_t *zone, dns_db_t *db); |
858 | | static void |
859 | | zone_detachdb(dns_zone_t *zone); |
860 | | static void |
861 | | zone_catz_enable(dns_zone_t *zone, dns_catz_zones_t *catzs); |
862 | | static void |
863 | | zone_catz_disable(dns_zone_t *zone); |
864 | | static isc_result_t |
865 | | default_journal(dns_zone_t *zone); |
866 | | static void |
867 | | zone_xfrdone(dns_zone_t *zone, uint32_t *expireopt, isc_result_t result); |
868 | | static isc_result_t |
869 | | zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, |
870 | | isc_result_t result); |
871 | | static void |
872 | | zone_needdump(dns_zone_t *zone, unsigned int delay); |
873 | | static void |
874 | | zone_shutdown(void *arg); |
875 | | static void |
876 | | zone_loaddone(void *arg, isc_result_t result); |
877 | | static isc_result_t |
878 | | zone_startload(dns_db_t *db, dns_zone_t *zone, isc_time_t loadtime); |
879 | | static void |
880 | | zone_namerd_tostr(dns_zone_t *zone, char *buf, size_t length); |
881 | | static void |
882 | | zone_name_tostr(dns_zone_t *zone, char *buf, size_t length); |
883 | | static void |
884 | | zone_rdclass_tostr(dns_zone_t *zone, char *buf, size_t length); |
885 | | static void |
886 | | zone_viewname_tostr(dns_zone_t *zone, char *buf, size_t length); |
887 | | static isc_result_t |
888 | | zone_send_secureserial(dns_zone_t *zone, uint32_t serial); |
889 | | static void |
890 | | refresh_callback(void *arg); |
891 | | static void |
892 | | stub_callback(void *arg); |
893 | | static void |
894 | | queue_soa_query(dns_zone_t *zone); |
895 | | static void |
896 | | soa_query(void *arg); |
897 | | static void |
898 | | ns_query(dns_zone_t *zone, dns_rdataset_t *soardataset, dns_stub_t *stub); |
899 | | static int |
900 | | message_count(dns_message_t *msg, dns_section_t section, dns_rdatatype_t type); |
901 | | static void |
902 | | checkds_cancel(dns_zone_t *zone); |
903 | | static void |
904 | | checkds_find_address(dns_checkds_t *checkds); |
905 | | static void |
906 | | checkds_send(dns_zone_t *zone); |
907 | | static void |
908 | | checkds_createmessage(dns_zone_t *zone, dns_message_t **messagep); |
909 | | static void |
910 | | checkds_done(void *arg); |
911 | | static void |
912 | | checkds_send_tons(dns_checkds_t *checkds); |
913 | | static void |
914 | | checkds_send_toaddr(void *arg); |
915 | | static void |
916 | | nsfetch_levelup(dns_nsfetch_t *nsfetch); |
917 | | static void |
918 | | notify_cancel(dns_zone_t *zone); |
919 | | static void |
920 | | notify_find_address(dns_notify_t *notify); |
921 | | static void |
922 | | notify_send(dns_notify_t *notify); |
923 | | static isc_result_t |
924 | | notify_createmessage(dns_zone_t *zone, unsigned int flags, |
925 | | dns_message_t **messagep); |
926 | | static void |
927 | | notify_done(void *arg); |
928 | | static void |
929 | | notify_send_toaddr(void *arg); |
930 | | static isc_result_t |
931 | | zone_dump(dns_zone_t *, bool); |
932 | | static void |
933 | | got_transfer_quota(void *arg); |
934 | | static isc_result_t |
935 | | zmgr_start_xfrin_ifquota(dns_zonemgr_t *zmgr, dns_zone_t *zone); |
936 | | static void |
937 | | zmgr_resume_xfrs(dns_zonemgr_t *zmgr, bool multi); |
938 | | static void |
939 | | zonemgr_free(dns_zonemgr_t *zmgr); |
940 | | static void |
941 | | rss_post(void *arg); |
942 | | |
943 | | static isc_result_t |
944 | | zone_get_from_db(dns_zone_t *zone, dns_db_t *db, unsigned int *nscount, |
945 | | unsigned int *soacount, uint32_t *soattl, uint32_t *serial, |
946 | | uint32_t *refresh, uint32_t *retry, uint32_t *expire, |
947 | | uint32_t *minimum, unsigned int *errors); |
948 | | |
949 | | static void |
950 | | zone_freedbargs(dns_zone_t *zone); |
951 | | static void |
952 | | forward_callback(void *arg); |
953 | | static void |
954 | | zone_saveunique(dns_zone_t *zone, const char *path, const char *templat); |
955 | | static void |
956 | | zone_maintenance(dns_zone_t *zone); |
957 | | static void |
958 | | zone_notify(dns_zone_t *zone, isc_time_t *now); |
959 | | static void |
960 | | dump_done(void *arg, isc_result_t result); |
961 | | static isc_result_t |
962 | | zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm, uint16_t keyid, |
963 | | bool deleteit); |
964 | | static isc_result_t |
965 | | delete_nsec(dns_db_t *db, dns_dbversion_t *ver, dns_dbnode_t *node, |
966 | | dns_name_t *name, dns_diff_t *diff); |
967 | | static void |
968 | | zone_rekey(dns_zone_t *zone); |
969 | | static isc_result_t |
970 | | zone_send_securedb(dns_zone_t *zone, dns_db_t *db); |
971 | | static dns_ttl_t |
972 | | zone_nsecttl(dns_zone_t *zone); |
973 | | static void |
974 | | setrl(isc_ratelimiter_t *rl, unsigned int *rate, unsigned int value); |
975 | | static void |
976 | | zone_journal_compact(dns_zone_t *zone, dns_db_t *db, uint32_t serial); |
977 | | static isc_result_t |
978 | | zone_journal_rollforward(dns_zone_t *zone, dns_db_t *db, bool *needdump, |
979 | | bool *fixjournal); |
980 | | static void |
981 | | setnsec3param(void *arg); |
982 | | |
983 | | static void |
984 | | zmgr_tlsctx_attach(dns_zonemgr_t *zmgr, isc_tlsctx_cache_t **ptlsctx_cache); |
985 | | /*%< |
986 | | * Attach to TLS client context cache used for zone transfers via |
987 | | * encrypted transports (e.g. XoT). |
988 | | * |
989 | | * The obtained reference needs to be detached by a call to |
990 | | * 'isc_tlsctx_cache_detach()' when not needed anymore. |
991 | | * |
992 | | * Requires: |
993 | | *\li 'zmgr' is a valid zone manager. |
994 | | *\li 'ptlsctx_cache' is not 'NULL' and points to 'NULL'. |
995 | | */ |
996 | | |
997 | 4 | #define ENTER zone_debuglog(zone, __func__, 1, "enter") |
998 | | |
999 | | static const unsigned int dbargc_default = 1; |
1000 | | static const char *dbargv_default[] = { "rbt" }; |
1001 | | |
1002 | | #define DNS_ZONE_JITTER_ADD(a, b, c) \ |
1003 | 0 | do { \ |
1004 | 0 | isc_interval_t _i; \ |
1005 | 0 | uint32_t _j; \ |
1006 | 0 | _j = (b)-isc_random_uniform((b) / 4); \ |
1007 | 0 | isc_interval_set(&_i, _j, 0); \ |
1008 | 0 | if (isc_time_add((a), &_i, (c)) != ISC_R_SUCCESS) { \ |
1009 | 0 | dns_zone_log(zone, ISC_LOG_WARNING, \ |
1010 | 0 | "epoch approaching: upgrade required: " \ |
1011 | 0 | "now + %s failed", \ |
1012 | 0 | #b); \ |
1013 | 0 | isc_interval_set(&_i, _j / 2, 0); \ |
1014 | 0 | (void)isc_time_add((a), &_i, (c)); \ |
1015 | 0 | } \ |
1016 | 0 | } while (0) |
1017 | | |
1018 | | #define DNS_ZONE_TIME_ADD(a, b, c) \ |
1019 | 0 | do { \ |
1020 | 0 | isc_interval_t _i; \ |
1021 | 0 | isc_interval_set(&_i, (b), 0); \ |
1022 | 0 | if (isc_time_add((a), &_i, (c)) != ISC_R_SUCCESS) { \ |
1023 | 0 | dns_zone_log(zone, ISC_LOG_WARNING, \ |
1024 | 0 | "epoch approaching: upgrade required: " \ |
1025 | 0 | "now + %s failed", \ |
1026 | 0 | #b); \ |
1027 | 0 | isc_interval_set(&_i, (b) / 2, 0); \ |
1028 | 0 | (void)isc_time_add((a), &_i, (c)); \ |
1029 | 0 | } \ |
1030 | 0 | } while (0) |
1031 | | |
1032 | | typedef struct nsec3param nsec3param_t; |
1033 | | struct nsec3param { |
1034 | | dns_rdata_nsec3param_t rdata; |
1035 | | unsigned char data[DNS_NSEC3PARAM_BUFFERSIZE + 1]; |
1036 | | unsigned int length; |
1037 | | bool nsec; |
1038 | | bool replace; |
1039 | | bool resalt; |
1040 | | bool lookup; |
1041 | | ISC_LINK(nsec3param_t) link; |
1042 | | }; |
1043 | | typedef ISC_LIST(nsec3param_t) nsec3paramlist_t; |
1044 | | |
1045 | | struct np3 { |
1046 | | dns_zone_t *zone; |
1047 | | nsec3param_t params; |
1048 | | ISC_LINK(struct np3) link; |
1049 | | }; |
1050 | | |
1051 | | struct setserial { |
1052 | | dns_zone_t *zone; |
1053 | | uint32_t serial; |
1054 | | }; |
1055 | | |
1056 | | struct stub_cb_args { |
1057 | | dns_stub_t *stub; |
1058 | | dns_tsigkey_t *tsig_key; |
1059 | | uint16_t udpsize; |
1060 | | int timeout; |
1061 | | bool reqnsid; |
1062 | | }; |
1063 | | |
1064 | | struct stub_glue_request { |
1065 | | dns_request_t *request; |
1066 | | dns_name_t name; |
1067 | | struct stub_cb_args *args; |
1068 | | bool ipv4; |
1069 | | }; |
1070 | | |
1071 | | /*% |
1072 | | * Increment resolver-related statistics counters. Zone must be locked. |
1073 | | */ |
1074 | | static void |
1075 | 0 | inc_stats(dns_zone_t *zone, isc_statscounter_t counter) { |
1076 | 0 | if (zone->stats != NULL) { |
1077 | 0 | isc_stats_increment(zone->stats, counter); |
1078 | 0 | } |
1079 | 0 | } |
1080 | | |
1081 | | /*** |
1082 | | *** Public functions. |
1083 | | ***/ |
1084 | | |
1085 | | void |
1086 | 2 | dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx, unsigned int tid) { |
1087 | 2 | isc_time_t now; |
1088 | 2 | dns_zone_t *zone = NULL; |
1089 | | |
1090 | 2 | REQUIRE(zonep != NULL && *zonep == NULL); |
1091 | 2 | REQUIRE(mctx != NULL); |
1092 | | |
1093 | 2 | now = isc_time_now(); |
1094 | 2 | zone = isc_mem_get(mctx, sizeof(*zone)); |
1095 | 2 | *zone = (dns_zone_t){ |
1096 | 2 | .masterformat = dns_masterformat_none, |
1097 | 2 | .journalsize = -1, |
1098 | 2 | .rdclass = dns_rdataclass_none, |
1099 | 2 | .type = dns_zone_none, |
1100 | 2 | .refresh = DNS_ZONE_DEFAULTREFRESH, |
1101 | 2 | .retry = DNS_ZONE_DEFAULTRETRY, |
1102 | 2 | .maxrefresh = DNS_ZONE_MAXREFRESH, |
1103 | 2 | .minrefresh = DNS_ZONE_MINREFRESH, |
1104 | 2 | .maxretry = DNS_ZONE_MAXRETRY, |
1105 | 2 | .minretry = DNS_ZONE_MINRETRY, |
1106 | 2 | .checkdstype = dns_checkdstype_yes, |
1107 | 2 | .notifytype = dns_notifytype_yes, |
1108 | 2 | .zero_no_soa_ttl = true, |
1109 | 2 | .check_names = dns_severity_ignore, |
1110 | 2 | .idlein = DNS_DEFAULT_IDLEIN, |
1111 | 2 | .idleout = DNS_DEFAULT_IDLEOUT, |
1112 | 2 | .maxxfrin = MAX_XFER_TIME, |
1113 | 2 | .maxxfrout = MAX_XFER_TIME, |
1114 | 2 | .sigvalidityinterval = 30 * 24 * 3600, |
1115 | 2 | .sigresigninginterval = 7 * 24 * 3600, |
1116 | 2 | .statlevel = dns_zonestat_none, |
1117 | 2 | .notifydelay = 5, |
1118 | 2 | .signatures = 10, |
1119 | 2 | .nodes = 100, |
1120 | 2 | .privatetype = (dns_rdatatype_t)0xffffU, |
1121 | 2 | .rpz_num = DNS_RPZ_INVALID_NUM, |
1122 | 2 | .requestixfr = true, |
1123 | 2 | .ixfr_ratio = 100, |
1124 | 2 | .requestexpire = true, |
1125 | 2 | .updatemethod = dns_updatemethod_increment, |
1126 | 2 | .tid = tid, |
1127 | 2 | .notifytime = now, |
1128 | 2 | .newincludes = ISC_LIST_INITIALIZER, |
1129 | 2 | .notifies = ISC_LIST_INITIALIZER, |
1130 | 2 | .checkds_requests = ISC_LIST_INITIALIZER, |
1131 | 2 | .signing = ISC_LIST_INITIALIZER, |
1132 | 2 | .nsec3chain = ISC_LIST_INITIALIZER, |
1133 | 2 | .setnsec3param_queue = ISC_LIST_INITIALIZER, |
1134 | 2 | .forwards = ISC_LIST_INITIALIZER, |
1135 | 2 | .link = ISC_LINK_INITIALIZER, |
1136 | 2 | .statelink = ISC_LINK_INITIALIZER, |
1137 | 2 | }; |
1138 | 2 | dns_remote_t r = { |
1139 | 2 | .magic = DNS_REMOTE_MAGIC, |
1140 | 2 | }; |
1141 | | |
1142 | 2 | isc_mem_attach(mctx, &zone->mctx); |
1143 | 2 | isc_mutex_init(&zone->lock); |
1144 | 2 | ZONEDB_INITLOCK(&zone->dblock); |
1145 | | |
1146 | 2 | isc_refcount_init(&zone->references, 1); |
1147 | 2 | isc_refcount_init(&zone->irefs, 0); |
1148 | 2 | dns_name_init(&zone->origin, NULL); |
1149 | 2 | isc_sockaddr_any(&zone->notifysrc4); |
1150 | 2 | isc_sockaddr_any6(&zone->notifysrc6); |
1151 | 2 | isc_sockaddr_any(&zone->parentalsrc4); |
1152 | 2 | isc_sockaddr_any6(&zone->parentalsrc6); |
1153 | 2 | isc_sockaddr_any(&zone->xfrsource4); |
1154 | 2 | isc_sockaddr_any6(&zone->xfrsource6); |
1155 | | |
1156 | 2 | zone->primaries = r; |
1157 | 2 | zone->parentals = r; |
1158 | 2 | zone->notify = r; |
1159 | 2 | zone->defaultkasp = NULL; |
1160 | | |
1161 | 2 | isc_stats_create(mctx, &zone->gluecachestats, |
1162 | 2 | dns_gluecachestatscounter_max); |
1163 | | |
1164 | 2 | zone->magic = ZONE_MAGIC; |
1165 | | |
1166 | | /* Must be after magic is set. */ |
1167 | 2 | dns_zone_setdbtype(zone, dbargc_default, dbargv_default); |
1168 | | |
1169 | 2 | *zonep = zone; |
1170 | 2 | } |
1171 | | |
1172 | | static void |
1173 | 0 | clear_keylist(dns_dnsseckeylist_t *list, isc_mem_t *mctx) { |
1174 | 0 | dns_dnsseckey_t *key; |
1175 | 0 | while (!ISC_LIST_EMPTY(*list)) { |
1176 | 0 | key = ISC_LIST_HEAD(*list); |
1177 | 0 | ISC_LIST_UNLINK(*list, key, link); |
1178 | 0 | dns_dnsseckey_destroy(mctx, &key); |
1179 | 0 | } |
1180 | 0 | } |
1181 | | |
1182 | | /* |
1183 | | * Free a zone. Because we require that there be no more |
1184 | | * outstanding events or references, no locking is necessary. |
1185 | | */ |
1186 | | static void |
1187 | 0 | zone_free(dns_zone_t *zone) { |
1188 | 0 | dns_signing_t *signing = NULL; |
1189 | 0 | dns_nsec3chain_t *nsec3chain = NULL; |
1190 | 0 | dns_include_t *include = NULL; |
1191 | |
|
1192 | 0 | REQUIRE(DNS_ZONE_VALID(zone)); |
1193 | 0 | REQUIRE(!LOCKED_ZONE(zone)); |
1194 | 0 | REQUIRE(zone->timer == NULL); |
1195 | 0 | REQUIRE(zone->zmgr == NULL); |
1196 | |
|
1197 | 0 | isc_refcount_destroy(&zone->references); |
1198 | 0 | isc_refcount_destroy(&zone->irefs); |
1199 | | |
1200 | | /* |
1201 | | * Managed objects. Order is important. |
1202 | | */ |
1203 | 0 | if (zone->request != NULL) { |
1204 | 0 | dns_request_destroy(&zone->request); /* XXXMPA */ |
1205 | 0 | } |
1206 | 0 | INSIST(zone->statelist == NULL); |
1207 | 0 | INSIST(zone->view == NULL); |
1208 | 0 | INSIST(zone->prev_view == NULL); |
1209 | | |
1210 | | /* Unmanaged objects */ |
1211 | 0 | for (struct np3 *npe = ISC_LIST_HEAD(zone->setnsec3param_queue); |
1212 | 0 | npe != NULL; npe = ISC_LIST_HEAD(zone->setnsec3param_queue)) |
1213 | 0 | { |
1214 | 0 | ISC_LIST_UNLINK(zone->setnsec3param_queue, npe, link); |
1215 | 0 | isc_mem_put(zone->mctx, npe, sizeof(*npe)); |
1216 | 0 | } |
1217 | |
|
1218 | 0 | for (signing = ISC_LIST_HEAD(zone->signing); signing != NULL; |
1219 | 0 | signing = ISC_LIST_HEAD(zone->signing)) |
1220 | 0 | { |
1221 | 0 | ISC_LIST_UNLINK(zone->signing, signing, link); |
1222 | 0 | dns_db_detach(&signing->db); |
1223 | 0 | dns_dbiterator_destroy(&signing->dbiterator); |
1224 | 0 | isc_mem_put(zone->mctx, signing, sizeof *signing); |
1225 | 0 | } |
1226 | 0 | for (nsec3chain = ISC_LIST_HEAD(zone->nsec3chain); nsec3chain != NULL; |
1227 | 0 | nsec3chain = ISC_LIST_HEAD(zone->nsec3chain)) |
1228 | 0 | { |
1229 | 0 | ISC_LIST_UNLINK(zone->nsec3chain, nsec3chain, link); |
1230 | 0 | dns_db_detach(&nsec3chain->db); |
1231 | 0 | dns_dbiterator_destroy(&nsec3chain->dbiterator); |
1232 | 0 | isc_mem_put(zone->mctx, nsec3chain, sizeof *nsec3chain); |
1233 | 0 | } |
1234 | 0 | for (include = ISC_LIST_HEAD(zone->includes); include != NULL; |
1235 | 0 | include = ISC_LIST_HEAD(zone->includes)) |
1236 | 0 | { |
1237 | 0 | ISC_LIST_UNLINK(zone->includes, include, link); |
1238 | 0 | isc_mem_free(zone->mctx, include->name); |
1239 | 0 | isc_mem_put(zone->mctx, include, sizeof *include); |
1240 | 0 | } |
1241 | 0 | for (include = ISC_LIST_HEAD(zone->newincludes); include != NULL; |
1242 | 0 | include = ISC_LIST_HEAD(zone->newincludes)) |
1243 | 0 | { |
1244 | 0 | ISC_LIST_UNLINK(zone->newincludes, include, link); |
1245 | 0 | isc_mem_free(zone->mctx, include->name); |
1246 | 0 | isc_mem_put(zone->mctx, include, sizeof *include); |
1247 | 0 | } |
1248 | 0 | if (zone->masterfile != NULL) { |
1249 | 0 | isc_mem_free(zone->mctx, zone->masterfile); |
1250 | 0 | } |
1251 | 0 | zone->masterfile = NULL; |
1252 | 0 | if (zone->keydirectory != NULL) { |
1253 | 0 | isc_mem_free(zone->mctx, zone->keydirectory); |
1254 | 0 | } |
1255 | 0 | zone->keydirectory = NULL; |
1256 | 0 | if (zone->kasp != NULL) { |
1257 | 0 | dns_kasp_detach(&zone->kasp); |
1258 | 0 | } |
1259 | 0 | if (zone->defaultkasp != NULL) { |
1260 | 0 | dns_kasp_detach(&zone->defaultkasp); |
1261 | 0 | } |
1262 | 0 | if (!ISC_LIST_EMPTY(zone->checkds_ok)) { |
1263 | 0 | clear_keylist(&zone->checkds_ok, zone->mctx); |
1264 | 0 | } |
1265 | |
|
1266 | 0 | zone->journalsize = -1; |
1267 | 0 | if (zone->journal != NULL) { |
1268 | 0 | isc_mem_free(zone->mctx, zone->journal); |
1269 | 0 | } |
1270 | 0 | zone->journal = NULL; |
1271 | 0 | if (zone->stats != NULL) { |
1272 | 0 | isc_stats_detach(&zone->stats); |
1273 | 0 | } |
1274 | 0 | if (zone->requeststats != NULL) { |
1275 | 0 | isc_stats_detach(&zone->requeststats); |
1276 | 0 | } |
1277 | 0 | if (zone->rcvquerystats != NULL) { |
1278 | 0 | dns_stats_detach(&zone->rcvquerystats); |
1279 | 0 | } |
1280 | 0 | if (zone->dnssecsignstats != NULL) { |
1281 | 0 | dns_stats_detach(&zone->dnssecsignstats); |
1282 | 0 | } |
1283 | 0 | if (zone->db != NULL) { |
1284 | 0 | zone_detachdb(zone); |
1285 | 0 | } |
1286 | 0 | if (zone->rpzs != NULL) { |
1287 | 0 | REQUIRE(zone->rpz_num < zone->rpzs->p.num_zones); |
1288 | 0 | dns_rpz_zones_detach(&zone->rpzs); |
1289 | 0 | zone->rpz_num = DNS_RPZ_INVALID_NUM; |
1290 | 0 | } |
1291 | 0 | if (zone->catzs != NULL) { |
1292 | 0 | dns_catz_zones_detach(&zone->catzs); |
1293 | 0 | } |
1294 | 0 | zone_freedbargs(zone); |
1295 | |
|
1296 | 0 | dns_zone_setparentals(zone, NULL, NULL, NULL, NULL, 0); |
1297 | 0 | dns_zone_setprimaries(zone, NULL, NULL, NULL, NULL, 0); |
1298 | 0 | dns_zone_setalsonotify(zone, NULL, NULL, NULL, NULL, 0); |
1299 | |
|
1300 | 0 | zone->check_names = dns_severity_ignore; |
1301 | 0 | if (zone->update_acl != NULL) { |
1302 | 0 | dns_acl_detach(&zone->update_acl); |
1303 | 0 | } |
1304 | 0 | if (zone->forward_acl != NULL) { |
1305 | 0 | dns_acl_detach(&zone->forward_acl); |
1306 | 0 | } |
1307 | 0 | if (zone->notify_acl != NULL) { |
1308 | 0 | dns_acl_detach(&zone->notify_acl); |
1309 | 0 | } |
1310 | 0 | if (zone->query_acl != NULL) { |
1311 | 0 | dns_acl_detach(&zone->query_acl); |
1312 | 0 | } |
1313 | 0 | if (zone->queryon_acl != NULL) { |
1314 | 0 | dns_acl_detach(&zone->queryon_acl); |
1315 | 0 | } |
1316 | 0 | if (zone->xfr_acl != NULL) { |
1317 | 0 | dns_acl_detach(&zone->xfr_acl); |
1318 | 0 | } |
1319 | 0 | if (dns_name_dynamic(&zone->origin)) { |
1320 | 0 | dns_name_free(&zone->origin, zone->mctx); |
1321 | 0 | } |
1322 | 0 | if (zone->strnamerd != NULL) { |
1323 | 0 | isc_mem_free(zone->mctx, zone->strnamerd); |
1324 | 0 | } |
1325 | 0 | if (zone->strname != NULL) { |
1326 | 0 | isc_mem_free(zone->mctx, zone->strname); |
1327 | 0 | } |
1328 | 0 | if (zone->strrdclass != NULL) { |
1329 | 0 | isc_mem_free(zone->mctx, zone->strrdclass); |
1330 | 0 | } |
1331 | 0 | if (zone->strviewname != NULL) { |
1332 | 0 | isc_mem_free(zone->mctx, zone->strviewname); |
1333 | 0 | } |
1334 | 0 | if (zone->ssutable != NULL) { |
1335 | 0 | dns_ssutable_detach(&zone->ssutable); |
1336 | 0 | } |
1337 | 0 | if (zone->gluecachestats != NULL) { |
1338 | 0 | isc_stats_detach(&zone->gluecachestats); |
1339 | 0 | } |
1340 | | |
1341 | | /* last stuff */ |
1342 | 0 | ZONEDB_DESTROYLOCK(&zone->dblock); |
1343 | 0 | isc_mutex_destroy(&zone->lock); |
1344 | 0 | zone->magic = 0; |
1345 | 0 | isc_mem_putanddetach(&zone->mctx, zone, sizeof(*zone)); |
1346 | 0 | } |
1347 | | |
1348 | | /* |
1349 | | * Returns true iff this the signed side of an inline-signing zone. |
1350 | | * Caller should hold zone lock. |
1351 | | */ |
1352 | | static bool |
1353 | 20 | inline_secure(dns_zone_t *zone) { |
1354 | 20 | REQUIRE(DNS_ZONE_VALID(zone)); |
1355 | 20 | if (zone->raw != NULL) { |
1356 | 0 | return (true); |
1357 | 0 | } |
1358 | 20 | return (false); |
1359 | 20 | } |
1360 | | |
1361 | | /* |
1362 | | * Returns true iff this the unsigned side of an inline-signing zone |
1363 | | * Caller should hold zone lock. |
1364 | | */ |
1365 | | static bool |
1366 | 12 | inline_raw(dns_zone_t *zone) { |
1367 | 12 | REQUIRE(DNS_ZONE_VALID(zone)); |
1368 | 12 | if (zone->secure != NULL) { |
1369 | 0 | return (true); |
1370 | 0 | } |
1371 | 12 | return (false); |
1372 | 12 | } |
1373 | | |
1374 | | /* |
1375 | | * Single shot. |
1376 | | */ |
1377 | | void |
1378 | 2 | dns_zone_setclass(dns_zone_t *zone, dns_rdataclass_t rdclass) { |
1379 | 2 | char namebuf[1024]; |
1380 | | |
1381 | 2 | REQUIRE(DNS_ZONE_VALID(zone)); |
1382 | 2 | REQUIRE(rdclass != dns_rdataclass_none); |
1383 | | |
1384 | | /* |
1385 | | * Test and set. |
1386 | | */ |
1387 | 2 | LOCK_ZONE(zone); |
1388 | 2 | INSIST(zone != zone->raw); |
1389 | 2 | REQUIRE(zone->rdclass == dns_rdataclass_none || |
1390 | 2 | zone->rdclass == rdclass); |
1391 | 2 | zone->rdclass = rdclass; |
1392 | | |
1393 | 2 | if (zone->strnamerd != NULL) { |
1394 | 2 | isc_mem_free(zone->mctx, zone->strnamerd); |
1395 | 2 | } |
1396 | 2 | if (zone->strrdclass != NULL) { |
1397 | 0 | isc_mem_free(zone->mctx, zone->strrdclass); |
1398 | 0 | } |
1399 | | |
1400 | 2 | zone_namerd_tostr(zone, namebuf, sizeof namebuf); |
1401 | 2 | zone->strnamerd = isc_mem_strdup(zone->mctx, namebuf); |
1402 | 2 | zone_rdclass_tostr(zone, namebuf, sizeof namebuf); |
1403 | 2 | zone->strrdclass = isc_mem_strdup(zone->mctx, namebuf); |
1404 | | |
1405 | 2 | if (inline_secure(zone)) { |
1406 | 0 | dns_zone_setclass(zone->raw, rdclass); |
1407 | 0 | } |
1408 | 2 | UNLOCK_ZONE(zone); |
1409 | 2 | } |
1410 | | |
1411 | | dns_rdataclass_t |
1412 | 0 | dns_zone_getclass(dns_zone_t *zone) { |
1413 | 0 | REQUIRE(DNS_ZONE_VALID(zone)); |
1414 | |
|
1415 | 0 | return (zone->rdclass); |
1416 | 0 | } |
1417 | | |
1418 | | void |
1419 | 0 | dns_zone_setnotifytype(dns_zone_t *zone, dns_notifytype_t notifytype) { |
1420 | 0 | REQUIRE(DNS_ZONE_VALID(zone)); |
1421 | |
|
1422 | 0 | LOCK_ZONE(zone); |
1423 | 0 | zone->notifytype = notifytype; |
1424 | 0 | UNLOCK_ZONE(zone); |
1425 | 0 | } |
1426 | | |
1427 | | void |
1428 | 0 | dns_zone_setcheckdstype(dns_zone_t *zone, dns_checkdstype_t checkdstype) { |
1429 | 0 | REQUIRE(DNS_ZONE_VALID(zone)); |
1430 | |
|
1431 | 0 | LOCK_ZONE(zone); |
1432 | 0 | zone->checkdstype = checkdstype; |
1433 | 0 | UNLOCK_ZONE(zone); |
1434 | 0 | } |
1435 | | |
1436 | | isc_result_t |
1437 | 0 | dns_zone_getserial(dns_zone_t *zone, uint32_t *serialp) { |
1438 | 0 | isc_result_t result; |
1439 | 0 | unsigned int soacount; |
1440 | |
|
1441 | 0 | REQUIRE(DNS_ZONE_VALID(zone)); |
1442 | 0 | REQUIRE(serialp != NULL); |
1443 | |
|
1444 | 0 | LOCK_ZONE(zone); |
1445 | 0 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); |
1446 | 0 | if (zone->db != NULL) { |
1447 | 0 | result = zone_get_from_db(zone, zone->db, NULL, &soacount, NULL, |
1448 | 0 | serialp, NULL, NULL, NULL, NULL, |
1449 | 0 | NULL); |
1450 | 0 | if (result == ISC_R_SUCCESS && soacount == 0) { |
1451 | 0 | result = ISC_R_FAILURE; |
1452 | 0 | } |
1453 | 0 | } else { |
1454 | 0 | result = DNS_R_NOTLOADED; |
1455 | 0 | } |
1456 | 0 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
1457 | 0 | UNLOCK_ZONE(zone); |
1458 | |
|
1459 | 0 | return (result); |
1460 | 0 | } |
1461 | | |
1462 | | /* |
1463 | | * Single shot. |
1464 | | */ |
1465 | | void |
1466 | 2 | dns_zone_settype(dns_zone_t *zone, dns_zonetype_t type) { |
1467 | 2 | char namebuf[1024]; |
1468 | | |
1469 | 2 | REQUIRE(DNS_ZONE_VALID(zone)); |
1470 | 2 | REQUIRE(type != dns_zone_none); |
1471 | | |
1472 | | /* |
1473 | | * Test and set. |
1474 | | */ |
1475 | 2 | LOCK_ZONE(zone); |
1476 | 2 | REQUIRE(zone->type == dns_zone_none || zone->type == type); |
1477 | 2 | zone->type = type; |
1478 | | |
1479 | 2 | if (zone->strnamerd != NULL) { |
1480 | 2 | isc_mem_free(zone->mctx, zone->strnamerd); |
1481 | 2 | } |
1482 | | |
1483 | 2 | zone_namerd_tostr(zone, namebuf, sizeof namebuf); |
1484 | 2 | zone->strnamerd = isc_mem_strdup(zone->mctx, namebuf); |
1485 | 2 | UNLOCK_ZONE(zone); |
1486 | 2 | } |
1487 | | |
1488 | | static void |
1489 | 2 | zone_freedbargs(dns_zone_t *zone) { |
1490 | 2 | unsigned int i; |
1491 | | |
1492 | | /* Free the old database argument list. */ |
1493 | 2 | if (zone->db_argv != NULL) { |
1494 | 0 | for (i = 0; i < zone->db_argc; i++) { |
1495 | 0 | isc_mem_free(zone->mctx, zone->db_argv[i]); |
1496 | 0 | } |
1497 | 0 | isc_mem_cput(zone->mctx, zone->db_argv, zone->db_argc, |
1498 | 0 | sizeof(*zone->db_argv)); |
1499 | 0 | } |
1500 | 2 | zone->db_argc = 0; |
1501 | 2 | zone->db_argv = NULL; |
1502 | 2 | } |
1503 | | |
1504 | | isc_result_t |
1505 | 0 | dns_zone_getdbtype(dns_zone_t *zone, char ***argv, isc_mem_t *mctx) { |
1506 | 0 | size_t size = 0; |
1507 | 0 | unsigned int i; |
1508 | 0 | isc_result_t result = ISC_R_SUCCESS; |
1509 | 0 | void *mem; |
1510 | 0 | char **tmp, *tmp2, *base; |
1511 | |
|
1512 | 0 | REQUIRE(DNS_ZONE_VALID(zone)); |
1513 | 0 | REQUIRE(argv != NULL && *argv == NULL); |
1514 | |
|
1515 | 0 | LOCK_ZONE(zone); |
1516 | 0 | size = ISC_CHECKED_MUL((zone->db_argc + 1), sizeof(char *)); |
1517 | 0 | for (i = 0; i < zone->db_argc; i++) { |
1518 | 0 | size += strlen(zone->db_argv[i]) + 1; |
1519 | 0 | } |
1520 | 0 | mem = isc_mem_allocate(mctx, size); |
1521 | 0 | { |
1522 | 0 | tmp = mem; |
1523 | 0 | tmp2 = mem; |
1524 | 0 | base = mem; |
1525 | 0 | tmp2 += ISC_CHECKED_MUL((zone->db_argc + 1), sizeof(char *)); |
1526 | 0 | for (i = 0; i < zone->db_argc; i++) { |
1527 | 0 | *tmp++ = tmp2; |
1528 | 0 | strlcpy(tmp2, zone->db_argv[i], size - (tmp2 - base)); |
1529 | 0 | tmp2 += strlen(tmp2) + 1; |
1530 | 0 | } |
1531 | 0 | *tmp = NULL; |
1532 | 0 | } |
1533 | 0 | UNLOCK_ZONE(zone); |
1534 | 0 | *argv = mem; |
1535 | 0 | return (result); |
1536 | 0 | } |
1537 | | |
1538 | | void |
1539 | | dns_zone_setdbtype(dns_zone_t *zone, unsigned int dbargc, |
1540 | 2 | const char *const *dbargv) { |
1541 | 2 | char **argv = NULL; |
1542 | 2 | unsigned int i; |
1543 | | |
1544 | 2 | REQUIRE(DNS_ZONE_VALID(zone)); |
1545 | 2 | REQUIRE(dbargc >= 1); |
1546 | 2 | REQUIRE(dbargv != NULL); |
1547 | | |
1548 | 2 | LOCK_ZONE(zone); |
1549 | | |
1550 | | /* Set up a new database argument list. */ |
1551 | 2 | argv = isc_mem_cget(zone->mctx, dbargc, sizeof(*argv)); |
1552 | 4 | for (i = 0; i < dbargc; i++) { |
1553 | 2 | argv[i] = NULL; |
1554 | 2 | } |
1555 | 4 | for (i = 0; i < dbargc; i++) { |
1556 | 2 | argv[i] = isc_mem_strdup(zone->mctx, dbargv[i]); |
1557 | 2 | } |
1558 | | |
1559 | | /* Free the old list. */ |
1560 | 2 | zone_freedbargs(zone); |
1561 | | |
1562 | 2 | zone->db_argc = dbargc; |
1563 | 2 | zone->db_argv = argv; |
1564 | | |
1565 | 2 | UNLOCK_ZONE(zone); |
1566 | 2 | } |
1567 | | |
1568 | | static void |
1569 | 2 | dns_zone_setview_helper(dns_zone_t *zone, dns_view_t *view) { |
1570 | 2 | char namebuf[1024]; |
1571 | | |
1572 | 2 | if (zone->prev_view == NULL && zone->view != NULL) { |
1573 | 0 | dns_view_weakattach(zone->view, &zone->prev_view); |
1574 | 0 | } |
1575 | | |
1576 | 2 | INSIST(zone != zone->raw); |
1577 | 2 | if (zone->view != NULL) { |
1578 | 0 | dns_view_sfd_del(zone->view, &zone->origin); |
1579 | 0 | dns_view_weakdetach(&zone->view); |
1580 | 0 | } |
1581 | 2 | dns_view_weakattach(view, &zone->view); |
1582 | 2 | dns_view_sfd_add(view, &zone->origin); |
1583 | | |
1584 | 2 | if (zone->strviewname != NULL) { |
1585 | 0 | isc_mem_free(zone->mctx, zone->strviewname); |
1586 | 0 | } |
1587 | 2 | if (zone->strnamerd != NULL) { |
1588 | 2 | isc_mem_free(zone->mctx, zone->strnamerd); |
1589 | 2 | } |
1590 | | |
1591 | 2 | zone_namerd_tostr(zone, namebuf, sizeof namebuf); |
1592 | 2 | zone->strnamerd = isc_mem_strdup(zone->mctx, namebuf); |
1593 | 2 | zone_viewname_tostr(zone, namebuf, sizeof namebuf); |
1594 | 2 | zone->strviewname = isc_mem_strdup(zone->mctx, namebuf); |
1595 | | |
1596 | 2 | if (inline_secure(zone)) { |
1597 | 0 | dns_zone_setview(zone->raw, view); |
1598 | 0 | } |
1599 | 2 | } |
1600 | | |
1601 | | void |
1602 | 2 | dns_zone_setview(dns_zone_t *zone, dns_view_t *view) { |
1603 | 2 | REQUIRE(DNS_ZONE_VALID(zone)); |
1604 | | |
1605 | 2 | LOCK_ZONE(zone); |
1606 | 2 | dns_zone_setview_helper(zone, view); |
1607 | 2 | UNLOCK_ZONE(zone); |
1608 | 2 | } |
1609 | | |
1610 | | dns_view_t * |
1611 | 0 | dns_zone_getview(dns_zone_t *zone) { |
1612 | 0 | REQUIRE(DNS_ZONE_VALID(zone)); |
1613 | |
|
1614 | 0 | return (zone->view); |
1615 | 0 | } |
1616 | | |
1617 | | void |
1618 | 0 | dns_zone_setviewcommit(dns_zone_t *zone) { |
1619 | 0 | REQUIRE(DNS_ZONE_VALID(zone)); |
1620 | |
|
1621 | 0 | LOCK_ZONE(zone); |
1622 | 0 | if (zone->prev_view != NULL) { |
1623 | 0 | dns_view_weakdetach(&zone->prev_view); |
1624 | 0 | } |
1625 | 0 | if (inline_secure(zone)) { |
1626 | 0 | dns_zone_setviewcommit(zone->raw); |
1627 | 0 | } |
1628 | 0 | UNLOCK_ZONE(zone); |
1629 | 0 | } |
1630 | | |
1631 | | void |
1632 | 0 | dns_zone_setviewrevert(dns_zone_t *zone) { |
1633 | 0 | REQUIRE(DNS_ZONE_VALID(zone)); |
1634 | |
|
1635 | 0 | LOCK_ZONE(zone); |
1636 | 0 | if (zone->prev_view != NULL) { |
1637 | 0 | dns_zone_setview_helper(zone, zone->prev_view); |
1638 | 0 | dns_view_weakdetach(&zone->prev_view); |
1639 | 0 | } |
1640 | 0 | if (zone->catzs != NULL) { |
1641 | 0 | zone_catz_enable(zone, zone->catzs); |
1642 | 0 | } |
1643 | 0 | if (inline_secure(zone)) { |
1644 | 0 | dns_zone_setviewrevert(zone->raw); |
1645 | 0 | } |
1646 | 0 | UNLOCK_ZONE(zone); |
1647 | 0 | } |
1648 | | |
1649 | | isc_result_t |
1650 | 2 | dns_zone_setorigin(dns_zone_t *zone, const dns_name_t *origin) { |
1651 | 2 | isc_result_t result = ISC_R_SUCCESS; |
1652 | 2 | char namebuf[1024]; |
1653 | | |
1654 | 2 | REQUIRE(DNS_ZONE_VALID(zone)); |
1655 | 2 | REQUIRE(origin != NULL); |
1656 | | |
1657 | 2 | LOCK_ZONE(zone); |
1658 | 2 | INSIST(zone != zone->raw); |
1659 | 2 | if (dns_name_dynamic(&zone->origin)) { |
1660 | 0 | dns_name_free(&zone->origin, zone->mctx); |
1661 | 0 | dns_name_init(&zone->origin, NULL); |
1662 | 0 | } |
1663 | 2 | dns_name_dup(origin, zone->mctx, &zone->origin); |
1664 | | |
1665 | 2 | if (zone->strnamerd != NULL) { |
1666 | 0 | isc_mem_free(zone->mctx, zone->strnamerd); |
1667 | 0 | } |
1668 | 2 | if (zone->strname != NULL) { |
1669 | 0 | isc_mem_free(zone->mctx, zone->strname); |
1670 | 0 | } |
1671 | | |
1672 | 2 | zone_namerd_tostr(zone, namebuf, sizeof namebuf); |
1673 | 2 | zone->strnamerd = isc_mem_strdup(zone->mctx, namebuf); |
1674 | 2 | zone_name_tostr(zone, namebuf, sizeof namebuf); |
1675 | 2 | zone->strname = isc_mem_strdup(zone->mctx, namebuf); |
1676 | | |
1677 | 2 | if (inline_secure(zone)) { |
1678 | 0 | result = dns_zone_setorigin(zone->raw, origin); |
1679 | 0 | } |
1680 | 2 | UNLOCK_ZONE(zone); |
1681 | 2 | return (result); |
1682 | 2 | } |
1683 | | |
1684 | | static isc_result_t |
1685 | 6 | dns_zone_setstring(dns_zone_t *zone, char **field, const char *value) { |
1686 | 6 | char *copy; |
1687 | | |
1688 | 6 | if (value != NULL) { |
1689 | 6 | copy = isc_mem_strdup(zone->mctx, value); |
1690 | 6 | } else { |
1691 | 0 | copy = NULL; |
1692 | 0 | } |
1693 | | |
1694 | 6 | if (*field != NULL) { |
1695 | 0 | isc_mem_free(zone->mctx, *field); |
1696 | 0 | } |
1697 | | |
1698 | 6 | *field = copy; |
1699 | 6 | return (ISC_R_SUCCESS); |
1700 | 6 | } |
1701 | | |
1702 | | isc_result_t |
1703 | | dns_zone_setfile(dns_zone_t *zone, const char *file, dns_masterformat_t format, |
1704 | 2 | const dns_master_style_t *style) { |
1705 | 2 | isc_result_t result = ISC_R_SUCCESS; |
1706 | | |
1707 | 2 | REQUIRE(DNS_ZONE_VALID(zone)); |
1708 | 2 | REQUIRE(zone->stream == NULL); |
1709 | | |
1710 | 2 | LOCK_ZONE(zone); |
1711 | 2 | result = dns_zone_setstring(zone, &zone->masterfile, file); |
1712 | 2 | if (result == ISC_R_SUCCESS) { |
1713 | 2 | zone->masterformat = format; |
1714 | 2 | if (format == dns_masterformat_text) { |
1715 | 2 | zone->masterstyle = style; |
1716 | 2 | } |
1717 | 2 | result = default_journal(zone); |
1718 | 2 | } |
1719 | 2 | UNLOCK_ZONE(zone); |
1720 | | |
1721 | 2 | return (result); |
1722 | 2 | } |
1723 | | |
1724 | | const char * |
1725 | 0 | dns_zone_getfile(dns_zone_t *zone) { |
1726 | 0 | REQUIRE(DNS_ZONE_VALID(zone)); |
1727 | |
|
1728 | 0 | return (zone->masterfile); |
1729 | 0 | } |
1730 | | |
1731 | | isc_result_t |
1732 | | dns_zone_setstream(dns_zone_t *zone, const FILE *stream, |
1733 | 0 | dns_masterformat_t format, const dns_master_style_t *style) { |
1734 | 0 | isc_result_t result = ISC_R_SUCCESS; |
1735 | |
|
1736 | 0 | REQUIRE(DNS_ZONE_VALID(zone)); |
1737 | 0 | REQUIRE(stream != NULL); |
1738 | 0 | REQUIRE(zone->masterfile == NULL); |
1739 | |
|
1740 | 0 | LOCK_ZONE(zone); |
1741 | 0 | zone->stream = stream; |
1742 | 0 | zone->masterformat = format; |
1743 | 0 | if (format == dns_masterformat_text) { |
1744 | 0 | zone->masterstyle = style; |
1745 | 0 | } |
1746 | 0 | result = default_journal(zone); |
1747 | 0 | UNLOCK_ZONE(zone); |
1748 | |
|
1749 | 0 | return (result); |
1750 | 0 | } |
1751 | | |
1752 | | dns_ttl_t |
1753 | 0 | dns_zone_getmaxttl(dns_zone_t *zone) { |
1754 | 0 | REQUIRE(DNS_ZONE_VALID(zone)); |
1755 | |
|
1756 | 0 | return (zone->maxttl); |
1757 | 0 | } |
1758 | | |
1759 | | void |
1760 | 0 | dns_zone_setmaxttl(dns_zone_t *zone, dns_ttl_t maxttl) { |
1761 | 0 | REQUIRE(DNS_ZONE_VALID(zone)); |
1762 | |
|
1763 | 0 | LOCK_ZONE(zone); |
1764 | 0 | if (maxttl != 0) { |
1765 | 0 | DNS_ZONE_SETOPTION(zone, DNS_ZONEOPT_CHECKTTL); |
1766 | 0 | } else { |
1767 | 0 | DNS_ZONE_CLROPTION(zone, DNS_ZONEOPT_CHECKTTL); |
1768 | 0 | } |
1769 | 0 | zone->maxttl = maxttl; |
1770 | 0 | UNLOCK_ZONE(zone); |
1771 | |
|
1772 | 0 | return; |
1773 | 0 | } |
1774 | | |
1775 | | static isc_result_t |
1776 | 2 | default_journal(dns_zone_t *zone) { |
1777 | 2 | isc_result_t result; |
1778 | 2 | char *journal; |
1779 | | |
1780 | 2 | REQUIRE(DNS_ZONE_VALID(zone)); |
1781 | 2 | REQUIRE(LOCKED_ZONE(zone)); |
1782 | | |
1783 | 2 | if (zone->masterfile != NULL) { |
1784 | | /* Calculate string length including '\0'. */ |
1785 | 2 | int len = strlen(zone->masterfile) + sizeof(".jnl"); |
1786 | 2 | journal = isc_mem_allocate(zone->mctx, len); |
1787 | 2 | strlcpy(journal, zone->masterfile, len); |
1788 | 2 | strlcat(journal, ".jnl", len); |
1789 | 2 | } else { |
1790 | 0 | journal = NULL; |
1791 | 0 | } |
1792 | 2 | result = dns_zone_setstring(zone, &zone->journal, journal); |
1793 | 2 | if (journal != NULL) { |
1794 | 2 | isc_mem_free(zone->mctx, journal); |
1795 | 2 | } |
1796 | 2 | return (result); |
1797 | 2 | } |
1798 | | |
1799 | | isc_result_t |
1800 | 0 | dns_zone_setjournal(dns_zone_t *zone, const char *myjournal) { |
1801 | 0 | isc_result_t result = ISC_R_SUCCESS; |
1802 | |
|
1803 | 0 | REQUIRE(DNS_ZONE_VALID(zone)); |
1804 | |
|
1805 | 0 | LOCK_ZONE(zone); |
1806 | 0 | result = dns_zone_setstring(zone, &zone->journal, myjournal); |
1807 | 0 | UNLOCK_ZONE(zone); |
1808 | |
|
1809 | 0 | return (result); |
1810 | 0 | } |
1811 | | |
1812 | | char * |
1813 | 0 | dns_zone_getjournal(dns_zone_t *zone) { |
1814 | 0 | REQUIRE(DNS_ZONE_VALID(zone)); |
1815 | |
|
1816 | 0 | return (zone->journal); |
1817 | 0 | } |
1818 | | |
1819 | | /* |
1820 | | * Return true iff the zone is "dynamic", in the sense that the zone's |
1821 | | * master file (if any) is written by the server, rather than being |
1822 | | * updated manually and read by the server. |
1823 | | * |
1824 | | * This is true for secondary zones, mirror zones, stub zones, key zones, |
1825 | | * and zones that allow dynamic updates either by having an update |
1826 | | * policy ("ssutable") or an "allow-update" ACL with a value other than |
1827 | | * exactly "{ none; }". |
1828 | | */ |
1829 | | bool |
1830 | 6 | dns_zone_isdynamic(dns_zone_t *zone, bool ignore_freeze) { |
1831 | 6 | REQUIRE(DNS_ZONE_VALID(zone)); |
1832 | | |
1833 | 6 | if (zone->type == dns_zone_secondary || zone->type == dns_zone_mirror || |
1834 | 6 | zone->type == dns_zone_stub || zone->type == dns_zone_key || |
1835 | 6 | (zone->type == dns_zone_redirect && |
1836 | 6 | dns_remote_addresses(&zone->primaries) != NULL)) |
1837 | 0 | { |
1838 | 0 | return (true); |
1839 | 0 | } |
1840 | | |
1841 | | /* Inline zones are always dynamic. */ |
1842 | 6 | if (zone->type == dns_zone_primary && zone->raw != NULL) { |
1843 | 0 | return (true); |
1844 | 0 | } |
1845 | | |
1846 | | /* If !ignore_freeze, we need check whether updates are disabled. */ |
1847 | 6 | if (zone->type == dns_zone_primary && |
1848 | 6 | (!zone->update_disabled || ignore_freeze) && |
1849 | 6 | ((zone->ssutable != NULL) || |
1850 | 6 | (zone->update_acl != NULL && !dns_acl_isnone(zone->update_acl)))) |
1851 | 0 | { |
1852 | 0 | return (true); |
1853 | 0 | } |
1854 | | |
1855 | 6 | return (false); |
1856 | 6 | } |
1857 | | |
1858 | | /* |
1859 | | * Set the response policy index and information for a zone. |
1860 | | */ |
1861 | | isc_result_t |
1862 | | dns_zone_rpz_enable(dns_zone_t *zone, dns_rpz_zones_t *rpzs, |
1863 | 0 | dns_rpz_num_t rpz_num) { |
1864 | | /* |
1865 | | * Only RBTDB zones can be used for response policy zones, |
1866 | | * because only they have the code to create the summary data. |
1867 | | * Only zones that are loaded instead of mmap()ed create the |
1868 | | * summary data and so can be policy zones. |
1869 | | */ |
1870 | 0 | if (strcmp(zone->db_argv[0], "rbt") != 0) { |
1871 | 0 | return (ISC_R_NOTIMPLEMENTED); |
1872 | 0 | } |
1873 | | |
1874 | | /* |
1875 | | * This must happen only once or be redundant. |
1876 | | */ |
1877 | 0 | LOCK_ZONE(zone); |
1878 | 0 | if (zone->rpzs != NULL) { |
1879 | 0 | REQUIRE(zone->rpzs == rpzs && zone->rpz_num == rpz_num); |
1880 | 0 | } else { |
1881 | 0 | REQUIRE(zone->rpz_num == DNS_RPZ_INVALID_NUM); |
1882 | 0 | dns_rpz_zones_attach(rpzs, &zone->rpzs); |
1883 | 0 | zone->rpz_num = rpz_num; |
1884 | 0 | } |
1885 | 0 | rpzs->defined |= DNS_RPZ_ZBIT(rpz_num); |
1886 | 0 | UNLOCK_ZONE(zone); |
1887 | |
|
1888 | 0 | return (ISC_R_SUCCESS); |
1889 | 0 | } |
1890 | | |
1891 | | dns_rpz_num_t |
1892 | 0 | dns_zone_get_rpz_num(dns_zone_t *zone) { |
1893 | 0 | return (zone->rpz_num); |
1894 | 0 | } |
1895 | | |
1896 | | /* |
1897 | | * If a zone is a response policy zone, mark its new database. |
1898 | | */ |
1899 | | void |
1900 | 2 | dns_zone_rpz_enable_db(dns_zone_t *zone, dns_db_t *db) { |
1901 | 2 | if (zone->rpz_num == DNS_RPZ_INVALID_NUM) { |
1902 | 2 | return; |
1903 | 2 | } |
1904 | 0 | REQUIRE(zone->rpzs != NULL); |
1905 | 0 | dns_rpz_dbupdate_register(db, zone->rpzs->zones[zone->rpz_num]); |
1906 | 0 | } |
1907 | | |
1908 | | static void |
1909 | 0 | dns_zone_rpz_disable_db(dns_zone_t *zone, dns_db_t *db) { |
1910 | 0 | if (zone->rpz_num == DNS_RPZ_INVALID_NUM) { |
1911 | 0 | return; |
1912 | 0 | } |
1913 | 0 | REQUIRE(zone->rpzs != NULL); |
1914 | 0 | dns_rpz_dbupdate_unregister(db, zone->rpzs->zones[zone->rpz_num]); |
1915 | 0 | } |
1916 | | |
1917 | | /* |
1918 | | * If a zone is a catalog zone, attach it to update notification in database. |
1919 | | */ |
1920 | | void |
1921 | 2 | dns_zone_catz_enable_db(dns_zone_t *zone, dns_db_t *db) { |
1922 | 2 | REQUIRE(DNS_ZONE_VALID(zone)); |
1923 | 2 | REQUIRE(db != NULL); |
1924 | | |
1925 | 2 | if (zone->catzs != NULL) { |
1926 | 0 | dns_catz_dbupdate_register(db, zone->catzs); |
1927 | 0 | } |
1928 | 2 | } |
1929 | | |
1930 | | static void |
1931 | 0 | dns_zone_catz_disable_db(dns_zone_t *zone, dns_db_t *db) { |
1932 | 0 | REQUIRE(DNS_ZONE_VALID(zone)); |
1933 | 0 | REQUIRE(db != NULL); |
1934 | |
|
1935 | 0 | if (zone->catzs != NULL) { |
1936 | 0 | dns_catz_dbupdate_unregister(db, zone->catzs); |
1937 | 0 | } |
1938 | 0 | } |
1939 | | |
1940 | | static void |
1941 | 0 | zone_catz_enable(dns_zone_t *zone, dns_catz_zones_t *catzs) { |
1942 | 0 | REQUIRE(DNS_ZONE_VALID(zone)); |
1943 | 0 | REQUIRE(catzs != NULL); |
1944 | |
|
1945 | 0 | INSIST(zone->catzs == NULL || zone->catzs == catzs); |
1946 | 0 | dns_catz_catzs_set_view(catzs, zone->view); |
1947 | 0 | if (zone->catzs == NULL) { |
1948 | 0 | dns_catz_zones_attach(catzs, &zone->catzs); |
1949 | 0 | } |
1950 | 0 | } |
1951 | | |
1952 | | void |
1953 | 0 | dns_zone_catz_enable(dns_zone_t *zone, dns_catz_zones_t *catzs) { |
1954 | 0 | REQUIRE(DNS_ZONE_VALID(zone)); |
1955 | |
|
1956 | 0 | LOCK_ZONE(zone); |
1957 | 0 | zone_catz_enable(zone, catzs); |
1958 | 0 | UNLOCK_ZONE(zone); |
1959 | 0 | } |
1960 | | |
1961 | | static void |
1962 | 0 | zone_catz_disable(dns_zone_t *zone) { |
1963 | 0 | REQUIRE(DNS_ZONE_VALID(zone)); |
1964 | |
|
1965 | 0 | if (zone->catzs != NULL) { |
1966 | 0 | if (zone->db != NULL) { |
1967 | 0 | dns_zone_catz_disable_db(zone, zone->db); |
1968 | 0 | } |
1969 | 0 | dns_catz_zones_detach(&zone->catzs); |
1970 | 0 | } |
1971 | 0 | } |
1972 | | |
1973 | | void |
1974 | 0 | dns_zone_catz_disable(dns_zone_t *zone) { |
1975 | 0 | REQUIRE(DNS_ZONE_VALID(zone)); |
1976 | |
|
1977 | 0 | LOCK_ZONE(zone); |
1978 | 0 | zone_catz_disable(zone); |
1979 | 0 | UNLOCK_ZONE(zone); |
1980 | 0 | } |
1981 | | |
1982 | | bool |
1983 | 0 | dns_zone_catz_is_enabled(dns_zone_t *zone) { |
1984 | 0 | REQUIRE(DNS_ZONE_VALID(zone)); |
1985 | |
|
1986 | 0 | return (zone->catzs != NULL); |
1987 | 0 | } |
1988 | | |
1989 | | /* |
1990 | | * Set catalog zone ownership of the zone |
1991 | | */ |
1992 | | void |
1993 | 0 | dns_zone_set_parentcatz(dns_zone_t *zone, dns_catz_zone_t *catz) { |
1994 | 0 | REQUIRE(DNS_ZONE_VALID(zone)); |
1995 | 0 | REQUIRE(catz != NULL); |
1996 | 0 | LOCK_ZONE(zone); |
1997 | 0 | INSIST(zone->parentcatz == NULL || zone->parentcatz == catz); |
1998 | 0 | zone->parentcatz = catz; |
1999 | 0 | UNLOCK_ZONE(zone); |
2000 | 0 | } |
2001 | | |
2002 | | dns_catz_zone_t * |
2003 | 0 | dns_zone_get_parentcatz(dns_zone_t *zone) { |
2004 | 0 | REQUIRE(DNS_ZONE_VALID(zone)); |
2005 | |
|
2006 | 0 | dns_catz_zone_t *parentcatz = NULL; |
2007 | |
|
2008 | 0 | LOCK_ZONE(zone); |
2009 | 0 | parentcatz = zone->parentcatz; |
2010 | 0 | UNLOCK_ZONE(zone); |
2011 | |
|
2012 | 0 | return (parentcatz); |
2013 | 0 | } |
2014 | | |
2015 | | static bool |
2016 | 0 | zone_touched(dns_zone_t *zone) { |
2017 | 0 | isc_result_t result; |
2018 | 0 | isc_time_t modtime; |
2019 | 0 | dns_include_t *include; |
2020 | |
|
2021 | 0 | REQUIRE(DNS_ZONE_VALID(zone)); |
2022 | |
|
2023 | 0 | result = isc_file_getmodtime(zone->masterfile, &modtime); |
2024 | 0 | if (result != ISC_R_SUCCESS || |
2025 | 0 | isc_time_compare(&modtime, &zone->loadtime) > 0) |
2026 | 0 | { |
2027 | 0 | return (true); |
2028 | 0 | } |
2029 | | |
2030 | 0 | for (include = ISC_LIST_HEAD(zone->includes); include != NULL; |
2031 | 0 | include = ISC_LIST_NEXT(include, link)) |
2032 | 0 | { |
2033 | 0 | result = isc_file_getmodtime(include->name, &modtime); |
2034 | 0 | if (result != ISC_R_SUCCESS || |
2035 | 0 | isc_time_compare(&modtime, &include->filetime) > 0) |
2036 | 0 | { |
2037 | 0 | return (true); |
2038 | 0 | } |
2039 | 0 | } |
2040 | | |
2041 | 0 | return (false); |
2042 | 0 | } |
2043 | | |
2044 | | /* |
2045 | | * Note: when dealing with inline-signed zones, external callers will always |
2046 | | * call zone_load() for the secure zone; zone_load() calls itself recursively |
2047 | | * in order to load the raw zone. |
2048 | | */ |
2049 | | static isc_result_t |
2050 | 2 | zone_load(dns_zone_t *zone, unsigned int flags, bool locked) { |
2051 | 2 | isc_result_t result; |
2052 | 2 | isc_time_t now; |
2053 | 2 | isc_time_t loadtime; |
2054 | 2 | dns_db_t *db = NULL; |
2055 | 2 | bool rbt, hasraw, is_dynamic; |
2056 | | |
2057 | 2 | REQUIRE(DNS_ZONE_VALID(zone)); |
2058 | | |
2059 | 2 | if (!locked) { |
2060 | 2 | LOCK_ZONE(zone); |
2061 | 2 | } |
2062 | | |
2063 | 2 | INSIST(zone != zone->raw); |
2064 | 2 | hasraw = inline_secure(zone); |
2065 | 2 | if (hasraw) { |
2066 | | /* |
2067 | | * We are trying to load an inline-signed zone. First call |
2068 | | * self recursively to try loading the raw version of the zone. |
2069 | | * Assuming the raw zone file is readable, there are two |
2070 | | * possibilities: |
2071 | | * |
2072 | | * a) the raw zone was not yet loaded and thus it will be |
2073 | | * loaded now, synchronously; if this succeeds, a |
2074 | | * subsequent attempt to load the signed zone file will |
2075 | | * take place and thus zone_postload() will be called |
2076 | | * twice: first for the raw zone and then for the secure |
2077 | | * zone; the latter call will take care of syncing the raw |
2078 | | * version with the secure version, |
2079 | | * |
2080 | | * b) the raw zone was already loaded and we are trying to |
2081 | | * reload it, which will happen asynchronously; this means |
2082 | | * zone_postload() will only be called for the raw zone |
2083 | | * because "result" returned by the zone_load() call below |
2084 | | * will not be ISC_R_SUCCESS but rather DNS_R_CONTINUE; |
2085 | | * zone_postload() called for the raw zone will take care |
2086 | | * of syncing the raw version with the secure version. |
2087 | | */ |
2088 | 0 | result = zone_load(zone->raw, flags, false); |
2089 | 0 | if (result != ISC_R_SUCCESS) { |
2090 | 0 | if (!locked) { |
2091 | 0 | UNLOCK_ZONE(zone); |
2092 | 0 | } |
2093 | 0 | return (result); |
2094 | 0 | } |
2095 | 0 | LOCK_ZONE(zone->raw); |
2096 | 0 | } |
2097 | | |
2098 | 2 | now = isc_time_now(); |
2099 | | |
2100 | 2 | INSIST(zone->type != dns_zone_none); |
2101 | | |
2102 | 2 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADING)) { |
2103 | 0 | if ((flags & DNS_ZONELOADFLAG_THAW) != 0) { |
2104 | 0 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_THAW); |
2105 | 0 | } |
2106 | 0 | result = DNS_R_CONTINUE; |
2107 | 0 | goto cleanup; |
2108 | 0 | } |
2109 | | |
2110 | 2 | INSIST(zone->db_argc >= 1); |
2111 | | |
2112 | 2 | rbt = strcmp(zone->db_argv[0], "rbt") == 0; |
2113 | | |
2114 | 2 | if (zone->db != NULL && zone->masterfile == NULL && rbt) { |
2115 | | /* |
2116 | | * The zone has no master file configured. |
2117 | | */ |
2118 | 0 | result = ISC_R_SUCCESS; |
2119 | 0 | goto cleanup; |
2120 | 0 | } |
2121 | | |
2122 | 2 | is_dynamic = dns_zone_isdynamic(zone, false); |
2123 | 2 | if (zone->db != NULL && is_dynamic) { |
2124 | | /* |
2125 | | * This is a secondary, stub, or dynamically updated zone |
2126 | | * being reloaded. Do nothing - the database we already |
2127 | | * have is guaranteed to be up-to-date. |
2128 | | */ |
2129 | 0 | if (zone->type == dns_zone_primary && !hasraw) { |
2130 | 0 | result = DNS_R_DYNAMIC; |
2131 | 0 | } else { |
2132 | 0 | result = ISC_R_SUCCESS; |
2133 | 0 | } |
2134 | 0 | goto cleanup; |
2135 | 0 | } |
2136 | | |
2137 | | /* |
2138 | | * Store the current time before the zone is loaded, so that if the |
2139 | | * file changes between the time of the load and the time that |
2140 | | * zone->loadtime is set, then the file will still be reloaded |
2141 | | * the next time dns_zone_load is called. |
2142 | | */ |
2143 | 2 | loadtime = isc_time_now(); |
2144 | | |
2145 | | /* |
2146 | | * Don't do the load if the file that stores the zone is older |
2147 | | * than the last time the zone was loaded. If the zone has not |
2148 | | * been loaded yet, zone->loadtime will be the epoch. |
2149 | | */ |
2150 | 2 | if (zone->masterfile != NULL) { |
2151 | 2 | isc_time_t filetime; |
2152 | | |
2153 | | /* |
2154 | | * The file is already loaded. If we are just doing a |
2155 | | * "rndc reconfig", we are done. |
2156 | | */ |
2157 | 2 | if (!isc_time_isepoch(&zone->loadtime) && |
2158 | 2 | (flags & DNS_ZONELOADFLAG_NOSTAT) != 0) |
2159 | 0 | { |
2160 | 0 | result = ISC_R_SUCCESS; |
2161 | 0 | goto cleanup; |
2162 | 0 | } |
2163 | | |
2164 | 2 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED) && |
2165 | 2 | !zone_touched(zone)) |
2166 | 0 | { |
2167 | 0 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, |
2168 | 0 | ISC_LOG_DEBUG(1), |
2169 | 0 | "skipping load: master file " |
2170 | 0 | "older than last load"); |
2171 | 0 | result = DNS_R_UPTODATE; |
2172 | 0 | goto cleanup; |
2173 | 0 | } |
2174 | | |
2175 | | /* |
2176 | | * If the file modification time is in the past |
2177 | | * set loadtime to that value. |
2178 | | */ |
2179 | 2 | result = isc_file_getmodtime(zone->masterfile, &filetime); |
2180 | 2 | if (result == ISC_R_SUCCESS && |
2181 | 2 | isc_time_compare(&loadtime, &filetime) > 0) |
2182 | 1 | { |
2183 | 1 | loadtime = filetime; |
2184 | 1 | } |
2185 | 2 | } |
2186 | | |
2187 | | /* |
2188 | | * Built in zones (with the exception of empty zones) don't need |
2189 | | * to be reloaded. |
2190 | | */ |
2191 | 2 | if (zone->type == dns_zone_primary && |
2192 | 2 | strcmp(zone->db_argv[0], "_builtin") == 0 && |
2193 | 2 | (zone->db_argc < 2 || strcmp(zone->db_argv[1], "empty") != 0) && |
2194 | 2 | DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED)) |
2195 | 0 | { |
2196 | 0 | result = ISC_R_SUCCESS; |
2197 | 0 | goto cleanup; |
2198 | 0 | } |
2199 | | |
2200 | | /* |
2201 | | * Zones associated with a DLZ don't need to be loaded either, |
2202 | | * but we need to associate the database with the zone object. |
2203 | | */ |
2204 | 2 | if (strcmp(zone->db_argv[0], "dlz") == 0) { |
2205 | 0 | dns_dlzdb_t *dlzdb; |
2206 | 0 | dns_dlzfindzone_t findzone; |
2207 | |
|
2208 | 0 | for (dlzdb = ISC_LIST_HEAD(zone->view->dlz_unsearched); |
2209 | 0 | dlzdb != NULL; dlzdb = ISC_LIST_NEXT(dlzdb, link)) |
2210 | 0 | { |
2211 | 0 | INSIST(DNS_DLZ_VALID(dlzdb)); |
2212 | 0 | if (strcmp(zone->db_argv[1], dlzdb->dlzname) == 0) { |
2213 | 0 | break; |
2214 | 0 | } |
2215 | 0 | } |
2216 | |
|
2217 | 0 | if (dlzdb == NULL) { |
2218 | 0 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, |
2219 | 0 | ISC_LOG_ERROR, |
2220 | 0 | "DLZ %s does not exist or is set " |
2221 | 0 | "to 'search yes;'", |
2222 | 0 | zone->db_argv[1]); |
2223 | 0 | result = ISC_R_NOTFOUND; |
2224 | 0 | goto cleanup; |
2225 | 0 | } |
2226 | | |
2227 | 0 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_write); |
2228 | | /* ask SDLZ driver if the zone is supported */ |
2229 | 0 | findzone = dlzdb->implementation->methods->findzone; |
2230 | 0 | result = (*findzone)(dlzdb->implementation->driverarg, |
2231 | 0 | dlzdb->dbdata, dlzdb->mctx, |
2232 | 0 | zone->view->rdclass, &zone->origin, NULL, |
2233 | 0 | NULL, &db); |
2234 | 0 | if (result != ISC_R_NOTFOUND) { |
2235 | 0 | if (zone->db != NULL) { |
2236 | 0 | zone_detachdb(zone); |
2237 | 0 | } |
2238 | 0 | zone_attachdb(zone, db); |
2239 | 0 | dns_db_detach(&db); |
2240 | 0 | result = ISC_R_SUCCESS; |
2241 | 0 | } |
2242 | 0 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write); |
2243 | |
|
2244 | 0 | if (result == ISC_R_SUCCESS) { |
2245 | 0 | if (dlzdb->configure_callback == NULL) { |
2246 | 0 | goto cleanup; |
2247 | 0 | } |
2248 | | |
2249 | 0 | result = (*dlzdb->configure_callback)(zone->view, dlzdb, |
2250 | 0 | zone); |
2251 | 0 | if (result != ISC_R_SUCCESS) { |
2252 | 0 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, |
2253 | 0 | ISC_LOG_ERROR, |
2254 | 0 | "DLZ configuration callback: %s", |
2255 | 0 | isc_result_totext(result)); |
2256 | 0 | } |
2257 | 0 | } |
2258 | 0 | goto cleanup; |
2259 | 0 | } |
2260 | | |
2261 | 2 | if ((zone->type == dns_zone_secondary || |
2262 | 2 | zone->type == dns_zone_mirror || zone->type == dns_zone_stub || |
2263 | 2 | (zone->type == dns_zone_redirect && |
2264 | 2 | dns_remote_addresses(&zone->primaries) != NULL)) && |
2265 | 2 | rbt) |
2266 | 0 | { |
2267 | 0 | if (zone->stream == NULL && |
2268 | 0 | (zone->masterfile == NULL || |
2269 | 0 | !isc_file_exists(zone->masterfile))) |
2270 | 0 | { |
2271 | 0 | if (zone->masterfile != NULL) { |
2272 | 0 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, |
2273 | 0 | ISC_LOG_DEBUG(1), |
2274 | 0 | "no master file"); |
2275 | 0 | } |
2276 | 0 | zone->refreshtime = now; |
2277 | 0 | if (zone->loop != NULL) { |
2278 | 0 | zone_settimer(zone, &now); |
2279 | 0 | } |
2280 | 0 | result = ISC_R_SUCCESS; |
2281 | 0 | goto cleanup; |
2282 | 0 | } |
2283 | 0 | } |
2284 | | |
2285 | 2 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, ISC_LOG_DEBUG(1), |
2286 | 2 | "starting load"); |
2287 | | |
2288 | 2 | result = dns_db_create(zone->mctx, zone->db_argv[0], &zone->origin, |
2289 | 2 | (zone->type == dns_zone_stub) ? dns_dbtype_stub |
2290 | 2 | : dns_dbtype_zone, |
2291 | 2 | zone->rdclass, zone->db_argc - 1, |
2292 | 2 | zone->db_argv + 1, &db); |
2293 | | |
2294 | 2 | if (result != ISC_R_SUCCESS) { |
2295 | 0 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, ISC_LOG_ERROR, |
2296 | 0 | "loading zone: creating database: %s", |
2297 | 0 | isc_result_totext(result)); |
2298 | 0 | goto cleanup; |
2299 | 0 | } |
2300 | 2 | dns_db_setloop(db, zone->loop); |
2301 | | |
2302 | 2 | if (zone->type == dns_zone_primary || |
2303 | 2 | zone->type == dns_zone_secondary || zone->type == dns_zone_mirror) |
2304 | 2 | { |
2305 | 2 | result = dns_db_setgluecachestats(db, zone->gluecachestats); |
2306 | 2 | if (result == ISC_R_NOTIMPLEMENTED) { |
2307 | 0 | result = ISC_R_SUCCESS; |
2308 | 0 | } |
2309 | 2 | if (result != ISC_R_SUCCESS) { |
2310 | 0 | goto cleanup; |
2311 | 0 | } |
2312 | 2 | } |
2313 | | |
2314 | 2 | if (!dns_db_ispersistent(db)) { |
2315 | 2 | if (zone->masterfile != NULL || zone->stream != NULL) { |
2316 | 2 | result = zone_startload(db, zone, loadtime); |
2317 | 2 | } else { |
2318 | 0 | result = DNS_R_NOMASTERFILE; |
2319 | 0 | if (zone->type == dns_zone_primary || |
2320 | 0 | (zone->type == dns_zone_redirect && |
2321 | 0 | dns_remote_addresses(&zone->primaries) == NULL)) |
2322 | 0 | { |
2323 | 0 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, |
2324 | 0 | ISC_LOG_ERROR, |
2325 | 0 | "loading zone: " |
2326 | 0 | "no master file configured"); |
2327 | 0 | goto cleanup; |
2328 | 0 | } |
2329 | 0 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, |
2330 | 0 | ISC_LOG_INFO, |
2331 | 0 | "loading zone: " |
2332 | 0 | "no master file configured: continuing"); |
2333 | 0 | } |
2334 | 2 | } |
2335 | | |
2336 | 2 | if (result == DNS_R_CONTINUE) { |
2337 | 0 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADING); |
2338 | 0 | if ((flags & DNS_ZONELOADFLAG_THAW) != 0) { |
2339 | 0 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_THAW); |
2340 | 0 | } |
2341 | 0 | goto cleanup; |
2342 | 0 | } |
2343 | | |
2344 | 2 | result = zone_postload(zone, db, loadtime, result); |
2345 | | |
2346 | 2 | cleanup: |
2347 | 2 | if (hasraw) { |
2348 | 0 | UNLOCK_ZONE(zone->raw); |
2349 | 0 | } |
2350 | 2 | if (!locked) { |
2351 | 2 | UNLOCK_ZONE(zone); |
2352 | 2 | } |
2353 | 2 | if (db != NULL) { |
2354 | 2 | dns_db_detach(&db); |
2355 | 2 | } |
2356 | 2 | return (result); |
2357 | 2 | } |
2358 | | |
2359 | | isc_result_t |
2360 | 2 | dns_zone_load(dns_zone_t *zone, bool newonly) { |
2361 | 2 | return (zone_load(zone, newonly ? DNS_ZONELOADFLAG_NOSTAT : 0, false)); |
2362 | 2 | } |
2363 | | |
2364 | | static void |
2365 | 0 | zone_asyncload(void *arg) { |
2366 | 0 | dns_asyncload_t *asl = arg; |
2367 | 0 | dns_zone_t *zone = asl->zone; |
2368 | 0 | isc_result_t result; |
2369 | |
|
2370 | 0 | REQUIRE(DNS_ZONE_VALID(zone)); |
2371 | |
|
2372 | 0 | LOCK_ZONE(zone); |
2373 | 0 | result = zone_load(zone, asl->flags, true); |
2374 | 0 | if (result != DNS_R_CONTINUE) { |
2375 | 0 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_LOADPENDING); |
2376 | 0 | } |
2377 | 0 | UNLOCK_ZONE(zone); |
2378 | | |
2379 | | /* Inform the zone table we've finished loading */ |
2380 | 0 | if (asl->loaded != NULL) { |
2381 | 0 | asl->loaded(asl->loaded_arg); |
2382 | 0 | } |
2383 | |
|
2384 | 0 | isc_mem_put(zone->mctx, asl, sizeof(*asl)); |
2385 | 0 | dns_zone_idetach(&zone); |
2386 | 0 | } |
2387 | | |
2388 | | isc_result_t |
2389 | | dns_zone_asyncload(dns_zone_t *zone, bool newonly, dns_zt_callback_t *done, |
2390 | 0 | void *arg) { |
2391 | 0 | dns_asyncload_t *asl = NULL; |
2392 | |
|
2393 | 0 | REQUIRE(DNS_ZONE_VALID(zone)); |
2394 | |
|
2395 | 0 | if (zone->zmgr == NULL) { |
2396 | 0 | return (ISC_R_FAILURE); |
2397 | 0 | } |
2398 | | |
2399 | | /* If we already have a load pending, stop now */ |
2400 | 0 | LOCK_ZONE(zone); |
2401 | 0 | if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADPENDING)) { |
2402 | 0 | UNLOCK_ZONE(zone); |
2403 | 0 | return (ISC_R_ALREADYRUNNING); |
2404 | 0 | } |
2405 | | |
2406 | 0 | asl = isc_mem_get(zone->mctx, sizeof(*asl)); |
2407 | |
|
2408 | 0 | asl->zone = NULL; |
2409 | 0 | asl->flags = newonly ? DNS_ZONELOADFLAG_NOSTAT : 0; |
2410 | 0 | asl->loaded = done; |
2411 | 0 | asl->loaded_arg = arg; |
2412 | |
|
2413 | 0 | zone_iattach(zone, &asl->zone); |
2414 | 0 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADPENDING); |
2415 | 0 | isc_async_run(zone->loop, zone_asyncload, asl); |
2416 | 0 | UNLOCK_ZONE(zone); |
2417 | |
|
2418 | 0 | return (ISC_R_SUCCESS); |
2419 | 0 | } |
2420 | | |
2421 | | bool |
2422 | 0 | dns__zone_loadpending(dns_zone_t *zone) { |
2423 | 0 | REQUIRE(DNS_ZONE_VALID(zone)); |
2424 | |
|
2425 | 0 | return (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADPENDING)); |
2426 | 0 | } |
2427 | | |
2428 | | isc_result_t |
2429 | 0 | dns_zone_loadandthaw(dns_zone_t *zone) { |
2430 | 0 | isc_result_t result; |
2431 | |
|
2432 | 0 | if (inline_raw(zone)) { |
2433 | 0 | result = zone_load(zone->secure, DNS_ZONELOADFLAG_THAW, false); |
2434 | 0 | } else { |
2435 | | /* |
2436 | | * When thawing a zone, we don't know what changes |
2437 | | * have been made. If we do DNSSEC maintenance on this |
2438 | | * zone, schedule a full sign for this zone. |
2439 | | */ |
2440 | 0 | if (zone->type == dns_zone_primary && |
2441 | 0 | DNS_ZONEKEY_OPTION(zone, DNS_ZONEKEY_MAINTAIN)) |
2442 | 0 | { |
2443 | 0 | DNS_ZONEKEY_SETOPTION(zone, DNS_ZONEKEY_FULLSIGN); |
2444 | 0 | } |
2445 | 0 | result = zone_load(zone, DNS_ZONELOADFLAG_THAW, false); |
2446 | 0 | } |
2447 | |
|
2448 | 0 | switch (result) { |
2449 | 0 | case DNS_R_CONTINUE: |
2450 | | /* Deferred thaw. */ |
2451 | 0 | break; |
2452 | 0 | case DNS_R_UPTODATE: |
2453 | 0 | case ISC_R_SUCCESS: |
2454 | 0 | case DNS_R_SEENINCLUDE: |
2455 | 0 | zone->update_disabled = false; |
2456 | 0 | break; |
2457 | 0 | case DNS_R_NOMASTERFILE: |
2458 | 0 | zone->update_disabled = false; |
2459 | 0 | break; |
2460 | 0 | default: |
2461 | | /* Error, remain in disabled state. */ |
2462 | 0 | break; |
2463 | 0 | } |
2464 | 0 | return (result); |
2465 | 0 | } |
2466 | | |
2467 | | static unsigned int |
2468 | 2 | get_primary_options(dns_zone_t *zone) { |
2469 | 2 | unsigned int options; |
2470 | | |
2471 | 2 | options = DNS_MASTER_ZONE | DNS_MASTER_RESIGN; |
2472 | 2 | if (zone->type == dns_zone_secondary || zone->type == dns_zone_mirror || |
2473 | 2 | (zone->type == dns_zone_redirect && |
2474 | 2 | dns_remote_addresses(&zone->primaries) == NULL)) |
2475 | 0 | { |
2476 | 0 | options |= DNS_MASTER_SECONDARY; |
2477 | 0 | } |
2478 | 2 | if (zone->type == dns_zone_key) { |
2479 | 0 | options |= DNS_MASTER_KEY; |
2480 | 0 | } |
2481 | 2 | if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNS)) { |
2482 | 0 | options |= DNS_MASTER_CHECKNS; |
2483 | 0 | } |
2484 | 2 | if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_FATALNS)) { |
2485 | 0 | options |= DNS_MASTER_FATALNS; |
2486 | 0 | } |
2487 | 2 | if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNAMES)) { |
2488 | 0 | options |= DNS_MASTER_CHECKNAMES; |
2489 | 0 | } |
2490 | 2 | if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNAMESFAIL)) { |
2491 | 0 | options |= DNS_MASTER_CHECKNAMESFAIL; |
2492 | 0 | } |
2493 | 2 | if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKMX)) { |
2494 | 0 | options |= DNS_MASTER_CHECKMX; |
2495 | 0 | } |
2496 | 2 | if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKMXFAIL)) { |
2497 | 0 | options |= DNS_MASTER_CHECKMXFAIL; |
2498 | 0 | } |
2499 | 2 | if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKWILDCARD)) { |
2500 | 0 | options |= DNS_MASTER_CHECKWILDCARD; |
2501 | 0 | } |
2502 | 2 | if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKTTL)) { |
2503 | 0 | options |= DNS_MASTER_CHECKTTL; |
2504 | 0 | } |
2505 | 2 | if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKSVCB)) { |
2506 | 0 | options |= DNS_MASTER_CHECKSVCB; |
2507 | 0 | } |
2508 | | |
2509 | 2 | return (options); |
2510 | 2 | } |
2511 | | |
2512 | | static void |
2513 | 0 | zone_registerinclude(const char *filename, void *arg) { |
2514 | 0 | isc_result_t result; |
2515 | 0 | dns_zone_t *zone = (dns_zone_t *)arg; |
2516 | 0 | dns_include_t *inc = NULL; |
2517 | |
|
2518 | 0 | REQUIRE(DNS_ZONE_VALID(zone)); |
2519 | |
|
2520 | 0 | if (filename == NULL) { |
2521 | 0 | return; |
2522 | 0 | } |
2523 | | |
2524 | | /* |
2525 | | * Suppress duplicates. |
2526 | | */ |
2527 | 0 | for (inc = ISC_LIST_HEAD(zone->newincludes); inc != NULL; |
2528 | 0 | inc = ISC_LIST_NEXT(inc, link)) |
2529 | 0 | { |
2530 | 0 | if (strcmp(filename, inc->name) == 0) { |
2531 | 0 | return; |
2532 | 0 | } |
2533 | 0 | } |
2534 | | |
2535 | 0 | inc = isc_mem_get(zone->mctx, sizeof(dns_include_t)); |
2536 | 0 | inc->name = isc_mem_strdup(zone->mctx, filename); |
2537 | 0 | ISC_LINK_INIT(inc, link); |
2538 | |
|
2539 | 0 | result = isc_file_getmodtime(filename, &inc->filetime); |
2540 | 0 | if (result != ISC_R_SUCCESS) { |
2541 | 0 | isc_time_settoepoch(&inc->filetime); |
2542 | 0 | } |
2543 | |
|
2544 | 0 | ISC_LIST_APPEND(zone->newincludes, inc, link); |
2545 | 0 | } |
2546 | | |
2547 | | static void |
2548 | 0 | get_raw_serial(dns_zone_t *raw, dns_masterrawheader_t *rawdata) { |
2549 | 0 | isc_result_t result; |
2550 | 0 | unsigned int soacount; |
2551 | |
|
2552 | 0 | LOCK(&raw->lock); |
2553 | 0 | if (raw->db != NULL) { |
2554 | 0 | result = zone_get_from_db(raw, raw->db, NULL, &soacount, NULL, |
2555 | 0 | &rawdata->sourceserial, NULL, NULL, |
2556 | 0 | NULL, NULL, NULL); |
2557 | 0 | if (result == ISC_R_SUCCESS && soacount > 0U) { |
2558 | 0 | rawdata->flags |= DNS_MASTERRAW_SOURCESERIALSET; |
2559 | 0 | } |
2560 | 0 | } |
2561 | 0 | UNLOCK(&raw->lock); |
2562 | 0 | } |
2563 | | |
2564 | | /* |
2565 | | * Save the raw serial number for inline-signing zones. |
2566 | | * (XXX: Other information from the header will be used |
2567 | | * for other purposes in the future, but for now this is |
2568 | | * all we're interested in.) |
2569 | | */ |
2570 | | static void |
2571 | 0 | zone_setrawdata(dns_zone_t *zone, dns_masterrawheader_t *header) { |
2572 | 0 | if ((header->flags & DNS_MASTERRAW_SOURCESERIALSET) == 0) { |
2573 | 0 | return; |
2574 | 0 | } |
2575 | | |
2576 | 0 | zone->sourceserial = header->sourceserial; |
2577 | 0 | zone->sourceserialset = true; |
2578 | 0 | } |
2579 | | |
2580 | | void |
2581 | 0 | dns_zone_setrawdata(dns_zone_t *zone, dns_masterrawheader_t *header) { |
2582 | 0 | if (zone == NULL) { |
2583 | 0 | return; |
2584 | 0 | } |
2585 | | |
2586 | 0 | LOCK_ZONE(zone); |
2587 | 0 | zone_setrawdata(zone, header); |
2588 | 0 | UNLOCK_ZONE(zone); |
2589 | 0 | } |
2590 | | |
2591 | | static isc_result_t |
2592 | 2 | zone_startload(dns_db_t *db, dns_zone_t *zone, isc_time_t loadtime) { |
2593 | 2 | isc_result_t result; |
2594 | 2 | isc_result_t tresult; |
2595 | 2 | unsigned int options; |
2596 | 2 | dns_load_t *load = isc_mem_get(zone->mctx, sizeof(*load)); |
2597 | | |
2598 | 2 | ENTER; |
2599 | | |
2600 | 2 | *load = (dns_load_t){ |
2601 | 2 | .loadtime = loadtime, |
2602 | 2 | }; |
2603 | | |
2604 | 2 | dns_zone_rpz_enable_db(zone, db); |
2605 | 2 | dns_zone_catz_enable_db(zone, db); |
2606 | | |
2607 | 2 | options = get_primary_options(zone); |
2608 | 2 | if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_MANYERRORS)) { |
2609 | 0 | options |= DNS_MASTER_MANYERRORS; |
2610 | 0 | } |
2611 | | |
2612 | 2 | zone_iattach(zone, &load->zone); |
2613 | 2 | dns_db_attach(db, &load->db); |
2614 | | |
2615 | 2 | dns_rdatacallbacks_init(&load->callbacks); |
2616 | 2 | load->callbacks.rawdata = zone_setrawdata; |
2617 | 2 | zone_iattach(zone, &load->callbacks.zone); |
2618 | | |
2619 | 2 | result = dns_db_beginload(db, &load->callbacks); |
2620 | 2 | if (result != ISC_R_SUCCESS) { |
2621 | 0 | goto cleanup; |
2622 | 0 | } |
2623 | | |
2624 | 2 | if (zone->zmgr != NULL && zone->db != NULL) { |
2625 | 0 | result = dns_master_loadfileasync( |
2626 | 0 | zone->masterfile, dns_db_origin(db), dns_db_origin(db), |
2627 | 0 | zone->rdclass, options, 0, &load->callbacks, zone->loop, |
2628 | 0 | zone_loaddone, load, &zone->loadctx, |
2629 | 0 | zone_registerinclude, zone, zone->mctx, |
2630 | 0 | zone->masterformat, zone->maxttl); |
2631 | 0 | if (result != ISC_R_SUCCESS) { |
2632 | 0 | goto cleanup; |
2633 | 0 | } |
2634 | | |
2635 | 0 | return (DNS_R_CONTINUE); |
2636 | 2 | } else if (zone->stream != NULL) { |
2637 | 0 | FILE *stream = UNCONST(zone->stream); |
2638 | 0 | result = dns_master_loadstream( |
2639 | 0 | stream, &zone->origin, &zone->origin, zone->rdclass, |
2640 | 0 | options, &load->callbacks, zone->mctx); |
2641 | 2 | } else { |
2642 | 2 | result = dns_master_loadfile( |
2643 | 2 | zone->masterfile, &zone->origin, &zone->origin, |
2644 | 2 | zone->rdclass, options, 0, &load->callbacks, |
2645 | 2 | zone_registerinclude, zone, zone->mctx, |
2646 | 2 | zone->masterformat, zone->maxttl); |
2647 | 2 | } |
2648 | | |
2649 | 2 | cleanup: |
2650 | 2 | if (result != ISC_R_SUCCESS) { |
2651 | 0 | dns_zone_rpz_disable_db(zone, load->db); |
2652 | 0 | dns_zone_catz_disable_db(zone, load->db); |
2653 | 0 | } |
2654 | | |
2655 | 2 | tresult = dns_db_endload(db, &load->callbacks); |
2656 | 2 | if (result == ISC_R_SUCCESS) { |
2657 | 2 | result = tresult; |
2658 | 2 | } |
2659 | | |
2660 | 2 | zone_idetach(&load->callbacks.zone); |
2661 | 2 | dns_db_detach(&load->db); |
2662 | 2 | zone_idetach(&load->zone); |
2663 | | |
2664 | 2 | isc_mem_put(zone->mctx, load, sizeof(*load)); |
2665 | 2 | return (result); |
2666 | 2 | } |
2667 | | |
2668 | | static bool |
2669 | | zone_check_mx(dns_zone_t *zone, dns_db_t *db, dns_name_t *name, |
2670 | 0 | dns_name_t *owner) { |
2671 | 0 | isc_result_t result; |
2672 | 0 | char ownerbuf[DNS_NAME_FORMATSIZE]; |
2673 | 0 | char namebuf[DNS_NAME_FORMATSIZE]; |
2674 | 0 | char altbuf[DNS_NAME_FORMATSIZE]; |
2675 | 0 | dns_fixedname_t fixed; |
2676 | 0 | dns_name_t *foundname; |
2677 | 0 | int level; |
2678 | | |
2679 | | /* |
2680 | | * "." means the services does not exist. |
2681 | | */ |
2682 | 0 | if (dns_name_equal(name, dns_rootname)) { |
2683 | 0 | return (true); |
2684 | 0 | } |
2685 | | |
2686 | | /* |
2687 | | * Outside of zone. |
2688 | | */ |
2689 | 0 | if (!dns_name_issubdomain(name, &zone->origin)) { |
2690 | 0 | if (zone->checkmx != NULL) { |
2691 | 0 | return ((zone->checkmx)(zone, name, owner)); |
2692 | 0 | } |
2693 | 0 | return (true); |
2694 | 0 | } |
2695 | | |
2696 | 0 | if (zone->type == dns_zone_primary) { |
2697 | 0 | level = ISC_LOG_ERROR; |
2698 | 0 | } else { |
2699 | 0 | level = ISC_LOG_WARNING; |
2700 | 0 | } |
2701 | |
|
2702 | 0 | foundname = dns_fixedname_initname(&fixed); |
2703 | |
|
2704 | 0 | result = dns_db_find(db, name, NULL, dns_rdatatype_a, 0, 0, NULL, |
2705 | 0 | foundname, NULL, NULL); |
2706 | 0 | if (result == ISC_R_SUCCESS) { |
2707 | 0 | return (true); |
2708 | 0 | } |
2709 | | |
2710 | 0 | if (result == DNS_R_NXRRSET) { |
2711 | 0 | result = dns_db_find(db, name, NULL, dns_rdatatype_aaaa, 0, 0, |
2712 | 0 | NULL, foundname, NULL, NULL); |
2713 | 0 | if (result == ISC_R_SUCCESS) { |
2714 | 0 | return (true); |
2715 | 0 | } |
2716 | 0 | } |
2717 | | |
2718 | 0 | dns_name_format(owner, ownerbuf, sizeof ownerbuf); |
2719 | 0 | dns_name_format(name, namebuf, sizeof namebuf); |
2720 | 0 | if (result == DNS_R_NXRRSET || result == DNS_R_NXDOMAIN || |
2721 | 0 | result == DNS_R_EMPTYNAME) |
2722 | 0 | { |
2723 | 0 | if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKMXFAIL)) { |
2724 | 0 | level = ISC_LOG_WARNING; |
2725 | 0 | } |
2726 | 0 | dns_zone_log(zone, level, |
2727 | 0 | "%s/MX '%s' has no address records (A or AAAA)", |
2728 | 0 | ownerbuf, namebuf); |
2729 | 0 | return ((level == ISC_LOG_WARNING) ? true : false); |
2730 | 0 | } |
2731 | | |
2732 | 0 | if (result == DNS_R_CNAME) { |
2733 | 0 | if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_WARNMXCNAME) || |
2734 | 0 | DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IGNOREMXCNAME)) |
2735 | 0 | { |
2736 | 0 | level = ISC_LOG_WARNING; |
2737 | 0 | } |
2738 | 0 | if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IGNOREMXCNAME)) { |
2739 | 0 | dns_zone_log(zone, level, |
2740 | 0 | "%s/MX '%s' is a CNAME (illegal)", |
2741 | 0 | ownerbuf, namebuf); |
2742 | 0 | } |
2743 | 0 | return ((level == ISC_LOG_WARNING) ? true : false); |
2744 | 0 | } |
2745 | | |
2746 | 0 | if (result == DNS_R_DNAME) { |
2747 | 0 | if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_WARNMXCNAME) || |
2748 | 0 | DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IGNOREMXCNAME)) |
2749 | 0 | { |
2750 | 0 | level = ISC_LOG_WARNING; |
2751 | 0 | } |
2752 | 0 | if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IGNOREMXCNAME)) { |
2753 | 0 | dns_name_format(foundname, altbuf, sizeof altbuf); |
2754 | 0 | dns_zone_log(zone, level, |
2755 | 0 | "%s/MX '%s' is below a DNAME" |
2756 | 0 | " '%s' (illegal)", |
2757 | 0 | ownerbuf, namebuf, altbuf); |
2758 | 0 | } |
2759 | 0 | return ((level == ISC_LOG_WARNING) ? true : false); |
2760 | 0 | } |
2761 | | |
2762 | 0 | if (zone->checkmx != NULL && result == DNS_R_DELEGATION) { |
2763 | 0 | return ((zone->checkmx)(zone, name, owner)); |
2764 | 0 | } |
2765 | | |
2766 | 0 | return (true); |
2767 | 0 | } |
2768 | | |
2769 | | static bool |
2770 | | zone_check_srv(dns_zone_t *zone, dns_db_t *db, dns_name_t *name, |
2771 | 0 | dns_name_t *owner) { |
2772 | 0 | isc_result_t result; |
2773 | 0 | char ownerbuf[DNS_NAME_FORMATSIZE]; |
2774 | 0 | char namebuf[DNS_NAME_FORMATSIZE]; |
2775 | 0 | char altbuf[DNS_NAME_FORMATSIZE]; |
2776 | 0 | dns_fixedname_t fixed; |
2777 | 0 | dns_name_t *foundname; |
2778 | 0 | int level; |
2779 | | |
2780 | | /* |
2781 | | * "." means the services does not exist. |
2782 | | */ |
2783 | 0 | if (dns_name_equal(name, dns_rootname)) { |
2784 | 0 | return (true); |
2785 | 0 | } |
2786 | | |
2787 | | /* |
2788 | | * Outside of zone. |
2789 | | */ |
2790 | 0 | if (!dns_name_issubdomain(name, &zone->origin)) { |
2791 | 0 | if (zone->checksrv != NULL) { |
2792 | 0 | return ((zone->checksrv)(zone, name, owner)); |
2793 | 0 | } |
2794 | 0 | return (true); |
2795 | 0 | } |
2796 | | |
2797 | 0 | if (zone->type == dns_zone_primary) { |
2798 | 0 | level = ISC_LOG_ERROR; |
2799 | 0 | } else { |
2800 | 0 | level = ISC_LOG_WARNING; |
2801 | 0 | } |
2802 | |
|
2803 | 0 | foundname = dns_fixedname_initname(&fixed); |
2804 | |
|
2805 | 0 | result = dns_db_find(db, name, NULL, dns_rdatatype_a, 0, 0, NULL, |
2806 | 0 | foundname, NULL, NULL); |
2807 | 0 | if (result == ISC_R_SUCCESS) { |
2808 | 0 | return (true); |
2809 | 0 | } |
2810 | | |
2811 | 0 | if (result == DNS_R_NXRRSET) { |
2812 | 0 | result = dns_db_find(db, name, NULL, dns_rdatatype_aaaa, 0, 0, |
2813 | 0 | NULL, foundname, NULL, NULL); |
2814 | 0 | if (result == ISC_R_SUCCESS) { |
2815 | 0 | return (true); |
2816 | 0 | } |
2817 | 0 | } |
2818 | | |
2819 | 0 | dns_name_format(owner, ownerbuf, sizeof ownerbuf); |
2820 | 0 | dns_name_format(name, namebuf, sizeof namebuf); |
2821 | 0 | if (result == DNS_R_NXRRSET || result == DNS_R_NXDOMAIN || |
2822 | 0 | result == DNS_R_EMPTYNAME) |
2823 | 0 | { |
2824 | 0 | dns_zone_log(zone, level, |
2825 | 0 | "%s/SRV '%s' has no address records (A or AAAA)", |
2826 | 0 | ownerbuf, namebuf); |
2827 | | /* XXX950 make fatal for 9.5.0. */ |
2828 | 0 | return (true); |
2829 | 0 | } |
2830 | | |
2831 | 0 | if (result == DNS_R_CNAME) { |
2832 | 0 | if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_WARNSRVCNAME) || |
2833 | 0 | DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IGNORESRVCNAME)) |
2834 | 0 | { |
2835 | 0 | level = ISC_LOG_WARNING; |
2836 | 0 | } |
2837 | 0 | if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IGNORESRVCNAME)) { |
2838 | 0 | dns_zone_log(zone, level, |
2839 | 0 | "%s/SRV '%s' is a CNAME (illegal)", |
2840 | 0 | ownerbuf, namebuf); |
2841 | 0 | } |
2842 | 0 | return ((level == ISC_LOG_WARNING) ? true : false); |
2843 | 0 | } |
2844 | | |
2845 | 0 | if (result == DNS_R_DNAME) { |
2846 | 0 | if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_WARNSRVCNAME) || |
2847 | 0 | DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IGNORESRVCNAME)) |
2848 | 0 | { |
2849 | 0 | level = ISC_LOG_WARNING; |
2850 | 0 | } |
2851 | 0 | if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IGNORESRVCNAME)) { |
2852 | 0 | dns_name_format(foundname, altbuf, sizeof altbuf); |
2853 | 0 | dns_zone_log(zone, level, |
2854 | 0 | "%s/SRV '%s' is below a " |
2855 | 0 | "DNAME '%s' (illegal)", |
2856 | 0 | ownerbuf, namebuf, altbuf); |
2857 | 0 | } |
2858 | 0 | return ((level == ISC_LOG_WARNING) ? true : false); |
2859 | 0 | } |
2860 | | |
2861 | 0 | if (zone->checksrv != NULL && result == DNS_R_DELEGATION) { |
2862 | 0 | return ((zone->checksrv)(zone, name, owner)); |
2863 | 0 | } |
2864 | | |
2865 | 0 | return (true); |
2866 | 0 | } |
2867 | | |
2868 | | static bool |
2869 | | zone_check_glue(dns_zone_t *zone, dns_db_t *db, dns_name_t *name, |
2870 | 0 | dns_name_t *owner) { |
2871 | 0 | bool answer = true; |
2872 | 0 | isc_result_t result, tresult; |
2873 | 0 | char ownerbuf[DNS_NAME_FORMATSIZE]; |
2874 | 0 | char namebuf[DNS_NAME_FORMATSIZE]; |
2875 | 0 | char altbuf[DNS_NAME_FORMATSIZE]; |
2876 | 0 | dns_fixedname_t fixed; |
2877 | 0 | dns_name_t *foundname; |
2878 | 0 | dns_rdataset_t a; |
2879 | 0 | dns_rdataset_t aaaa; |
2880 | 0 | int level; |
2881 | | |
2882 | | /* |
2883 | | * Outside of zone. |
2884 | | */ |
2885 | 0 | if (!dns_name_issubdomain(name, &zone->origin)) { |
2886 | 0 | if (zone->checkns != NULL) { |
2887 | 0 | return ((zone->checkns)(zone, name, owner, NULL, NULL)); |
2888 | 0 | } |
2889 | 0 | return (true); |
2890 | 0 | } |
2891 | | |
2892 | 0 | if (zone->type == dns_zone_primary) { |
2893 | 0 | level = ISC_LOG_ERROR; |
2894 | 0 | } else { |
2895 | 0 | level = ISC_LOG_WARNING; |
2896 | 0 | } |
2897 | |
|
2898 | 0 | foundname = dns_fixedname_initname(&fixed); |
2899 | 0 | dns_rdataset_init(&a); |
2900 | 0 | dns_rdataset_init(&aaaa); |
2901 | | |
2902 | | /* |
2903 | | * Perform a regular lookup to catch DNAME records then look |
2904 | | * for glue. |
2905 | | */ |
2906 | 0 | result = dns_db_find(db, name, NULL, dns_rdatatype_a, 0, 0, NULL, |
2907 | 0 | foundname, &a, NULL); |
2908 | 0 | switch (result) { |
2909 | 0 | case ISC_R_SUCCESS: |
2910 | 0 | case DNS_R_DNAME: |
2911 | 0 | case DNS_R_CNAME: |
2912 | 0 | break; |
2913 | 0 | default: |
2914 | 0 | if (dns_rdataset_isassociated(&a)) { |
2915 | 0 | dns_rdataset_disassociate(&a); |
2916 | 0 | } |
2917 | 0 | result = dns_db_find(db, name, NULL, dns_rdatatype_a, |
2918 | 0 | DNS_DBFIND_GLUEOK, 0, NULL, foundname, &a, |
2919 | 0 | NULL); |
2920 | 0 | } |
2921 | 0 | if (result == ISC_R_SUCCESS) { |
2922 | 0 | dns_rdataset_disassociate(&a); |
2923 | 0 | return (true); |
2924 | 0 | } else if (result == DNS_R_DELEGATION) { |
2925 | 0 | dns_rdataset_disassociate(&a); |
2926 | 0 | } |
2927 | | |
2928 | 0 | if (result == DNS_R_NXRRSET || result == DNS_R_DELEGATION || |
2929 | 0 | result == DNS_R_GLUE) |
2930 | 0 | { |
2931 | 0 | tresult = dns_db_find(db, name, NULL, dns_rdatatype_aaaa, |
2932 | 0 | DNS_DBFIND_GLUEOK, 0, NULL, foundname, |
2933 | 0 | &aaaa, NULL); |
2934 | 0 | if (tresult == ISC_R_SUCCESS) { |
2935 | 0 | if (dns_rdataset_isassociated(&a)) { |
2936 | 0 | dns_rdataset_disassociate(&a); |
2937 | 0 | } |
2938 | 0 | dns_rdataset_disassociate(&aaaa); |
2939 | 0 | return (true); |
2940 | 0 | } |
2941 | 0 | if (tresult == DNS_R_DELEGATION || tresult == DNS_R_DNAME) { |
2942 | 0 | dns_rdataset_disassociate(&aaaa); |
2943 | 0 | } |
2944 | 0 | if (result == DNS_R_GLUE || tresult == DNS_R_GLUE) { |
2945 | | /* |
2946 | | * Check glue against child zone. |
2947 | | */ |
2948 | 0 | if (zone->checkns != NULL) { |
2949 | 0 | answer = (zone->checkns)(zone, name, owner, &a, |
2950 | 0 | &aaaa); |
2951 | 0 | } |
2952 | 0 | if (dns_rdataset_isassociated(&a)) { |
2953 | 0 | dns_rdataset_disassociate(&a); |
2954 | 0 | } |
2955 | 0 | if (dns_rdataset_isassociated(&aaaa)) { |
2956 | 0 | dns_rdataset_disassociate(&aaaa); |
2957 | 0 | } |
2958 | 0 | return (answer); |
2959 | 0 | } |
2960 | 0 | } |
2961 | | |
2962 | 0 | dns_name_format(owner, ownerbuf, sizeof ownerbuf); |
2963 | 0 | dns_name_format(name, namebuf, sizeof namebuf); |
2964 | 0 | if (result == DNS_R_NXRRSET || result == DNS_R_NXDOMAIN || |
2965 | 0 | result == DNS_R_EMPTYNAME || result == DNS_R_DELEGATION) |
2966 | 0 | { |
2967 | 0 | const char *what; |
2968 | 0 | bool required = false; |
2969 | 0 | if (dns_name_issubdomain(name, owner)) { |
2970 | 0 | what = "REQUIRED GLUE "; |
2971 | 0 | required = true; |
2972 | 0 | } else if (result == DNS_R_DELEGATION) { |
2973 | 0 | what = "SIBLING GLUE "; |
2974 | 0 | } else { |
2975 | 0 | what = ""; |
2976 | 0 | } |
2977 | |
|
2978 | 0 | if (result != DNS_R_DELEGATION || required || |
2979 | 0 | DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKSIBLING)) |
2980 | 0 | { |
2981 | 0 | dns_zone_log(zone, level, |
2982 | 0 | "%s/NS '%s' has no %s" |
2983 | 0 | "address records (A or AAAA)", |
2984 | 0 | ownerbuf, namebuf, what); |
2985 | | /* |
2986 | | * Log missing address record. |
2987 | | */ |
2988 | 0 | if (result == DNS_R_DELEGATION && zone->checkns != NULL) |
2989 | 0 | { |
2990 | 0 | (void)(zone->checkns)(zone, name, owner, &a, |
2991 | 0 | &aaaa); |
2992 | 0 | } |
2993 | | /* XXX950 make fatal for 9.5.0. */ |
2994 | | /* answer = false; */ |
2995 | 0 | } |
2996 | 0 | } else if (result == DNS_R_CNAME) { |
2997 | 0 | dns_zone_log(zone, level, "%s/NS '%s' is a CNAME (illegal)", |
2998 | 0 | ownerbuf, namebuf); |
2999 | | /* XXX950 make fatal for 9.5.0. */ |
3000 | | /* answer = false; */ |
3001 | 0 | } else if (result == DNS_R_DNAME) { |
3002 | 0 | dns_name_format(foundname, altbuf, sizeof altbuf); |
3003 | 0 | dns_zone_log(zone, level, |
3004 | 0 | "%s/NS '%s' is below a DNAME '%s' (illegal)", |
3005 | 0 | ownerbuf, namebuf, altbuf); |
3006 | | /* XXX950 make fatal for 9.5.0. */ |
3007 | | /* answer = false; */ |
3008 | 0 | } |
3009 | |
|
3010 | 0 | if (dns_rdataset_isassociated(&a)) { |
3011 | 0 | dns_rdataset_disassociate(&a); |
3012 | 0 | } |
3013 | 0 | if (dns_rdataset_isassociated(&aaaa)) { |
3014 | 0 | dns_rdataset_disassociate(&aaaa); |
3015 | 0 | } |
3016 | 0 | return (answer); |
3017 | 0 | } |
3018 | | |
3019 | | static bool |
3020 | | zone_rrset_check_dup(dns_zone_t *zone, dns_name_t *owner, |
3021 | 0 | dns_rdataset_t *rdataset) { |
3022 | 0 | dns_rdataset_t tmprdataset; |
3023 | 0 | isc_result_t result; |
3024 | 0 | bool answer = true; |
3025 | 0 | bool format = true; |
3026 | 0 | int level = ISC_LOG_WARNING; |
3027 | 0 | char ownerbuf[DNS_NAME_FORMATSIZE]; |
3028 | 0 | char typebuf[DNS_RDATATYPE_FORMATSIZE]; |
3029 | 0 | unsigned int count1 = 0; |
3030 | |
|
3031 | 0 | if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKDUPRRFAIL)) { |
3032 | 0 | level = ISC_LOG_ERROR; |
3033 | 0 | } |
3034 | |
|
3035 | 0 | dns_rdataset_init(&tmprdataset); |
3036 | 0 | for (result = dns_rdataset_first(rdataset); result == ISC_R_SUCCESS; |
3037 | 0 | result = dns_rdataset_next(rdataset)) |
3038 | 0 | { |
3039 | 0 | dns_rdata_t rdata1 = DNS_RDATA_INIT; |
3040 | 0 | unsigned int count2 = 0; |
3041 | |
|
3042 | 0 | count1++; |
3043 | 0 | dns_rdataset_current(rdataset, &rdata1); |
3044 | 0 | dns_rdataset_clone(rdataset, &tmprdataset); |
3045 | 0 | for (result = dns_rdataset_first(&tmprdataset); |
3046 | 0 | result == ISC_R_SUCCESS; |
3047 | 0 | result = dns_rdataset_next(&tmprdataset)) |
3048 | 0 | { |
3049 | 0 | dns_rdata_t rdata2 = DNS_RDATA_INIT; |
3050 | 0 | count2++; |
3051 | 0 | if (count1 >= count2) { |
3052 | 0 | continue; |
3053 | 0 | } |
3054 | 0 | dns_rdataset_current(&tmprdataset, &rdata2); |
3055 | 0 | if (dns_rdata_casecompare(&rdata1, &rdata2) == 0) { |
3056 | 0 | if (format) { |
3057 | 0 | dns_name_format(owner, ownerbuf, |
3058 | 0 | sizeof ownerbuf); |
3059 | 0 | dns_rdatatype_format(rdata1.type, |
3060 | 0 | typebuf, |
3061 | 0 | sizeof(typebuf)); |
3062 | 0 | format = false; |
3063 | 0 | } |
3064 | 0 | dns_zone_log(zone, level, |
3065 | 0 | "%s/%s has " |
3066 | 0 | "semantically identical records", |
3067 | 0 | ownerbuf, typebuf); |
3068 | 0 | if (level == ISC_LOG_ERROR) { |
3069 | 0 | answer = false; |
3070 | 0 | } |
3071 | 0 | break; |
3072 | 0 | } |
3073 | 0 | } |
3074 | 0 | dns_rdataset_disassociate(&tmprdataset); |
3075 | 0 | if (!format) { |
3076 | 0 | break; |
3077 | 0 | } |
3078 | 0 | } |
3079 | 0 | return (answer); |
3080 | 0 | } |
3081 | | |
3082 | | static bool |
3083 | 0 | zone_check_dup(dns_zone_t *zone, dns_db_t *db) { |
3084 | 0 | dns_dbiterator_t *dbiterator = NULL; |
3085 | 0 | dns_dbnode_t *node = NULL; |
3086 | 0 | dns_fixedname_t fixed; |
3087 | 0 | dns_name_t *name; |
3088 | 0 | dns_rdataset_t rdataset; |
3089 | 0 | dns_rdatasetiter_t *rdsit = NULL; |
3090 | 0 | bool ok = true; |
3091 | 0 | isc_result_t result; |
3092 | |
|
3093 | 0 | name = dns_fixedname_initname(&fixed); |
3094 | 0 | dns_rdataset_init(&rdataset); |
3095 | |
|
3096 | 0 | result = dns_db_createiterator(db, 0, &dbiterator); |
3097 | 0 | if (result != ISC_R_SUCCESS) { |
3098 | 0 | return (true); |
3099 | 0 | } |
3100 | | |
3101 | 0 | for (result = dns_dbiterator_first(dbiterator); result == ISC_R_SUCCESS; |
3102 | 0 | result = dns_dbiterator_next(dbiterator)) |
3103 | 0 | { |
3104 | 0 | result = dns_dbiterator_current(dbiterator, &node, name); |
3105 | 0 | if (result != ISC_R_SUCCESS) { |
3106 | 0 | continue; |
3107 | 0 | } |
3108 | | |
3109 | 0 | result = dns_db_allrdatasets(db, node, NULL, 0, 0, &rdsit); |
3110 | 0 | if (result != ISC_R_SUCCESS) { |
3111 | 0 | continue; |
3112 | 0 | } |
3113 | | |
3114 | 0 | for (result = dns_rdatasetiter_first(rdsit); |
3115 | 0 | result == ISC_R_SUCCESS; |
3116 | 0 | result = dns_rdatasetiter_next(rdsit)) |
3117 | 0 | { |
3118 | 0 | dns_rdatasetiter_current(rdsit, &rdataset); |
3119 | 0 | if (!zone_rrset_check_dup(zone, name, &rdataset)) { |
3120 | 0 | ok = false; |
3121 | 0 | } |
3122 | 0 | dns_rdataset_disassociate(&rdataset); |
3123 | 0 | } |
3124 | 0 | dns_rdatasetiter_destroy(&rdsit); |
3125 | 0 | dns_db_detachnode(db, &node); |
3126 | 0 | } |
3127 | |
|
3128 | 0 | if (node != NULL) { |
3129 | 0 | dns_db_detachnode(db, &node); |
3130 | 0 | } |
3131 | 0 | dns_dbiterator_destroy(&dbiterator); |
3132 | |
|
3133 | 0 | return (ok); |
3134 | 0 | } |
3135 | | |
3136 | | static bool |
3137 | 0 | isspf(const dns_rdata_t *rdata) { |
3138 | 0 | char buf[1024]; |
3139 | 0 | const unsigned char *data = rdata->data; |
3140 | 0 | unsigned int rdl = rdata->length, i = 0, tl, len; |
3141 | |
|
3142 | 0 | while (rdl > 0U) { |
3143 | 0 | len = tl = *data; |
3144 | 0 | ++data; |
3145 | 0 | --rdl; |
3146 | 0 | INSIST(tl <= rdl); |
3147 | 0 | if (len > sizeof(buf) - i - 1) { |
3148 | 0 | len = sizeof(buf) - i - 1; |
3149 | 0 | } |
3150 | 0 | memmove(buf + i, data, len); |
3151 | 0 | i += len; |
3152 | 0 | data += tl; |
3153 | 0 | rdl -= tl; |
3154 | 0 | } |
3155 | |
|
3156 | 0 | if (i < 6U) { |
3157 | 0 | return (false); |
3158 | 0 | } |
3159 | | |
3160 | 0 | buf[i] = 0; |
3161 | 0 | if (strncmp(buf, "v=spf1", 6) == 0 && (buf[6] == 0 || buf[6] == ' ')) { |
3162 | 0 | return (true); |
3163 | 0 | } |
3164 | 0 | return (false); |
3165 | 0 | } |
3166 | | |
3167 | | static bool |
3168 | 0 | integrity_checks(dns_zone_t *zone, dns_db_t *db) { |
3169 | 0 | dns_dbiterator_t *dbiterator = NULL; |
3170 | 0 | dns_dbnode_t *node = NULL; |
3171 | 0 | dns_rdataset_t rdataset; |
3172 | 0 | dns_fixedname_t fixed; |
3173 | 0 | dns_fixedname_t fixedbottom; |
3174 | 0 | dns_rdata_mx_t mx; |
3175 | 0 | dns_rdata_ns_t ns; |
3176 | 0 | dns_rdata_in_srv_t srv; |
3177 | 0 | dns_rdata_t rdata; |
3178 | 0 | dns_name_t *name; |
3179 | 0 | dns_name_t *bottom; |
3180 | 0 | isc_result_t result; |
3181 | 0 | bool ok = true, have_spf, have_txt; |
3182 | 0 | int level; |
3183 | 0 | char namebuf[DNS_NAME_FORMATSIZE]; |
3184 | |
|
3185 | 0 | name = dns_fixedname_initname(&fixed); |
3186 | 0 | bottom = dns_fixedname_initname(&fixedbottom); |
3187 | 0 | dns_rdataset_init(&rdataset); |
3188 | 0 | dns_rdata_init(&rdata); |
3189 | |
|
3190 | 0 | result = dns_db_createiterator(db, 0, &dbiterator); |
3191 | 0 | if (result != ISC_R_SUCCESS) { |
3192 | 0 | return (true); |
3193 | 0 | } |
3194 | | |
3195 | 0 | result = dns_dbiterator_first(dbiterator); |
3196 | 0 | while (result == ISC_R_SUCCESS) { |
3197 | 0 | result = dns_dbiterator_current(dbiterator, &node, name); |
3198 | 0 | if (result != ISC_R_SUCCESS) { |
3199 | 0 | goto cleanup; |
3200 | 0 | } |
3201 | | |
3202 | | /* |
3203 | | * Is this name visible in the zone? |
3204 | | */ |
3205 | 0 | if (!dns_name_issubdomain(name, &zone->origin) || |
3206 | 0 | (dns_name_countlabels(bottom) > 0 && |
3207 | 0 | dns_name_issubdomain(name, bottom))) |
3208 | 0 | { |
3209 | 0 | goto next; |
3210 | 0 | } |
3211 | | |
3212 | 0 | dns_dbiterator_pause(dbiterator); |
3213 | | |
3214 | | /* |
3215 | | * Don't check the NS records at the origin. |
3216 | | */ |
3217 | 0 | if (dns_name_equal(name, &zone->origin)) { |
3218 | 0 | goto checkfords; |
3219 | 0 | } |
3220 | | |
3221 | 0 | result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_ns, |
3222 | 0 | 0, 0, &rdataset, NULL); |
3223 | 0 | if (result != ISC_R_SUCCESS) { |
3224 | 0 | goto checkfords; |
3225 | 0 | } |
3226 | | /* |
3227 | | * Remember bottom of zone due to NS. |
3228 | | */ |
3229 | 0 | dns_name_copy(name, bottom); |
3230 | |
|
3231 | 0 | result = dns_rdataset_first(&rdataset); |
3232 | 0 | while (result == ISC_R_SUCCESS) { |
3233 | 0 | dns_rdataset_current(&rdataset, &rdata); |
3234 | 0 | result = dns_rdata_tostruct(&rdata, &ns, NULL); |
3235 | 0 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
3236 | 0 | if (!zone_check_glue(zone, db, &ns.name, name)) { |
3237 | 0 | ok = false; |
3238 | 0 | } |
3239 | 0 | dns_rdata_reset(&rdata); |
3240 | 0 | result = dns_rdataset_next(&rdataset); |
3241 | 0 | } |
3242 | 0 | dns_rdataset_disassociate(&rdataset); |
3243 | 0 | goto next; |
3244 | | |
3245 | 0 | checkfords: |
3246 | 0 | result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_ds, |
3247 | 0 | 0, 0, &rdataset, NULL); |
3248 | 0 | if (result != ISC_R_SUCCESS) { |
3249 | 0 | goto checkfordname; |
3250 | 0 | } |
3251 | 0 | dns_rdataset_disassociate(&rdataset); |
3252 | |
|
3253 | 0 | if (zone->type == dns_zone_primary) { |
3254 | 0 | level = ISC_LOG_ERROR; |
3255 | 0 | ok = false; |
3256 | 0 | } else { |
3257 | 0 | level = ISC_LOG_WARNING; |
3258 | 0 | } |
3259 | 0 | dns_name_format(name, namebuf, sizeof(namebuf)); |
3260 | 0 | dns_zone_log(zone, level, "DS not at delegation point (%s)", |
3261 | 0 | namebuf); |
3262 | |
|
3263 | 0 | checkfordname: |
3264 | 0 | result = dns_db_findrdataset(db, node, NULL, |
3265 | 0 | dns_rdatatype_dname, 0, 0, |
3266 | 0 | &rdataset, NULL); |
3267 | 0 | if (result == ISC_R_SUCCESS) { |
3268 | | /* |
3269 | | * Remember bottom of zone due to DNAME. |
3270 | | */ |
3271 | 0 | dns_name_copy(name, bottom); |
3272 | 0 | dns_rdataset_disassociate(&rdataset); |
3273 | 0 | } |
3274 | |
|
3275 | 0 | result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_mx, |
3276 | 0 | 0, 0, &rdataset, NULL); |
3277 | 0 | if (result != ISC_R_SUCCESS) { |
3278 | 0 | goto checksrv; |
3279 | 0 | } |
3280 | 0 | result = dns_rdataset_first(&rdataset); |
3281 | 0 | while (result == ISC_R_SUCCESS) { |
3282 | 0 | dns_rdataset_current(&rdataset, &rdata); |
3283 | 0 | result = dns_rdata_tostruct(&rdata, &mx, NULL); |
3284 | 0 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
3285 | 0 | if (!zone_check_mx(zone, db, &mx.mx, name)) { |
3286 | 0 | ok = false; |
3287 | 0 | } |
3288 | 0 | dns_rdata_reset(&rdata); |
3289 | 0 | result = dns_rdataset_next(&rdataset); |
3290 | 0 | } |
3291 | 0 | dns_rdataset_disassociate(&rdataset); |
3292 | |
|
3293 | 0 | checksrv: |
3294 | 0 | if (zone->rdclass != dns_rdataclass_in) { |
3295 | 0 | goto next; |
3296 | 0 | } |
3297 | 0 | result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_srv, |
3298 | 0 | 0, 0, &rdataset, NULL); |
3299 | 0 | if (result != ISC_R_SUCCESS) { |
3300 | 0 | goto checkspf; |
3301 | 0 | } |
3302 | 0 | result = dns_rdataset_first(&rdataset); |
3303 | 0 | while (result == ISC_R_SUCCESS) { |
3304 | 0 | dns_rdataset_current(&rdataset, &rdata); |
3305 | 0 | result = dns_rdata_tostruct(&rdata, &srv, NULL); |
3306 | 0 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
3307 | 0 | if (!zone_check_srv(zone, db, &srv.target, name)) { |
3308 | 0 | ok = false; |
3309 | 0 | } |
3310 | 0 | dns_rdata_reset(&rdata); |
3311 | 0 | result = dns_rdataset_next(&rdataset); |
3312 | 0 | } |
3313 | 0 | dns_rdataset_disassociate(&rdataset); |
3314 | |
|
3315 | 0 | checkspf: |
3316 | | /* |
3317 | | * Check if there is a type SPF record without an |
3318 | | * SPF-formatted type TXT record also being present. |
3319 | | */ |
3320 | 0 | if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKSPF)) { |
3321 | 0 | goto next; |
3322 | 0 | } |
3323 | 0 | if (zone->rdclass != dns_rdataclass_in) { |
3324 | 0 | goto next; |
3325 | 0 | } |
3326 | 0 | have_spf = have_txt = false; |
3327 | 0 | result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_spf, |
3328 | 0 | 0, 0, &rdataset, NULL); |
3329 | 0 | if (result == ISC_R_SUCCESS) { |
3330 | 0 | dns_rdataset_disassociate(&rdataset); |
3331 | 0 | have_spf = true; |
3332 | 0 | } |
3333 | 0 | result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_txt, |
3334 | 0 | 0, 0, &rdataset, NULL); |
3335 | 0 | if (result != ISC_R_SUCCESS) { |
3336 | 0 | goto notxt; |
3337 | 0 | } |
3338 | 0 | result = dns_rdataset_first(&rdataset); |
3339 | 0 | while (result == ISC_R_SUCCESS) { |
3340 | 0 | dns_rdataset_current(&rdataset, &rdata); |
3341 | 0 | have_txt = isspf(&rdata); |
3342 | 0 | dns_rdata_reset(&rdata); |
3343 | 0 | if (have_txt) { |
3344 | 0 | break; |
3345 | 0 | } |
3346 | 0 | result = dns_rdataset_next(&rdataset); |
3347 | 0 | } |
3348 | 0 | dns_rdataset_disassociate(&rdataset); |
3349 | |
|
3350 | 0 | notxt: |
3351 | 0 | if (have_spf && !have_txt) { |
3352 | 0 | dns_name_format(name, namebuf, sizeof(namebuf)); |
3353 | 0 | dns_zone_log(zone, ISC_LOG_WARNING, |
3354 | 0 | "'%s' found type " |
3355 | 0 | "SPF record but no SPF TXT record found, " |
3356 | 0 | "add matching type TXT record", |
3357 | 0 | namebuf); |
3358 | 0 | } |
3359 | |
|
3360 | 0 | next: |
3361 | 0 | dns_db_detachnode(db, &node); |
3362 | 0 | result = dns_dbiterator_next(dbiterator); |
3363 | 0 | } |
3364 | | |
3365 | 0 | cleanup: |
3366 | 0 | if (node != NULL) { |
3367 | 0 | dns_db_detachnode(db, &node); |
3368 | 0 | } |
3369 | 0 | dns_dbiterator_destroy(&dbiterator); |
3370 | |
|
3371 | 0 | return (ok); |
3372 | 0 | } |
3373 | | |
3374 | | /* |
3375 | | * OpenSSL verification of RSA keys with exponent 3 is known to be |
3376 | | * broken prior OpenSSL 0.9.8c/0.9.7k. Look for such keys and warn |
3377 | | * if they are in use. |
3378 | | */ |
3379 | | static void |
3380 | 2 | zone_check_dnskeys(dns_zone_t *zone, dns_db_t *db) { |
3381 | 2 | dns_dbnode_t *node = NULL; |
3382 | 2 | dns_dbversion_t *version = NULL; |
3383 | 2 | dns_rdata_dnskey_t dnskey; |
3384 | 2 | dns_rdata_t rdata = DNS_RDATA_INIT; |
3385 | 2 | dns_rdataset_t rdataset; |
3386 | 2 | isc_result_t result; |
3387 | | |
3388 | 2 | result = dns_db_findnode(db, &zone->origin, false, &node); |
3389 | 2 | if (result != ISC_R_SUCCESS) { |
3390 | 0 | goto cleanup; |
3391 | 0 | } |
3392 | | |
3393 | 2 | dns_db_currentversion(db, &version); |
3394 | 2 | dns_rdataset_init(&rdataset); |
3395 | 2 | result = dns_db_findrdataset(db, node, version, dns_rdatatype_dnskey, |
3396 | 2 | dns_rdatatype_none, 0, &rdataset, NULL); |
3397 | 2 | if (result != ISC_R_SUCCESS) { |
3398 | 2 | goto cleanup; |
3399 | 2 | } |
3400 | | |
3401 | 0 | for (result = dns_rdataset_first(&rdataset); result == ISC_R_SUCCESS; |
3402 | 0 | result = dns_rdataset_next(&rdataset)) |
3403 | 0 | { |
3404 | 0 | dns_rdataset_current(&rdataset, &rdata); |
3405 | 0 | result = dns_rdata_tostruct(&rdata, &dnskey, NULL); |
3406 | 0 | INSIST(result == ISC_R_SUCCESS); |
3407 | | |
3408 | | /* |
3409 | | * RFC 3110, section 4: Performance Considerations: |
3410 | | * |
3411 | | * A public exponent of 3 minimizes the effort needed to verify |
3412 | | * a signature. Use of 3 as the public exponent is weak for |
3413 | | * confidentiality uses since, if the same data can be collected |
3414 | | * encrypted under three different keys with an exponent of 3 |
3415 | | * then, using the Chinese Remainder Theorem [NETSEC], the |
3416 | | * original plain text can be easily recovered. If a key is |
3417 | | * known to be used only for authentication, as is the case with |
3418 | | * DNSSEC, then an exponent of 3 is acceptable. However other |
3419 | | * applications in the future may wish to leverage DNS |
3420 | | * distributed keys for applications that do require |
3421 | | * confidentiality. For keys which might have such other uses, |
3422 | | * a more conservative choice would be 65537 (F4, the fourth |
3423 | | * fermat number). |
3424 | | */ |
3425 | 0 | if (dnskey.datalen > 1 && dnskey.data[0] == 1 && |
3426 | 0 | dnskey.data[1] == 3 && |
3427 | 0 | (dnskey.algorithm == DNS_KEYALG_RSAMD5 || |
3428 | 0 | dnskey.algorithm == DNS_KEYALG_RSASHA1 || |
3429 | 0 | dnskey.algorithm == DNS_KEYALG_NSEC3RSASHA1 || |
3430 | 0 | dnskey.algorithm == DNS_KEYALG_RSASHA256 || |
3431 | 0 | dnskey.algorithm == DNS_KEYALG_RSASHA512)) |
3432 | 0 | { |
3433 | 0 | char algorithm[DNS_SECALG_FORMATSIZE]; |
3434 | 0 | isc_region_t r; |
3435 | |
|
3436 | 0 | dns_rdata_toregion(&rdata, &r); |
3437 | 0 | dns_secalg_format(dnskey.algorithm, algorithm, |
3438 | 0 | sizeof(algorithm)); |
3439 | |
|
3440 | 0 | dnssec_log(zone, ISC_LOG_WARNING, |
3441 | 0 | "weak %s (%u) key found (exponent=3, id=%u)", |
3442 | 0 | algorithm, dnskey.algorithm, |
3443 | 0 | dst_region_computeid(&r)); |
3444 | 0 | } |
3445 | 0 | dns_rdata_reset(&rdata); |
3446 | 0 | } |
3447 | 0 | dns_rdataset_disassociate(&rdataset); |
3448 | |
|
3449 | 2 | cleanup: |
3450 | 2 | if (node != NULL) { |
3451 | 2 | dns_db_detachnode(db, &node); |
3452 | 2 | } |
3453 | 2 | if (version != NULL) { |
3454 | 2 | dns_db_closeversion(db, &version, false); |
3455 | 2 | } |
3456 | 2 | } |
3457 | | |
3458 | | static void |
3459 | 0 | resume_signingwithkey(dns_zone_t *zone) { |
3460 | 0 | dns_dbnode_t *node = NULL; |
3461 | 0 | dns_dbversion_t *version = NULL; |
3462 | 0 | dns_rdata_t rdata = DNS_RDATA_INIT; |
3463 | 0 | dns_rdataset_t rdataset; |
3464 | 0 | isc_result_t result; |
3465 | 0 | dns_db_t *db = NULL; |
3466 | |
|
3467 | 0 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); |
3468 | 0 | if (zone->db != NULL) { |
3469 | 0 | dns_db_attach(zone->db, &db); |
3470 | 0 | } |
3471 | 0 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
3472 | 0 | if (db == NULL) { |
3473 | 0 | goto cleanup; |
3474 | 0 | } |
3475 | | |
3476 | 0 | result = dns_db_findnode(db, &zone->origin, false, &node); |
3477 | 0 | if (result != ISC_R_SUCCESS) { |
3478 | 0 | goto cleanup; |
3479 | 0 | } |
3480 | | |
3481 | 0 | dns_db_currentversion(db, &version); |
3482 | 0 | dns_rdataset_init(&rdataset); |
3483 | 0 | result = dns_db_findrdataset(db, node, version, zone->privatetype, |
3484 | 0 | dns_rdatatype_none, 0, &rdataset, NULL); |
3485 | 0 | if (result != ISC_R_SUCCESS) { |
3486 | 0 | INSIST(!dns_rdataset_isassociated(&rdataset)); |
3487 | 0 | goto cleanup; |
3488 | 0 | } |
3489 | | |
3490 | 0 | for (result = dns_rdataset_first(&rdataset); result == ISC_R_SUCCESS; |
3491 | 0 | result = dns_rdataset_next(&rdataset)) |
3492 | 0 | { |
3493 | 0 | dns_rdataset_current(&rdataset, &rdata); |
3494 | 0 | if (rdata.length != 5 || rdata.data[0] == 0 || |
3495 | 0 | rdata.data[4] != 0) |
3496 | 0 | { |
3497 | 0 | dns_rdata_reset(&rdata); |
3498 | 0 | continue; |
3499 | 0 | } |
3500 | | |
3501 | 0 | result = zone_signwithkey(zone, rdata.data[0], |
3502 | 0 | (rdata.data[1] << 8) | rdata.data[2], |
3503 | 0 | rdata.data[3]); |
3504 | 0 | if (result != ISC_R_SUCCESS) { |
3505 | 0 | dnssec_log(zone, ISC_LOG_ERROR, |
3506 | 0 | "zone_signwithkey failed: %s", |
3507 | 0 | isc_result_totext(result)); |
3508 | 0 | } |
3509 | 0 | dns_rdata_reset(&rdata); |
3510 | 0 | } |
3511 | 0 | dns_rdataset_disassociate(&rdataset); |
3512 | |
|
3513 | 0 | cleanup: |
3514 | 0 | if (db != NULL) { |
3515 | 0 | if (node != NULL) { |
3516 | 0 | dns_db_detachnode(db, &node); |
3517 | 0 | } |
3518 | 0 | if (version != NULL) { |
3519 | 0 | dns_db_closeversion(db, &version, false); |
3520 | 0 | } |
3521 | 0 | dns_db_detach(&db); |
3522 | 0 | } |
3523 | 0 | } |
3524 | | |
3525 | | /* |
3526 | | * Initiate adding/removing NSEC3 records belonging to the chain defined by the |
3527 | | * supplied NSEC3PARAM RDATA. |
3528 | | * |
3529 | | * Zone must be locked by caller. |
3530 | | */ |
3531 | | static isc_result_t |
3532 | 0 | zone_addnsec3chain(dns_zone_t *zone, dns_rdata_nsec3param_t *nsec3param) { |
3533 | 0 | dns_nsec3chain_t *nsec3chain, *current; |
3534 | 0 | dns_dbversion_t *version = NULL; |
3535 | 0 | bool nseconly = false, nsec3ok = false; |
3536 | 0 | isc_result_t result; |
3537 | 0 | isc_time_t now; |
3538 | 0 | unsigned int options = 0; |
3539 | 0 | char saltbuf[255 * 2 + 1]; |
3540 | 0 | char flags[sizeof("INITIAL|REMOVE|CREATE|NONSEC|OPTOUT")]; |
3541 | 0 | dns_db_t *db = NULL; |
3542 | |
|
3543 | 0 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); |
3544 | 0 | if (zone->db != NULL) { |
3545 | 0 | dns_db_attach(zone->db, &db); |
3546 | 0 | } |
3547 | 0 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
3548 | |
|
3549 | 0 | if (db == NULL) { |
3550 | 0 | result = ISC_R_SUCCESS; |
3551 | 0 | goto cleanup; |
3552 | 0 | } |
3553 | | |
3554 | | /* |
3555 | | * If this zone is not NSEC3-capable, attempting to remove any NSEC3 |
3556 | | * chain from it is pointless as it would not be possible for the |
3557 | | * latter to exist in the first place. |
3558 | | */ |
3559 | 0 | dns_db_currentversion(db, &version); |
3560 | 0 | result = dns_nsec_nseconly(db, version, NULL, &nseconly); |
3561 | 0 | nsec3ok = (result == ISC_R_SUCCESS && !nseconly); |
3562 | 0 | dns_db_closeversion(db, &version, false); |
3563 | 0 | if (!nsec3ok && (nsec3param->flags & DNS_NSEC3FLAG_REMOVE) == 0) { |
3564 | 0 | result = ISC_R_SUCCESS; |
3565 | 0 | goto cleanup; |
3566 | 0 | } |
3567 | | |
3568 | | /* |
3569 | | * Allocate and initialize structure preserving state of |
3570 | | * adding/removing records belonging to this NSEC3 chain between |
3571 | | * separate zone_nsec3chain() calls. |
3572 | | */ |
3573 | 0 | nsec3chain = isc_mem_get(zone->mctx, sizeof *nsec3chain); |
3574 | |
|
3575 | 0 | nsec3chain->magic = 0; |
3576 | 0 | nsec3chain->done = false; |
3577 | 0 | nsec3chain->db = NULL; |
3578 | 0 | nsec3chain->dbiterator = NULL; |
3579 | 0 | nsec3chain->nsec3param.common.rdclass = nsec3param->common.rdclass; |
3580 | 0 | nsec3chain->nsec3param.common.rdtype = nsec3param->common.rdtype; |
3581 | 0 | nsec3chain->nsec3param.hash = nsec3param->hash; |
3582 | 0 | nsec3chain->nsec3param.iterations = nsec3param->iterations; |
3583 | 0 | nsec3chain->nsec3param.flags = nsec3param->flags; |
3584 | 0 | nsec3chain->nsec3param.salt_length = nsec3param->salt_length; |
3585 | 0 | memmove(nsec3chain->salt, nsec3param->salt, nsec3param->salt_length); |
3586 | 0 | nsec3chain->nsec3param.salt = nsec3chain->salt; |
3587 | 0 | nsec3chain->seen_nsec = false; |
3588 | 0 | nsec3chain->delete_nsec = false; |
3589 | 0 | nsec3chain->save_delete_nsec = false; |
3590 | | |
3591 | | /* |
3592 | | * Log NSEC3 parameters defined by supplied NSEC3PARAM RDATA. |
3593 | | */ |
3594 | 0 | if (nsec3param->flags == 0) { |
3595 | 0 | strlcpy(flags, "NONE", sizeof(flags)); |
3596 | 0 | } else { |
3597 | 0 | flags[0] = '\0'; |
3598 | 0 | if ((nsec3param->flags & DNS_NSEC3FLAG_REMOVE) != 0) { |
3599 | 0 | strlcat(flags, "REMOVE", sizeof(flags)); |
3600 | 0 | } |
3601 | 0 | if ((nsec3param->flags & DNS_NSEC3FLAG_INITIAL) != 0) { |
3602 | 0 | if (flags[0] == '\0') { |
3603 | 0 | strlcpy(flags, "INITIAL", sizeof(flags)); |
3604 | 0 | } else { |
3605 | 0 | strlcat(flags, "|INITIAL", sizeof(flags)); |
3606 | 0 | } |
3607 | 0 | } |
3608 | 0 | if ((nsec3param->flags & DNS_NSEC3FLAG_CREATE) != 0) { |
3609 | 0 | if (flags[0] == '\0') { |
3610 | 0 | strlcpy(flags, "CREATE", sizeof(flags)); |
3611 | 0 | } else { |
3612 | 0 | strlcat(flags, "|CREATE", sizeof(flags)); |
3613 | 0 | } |
3614 | 0 | } |
3615 | 0 | if ((nsec3param->flags & DNS_NSEC3FLAG_NONSEC) != 0) { |
3616 | 0 | if (flags[0] == '\0') { |
3617 | 0 | strlcpy(flags, "NONSEC", sizeof(flags)); |
3618 | 0 | } else { |
3619 | 0 | strlcat(flags, "|NONSEC", sizeof(flags)); |
3620 | 0 | } |
3621 | 0 | } |
3622 | 0 | if ((nsec3param->flags & DNS_NSEC3FLAG_OPTOUT) != 0) { |
3623 | 0 | if (flags[0] == '\0') { |
3624 | 0 | strlcpy(flags, "OPTOUT", sizeof(flags)); |
3625 | 0 | } else { |
3626 | 0 | strlcat(flags, "|OPTOUT", sizeof(flags)); |
3627 | 0 | } |
3628 | 0 | } |
3629 | 0 | } |
3630 | 0 | result = dns_nsec3param_salttotext(nsec3param, saltbuf, |
3631 | 0 | sizeof(saltbuf)); |
3632 | 0 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
3633 | 0 | dnssec_log(zone, ISC_LOG_INFO, "zone_addnsec3chain(%u,%s,%u,%s)", |
3634 | 0 | nsec3param->hash, flags, nsec3param->iterations, saltbuf); |
3635 | | |
3636 | | /* |
3637 | | * If the NSEC3 chain defined by the supplied NSEC3PARAM RDATA is |
3638 | | * currently being processed, interrupt its processing to avoid |
3639 | | * simultaneously adding and removing records for the same NSEC3 chain. |
3640 | | */ |
3641 | 0 | for (current = ISC_LIST_HEAD(zone->nsec3chain); current != NULL; |
3642 | 0 | current = ISC_LIST_NEXT(current, link)) |
3643 | 0 | { |
3644 | 0 | if ((current->db == db) && |
3645 | 0 | (current->nsec3param.hash == nsec3param->hash) && |
3646 | 0 | (current->nsec3param.iterations == |
3647 | 0 | nsec3param->iterations) && |
3648 | 0 | (current->nsec3param.salt_length == |
3649 | 0 | nsec3param->salt_length) && |
3650 | 0 | memcmp(current->nsec3param.salt, nsec3param->salt, |
3651 | 0 | nsec3param->salt_length) == 0) |
3652 | 0 | { |
3653 | 0 | current->done = true; |
3654 | 0 | } |
3655 | 0 | } |
3656 | | |
3657 | | /* |
3658 | | * Attach zone database to the structure initialized above and create |
3659 | | * an iterator for it with appropriate options in order to avoid |
3660 | | * creating NSEC3 records for NSEC3 records. |
3661 | | */ |
3662 | 0 | dns_db_attach(db, &nsec3chain->db); |
3663 | 0 | if ((nsec3chain->nsec3param.flags & DNS_NSEC3FLAG_CREATE) != 0) { |
3664 | 0 | options = DNS_DB_NONSEC3; |
3665 | 0 | } |
3666 | 0 | result = dns_db_createiterator(nsec3chain->db, options, |
3667 | 0 | &nsec3chain->dbiterator); |
3668 | 0 | if (result == ISC_R_SUCCESS) { |
3669 | 0 | result = dns_dbiterator_first(nsec3chain->dbiterator); |
3670 | 0 | } |
3671 | 0 | if (result == ISC_R_SUCCESS) { |
3672 | | /* |
3673 | | * Database iterator initialization succeeded. We are now |
3674 | | * ready to kick off adding/removing records belonging to this |
3675 | | * NSEC3 chain. Append the structure initialized above to the |
3676 | | * "nsec3chain" list for the zone and set the appropriate zone |
3677 | | * timer so that zone_nsec3chain() is called as soon as |
3678 | | * possible. |
3679 | | */ |
3680 | 0 | dns_dbiterator_pause(nsec3chain->dbiterator); |
3681 | 0 | ISC_LIST_INITANDAPPEND(zone->nsec3chain, nsec3chain, link); |
3682 | 0 | nsec3chain = NULL; |
3683 | 0 | if (isc_time_isepoch(&zone->nsec3chaintime)) { |
3684 | 0 | now = isc_time_now(); |
3685 | 0 | zone->nsec3chaintime = now; |
3686 | 0 | if (zone->loop != NULL) { |
3687 | 0 | zone_settimer(zone, &now); |
3688 | 0 | } |
3689 | 0 | } |
3690 | 0 | } |
3691 | |
|
3692 | 0 | if (nsec3chain != NULL) { |
3693 | 0 | if (nsec3chain->db != NULL) { |
3694 | 0 | dns_db_detach(&nsec3chain->db); |
3695 | 0 | } |
3696 | 0 | if (nsec3chain->dbiterator != NULL) { |
3697 | 0 | dns_dbiterator_destroy(&nsec3chain->dbiterator); |
3698 | 0 | } |
3699 | 0 | isc_mem_put(zone->mctx, nsec3chain, sizeof *nsec3chain); |
3700 | 0 | } |
3701 | |
|
3702 | 0 | cleanup: |
3703 | 0 | if (db != NULL) { |
3704 | 0 | dns_db_detach(&db); |
3705 | 0 | } |
3706 | 0 | return (result); |
3707 | 0 | } |
3708 | | |
3709 | | /* |
3710 | | * Find private-type records at the zone apex which signal that an NSEC3 chain |
3711 | | * should be added or removed. For each such record, extract NSEC3PARAM RDATA |
3712 | | * and pass it to zone_addnsec3chain(). |
3713 | | * |
3714 | | * Zone must be locked by caller. |
3715 | | */ |
3716 | | static void |
3717 | 0 | resume_addnsec3chain(dns_zone_t *zone) { |
3718 | 0 | dns_dbnode_t *node = NULL; |
3719 | 0 | dns_dbversion_t *version = NULL; |
3720 | 0 | dns_rdataset_t rdataset; |
3721 | 0 | isc_result_t result; |
3722 | 0 | dns_rdata_nsec3param_t nsec3param; |
3723 | 0 | bool nseconly = false, nsec3ok = false; |
3724 | 0 | dns_db_t *db = NULL; |
3725 | |
|
3726 | 0 | INSIST(LOCKED_ZONE(zone)); |
3727 | |
|
3728 | 0 | if (zone->privatetype == 0) { |
3729 | 0 | return; |
3730 | 0 | } |
3731 | | |
3732 | 0 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); |
3733 | 0 | if (zone->db != NULL) { |
3734 | 0 | dns_db_attach(zone->db, &db); |
3735 | 0 | } |
3736 | 0 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
3737 | 0 | if (db == NULL) { |
3738 | 0 | goto cleanup; |
3739 | 0 | } |
3740 | | |
3741 | 0 | result = dns_db_findnode(db, &zone->origin, false, &node); |
3742 | 0 | if (result != ISC_R_SUCCESS) { |
3743 | 0 | goto cleanup; |
3744 | 0 | } |
3745 | | |
3746 | 0 | dns_db_currentversion(db, &version); |
3747 | | |
3748 | | /* |
3749 | | * In order to create NSEC3 chains we need the DNSKEY RRset at zone |
3750 | | * apex to exist and contain no keys using NSEC-only algorithms. |
3751 | | */ |
3752 | 0 | result = dns_nsec_nseconly(db, version, NULL, &nseconly); |
3753 | 0 | nsec3ok = (result == ISC_R_SUCCESS && !nseconly); |
3754 | | |
3755 | | /* |
3756 | | * Get the RRset containing all private-type records at the zone apex. |
3757 | | */ |
3758 | 0 | dns_rdataset_init(&rdataset); |
3759 | 0 | result = dns_db_findrdataset(db, node, version, zone->privatetype, |
3760 | 0 | dns_rdatatype_none, 0, &rdataset, NULL); |
3761 | 0 | if (result != ISC_R_SUCCESS) { |
3762 | 0 | INSIST(!dns_rdataset_isassociated(&rdataset)); |
3763 | 0 | goto cleanup; |
3764 | 0 | } |
3765 | | |
3766 | 0 | for (result = dns_rdataset_first(&rdataset); result == ISC_R_SUCCESS; |
3767 | 0 | result = dns_rdataset_next(&rdataset)) |
3768 | 0 | { |
3769 | 0 | unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE]; |
3770 | 0 | dns_rdata_t rdata = DNS_RDATA_INIT; |
3771 | 0 | dns_rdata_t private = DNS_RDATA_INIT; |
3772 | |
|
3773 | 0 | dns_rdataset_current(&rdataset, &private); |
3774 | | /* |
3775 | | * Try extracting NSEC3PARAM RDATA from this private-type |
3776 | | * record. Failure means this private-type record does not |
3777 | | * represent an NSEC3PARAM record, so skip it. |
3778 | | */ |
3779 | 0 | if (!dns_nsec3param_fromprivate(&private, &rdata, buf, |
3780 | 0 | sizeof(buf))) |
3781 | 0 | { |
3782 | 0 | continue; |
3783 | 0 | } |
3784 | 0 | result = dns_rdata_tostruct(&rdata, &nsec3param, NULL); |
3785 | 0 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
3786 | 0 | if (((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0) || |
3787 | 0 | ((nsec3param.flags & DNS_NSEC3FLAG_CREATE) != 0 && nsec3ok)) |
3788 | 0 | { |
3789 | | /* |
3790 | | * Pass the NSEC3PARAM RDATA contained in this |
3791 | | * private-type record to zone_addnsec3chain() so that |
3792 | | * it can kick off adding or removing NSEC3 records. |
3793 | | */ |
3794 | 0 | result = zone_addnsec3chain(zone, &nsec3param); |
3795 | 0 | if (result != ISC_R_SUCCESS) { |
3796 | 0 | dnssec_log(zone, ISC_LOG_ERROR, |
3797 | 0 | "zone_addnsec3chain failed: %s", |
3798 | 0 | isc_result_totext(result)); |
3799 | 0 | } |
3800 | 0 | } |
3801 | 0 | } |
3802 | 0 | dns_rdataset_disassociate(&rdataset); |
3803 | |
|
3804 | 0 | cleanup: |
3805 | 0 | if (db != NULL) { |
3806 | 0 | if (node != NULL) { |
3807 | 0 | dns_db_detachnode(db, &node); |
3808 | 0 | } |
3809 | 0 | if (version != NULL) { |
3810 | 0 | dns_db_closeversion(db, &version, false); |
3811 | 0 | } |
3812 | 0 | dns_db_detach(&db); |
3813 | 0 | } |
3814 | 0 | } |
3815 | | |
3816 | | static void |
3817 | 0 | set_resigntime(dns_zone_t *zone) { |
3818 | 0 | dns_rdataset_t rdataset; |
3819 | 0 | dns_fixedname_t fixed; |
3820 | 0 | unsigned int resign; |
3821 | 0 | isc_result_t result; |
3822 | 0 | uint32_t nanosecs; |
3823 | 0 | dns_db_t *db = NULL; |
3824 | |
|
3825 | 0 | INSIST(LOCKED_ZONE(zone)); |
3826 | | |
3827 | | /* We only re-sign zones that can be dynamically updated */ |
3828 | 0 | if (!dns_zone_isdynamic(zone, false)) { |
3829 | 0 | return; |
3830 | 0 | } |
3831 | | |
3832 | 0 | if (inline_raw(zone)) { |
3833 | 0 | return; |
3834 | 0 | } |
3835 | | |
3836 | 0 | dns_rdataset_init(&rdataset); |
3837 | 0 | dns_fixedname_init(&fixed); |
3838 | |
|
3839 | 0 | ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); |
3840 | 0 | if (zone->db != NULL) { |
3841 | 0 | dns_db_attach(zone->db, &db); |
3842 | 0 | } |
3843 | 0 | ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); |
3844 | 0 | if (db == NULL) { |
3845 | 0 | isc_time_settoepoch(&zone->resigntime); |
3846 | 0 | return; |
3847 | 0 | } |
3848 | | |
3849 | 0 | result = dns_db_getsigningtime(db, &rdataset, |
3850 | 0 | dns_fixedname_name(&fixed)); |
3851 | 0 | if (result != ISC_R_SUCCESS) { |
3852 | 0 | isc_time_settoepoch(&zone->resigntime); |
3853 | 0 | goto cleanup; |
3854 | 0 | } |
3855 | | |
3856 | 0 | resign = rdataset.resign - dns_zone_getsigresigninginterval(zone); |
3857 | 0 | dns_rdataset_disassociate(&rdataset); |
3858 | 0 | nanosecs = isc_random_uniform(1000000000); |
3859 | 0 | isc_time_set(&zone->resigntime, resign, nanosecs); |
3860 | |
|
3861 | 0 | cleanup: |
3862 | 0 | dns_db_detach(&db); |
3863 | 0 | return; |
3864 | 0 | } |
3865 | | |
3866 | | static isc_result_t |
3867 | 2 | check_nsec3param(dns_zone_t *zone, dns_db_t *db) { |
3868 | 2 | bool ok = false; |
3869 | 2 | dns_dbnode_t *node = NULL; |
3870 | 2 | dns_dbversion_t *version = NULL; |
3871 | 2 | dns_rdata_nsec3param_t nsec3param; |
3872 | 2 | dns_rdataset_t rdataset; |
3873 | 2 | isc_result_t result; |
3874 | 2 | bool dynamic = (zone->type == dns_zone_primary) |
3875 | 2 | ? dns_zone_isdynamic(zone, false) |
3876 | 2 | : false; |
3877 | | |
3878 | 2 | dns_rdataset_init(&rdataset); |
3879 | 2 | result = dns_db_findnode(db, &zone->origin, false, &node); |
3880 | 2 | if (result != ISC_R_SUCCESS) { |
3881 | 0 | dns_zone_log(zone, ISC_LOG_ERROR, |
3882 | 0 | "nsec3param lookup failure: %s", |
3883 | 0 | isc_result_totext(result)); |
3884 | 0 | return (result); |
3885 | 0 | } |
3886 | 2 | dns_db_currentversion(db, &version); |
3887 | | |
3888 | 2 | result = dns_db_findrdataset(db, node, version, |
3889 | 2 | dns_rdatatype_nsec3param, |
3890 | 2 | dns_rdatatype_none, 0, &rdataset, NULL); |
3891 | 2 | if (result == ISC_R_NOTFOUND) { |
3892 | 2 | INSIST(!dns_rdataset_isassociated(&rdataset)); |
3893 | 2 | result = ISC_R_SUCCESS; |
3894 | 2 | goto cleanup; |
3895 | 2 | } |
3896 | 0 | if (result != ISC_R_SUCCESS) { |
3897 | 0 | INSIST(!dns_rdataset_isassociated(&rdataset)); |
3898 | 0 | dns_zone_log(zone, ISC_LOG_ERROR, |
3899 | 0 | "nsec3param lookup failure: %s", |
3900 | 0 | isc_result_totext(result)); |
3901 | 0 | goto cleanup; |
3902 | 0 | } |
3903 | | |
3904 | 0 | for (result = dns_rdataset_first(&rdataset); result == ISC_R_SUCCESS; |
3905 | 0 | result = dns_rdataset_next(&rdataset)) |
3906 | 0 | { |
3907 | 0 | dns_rdata_t rdata = DNS_RDATA_INIT; |
3908 | |
|
3909 | 0 | dns_rdataset_current(&rdataset, &rdata); |
3910 | 0 | result = dns_rdata_tostruct(&rdata, &nsec3param, NULL); |
3911 | 0 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
3912 | | |
3913 | | /* |
3914 | | * For dynamic zones we must support every algorithm so we |
3915 | | * can regenerate all the NSEC3 chains. |
3916 | | * For non-dynamic zones we only need to find a supported |
3917 | | * algorithm. |
3918 | | */ |
3919 | 0 | if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_NSEC3TESTZONE) && |
3920 | 0 | nsec3param.hash == DNS_NSEC3_UNKNOWNALG && !dynamic) |
3921 | 0 | { |
3922 | 0 | dns_zone_log(zone, ISC_LOG_WARNING, |
3923 | 0 | "nsec3 test \"unknown\" hash algorithm " |
3924 | 0 | "found: %u", |
3925 | 0 | nsec3param.hash); |
3926 | 0 | ok = true; |
3927 | 0 | } else if (!dns_nsec3_supportedhash(nsec3param.hash)) { |
3928 | 0 | if (dynamic) { |
3929 | 0 | dns_zone_log(zone, ISC_LOG_ERROR, |
3930 | 0 | "unsupported nsec3 hash algorithm" |
3931 | 0 | " in dynamic zone: %u", |
3932 | 0 | nsec3param.hash); |
3933 | 0 | result = DNS_R_BADZONE; |
3934 | | /* Stop second error message. */ |
3935 | 0 | ok = true; |
3936 | 0 | break; |
3937 | 0 | } else { |
3938 | 0 | dns_zone_log(zone, ISC_LOG_WARNING, |
3939 | 0 | "unsupported nsec3 hash " |
3940 | 0 | "algorithm: %u", |
3941 | 0 | nsec3param.hash); |
3942 | 0 | } |
3943 | 0 | } else { |
3944 | 0 | ok = true; |
3945 | 0 | } |
3946 | | |
3947 | | /* |
3948 | | * Warn if the zone has excessive NSEC3 iterations. |
3949 | | */ |
3950 | 0 | if (nsec3param.iterations > dns_nsec3_maxiterations()) { |
3951 | 0 | dnssec_log(zone, ISC_LOG_WARNING, |
3952 | 0 | "excessive NSEC3PARAM iterations %u > %u", |
3953 | 0 | nsec3param.iterations, |
3954 | 0 | dns_nsec3_maxiterations()); |
3955 | 0 | } |
3956 | 0 | } |
3957 | 0 | if (result == ISC_R_NOMORE) { |
3958 | 0 | result = ISC_R_SUCCESS; |
3959 | 0 | } |
3960 | |
|
3961 | 0 | if (!ok) { |
3962 | 0 | result = DNS_R_BADZONE; |
3963 | 0 | dns_zone_log(zone, ISC_LOG_ERROR, |
3964 | 0 | "no supported nsec3 hash algorithm"); |
3965 | 0 | } |
3966 | |
|
3967 | 2 | cleanup: |
3968 | 2 | if (dns_rdataset_isassociated(&rdataset)) { |
3969 | 0 | dns_rdataset_disassociate(&rdataset); |
3970 | 0 | } |
3971 | 2 | dns_db_closeversion(db, &version, false); |
3972 | 2 | dns_db_detachnode(db, &node); |
3973 | 2 | return (result); |
3974 | 0 | } |
3975 | | |
3976 | | /* |
3977 | | * Set the timer for refreshing the key zone to the soonest future time |
3978 | | * of the set (current timer, keydata->refresh, keydata->addhd, |
3979 | | * keydata->removehd). |
3980 | | */ |
3981 | | static void |
3982 | | set_refreshkeytimer(dns_zone_t *zone, dns_rdata_keydata_t *key, |
3983 | 0 | isc_stdtime_t now, bool force) { |
3984 | 0 | isc_stdtime_t then; |
3985 | 0 | isc_time_t timenow, timethen; |
3986 | 0 | char timebuf[80]; |
3987 | |
|
3988 | 0 | ENTER; |
3989 | 0 | then = key->refresh; |
3990 | 0 | if (force) { |
3991 | 0 | then = now; |
3992 | 0 | } |
3993 | 0 | if (key->addhd > now && key->addhd < then) { |
3994 | 0 | then = key->addhd; |
3995 | 0 | } |
3996 | 0 | if (key->removehd > now && key->removehd < then) { |
3997 | 0 | then = key->removehd; |
3998 | 0 | } |
3999 | |
|
4000 | 0 | timenow = isc_time_now(); |
4001 | 0 | if (then > now) { |
4002 | 0 | DNS_ZONE_TIME_ADD(&timenow, then - now, &timethen); |
4003 | 0 | } else { |
4004 | 0 | timethen = timenow; |
4005 | 0 | } |
4006 | 0 | if (isc_time_compare(&zone->refreshkeytime, &timenow) < 0 || |
4007 | 0 | isc_time_compare(&timethen, &zone->refreshkeytime) < 0) |
4008 | 0 | { |
4009 | 0 | zone->refreshkeytime = timethen; |
4010 | 0 | } |
4011 | |
|
4012 | 0 | isc_time_formattimestamp(&zone->refreshkeytime, timebuf, 80); |
4013 | 0 | dns_zone_log(zone, ISC_LOG_DEBUG(1), "next key refresh: %s", timebuf); |
4014 | 0 | zone_settimer(zone, &timenow); |
4015 | 0 | } |
4016 | | |
4017 | | /* |
4018 | | * If keynode references a key or a DS rdataset, and if the key |
4019 | | * zone does not contain a KEYDATA record for the corresponding name, |
4020 | | * then create an empty KEYDATA and push it into the zone as a placeholder, |
4021 | | * then schedule a key refresh immediately. This new KEYDATA record will be |
4022 | | * updated during the refresh. |
4023 | | * |
4024 | | * If the key zone is changed, set '*changed' to true. |
4025 | | */ |
4026 | | static isc_result_t |
4027 | | create_keydata(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, |
4028 | | dns_diff_t *diff, dns_keynode_t *keynode, dns_name_t *keyname, |
4029 | 0 | bool *changed) { |
4030 | 0 | isc_result_t result = ISC_R_SUCCESS; |
4031 | 0 | dns_rdata_t rdata = DNS_RDATA_INIT; |
4032 | 0 | dns_rdata_keydata_t kd; |
4033 | 0 | unsigned char rrdata[4096]; |
4034 | 0 | isc_buffer_t rrdatabuf; |
4035 | 0 | isc_stdtime_t now = isc_stdtime_now(); |
4036 | |
|
4037 | 0 | REQUIRE(keynode != NULL); |
4038 | |
|
4039 | 0 | ENTER; |
4040 | | |
4041 | | /* |
4042 | | * If the keynode has no trust anchor set, we shouldn't be here. |
4043 | | */ |
4044 | 0 | if (!dns_keynode_dsset(keynode, NULL)) { |
4045 | 0 | return (ISC_R_FAILURE); |
4046 | 0 | } |
4047 | | |
4048 | 0 | memset(&kd, 0, sizeof(kd)); |
4049 | 0 | kd.common.rdclass = zone->rdclass; |
4050 | 0 | kd.common.rdtype = dns_rdatatype_keydata; |
4051 | 0 | ISC_LINK_INIT(&kd.common, link); |
4052 | |
|
4053 | 0 | isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata)); |
4054 | |
|
4055 | 0 | CHECK(dns_rdata_fromstruct(&rdata, zone->rdclass, dns_rdatatype_keydata, |
4056 | 0 | &kd, &rrdatabuf)); |
4057 | | /* Add rdata to zone. */ |
4058 | 0 | CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_ADD, keyname, 0, &rdata)); |
4059 | 0 | *changed = true; |
4060 | | |
4061 | | /* Refresh new keys from the zone apex as soon as possible. */ |
4062 | 0 | set_refreshkeytimer(zone, &kd, now, true); |
4063 | 0 | return (ISC_R_SUCCESS); |
4064 | | |
4065 | 0 | failure: |
4066 | 0 | return (result); |
4067 | 0 | } |
4068 | | |
4069 | | /* |
4070 | | * Remove from the key zone all the KEYDATA records found in rdataset. |
4071 | | */ |
4072 | | static isc_result_t |
4073 | | delete_keydata(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff, |
4074 | 0 | dns_name_t *name, dns_rdataset_t *rdataset) { |
4075 | 0 | dns_rdata_t rdata = DNS_RDATA_INIT; |
4076 | 0 | isc_result_t result, uresult; |
4077 | |
|
4078 | 0 | for (result = dns_rdataset_first(rdataset); result == ISC_R_SUCCESS; |
4079 | 0 | result = dns_rdataset_next(rdataset)) |
4080 | 0 | { |
4081 | 0 | dns_rdata_reset(&rdata); |
4082 | 0 | dns_rdataset_current(rdataset, &rdata); |
4083 | 0 | uresult = update_one_rr(db, ver, diff, DNS_DIFFOP_DEL, name, 0, |
4084 | 0 | &rdata); |
4085 | 0 | if (uresult != ISC_R_SUCCESS) { |
4086 | 0 | return (uresult); |
4087 | 0 | } |
4088 | 0 | } |
4089 | 0 | if (result == ISC_R_NOMORE) { |
4090 | 0 | result = ISC_R_SUCCESS; |
4091 | 0 | } |
4092 | 0 | return (result); |
4093 | 0 | } |
4094 | | |
4095 | | /* |
4096 | | * Compute the DNSSEC key ID for a DNSKEY record. |
4097 | | */ |
4098 | | static isc_result_t |
4099 | | compute_tag(dns_name_t *name, dns_rdata_dnskey_t *dnskey, isc_mem_t *mctx, |
4100 | 0 | dns_keytag_t *tag) { |
4101 | 0 | isc_result_t result; |
4102 | 0 | dns_rdata_t rdata = DNS_RDATA_INIT; |
4103 | 0 | unsigned char data[4096]; |
4104 | 0 | isc_buffer_t buffer; |
4105 | 0 | dst_key_t *dstkey = NULL; |
4106 | |
|
4107 | 0 | isc_buffer_init(&buffer, data, sizeof(data)); |
4108 | 0 | dns_rdata_fromstruct(&rdata, dnskey->common.rdclass, |
4109 | 0 | dns_rdatatype_dnskey, dnskey, &buffer); |
4110 | |
|
4111 | 0 | result = dns_dnssec_keyfromrdata(name, &rdata, mctx, &dstkey); |
4112 | 0 | if (result == ISC_R_SUCCESS) { |
4113 | 0 | *tag = dst_key_id(dstkey); |
4114 | 0 | dst_key_free(&dstkey); |
4115 | 0 | } |
4116 | |
|
4117 | 0 | return (result); |
4118 | 0 | } |
4119 | | |
4120 | | /* |
4121 | | * Synth-from-dnssec callbacks to add/delete names from namespace tree. |
4122 | | */ |
4123 | | static void |
4124 | 0 | sfd_add(const dns_name_t *name, void *arg) { |
4125 | 0 | if (arg != NULL) { |
4126 | 0 | dns_view_sfd_add(arg, name); |
4127 | 0 | } |
4128 | 0 | } |
4129 | | |
4130 | | static void |
4131 | 0 | sfd_del(const dns_name_t *name, void *arg) { |
4132 | 0 | if (arg != NULL) { |
4133 | 0 | dns_view_sfd_del(arg, name); |
4134 | 0 | } |
4135 | 0 | } |
4136 | | |
4137 | | /* |
4138 | | * Add key to the security roots. |
4139 | | */ |
4140 | | static void |
4141 | | trust_key(dns_zone_t *zone, dns_name_t *keyname, dns_rdata_dnskey_t *dnskey, |
4142 | 0 | bool initial) { |
4143 | 0 | isc_result_t result; |
4144 | 0 | dns_rdata_t rdata = DNS_RDATA_INIT; |
4145 | 0 | unsigned char data[4096], digest[ISC_MAX_MD_SIZE]; |
4146 | 0 | isc_buffer_t buffer; |
4147 | 0 | dns_keytable_t *sr = NULL; |
4148 | 0 | dns_rdata_ds_t ds; |
4149 | |
|
4150 | 0 | result = dns_view_getsecroots(zone->view, &sr); |
4151 | 0 | if (result != ISC_R_SUCCESS) { |
4152 | 0 | return; |
4153 | 0 | } |
4154 | | |
4155 | | /* Build DS record for key. */ |
4156 | 0 | isc_buffer_init(&buffer, data, sizeof(data)); |
4157 | 0 | dns_rdata_fromstruct(&rdata, dnskey->common.rdclass, |
4158 | 0 | dns_rdatatype_dnskey, dnskey, &buffer); |
4159 | 0 | CHECK(dns_ds_fromkeyrdata(keyname, &rdata, DNS_DSDIGEST_SHA256, digest, |
4160 | 0 | &ds)); |
4161 | 0 | CHECK(dns_keytable_add(sr, true, initial, keyname, &ds, sfd_add, |
4162 | 0 | zone->view)); |
4163 | | |
4164 | 0 | dns_keytable_detach(&sr); |
4165 | |
|
4166 | 0 | failure: |
4167 | 0 | if (sr != NULL) { |
4168 | 0 | dns_keytable_detach(&sr); |
4169 | 0 | } |
4170 | 0 | return; |
4171 | 0 | } |
4172 | | |
4173 | | /* |
4174 | | * Add a null key to the security roots for so that all queries |
4175 | | * to the zone will fail. |
4176 | | */ |
4177 | | static void |
4178 | 0 | fail_secure(dns_zone_t *zone, dns_name_t *keyname) { |
4179 | 0 | isc_result_t result; |
4180 | 0 | dns_keytable_t *sr = NULL; |
4181 | |
|
4182 | 0 | result = dns_view_getsecroots(zone->view, &sr); |
4183 | 0 | if (result == ISC_R_SUCCESS) { |
4184 | 0 | dns_keytable_marksecure(sr, keyname); |
4185 | 0 | dns_keytable_detach(&sr); |
4186 | 0 | } |
4187 | 0 | } |
4188 | | |
4189 | | /* |
4190 | | * Scan a set of KEYDATA records from the key zone. The ones that are |
4191 | | * valid (i.e., the add holddown timer has expired) become trusted keys. |
4192 | | */ |
4193 | | static void |
4194 | 0 | load_secroots(dns_zone_t *zone, dns_name_t *name, dns_rdataset_t *rdataset) { |
4195 | 0 | isc_result_t result; |
4196 | 0 | dns_rdata_t rdata = DNS_RDATA_INIT; |
4197 | 0 | dns_rdata_keydata_t keydata; |
4198 | 0 | dns_rdata_dnskey_t dnskey; |
4199 | 0 | int trusted = 0, revoked = 0, pending = 0; |
4200 | 0 | isc_stdtime_t now = isc_stdtime_now(); |
4201 | 0 | dns_keytable_t *sr = NULL; |
4202 | |
|
4203 | 0 | result = dns_view_getsecroots(zone->view, &sr); |
4204 | 0 | if (result == ISC_R_SUCCESS) { |
4205 | 0 | dns_keytable_delete(sr, name, sfd_del, zone->view); |
4206 | 0 | dns_keytable_detach(&sr); |
4207 | 0 | } |
4208 | | |
4209 | | /* Now insert all the accepted trust anchors from this keydata set. */ |
4210 | 0 | for (result = dns_rdataset_first(rdataset); result == ISC_R_SUCCESS; |
4211 | 0 | result = dns_rdataset_next(rdataset)) |
4212 | 0 | { |
4213 | 0 | dns_rdata_reset(&rdata); |
4214 | 0 | dns_rdataset_current(rdataset, &rdata); |
4215 | | |
4216 | | /* Convert rdata to keydata. */ |
4217 | 0 | result = dns_rdata_tostruct(&rdata, &keydata, NULL); |
4218 | 0 | if (result == ISC_R_NOTIMPLEMENTED) { |
4219 | 0 | continue; |
4220 | 0 | } |
4221 | 0 | RUNTIME_CHECK(result == ISC_R_SUCCESS); |
4222 | | |
4223 | | /* Set the key refresh timer to force a fast refresh. */ |
4224 | 0 | set_refreshkeytimer(zone, &keydata, now, true); |
4225 | | |
4226 | | /* If the removal timer is nonzero, this key was revoked. */ |
4227 | 0 | if (keydata.removehd != 0) { |
4228 | 0 | revoked++; |
4229 | 0 | continue; |
4230 | 0 | } |
4231 | | |
4232 | | /* |
4233 | | * If the add timer is still pending, this key is not |
4234 | | * trusted yet. |
4235 | | */ |
4236 | 0 | if (now < keydata.addhd) { |
4237 | 0 | pending++; |
4238 | 0 | continue; |
4239 | 0 | } |
4240 | | |
4241 | | /* Convert keydata to dnskey. */ |
4242 | 0 | dns_keydata_todnskey(&keydata, &dnskey, NULL); |
4243 | | |
4244 | | /* Add to keytables. */ |
4245 | 0 | trusted++; |
4246 | 0 | trust_key(zone, name, &dnskey, (keydata.addhd == 0)); |
4247 | 0 | } |
4248 | |
|
4249 | 0 | if (trusted == 0 && pending != 0) { |
4250 | 0 | char namebuf[DNS_NAME_FORMATSIZE]; |
4251 | 0 | dns_name_format(name, namebuf, sizeof namebuf); |
4252 | 0 | dnssec_log(zone, ISC_LOG_ERROR, |
4253 | 0 | "No valid trust anchors for '%s'!", namebuf); |
4254 | 0 | dnssec_log(zone, ISC_LOG_ERROR, |
4255 | 0 | "%d key(s) revoked, %d still pending", revoked, |
4256 | 0 | pending); |
4257 | 0 | dnssec_log(zone, ISC_LOG_ERROR, "All queries to '%s' will fail", |
4258 | 0 | namebuf); |
4259 | 0 | fail_secure(zone, name); |
4260 | 0 | } |
4261 | 0 | } |
4262 | | |
4263 | | static isc_result_t |
4264 | | do_one_tuple(dns_difftuple_t **tuple, dns_db_t *db, dns_dbversion_t *ver, |
4265 | 0 | dns_diff_t *diff) { |
4266 | 0 | dns_diff_t temp_diff; |
4267 | 0 | isc_result_t result; |
4268 | | |
4269 | | /* |
4270 | | * Create a singleton diff. |
4271 | | */ |
4272 | 0 | dns_diff_init(diff->mctx, &temp_diff); |
4273 | 0 | ISC_LIST_APPEND(temp_diff.tuples, *tuple, link); |
4274 | | |
4275 | | /* |
4276 | | * Apply it to the database. |
4277 | | */ |
4278 | 0 | result = dns_diff_apply(&temp_diff, db, ver); |
4279 | 0 | ISC_LIST_UNLINK(temp_diff.tuples, *tuple, link); |
4280 | 0 | if (result != ISC_R_SUCCESS) { |
4281 | 0 | dns_difftuple_free(tuple); |
4282 | 0 | return (result); |
4283 | 0 | } |
4284 | | |
4285 | | /* |
4286 | | * Merge it into the current pending journal entry. |
4287 | | */ |
4288 | 0 | dns_diff_appendminimal(diff, tuple); |
4289 | | |
4290 | | /* |
4291 | | * Do not clear temp_diff. |
4292 | | */ |
4293 | 0 | return (ISC_R_SUCCESS); |
4294 | 0 | } |
4295 | | |
4296 | | static isc_result_t |
4297 | | update_one_rr(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff, |
4298 | | dns_diffop_t op, dns_name_t *name, dns_ttl_t ttl, |
4299 | 0 | dns_rdata_t *rdata) { |
4300 | 0 | dns_difftuple_t *tuple = NULL; |
4301 | 0 | isc_result_t result; |
4302 | 0 | result = dns_difftuple_create(diff->mctx, op, name, ttl, rdata, &tuple); |
4303 | 0 | if (result != ISC_R_SUCCESS) { |
4304 | 0 | return (result); |
4305 | 0 | } |
4306 | 0 | return (do_one_tuple(&tuple, db, ver, diff)); |
4307 | 0 | } |
4308 | | |
4309 | | static isc_result_t |
4310 | | update_soa_serial(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, |
4311 | | dns_diff_t *diff, isc_mem_t *mctx, |
4312 | 0 | dns_updatemethod_t method) { |
4313 | 0 | dns_difftuple_t *deltuple = NULL; |
4314 | 0 | dns_difftuple_t *addtuple = NULL; |
4315 | 0 | uint32_t serial; |
4316 | 0 | isc_result_t result; |
4317 | 0 | dns_updatemethod_t used = dns_updatemethod_none; |
4318 | |
|
4319 | 0 | INSIST(method != dns_updatemethod_none); |
4320 | |
|
4321 | 0 | CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_DEL, &deltuple)); |
4322 | 0 | CHECK(dns_difftuple_copy(deltuple, &addtuple)); |
4323 | 0 | addtuple->op = DNS_DIFFOP_ADD; |
4324 | |
|
4325 | 0 | serial = dns_soa_getserial(&addtuple->rdata); |
4326 | 0 | serial = dns_update_soaserial(serial, method, &used); |
4327 | 0 | if (method != used) { |
4328 | 0 | dns_zone_log(zone, ISC_LOG_WARNING, |
4329 | 0 | "update_soa_serial:new serial would be lower than " |
4330 | 0 | "old serial, using increment method instead"); |
4331 | 0 | } |
4332 | 0 | dns_soa_setserial(serial, &addtuple->rdata); |
4333 | 0 | CHECK(do_one_tuple(&deltuple, db, ver, diff)); |
4334 | 0 | CHECK(do_one_tuple(&addtuple, db, ver, diff)); |
4335 | 0 | result = ISC_R_SUCCESS; |
4336 | |
|
4337 | 0 | failure: |
4338 | 0 | if (addtuple != NULL) { |
4339 | 0 | dns_difftuple_free(&addtuple); |
4340 | 0 | } |
4341 | 0 | if (deltuple != NULL) { |
4342 | 0 | dns_difftuple_free(&deltuple); |
4343 | 0 | } |
4344 | 0 | return (result); |
4345 | 0 | } |
4346 | | |
4347 | | /* |
4348 | | * Write all transactions in 'diff' to the zone journal file. |
4349 | | */ |
4350 | | static isc_result_t |
4351 | | zone_journal(dns_zone_t *zone, dns_diff_t *diff, uint32_t *sourceserial, |
4352 | 0 | const char *caller) { |
4353 | 0 | const char *journalfile; |
4354 | 0 | isc_result_t result = ISC_R_SUCCESS; |
4355 | 0 | dns_journal_t *journal = NULL; |
4356 | 0 | unsigned int mode = DNS_JOURNAL_CREATE | DNS_JOURNAL_WRITE; |
4357 | |
|
4358 | 0 | ENTER; |
4359 | 0 | journalfile = dns_zone_getjournal(zone); |
4360 | 0 | if (journalfile != NULL) { |
4361 | 0 | result = dns_journal_open(zone->mctx, journalfile, mode, |
4362 | 0 | &journal); |
4363 | 0 | if (result != ISC_R_SUCCESS) { |
4364 | 0 | dns_zone_log(zone, ISC_LOG_ERROR, |
4365 | 0 | "%s:dns_journal_open -> %s", caller, |
4366 | 0 | isc_result_totext(result)); |
4367 | 0 | return (result); |
4368 | 0 | } |
4369 | | |
4370 | 0 | if (sourceserial != NULL) { |
4371 | 0 | dns_journal_set_sourceserial(journal, *sourceserial); |
4372 | 0 | } |
4373 | |
|
4374 | 0 | result = dns_journal_write_transaction(journal, diff); |
4375 | 0 | if (result != ISC_R_SUCCESS) { |
4376 | 0 | dns_zone_log(zone, ISC_LOG_ERROR, |
4377 | 0 | "%s:dns_journal_write_transaction -> %s", |
4378 | 0 | caller, isc_result_totext(result)); |
4379 | 0 | } |
4380 | 0 | dns_journal_destroy(&journal); |
4381 | 0 | } |
4382 | | |
4383 | 0 | return (result); |
4384 | 0 | } |
4385 | | |
4386 | | /* |
4387 | | * Create an SOA record for a newly-created zone |
4388 | | */ |
4389 | | static isc_result_t |
4390 | 0 | add_soa(dns_zone_t *zone, dns_db_t *db) { |
4391 | 0 | isc_result_t result; |
4392 | 0 | dns_rdata_t rdata = DNS_RDATA_INIT; |
4393 | 0 | unsigned char buf[DNS_SOA_BUFFERSIZE]; |
4394 | 0 | dns_dbversion_t *ver = NULL; |
4395 | 0 | dns_diff_t diff; |
4396 | |
|
4397 | 0 | dns_zone_log(zone, ISC_LOG_DEBUG(1), "creating SOA"); |
4398 | |
|
4399 | 0 | dns_diff_init(zone->mctx, &diff); |
4400 | 0 | result = dns_db_newversion(db, &ver); |
4401 | 0 | if (result != ISC_R_SUCCESS) { |
4402 | 0 | dns_zone_log(zone, ISC_LOG_ERROR, |
4403 | 0 | "add_soa:dns_db_newversion -> %s", |
4404 | 0 | isc_result_totext(result)); |
4405 | 0 | goto failure; |
4406 | 0 | } |
4407 | | |
4408 | | /* Build SOA record */ |
4409 | 0 | result = dns_soa_buildrdata(&zone->origin, dns_rootname, zone->rdclass, |
4410 | 0 | 0, 0, 0, 0, 0, buf, &rdata); |
4411 | 0 | if (result != ISC_R_SUCCESS) { |
4412 | 0 | dns_zone_log(zone, ISC_LOG_ERROR, |
4413 | 0 | "add_soa:dns_soa_buildrdata -> %s", |
4414 | 0 | isc_result_totext(result)); |
4415 | 0 | goto failure; |
4416 | 0 | } |
4417 | | |
4418 | 0 | result = update_one_rr(db, ver, &diff, DNS_DIFFOP_ADD, &zone->origin, 0, |
4419 | 0 | &rdata); |
4420 | |
|
4421 | 0 | failure: |
4422 | 0 | dns_diff_clear(&diff); |
4423 | 0 | if (ver != NULL) { |
4424 | 0 | dns_db_closeversion(db, &ver, (result == ISC_R_SUCCESS)); |
4425 | 0 | } |
4426 | |
|
4427 | 0 | INSIST(ver == NULL); |
4428 | |
|
4429 | 0 | return (result); |
4430 | 0 | } |
4431 | | |
4432 | | struct addifmissing_arg { |
4433 | | dns_db_t *db; |
4434 | | dns_dbversion_t *ver; |
4435 | | dns_diff_t *diff; |
4436 | | dns_zone_t *zone; |
4437 | | bool *changed; |
4438 | | isc_result_t result; |
4439 | | }; |
4440 | | |
4441 | | static void |
4442 | | addifmissing(dns_keytable_t *keytable, dns_keynode_t *keynode, |
4443 | 0 | dns_name_t *keyname, void *arg) { |
4444 | 0 | dns_db_t *db = ((struct addifmissing_arg *)arg)->db; |
4445 | 0 | dns_dbversion_t *ver = ((struct addifmissing_arg *)arg)->ver; |
4446 | 0 | dns_diff_t *diff = ((struct addifmissing_arg *)arg)->diff; |
4447 | 0 | dns_zone_t *zone = ((struct addifmissing_arg *)arg)->zone; |
4448 | 0 | bool *changed = ((struct addifmissing_arg *)arg)->changed; |
4449 | 0 | isc_result_t result; |
4450 | 0 | dns_fixedname_t fname; |
4451 | |
|
4452 | 0 | UNUSED(keytable); |
4453 | |
|
4454 | 0 | if (((struct addifmissing_arg *)arg)->result != ISC_R_SUCCESS) { |
4455 | 0 | return; |
4456 | 0 | } |
4457 | | |
4458 | 0 | if (!dns_keynode_managed(keynode)) { |
4459 | 0 | return; |
4460 | 0 | } |
4461 | | |
4462 | | /* |
4463 | | * If the keynode has no trust anchor set, return. |
4464 | | */ |
4465 | 0 | if (!dns_keynode_dsset(keynode, NULL)) { |
4466 | 0 | return; |
4467 | 0 | } |
4468 | | |
4469 | | /* |
4470 | | * Check whether there's already a KEYDATA entry for this name; |
4471 | | * if so, we don't need to add another. |
4472 | | */ |
4473 | 0 | dns_fixedname_init(&fname); |
4474 | 0 | result = dns_db_find(db, keyname, ver, dns_rdatatype_keydata, |
4475 | 0 | DNS_DBFIND_NOWILD, 0, NULL, |
4476 | 0 | dns_fixedname_name(&fname), NULL, NULL); |
4477 | 0 | if (result == ISC_R_SUCCESS) { |
4478 | 0 | return; |
4479 | 0 | } |
4480 | | |
4481 | | /* |
4482 | | * Create the keydata. |
4483 | | */ |
4484 | 0 | result = create_keydata(zone, db, ver, diff, keynode, keyname, changed); |
4485 | 0 | if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE) { |
4486 | 0 | ((struct addifmissing_arg *)arg)->result = result; |
4487 | 0 | } |
4488 | 0 | } |
4489 | | |
4490 | | /* |
4491 | | * Synchronize the set of initializing keys found in managed-keys {} |
4492 | | * statements with the set of trust anchors found in the managed-keys.bind |
4493 | | * zone. If a domain is no longer named in managed-keys, delete all keys |
4494 | | * from that domain from the key zone. If a domain is configured as an |
4495 | | * initial-key in trust-anchors, but there are no references to it in the |
4496 | | * key zone, load the key zone with the initializing key(s) for that |
4497 | | * domain and schedule a key refresh. If a domain is configured as |
4498 | | * an initial-ds in trust-anchors, fetch the DNSKEY RRset, load the key |
4499 | | * zone with the matching key, and schedule a key refresh. |
4500 | | */ |
4501 | | static isc_result_t |
4502 | 0 | sync_keyzone(dns_zone_t *zone, dns_db_t *db) { |
4503 | 0 | isc_result_t result = ISC_R_SUCCESS; |
4504 | 0 | bool changed = false; |
4505 | 0 | bool commit = false; |
4506 | 0 | dns_keynode_t *keynode = NULL; |
4507 | 0 | dns_view_t *view = zone->view; |
4508 | 0 | dns_keytable_t *sr = NULL; |
4509 | 0 | dns_dbversion_t *ver = NULL; |
4510 | 0 | dns_diff_t diff; |
4511 | 0 | dns_rriterator_t rrit; |
4512 | 0 | struct addifmissing_arg arg; |
4513 | |
|
4514 | 0 | dns_zone_log(zone, ISC_LOG_DEBUG(1), "synchronizing trusted keys"); |
4515 | |
|
4516 | 0 | dns_diff_init(zone->mctx, &diff); |
4517 | |
|
4518 | 0 | CHECK(dns_view_getsecroots(view, &sr)); |
4519 | | |
4520 | 0 | result = dns_db_newversion(db, &ver); |
4521 | 0 | if (result != ISC_R_SUCCESS) { |
4522 | 0 | dnssec_log(zone, ISC_LOG_ERROR, |
4523 | 0 | "sync_keyzone:dns_db_newversion -> %s", |
4524 | 0 | isc_result_totext(result)); |
4525 | 0 | goto failure; |
4526 | 0 | } |
4527 | | |
4528 | | /* |
4529 | | * Walk the zone DB. If we find any keys whose names are no longer |
4530 | | * in trust-anchors, or which have been changed from initial to static, |
4531 | | * (meaning they are permanent and not RFC5011-maintained), delete |
4532 | | * them from the zone. Otherwise call load_secroots(), which |
4533 | | * loads keys into secroots as appropriate. |
4534 | | */ |
4535 | 0 | dns_rriterator_init(&rrit, db, ver, 0); |
4536 | 0 | for (result = dns_rriterator_first(&rrit); result == ISC_R_SUCCESS; |
4537 | 0 | result = dns_rriterator_nextrrset(&rrit)) |
4538 | 0 | { |
4539 | 0 | dns_rdataset_t *rdataset = NULL; |
4540 | 0 | dns_rdata_t rdata = DNS_RDATA_INIT; |
4541 | 0 | dns_rdata_keydata_t keydata; |
4542 | 0 | isc_stdtime_t now = isc_stdtime_now(); |
4543 | 0 | bool load = true; |
4544 | 0 | dns_name_t *rrname = NULL; |
4545 | 0 | uint32_t ttl; |
4546 | |
|
4547 | 0 | dns_rriterator_current(&rrit, &rrname, &ttl, &rdataset, NULL); |
4548 | 0 | if (!dns_rdataset_isassociated(rdataset)) { |
4549 | 0 | dns_rriterator_destroy(&rrit); |
4550 | 0 | goto failure; |
4551 | 0 | } |
4552 | | |
4553 | 0 | if (rdataset->type != dns_rdatatype_keydata) { |
4554 | 0 | continue; |
4555 | 0 | } |
4556 | | |
4557 | | /* |
4558 | | * The managed-keys zone can contain a placeholder instead of |
4559 | | * legitimate data, in which case we will not use it, and we |
4560 | | * will try to refresh it. |
4561 | | */ |
4562 | 0 | for (result = dns_rdataset_first(rdataset); |
4563 | 0 | result == ISC_R_SUCCESS; |
4564 | 0 | result = dns_rdataset_next(rdataset)) |
4565 | 0 | { |
4566 | 0 | isc_result_t iresult; |
4567 | |
|
4568 | 0 | dns_rdata_reset(&rdata); |
4569 | 0 | dns_rdataset_current(rdataset, &rdata); |
4570 | |
|
4571 | 0 | iresult = dns_rdata_tostruct(&rdata, &keydata, NULL); |
4572 | | /* Do we have a valid placeholder KEYDATA record? */ |
4573 | 0 | if (iresult == ISC_R_SUCCESS && keydata.flags == 0 && |
4574 | 0 | keydata.protocol == 0 && keydata.algorithm == 0) |
4575 | 0 | { |
4576 | 0 | set_refreshkeytimer(zone, &keydata, now, true); |
4577 | 0 | load = false; |
4578 | 0 | } |
4579 | 0 | } |
4580 | | |
4581 | | /* |
4582 | | * Release db wrlock to prevent LOR reports against |
4583 | | * dns_keytable_forall() call below. |
4584 | | */ |
4585 | 0 | dns_rriterator_pause(&rrit); |
4586 | 0 | result = dns_keytable_find(sr, rrname, &keynode); |
4587 | 0 | if (result != ISC_R_SUCCESS || !dns_keynode_managed(keynode)) { |
4588 | 0 | CHECK(delete_keydata(db, ver, &diff, rrname, rdataset)); |
4589 | 0 | changed = true; |
4590 | 0 | } else if (load) { |
4591 | 0 | load_secroots(zone, rrname, rdataset); |
4592 | 0 | } |
4593 | | |
4594 | 0 | if (keynode != NULL) { |
4595 | 0 | dns_keynode_detach(&keynode); |
4596 | 0 | } |
4597 | 0 | } |
4598 | 0 | dns_rriterator_destroy(&rrit); |
4599 | | |
4600 | | /* |
4601 | | * Walk secroots to find any initial keys that aren't in |
4602 | | * the zone. If we find any, add them to the zone directly. |
4603 | | * If any DS-style initial keys are found, refresh the key |
4604 | | * zone so that they'll be looked up. |
4605 | | */ |
4606 | 0 | arg.db = db; |
4607 | 0 | arg.ver = ver; |
4608 | 0 | arg.result = ISC_R_SUCCESS; |
4609 | 0 | arg.diff = &diff; |
4610 | 0 | arg.zone = zone; |
4611 | 0 | arg.changed = &changed; |
4612 | 0 | dns_keytable_forall(sr, addifmissing, &arg); |
4613 | 0 | result = arg.result; |
4614 | 0 | if (changed) { |
4615 | | /* Write changes to journal file. */ |
4616 | 0 | CHECK(update_soa_serial(zone, db, ver, &diff, zone->mctx, |
4617 | 0 | zone->updatemethod)); |
4618 | 0 | CHECK(zone_journal(zone, &diff, NULL, "sync_keyzone")); |
4619 | | |
4620 | 0 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED); |
4621 | 0 | zone_needdump(zone, 30); |
4622 | 0 | commit = true; |
4623 | 0 | } |
4624 | | |
4625 | 0 | failure: |
4626 | 0 | if (result != ISC_R_SUCCESS) { |
4627 | 0 | dnssec_log(zone, ISC_LOG_ERROR, |
4628 | 0 | "unable to synchronize managed keys: %s", |
4629 | 0 | isc_result_totext(result)); |
4630 | 0 | isc_time_settoepoch(&zone->refreshkeytime); |
4631 | 0 | } |
4632 | 0 | if (keynode != NULL) { |
4633 | 0 | dns_keynode_detach(&keynode); |
4634 | 0 | } |
4635 | 0 | if (sr != NULL) { |
4636 | 0 | dns_keytable_detach(&sr); |
4637 | 0 | } |
4638 | 0 | if (ver != NULL) { |
4639 | 0 | dns_db_closeversion(db, &ver, commit); |
4640 | 0 | } |
4641 | 0 | dns_diff_clear(&diff); |
4642 | |
|
4643 | 0 | INSIST(ver == NULL); |
4644 | |
|
4645 | 0 | return (result); |
4646 | 0 | } |
4647 | | |
4648 | | isc_result_t |
4649 | 0 | dns_zone_synckeyzone(dns_zone_t *zone) { |
4650 | 0 | isc_result_t result; |
4651 | 0 | dns_db_t *db = NULL; |
4652 | |
|
4653 | 0 | if (zone->type != dns_zone_key) { |
4654 | 0 | return (DNS_R_BADZONE); |
4655 | 0 | } |
4656 | | |
4657 | 0 | CHECK(dns_zone_getdb(zone, &db)); |
4658 | | |
4659 | 0 | LOCK_ZONE(zone); |
4660 | 0 | result = sync_keyzone(zone, db); |
4661 | 0 | UNLOCK_ZONE(zone); |
4662 | |
|
4663 | 0 | failure: |
4664 | 0 | if (db != NULL) { |
4665 | 0 | dns_db_detach(&db); |
4666 | 0 | } |
4667 | 0 | return (result); |
4668 | 0 | } |
4669 | | |
4670 | | static void |
4671 | 0 | maybe_send_secure(dns_zone_t *zone) { |
4672 | 0 | isc_result_t result; |
4673 | | |
4674 | | /* |
4675 | | * We've finished loading, or else failed to load, an inline-signing |
4676 | | * 'secure' zone. We now need information about the status of the |
4677 | | * 'raw' zone. If we failed to load, then we need it to send a |
4678 | | * copy of its database; if we succeeded, we need it to send its |
4679 | | * serial number so that we can sync with it. If it has not yet |
4680 | | * loaded, we set a flag so that it will send the necessary |
4681 | | * information when it has finished loading. |
4682 | | */ |
4683 | 0 | if (zone->raw->db != NULL) { |
4684 | 0 | if (zone->db != NULL) { |
4685 | 0 | uint32_t serial; |
4686 | 0 | unsigned int soacount; |
4687 | |
|
4688 | 0 | result = zone_get_from_db( |
4689 | 0 | zone->raw, zone->raw->db, NULL, &soacount, NULL, |
4690 | 0 | &serial, NULL, NULL, NULL, NULL, NULL); |
4691 | 0 | if (result == ISC_R_SUCCESS && soacount > 0U) { |
4692 | 0 | zone_send_secureserial(zone->raw, serial); |
4693 | 0 | } |
4694 | 0 | } else { |
4695 | 0 | zone_send_securedb(zone->raw, zone->raw->db); |
4696 | 0 | } |
4697 | 0 | } else { |
4698 | 0 | DNS_ZONE_SETFLAG(zone->raw, DNS_ZONEFLG_SENDSECURE); |
4699 | 0 | } |
4700 | 0 | } |
4701 | | |
4702 | | static bool |
4703 | 0 | zone_unchanged(dns_db_t *db1, dns_db_t *db2, isc_mem_t *mctx) { |
4704 | 0 | isc_result_t result; |
4705 | 0 | bool answer = false; |
4706 | 0 | dns_diff_t diff; |
4707 | |
|
4708 | 0 | dns_diff_init(mctx, &diff); |
4709 | 0 | result = dns_db_diffx(&diff, db1, NULL, db2, NULL, NULL); |
4710 | 0 | if (result == ISC_R_SUCCESS && ISC_LIST_EMPTY(diff.tuples)) { |
4711 | 0 | answer = true; |
4712 | 0 | } |
4713 | 0 | dns_diff_clear(&diff); |
4714 | 0 | return (answer); |
4715 | 0 | } |
4716 | | |
4717 | | static void |
4718 | 0 | process_zone_setnsec3param(dns_zone_t *zone) { |
4719 | 0 | struct np3 *npe = NULL; |
4720 | 0 | while ((npe = ISC_LIST_HEAD(zone->setnsec3param_queue)) != NULL) { |
4721 | 0 | ISC_LIST_UNLINK(zone->setnsec3param_queue, npe, link); |
4722 | 0 | zone_iattach(zone, &npe->zone); |
4723 | 0 | isc_async_run(zone->loop, setnsec3param, npe); |
4724 | 0 | } |
4725 | 0 | } |
4726 | | |
4727 | | /* |
4728 | | * The zone is presumed to be locked. |
4729 | | * If this is a inline_raw zone the secure version is also locked. |
4730 | | */ |
4731 | | static isc_result_t |
4732 | | zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, |
4733 | 2 | isc_result_t result) { |
4734 | 2 | unsigned int soacount = 0; |
4735 | 2 | unsigned int nscount = 0; |
4736 | 2 | unsigned int errors = 0; |
4737 | 2 | uint32_t serial, oldserial, refresh, retry, expire, minimum, soattl; |
4738 | 2 | isc_time_t now; |
4739 | 2 | bool needdump = false; |
4740 | 2 | bool fixjournal = false; |
4741 | 2 | bool hasinclude = DNS_ZONE_FLAG(zone, DNS_ZONEFLG_HASINCLUDE); |
4742 | 2 | bool noprimary = false; |
4743 | 2 | bool had_db = false; |
4744 | 2 | dns_include_t *inc; |
4745 | 2 | bool is_dynamic = false; |
4746 | | |
4747 | 2 | INSIST(LOCKED_ZONE(zone)); |
4748 | 2 | if (inline_raw(zone)) { |
4749 | 0 | INSIST(LOCKED_ZONE(zone->secure)); |
4750 | 0 | } |
4751 | | |
4752 | 2 | now = isc_time_now(); |
4753 | | |
4754 | | /* |
4755 | | * Initiate zone transfer? We may need a error code that |
4756 | | * indicates that the "permanent" form does not exist. |
4757 | | * XXX better error feedback to log. |
4758 | | */ |
4759 | 2 | if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE) { |
4760 | 0 | if (zone->type == dns_zone_secondary || |
4761 | 0 | zone->type == dns_zone_mirror || |
4762 | 0 | zone->type == dns_zone_stub || |
4763 | 0 | (zone->type == dns_zone_redirect && |
4764 | 0 | dns_remote_addresses(&zone->primaries) == NULL)) |
4765 | 0 | { |
4766 | 0 | if (result == ISC_R_FILENOTFOUND) { |
4767 | 0 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, |
4768 | 0 | ISC_LOG_DEBUG(1), |
4769 | 0 | "no master file"); |
4770 | 0 | } else if (result != DNS_R_NOMASTERFILE) { |
4771 | 0 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, |
4772 | 0 | ISC_LOG_ERROR, |
4773 | 0 | "loading from master file %s " |
4774 | 0 | "failed: %s", |
4775 | 0 | zone->masterfile, |
4776 | 0 | isc_result_totext(result)); |
4777 | 0 | } |
4778 | 0 | } else if (zone->type == dns_zone_primary && |
4779 | 0 | inline_secure(zone) && result == ISC_R_FILENOTFOUND) |
4780 | 0 | { |
4781 | 0 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, |
4782 | 0 | ISC_LOG_DEBUG(1), |
4783 | 0 | "no master file, requesting db"); |
4784 | 0 | maybe_send_secure(zone); |
4785 | 0 | } else { |
4786 | 0 | int level = ISC_LOG_ERROR; |
4787 | 0 | if (zone->type == dns_zone_key && |
4788 | 0 | result == ISC_R_FILENOTFOUND) |
4789 | 0 | { |
4790 | 0 | level = ISC_LOG_DEBUG(1); |
4791 | 0 | } |
4792 | 0 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, level, |
4793 | 0 | "loading from master file %s failed: %s", |
4794 | 0 | zone->masterfile, |
4795 | 0 | isc_result_totext(result)); |
4796 | 0 | noprimary = true; |
4797 | 0 | } |
4798 | |
|
4799 | 0 | if (zone->type != dns_zone_key) { |
4800 | 0 | goto cleanup; |
4801 | 0 | } |
4802 | 0 | } |
4803 | | |
4804 | 2 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, ISC_LOG_DEBUG(2), |
4805 | 2 | "number of nodes in database: %u", |
4806 | 2 | dns_db_nodecount(db, dns_dbtree_main)); |
4807 | | |
4808 | 2 | if (result == DNS_R_SEENINCLUDE) { |
4809 | 0 | DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_HASINCLUDE); |
4810 | 2 | } else { |
4811 | 2 | DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_HASINCLUDE); |
4812 | 2 | } |
4813 | | |
4814 | | /* |
4815 | | * If there's no master file for a key zone, then the zone is new: |
4816 | | * create an SOA record. (We do this now, instead of later, so that |
4817 | | * if there happens to be a journal file, we can roll forward from |
4818 | | * a sane starting point.) |
4819 | | */ |
4820 | 2 | if (noprimary && zone->type == dns_zone_key) { |
4821 | 0 | result = add_soa(zone, db); |
4822 | 0 | if (result != ISC_R_SUCCESS) { |
4823 | 0 | goto cleanup; |
4824 | 0 | } |
4825 | 0 | } |
4826 | | |
4827 | | /* |
4828 | | * Apply update log, if any, on initial load. |
4829 | | */ |
4830 | 2 | if (zone->journal != NULL && |
4831 | 2 | !DNS_ZONE_OPTION(zone, DNS_ZONEOPT_NOMERGE) && |
4832 | 2 | !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED)) |
4833 | 2 | { |
4834 | 2 | result = zone_journal_rollforward(zone, db, &needdump, |
4835 | 2 | &fixjournal); |
4836 | 2 | if (result != ISC_R_SUCCESS) { |
4837 | 0 | goto cleanup; |
4838 | 0 | } |
4839 | 2 | } |
4840 | | |
4841 | | /* |
4842 | | * Obtain ns, soa and cname counts for top of zone. |
4843 | | */ |
4844 | 2 | INSIST(db != NULL); |
4845 | 2 | result = zone_get_from_db(zone, db, &nscount, &soacount, &soattl, |
4846 | 2 | &serial, &refresh, &retry, &expire, &minimum, |
4847 | 2 | &errors); |
4848 | 2 | if (result != ISC_R_SUCCESS && zone->type != dns_zone_key) { |
4849 | 0 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, ISC_LOG_ERROR, |
4850 | 0 | "could not find NS and/or SOA records"); |
4851 | 0 | } |
4852 | | |
4853 | | /* |
4854 | | * Process any queued NSEC3PARAM change requests. Only for dynamic |
4855 | | * zones, an inline-signing zone will perform this action when |
4856 | | * receiving the secure db (receive_secure_db). |
4857 | | */ |
4858 | 2 | is_dynamic = dns_zone_isdynamic(zone, true); |
4859 | 2 | if (is_dynamic) { |
4860 | 0 | process_zone_setnsec3param(zone); |
4861 | 0 | } |
4862 | | |
4863 | | /* |
4864 | | * Check to make sure the journal is up to date, and remove the |
4865 | | * journal file if it isn't, as we wouldn't be able to apply |
4866 | | * updates otherwise. |
4867 | | */ |
4868 | 2 | if (zone->journal != NULL && is_dynamic && |
4869 | 2 | !DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IXFRFROMDIFFS)) |
4870 | 0 | { |
4871 | 0 | uint32_t jserial; |
4872 | 0 | dns_journal_t *journal = NULL; |
4873 | 0 | bool empty = false; |
4874 | |
|
4875 | 0 | result = dns_journal_open(zone->mctx, zone->journal, |
4876 | 0 | DNS_JOURNAL_READ, &journal); |
4877 | 0 | if (result == ISC_R_SUCCESS) { |
4878 | 0 | jserial = dns_journal_last_serial(journal); |
4879 | 0 | empty = dns_journal_empty(journal); |
4880 | 0 | dns_journal_destroy(&journal); |
4881 | 0 | } else { |
4882 | 0 | jserial = serial; |
4883 | 0 | result = ISC_R_SUCCESS; |
4884 | 0 | } |
4885 | |
|
4886 | 0 | if (jserial != serial) { |
4887 | 0 | if (!empty) { |
4888 | 0 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, |
4889 | 0 | ISC_LOG_INFO, |
4890 | 0 | "journal file is out of date: " |
4891 | 0 | "removing journal file"); |
4892 | 0 | } |
4893 | 0 | if (remove(zone->journal) < 0 && errno != ENOENT) { |
4894 | 0 | char strbuf[ISC_STRERRORSIZE]; |
4895 | 0 | strerror_r(errno, strbuf, sizeof(strbuf)); |
4896 | 0 | isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, |
4897 | 0 | DNS_LOGMODULE_ZONE, |
4898 | 0 | ISC_LOG_WARNING, |
4899 | 0 | "unable to remove journal " |
4900 | 0 | "'%s': '%s'", |
4901 | 0 | zone->journal, strbuf); |
4902 | 0 | } |
4903 | 0 | } |
4904 | 0 | } |
4905 | | |
4906 | 2 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, ISC_LOG_DEBUG(1), |
4907 | 2 | "loaded; checking validity"); |
4908 | | |
4909 | | /* |
4910 | | * Primary / Secondary / Mirror / Stub zones require both NS and SOA |
4911 | | * records at the top of the zone. |
4912 | | */ |
4913 | | |
4914 | 2 | switch (zone->type) { |
4915 | 0 | case dns_zone_dlz: |
4916 | 2 | case dns_zone_primary: |
4917 | 2 | case dns_zone_secondary: |
4918 | 2 | case dns_zone_mirror: |
4919 | 2 | case dns_zone_stub: |
4920 | 2 | case dns_zone_redirect: |
4921 | 2 | if (soacount != 1) { |
4922 | 0 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, |
4923 | 0 | ISC_LOG_ERROR, "has %d SOA records", |
4924 | 0 | soacount); |
4925 | 0 | result = DNS_R_BADZONE; |
4926 | 0 | } |
4927 | 2 | if (nscount == 0) { |
4928 | 0 | dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, |
4929 | 0 | ISC_LOG_ERROR, "has no NS records"); |
4930 | 0 | result = DNS_R_BADZONE; |
4931 | 0 | } |
4932 | 2 | if (result != ISC_R_SUCCESS) { |
4933 | 0 | goto cleanup; |
4934 | 0 | } |
4935 | 2 | if (zone->type == dns_zone_primary && errors != 0) { |
4936 | 0 | result = DNS_R_BADZONE; |
4937 | 0 | goto cleanup; |
4938 | 0 | } |
4939 | 2 | if (zone->type != dns_zone_stub && |
4940 | 2 | zone->type != dns_zone_redirect) |
4941 | 2 | { |
4942 | 2 | result = check_nsec3param(zone, db); |
4943 | 2 | if (result != ISC_R_SUCCESS) { |
4944 | 0 | goto cleanup; |
4945 | 0 | } |
4946 | 2 | } |
4947 | 2 | if (zone->type == dns_zone_primary && |
4948 | 2 | DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKINTEGRITY) && |
4949 | 2 | !integrity_checks(zone, db)) |
4950 | 0 | { |
4951 | 0 | result = DNS_R_BADZONE; |
4952 | 0 | goto cleanup; |
4953 | 0 | } |
4954 | 2 | if (zone->type == dns_zone_primary && |
|