Remove building with NOCRYPTO option
[minix.git] / external / bsd / bind / dist / bin / dnssec / dnssec-signzone.c
blob75e4d9de019e84054f5257ee78af6a12c213fe7c
1 /* $NetBSD: dnssec-signzone.c,v 1.15 2015/07/08 17:28:55 christos Exp $ */
3 /*
4 * Portions Copyright (C) 2004-2015 Internet Systems Consortium, Inc. ("ISC")
5 * Portions Copyright (C) 1999-2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
12 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
13 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE
14 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
17 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 * Portions Copyright (C) 1995-2000 by Network Associates, Inc.
21 * Permission to use, copy, modify, and/or distribute this software for any
22 * purpose with or without fee is hereby granted, provided that the above
23 * copyright notice and this permission notice appear in all copies.
25 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
26 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
27 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE
28 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
29 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
30 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
31 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
34 /*! \file */
36 #include <config.h>
38 #include <stdlib.h>
39 #include <time.h>
40 #include <unistd.h>
42 #include <isc/app.h>
43 #include <isc/base32.h>
44 #include <isc/commandline.h>
45 #include <isc/entropy.h>
46 #include <isc/event.h>
47 #include <isc/file.h>
48 #include <isc/hash.h>
49 #include <isc/hex.h>
50 #include <isc/mem.h>
51 #include <isc/mutex.h>
52 #include <isc/os.h>
53 #include <isc/print.h>
54 #include <isc/random.h>
55 #include <isc/rwlock.h>
56 #include <isc/serial.h>
57 #include <isc/stdio.h>
58 #include <isc/stdlib.h>
59 #include <isc/string.h>
60 #include <isc/task.h>
61 #include <isc/time.h>
62 #include <isc/util.h>
64 #include <dns/db.h>
65 #include <dns/dbiterator.h>
66 #include <dns/diff.h>
67 #include <dns/dnssec.h>
68 #include <dns/ds.h>
69 #include <dns/fixedname.h>
70 #include <dns/keyvalues.h>
71 #include <dns/log.h>
72 #include <dns/master.h>
73 #include <dns/masterdump.h>
74 #include <dns/nsec.h>
75 #include <dns/nsec3.h>
76 #include <dns/rdata.h>
77 #include <dns/rdatalist.h>
78 #include <dns/rdataset.h>
79 #include <dns/rdataclass.h>
80 #include <dns/rdatasetiter.h>
81 #include <dns/rdatastruct.h>
82 #include <dns/rdatatype.h>
83 #include <dns/result.h>
84 #include <dns/soa.h>
85 #include <dns/time.h>
87 #include <dst/dst.h>
89 #ifdef PKCS11CRYPTO
90 #include <pk11/result.h>
91 #endif
93 #include "dnssectool.h"
95 #ifndef PATH_MAX
96 #define PATH_MAX 1024 /* AIX, WIN32, and others don't define this. */
97 #endif
99 const char *program = "dnssec-signzone";
100 int verbose;
102 typedef struct hashlist hashlist_t;
104 static int nsec_datatype = dns_rdatatype_nsec;
106 #define IS_NSEC3 (nsec_datatype == dns_rdatatype_nsec3)
107 #define OPTOUT(x) (((x) & DNS_NSEC3FLAG_OPTOUT) != 0)
109 #define REVOKE(x) ((dst_key_flags(x) & DNS_KEYFLAG_REVOKE) != 0)
111 #define BUFSIZE 2048
112 #define MAXDSKEYS 8
114 #define SIGNER_EVENTCLASS ISC_EVENTCLASS(0x4453)
115 #define SIGNER_EVENT_WRITE (SIGNER_EVENTCLASS + 0)
116 #define SIGNER_EVENT_WORK (SIGNER_EVENTCLASS + 1)
118 #define SOA_SERIAL_KEEP 0
119 #define SOA_SERIAL_INCREMENT 1
120 #define SOA_SERIAL_UNIXTIME 2
122 typedef struct signer_event sevent_t;
123 struct signer_event {
124 ISC_EVENT_COMMON(sevent_t);
125 dns_fixedname_t *fname;
126 dns_dbnode_t *node;
129 static dns_dnsseckeylist_t keylist;
130 static unsigned int keycount = 0;
131 isc_rwlock_t keylist_lock;
132 static isc_stdtime_t starttime = 0, endtime = 0, dnskey_endtime = 0, now;
133 static int cycle = -1;
134 static int jitter = 0;
135 static isc_boolean_t tryverify = ISC_FALSE;
136 static isc_boolean_t printstats = ISC_FALSE;
137 static isc_mem_t *mctx = NULL;
138 static isc_entropy_t *ectx = NULL;
139 static dns_ttl_t zone_soa_min_ttl;
140 static dns_ttl_t soa_ttl;
141 static FILE *outfp = NULL;
142 static char *tempfile = NULL;
143 static const dns_master_style_t *masterstyle;
144 static dns_masterformat_t inputformat = dns_masterformat_text;
145 static dns_masterformat_t outputformat = dns_masterformat_text;
146 static isc_uint32_t rawversion = 1, serialnum = 0;
147 static isc_boolean_t snset = ISC_FALSE;
148 static unsigned int nsigned = 0, nretained = 0, ndropped = 0;
149 static unsigned int nverified = 0, nverifyfailed = 0;
150 static const char *directory = NULL, *dsdir = NULL;
151 static isc_mutex_t namelock, statslock;
152 static isc_taskmgr_t *taskmgr = NULL;
153 static dns_db_t *gdb; /* The database */
154 static dns_dbversion_t *gversion; /* The database version */
155 static dns_dbiterator_t *gdbiter; /* The database iterator */
156 static dns_rdataclass_t gclass; /* The class */
157 static dns_name_t *gorigin; /* The database origin */
158 static int nsec3flags = 0;
159 static dns_iterations_t nsec3iter = 10U;
160 static unsigned char saltbuf[255];
161 static unsigned char *gsalt = saltbuf;
162 static size_t salt_length = 0;
163 static isc_task_t *master = NULL;
164 static unsigned int ntasks = 0;
165 static isc_boolean_t shuttingdown = ISC_FALSE, finished = ISC_FALSE;
166 static isc_boolean_t nokeys = ISC_FALSE;
167 static isc_boolean_t removefile = ISC_FALSE;
168 static isc_boolean_t generateds = ISC_FALSE;
169 static isc_boolean_t ignore_kskflag = ISC_FALSE;
170 static isc_boolean_t keyset_kskonly = ISC_FALSE;
171 static dns_name_t *dlv = NULL;
172 static dns_fixedname_t dlv_fixed;
173 static dns_master_style_t *dsstyle = NULL;
174 static unsigned int serialformat = SOA_SERIAL_KEEP;
175 static unsigned int hash_length = 0;
176 static isc_boolean_t unknownalg = ISC_FALSE;
177 static isc_boolean_t disable_zone_check = ISC_FALSE;
178 static isc_boolean_t update_chain = ISC_FALSE;
179 static isc_boolean_t set_keyttl = ISC_FALSE;
180 static dns_ttl_t keyttl;
181 static isc_boolean_t smartsign = ISC_FALSE;
182 static isc_boolean_t remove_orphansigs = ISC_FALSE;
183 static isc_boolean_t remove_inactkeysigs = ISC_FALSE;
184 static isc_boolean_t output_dnssec_only = ISC_FALSE;
185 static isc_boolean_t output_stdout = ISC_FALSE;
186 isc_boolean_t set_maxttl = ISC_FALSE;
187 static dns_ttl_t maxttl = 0;
189 #define INCSTAT(counter) \
190 if (printstats) { \
191 LOCK(&statslock); \
192 counter++; \
193 UNLOCK(&statslock); \
196 static void
197 sign(isc_task_t *task, isc_event_t *event);
199 static void
200 dumpnode(dns_name_t *name, dns_dbnode_t *node) {
201 dns_rdataset_t rds;
202 dns_rdatasetiter_t *iter = NULL;
203 isc_buffer_t *buffer = NULL;
204 isc_region_t r;
205 isc_result_t result;
206 unsigned bufsize = 4096;
208 if (outputformat != dns_masterformat_text)
209 return;
211 if (!output_dnssec_only) {
212 result = dns_master_dumpnodetostream(mctx, gdb, gversion, node,
213 name, masterstyle, outfp);
214 check_result(result, "dns_master_dumpnodetostream");
215 return;
218 result = dns_db_allrdatasets(gdb, node, gversion, 0, &iter);
219 check_result(result, "dns_db_allrdatasets");
221 dns_rdataset_init(&rds);
223 result = isc_buffer_allocate(mctx, &buffer, bufsize);
224 check_result(result, "isc_buffer_allocate");
226 for (result = dns_rdatasetiter_first(iter);
227 result == ISC_R_SUCCESS;
228 result = dns_rdatasetiter_next(iter)) {
230 dns_rdatasetiter_current(iter, &rds);
232 if (rds.type != dns_rdatatype_rrsig &&
233 rds.type != dns_rdatatype_nsec &&
234 rds.type != dns_rdatatype_nsec3 &&
235 rds.type != dns_rdatatype_nsec3param &&
236 (!smartsign || rds.type != dns_rdatatype_dnskey)) {
237 dns_rdataset_disassociate(&rds);
238 continue;
241 for (;;) {
242 result = dns_master_rdatasettotext(name, &rds,
243 masterstyle, buffer);
244 if (result != ISC_R_NOSPACE)
245 break;
247 bufsize <<= 1;
248 isc_buffer_free(&buffer);
249 result = isc_buffer_allocate(mctx, &buffer, bufsize);
250 check_result(result, "isc_buffer_allocate");
252 check_result(result, "dns_master_rdatasettotext");
254 isc_buffer_usedregion(buffer, &r);
255 result = isc_stdio_write(r.base, 1, r.length, outfp, NULL);
256 check_result(result, "isc_stdio_write");
257 isc_buffer_clear(buffer);
259 dns_rdataset_disassociate(&rds);
262 isc_buffer_free(&buffer);
263 dns_rdatasetiter_destroy(&iter);
267 * Sign the given RRset with given key, and add the signature record to the
268 * given tuple.
270 static void
271 signwithkey(dns_name_t *name, dns_rdataset_t *rdataset, dst_key_t *key,
272 dns_ttl_t ttl, dns_diff_t *add, const char *logmsg)
274 isc_result_t result;
275 isc_stdtime_t jendtime, expiry;
276 char keystr[DST_KEY_FORMATSIZE];
277 dns_rdata_t trdata = DNS_RDATA_INIT;
278 unsigned char array[BUFSIZE];
279 isc_buffer_t b;
280 dns_difftuple_t *tuple;
282 dst_key_format(key, keystr, sizeof(keystr));
283 vbprintf(1, "\t%s %s\n", logmsg, keystr);
285 if (rdataset->type == dns_rdatatype_dnskey)
286 expiry = dnskey_endtime;
287 else
288 expiry = endtime;
290 jendtime = (jitter != 0) ? isc_random_jitter(expiry, jitter) : expiry;
291 isc_buffer_init(&b, array, sizeof(array));
292 result = dns_dnssec_sign(name, rdataset, key, &starttime, &jendtime,
293 mctx, &b, &trdata);
294 isc_entropy_stopcallbacksources(ectx);
295 if (result != ISC_R_SUCCESS) {
296 fatal("dnskey '%s' failed to sign data: %s",
297 keystr, isc_result_totext(result));
299 INCSTAT(nsigned);
301 if (tryverify) {
302 result = dns_dnssec_verify(name, rdataset, key,
303 ISC_TRUE, mctx, &trdata);
304 if (result == ISC_R_SUCCESS) {
305 vbprintf(3, "\tsignature verified\n");
306 INCSTAT(nverified);
307 } else {
308 vbprintf(3, "\tsignature failed to verify\n");
309 INCSTAT(nverifyfailed);
313 tuple = NULL;
314 result = dns_difftuple_create(mctx, DNS_DIFFOP_ADDRESIGN,
315 name, ttl, &trdata, &tuple);
316 check_result(result, "dns_difftuple_create");
317 dns_diff_append(add, &tuple);
320 static inline isc_boolean_t
321 issigningkey(dns_dnsseckey_t *key) {
322 return (key->force_sign || key->hint_sign);
325 static inline isc_boolean_t
326 ispublishedkey(dns_dnsseckey_t *key) {
327 return ((key->force_publish || key->hint_publish) &&
328 !key->hint_remove);
331 static inline isc_boolean_t
332 iszonekey(dns_dnsseckey_t *key) {
333 return (ISC_TF(dns_name_equal(dst_key_name(key->key), gorigin) &&
334 dst_key_iszonekey(key->key)));
337 static inline isc_boolean_t
338 isksk(dns_dnsseckey_t *key) {
339 return (key->ksk);
342 static inline isc_boolean_t
343 iszsk(dns_dnsseckey_t *key) {
344 return (ignore_kskflag || !key->ksk);
348 * Find the key that generated an RRSIG, if it is in the key list. If
349 * so, return a pointer to it, otherwise return NULL.
351 * No locking is performed here, this must be done by the caller.
353 static dns_dnsseckey_t *
354 keythatsigned_unlocked(dns_rdata_rrsig_t *rrsig) {
355 dns_dnsseckey_t *key;
357 for (key = ISC_LIST_HEAD(keylist);
358 key != NULL;
359 key = ISC_LIST_NEXT(key, link)) {
360 if (rrsig->keyid == dst_key_id(key->key) &&
361 rrsig->algorithm == dst_key_alg(key->key) &&
362 dns_name_equal(&rrsig->signer, dst_key_name(key->key)))
363 return (key);
365 return (NULL);
369 * Finds the key that generated a RRSIG, if possible. First look at the keys
370 * that we've loaded already, and then see if there's a key on disk.
372 static dns_dnsseckey_t *
373 keythatsigned(dns_rdata_rrsig_t *rrsig) {
374 isc_result_t result;
375 dst_key_t *pubkey = NULL, *privkey = NULL;
376 dns_dnsseckey_t *key = NULL;
378 isc_rwlock_lock(&keylist_lock, isc_rwlocktype_read);
379 key = keythatsigned_unlocked(rrsig);
380 isc_rwlock_unlock(&keylist_lock, isc_rwlocktype_read);
381 if (key != NULL)
382 return (key);
385 * We did not find the key in our list. Get a write lock now, since
386 * we may be modifying the bits. We could do the tryupgrade() dance,
387 * but instead just get a write lock and check once again to see if
388 * it is on our list. It's possible someone else may have added it
389 * after all.
391 isc_rwlock_lock(&keylist_lock, isc_rwlocktype_write);
392 key = keythatsigned_unlocked(rrsig);
393 if (key != NULL) {
394 isc_rwlock_unlock(&keylist_lock, isc_rwlocktype_write);
395 return (key);
398 result = dst_key_fromfile(&rrsig->signer, rrsig->keyid,
399 rrsig->algorithm, DST_TYPE_PUBLIC,
400 directory, mctx, &pubkey);
401 if (result != ISC_R_SUCCESS) {
402 isc_rwlock_unlock(&keylist_lock, isc_rwlocktype_write);
403 return (NULL);
406 result = dst_key_fromfile(&rrsig->signer, rrsig->keyid,
407 rrsig->algorithm,
408 DST_TYPE_PUBLIC | DST_TYPE_PRIVATE,
409 directory, mctx, &privkey);
410 if (result == ISC_R_SUCCESS) {
411 dst_key_free(&pubkey);
412 result = dns_dnsseckey_create(mctx, &privkey, &key);
413 } else
414 result = dns_dnsseckey_create(mctx, &pubkey, &key);
416 if (result == ISC_R_SUCCESS) {
417 key->force_publish = ISC_FALSE;
418 key->force_sign = ISC_FALSE;
419 key->index = keycount++;
420 ISC_LIST_APPEND(keylist, key, link);
423 isc_rwlock_unlock(&keylist_lock, isc_rwlocktype_write);
424 return (key);
428 * Check to see if we expect to find a key at this name. If we see a RRSIG
429 * and can't find the signing key that we expect to find, we drop the rrsig.
430 * I'm not sure if this is completely correct, but it seems to work.
432 static isc_boolean_t
433 expecttofindkey(dns_name_t *name) {
434 unsigned int options = DNS_DBFIND_NOWILD;
435 dns_fixedname_t fname;
436 isc_result_t result;
437 char namestr[DNS_NAME_FORMATSIZE];
439 dns_fixedname_init(&fname);
440 result = dns_db_find(gdb, name, gversion, dns_rdatatype_dnskey, options,
441 0, NULL, dns_fixedname_name(&fname), NULL, NULL);
442 switch (result) {
443 case ISC_R_SUCCESS:
444 case DNS_R_NXDOMAIN:
445 case DNS_R_NXRRSET:
446 return (ISC_TRUE);
447 case DNS_R_DELEGATION:
448 case DNS_R_CNAME:
449 case DNS_R_DNAME:
450 return (ISC_FALSE);
452 dns_name_format(name, namestr, sizeof(namestr));
453 fatal("failure looking for '%s DNSKEY' in database: %s",
454 namestr, isc_result_totext(result));
455 /* NOTREACHED */
456 return (ISC_FALSE); /* removes a warning */
459 static inline isc_boolean_t
460 setverifies(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
461 dns_rdata_t *rrsig)
463 isc_result_t result;
464 result = dns_dnssec_verify(name, set, key, ISC_FALSE, mctx, rrsig);
465 if (result == ISC_R_SUCCESS) {
466 INCSTAT(nverified);
467 return (ISC_TRUE);
468 } else {
469 INCSTAT(nverifyfailed);
470 return (ISC_FALSE);
475 * Signs a set. Goes through contortions to decide if each RRSIG should
476 * be dropped or retained, and then determines if any new SIGs need to
477 * be generated.
479 static void
480 signset(dns_diff_t *del, dns_diff_t *add, dns_dbnode_t *node, dns_name_t *name,
481 dns_rdataset_t *set)
483 dns_rdataset_t sigset;
484 dns_rdata_t sigrdata = DNS_RDATA_INIT;
485 dns_rdata_rrsig_t rrsig;
486 dns_dnsseckey_t *key;
487 isc_result_t result;
488 isc_boolean_t nosigs = ISC_FALSE;
489 isc_boolean_t *wassignedby, *nowsignedby;
490 int arraysize;
491 dns_difftuple_t *tuple;
492 dns_ttl_t ttl;
493 int i;
494 char namestr[DNS_NAME_FORMATSIZE];
495 char typestr[TYPE_FORMATSIZE];
496 char sigstr[SIG_FORMATSIZE];
498 dns_name_format(name, namestr, sizeof(namestr));
499 type_format(set->type, typestr, sizeof(typestr));
501 ttl = ISC_MIN(set->ttl, endtime - starttime);
503 dns_rdataset_init(&sigset);
504 result = dns_db_findrdataset(gdb, node, gversion, dns_rdatatype_rrsig,
505 set->type, 0, &sigset, NULL);
506 if (result == ISC_R_NOTFOUND) {
507 vbprintf(2, "no existing signatures for %s/%s\n",
508 namestr, typestr);
509 result = ISC_R_SUCCESS;
510 nosigs = ISC_TRUE;
512 if (result != ISC_R_SUCCESS)
513 fatal("failed while looking for '%s RRSIG %s': %s",
514 namestr, typestr, isc_result_totext(result));
516 vbprintf(1, "%s/%s:\n", namestr, typestr);
518 arraysize = keycount;
519 if (!nosigs)
520 arraysize += dns_rdataset_count(&sigset);
521 wassignedby = isc_mem_get(mctx, arraysize * sizeof(isc_boolean_t));
522 nowsignedby = isc_mem_get(mctx, arraysize * sizeof(isc_boolean_t));
523 if (wassignedby == NULL || nowsignedby == NULL)
524 fatal("out of memory");
526 for (i = 0; i < arraysize; i++)
527 wassignedby[i] = nowsignedby[i] = ISC_FALSE;
529 if (nosigs)
530 result = ISC_R_NOMORE;
531 else
532 result = dns_rdataset_first(&sigset);
534 while (result == ISC_R_SUCCESS) {
535 isc_boolean_t expired, future;
536 isc_boolean_t keep = ISC_FALSE, resign = ISC_FALSE;
538 dns_rdataset_current(&sigset, &sigrdata);
540 result = dns_rdata_tostruct(&sigrdata, &rrsig, NULL);
541 check_result(result, "dns_rdata_tostruct");
543 future = isc_serial_lt(now, rrsig.timesigned);
545 key = keythatsigned(&rrsig);
546 sig_format(&rrsig, sigstr, sizeof(sigstr));
547 if (key != NULL && issigningkey(key))
548 expired = isc_serial_gt(now + cycle, rrsig.timeexpire);
549 else
550 expired = isc_serial_gt(now, rrsig.timeexpire);
552 if (isc_serial_gt(rrsig.timesigned, rrsig.timeexpire)) {
553 /* rrsig is dropped and not replaced */
554 vbprintf(2, "\trrsig by %s dropped - "
555 "invalid validity period\n",
556 sigstr);
557 } else if (key == NULL && !future &&
558 expecttofindkey(&rrsig.signer)) {
559 /* rrsig is dropped and not replaced */
560 vbprintf(2, "\trrsig by %s dropped - "
561 "private dnskey not found\n",
562 sigstr);
563 } else if (key == NULL || future) {
564 keep = (!expired && !remove_orphansigs);
565 vbprintf(2, "\trrsig by %s %s - dnskey not found\n",
566 keep ? "retained" : "dropped", sigstr);
567 } else if (!dns_dnssec_keyactive(key->key, now) &&
568 remove_inactkeysigs) {
569 keep = ISC_FALSE;
570 vbprintf(2, "\trrsig by %s dropped - key inactive\n",
571 sigstr);
572 } else if (issigningkey(key)) {
573 wassignedby[key->index] = ISC_TRUE;
575 if (!expired && rrsig.originalttl == set->ttl &&
576 setverifies(name, set, key->key, &sigrdata)) {
577 vbprintf(2, "\trrsig by %s retained\n", sigstr);
578 keep = ISC_TRUE;
579 } else {
580 vbprintf(2, "\trrsig by %s dropped - %s\n",
581 sigstr, expired ? "expired" :
582 rrsig.originalttl != set->ttl ?
583 "ttl change" : "failed to verify");
584 resign = ISC_TRUE;
586 } else if (!ispublishedkey(key) && remove_orphansigs) {
587 vbprintf(2, "\trrsig by %s dropped - dnskey removed\n",
588 sigstr);
589 } else if (iszonekey(key)) {
590 wassignedby[key->index] = ISC_TRUE;
592 if (!expired && rrsig.originalttl == set->ttl &&
593 setverifies(name, set, key->key, &sigrdata)) {
594 vbprintf(2, "\trrsig by %s retained\n", sigstr);
595 keep = ISC_TRUE;
596 } else {
597 vbprintf(2, "\trrsig by %s dropped - %s\n",
598 sigstr, expired ? "expired" :
599 rrsig.originalttl != set->ttl ?
600 "ttl change" : "failed to verify");
602 } else if (!expired) {
603 vbprintf(2, "\trrsig by %s retained\n", sigstr);
604 keep = ISC_TRUE;
605 } else {
606 vbprintf(2, "\trrsig by %s expired\n", sigstr);
609 if (keep) {
610 if (key != NULL)
611 nowsignedby[key->index] = ISC_TRUE;
612 INCSTAT(nretained);
613 if (sigset.ttl != ttl) {
614 vbprintf(2, "\tfixing ttl %s\n", sigstr);
615 tuple = NULL;
616 result = dns_difftuple_create(mctx,
617 DNS_DIFFOP_DELRESIGN,
618 name, sigset.ttl,
619 &sigrdata, &tuple);
620 check_result(result, "dns_difftuple_create");
621 dns_diff_append(del, &tuple);
622 result = dns_difftuple_create(mctx,
623 DNS_DIFFOP_ADDRESIGN,
624 name, ttl,
625 &sigrdata, &tuple);
626 check_result(result, "dns_difftuple_create");
627 dns_diff_append(add, &tuple);
629 } else {
630 tuple = NULL;
631 vbprintf(2, "removing signature by %s\n", sigstr);
632 result = dns_difftuple_create(mctx,
633 DNS_DIFFOP_DELRESIGN,
634 name, sigset.ttl,
635 &sigrdata, &tuple);
636 check_result(result, "dns_difftuple_create");
637 dns_diff_append(del, &tuple);
638 INCSTAT(ndropped);
641 if (resign) {
642 INSIST(!keep);
644 signwithkey(name, set, key->key, ttl, add,
645 "resigning with dnskey");
646 nowsignedby[key->index] = ISC_TRUE;
649 dns_rdata_reset(&sigrdata);
650 dns_rdata_freestruct(&rrsig);
651 result = dns_rdataset_next(&sigset);
653 if (result == ISC_R_NOMORE)
654 result = ISC_R_SUCCESS;
656 check_result(result, "dns_rdataset_first/next");
657 if (dns_rdataset_isassociated(&sigset))
658 dns_rdataset_disassociate(&sigset);
660 for (key = ISC_LIST_HEAD(keylist);
661 key != NULL;
662 key = ISC_LIST_NEXT(key, link))
664 if (nowsignedby[key->index])
665 continue;
667 if (!issigningkey(key))
668 continue;
670 if (set->type == dns_rdatatype_dnskey &&
671 dns_name_equal(name, gorigin)) {
672 isc_boolean_t have_ksk;
673 dns_dnsseckey_t *tmpkey;
675 have_ksk = isksk(key);
676 for (tmpkey = ISC_LIST_HEAD(keylist);
677 tmpkey != NULL;
678 tmpkey = ISC_LIST_NEXT(tmpkey, link)) {
679 if (dst_key_alg(key->key) !=
680 dst_key_alg(tmpkey->key))
681 continue;
682 if (REVOKE(tmpkey->key))
683 continue;
684 if (isksk(tmpkey))
685 have_ksk = ISC_TRUE;
687 if (isksk(key) || !have_ksk ||
688 (iszsk(key) && !keyset_kskonly))
689 signwithkey(name, set, key->key, ttl, add,
690 "signing with dnskey");
691 } else if (iszsk(key)) {
692 signwithkey(name, set, key->key, ttl, add,
693 "signing with dnskey");
697 isc_mem_put(mctx, wassignedby, arraysize * sizeof(isc_boolean_t));
698 isc_mem_put(mctx, nowsignedby, arraysize * sizeof(isc_boolean_t));
701 struct hashlist {
702 unsigned char *hashbuf;
703 size_t entries;
704 size_t size;
705 size_t length;
708 static void
709 hashlist_init(hashlist_t *l, unsigned int nodes, unsigned int length) {
711 l->entries = 0;
712 l->length = length + 1;
714 if (nodes != 0) {
715 l->size = nodes;
716 l->hashbuf = malloc(l->size * l->length);
717 if (l->hashbuf == NULL)
718 l->size = 0;
719 } else {
720 l->size = 0;
721 l->hashbuf = NULL;
725 static void
726 hashlist_add(hashlist_t *l, const unsigned char *hash, size_t len)
729 REQUIRE(len <= l->length);
731 if (l->entries == l->size) {
732 l->size = l->size * 2 + 100;
733 l->hashbuf = realloc(l->hashbuf, l->size * l->length);
734 if (l->hashbuf == NULL)
735 fatal("unable to grow hashlist: out of memory");
737 memset(l->hashbuf + l->entries * l->length, 0, l->length);
738 memmove(l->hashbuf + l->entries * l->length, hash, len);
739 l->entries++;
742 static void
743 hashlist_add_dns_name(hashlist_t *l, /*const*/ dns_name_t *name,
744 unsigned int hashalg, unsigned int iterations,
745 const unsigned char *salt, size_t salt_len,
746 isc_boolean_t speculative)
748 char nametext[DNS_NAME_FORMATSIZE];
749 unsigned char hash[NSEC3_MAX_HASH_LENGTH + 1];
750 unsigned int len;
751 size_t i;
753 len = isc_iterated_hash(hash, hashalg, iterations,
754 salt, (int)salt_len,
755 name->ndata, name->length);
756 if (verbose) {
757 dns_name_format(name, nametext, sizeof nametext);
758 for (i = 0 ; i < len; i++)
759 fprintf(stderr, "%02x", hash[i]);
760 fprintf(stderr, " %s\n", nametext);
762 hash[len++] = speculative ? 1 : 0;
763 hashlist_add(l, hash, len);
766 static int
767 hashlist_comp(const void *a, const void *b) {
768 return (memcmp(a, b, hash_length + 1));
771 static void
772 hashlist_sort(hashlist_t *l) {
773 qsort(l->hashbuf, l->entries, l->length, hashlist_comp);
776 static isc_boolean_t
777 hashlist_hasdup(hashlist_t *l) {
778 unsigned char *current;
779 unsigned char *next = l->hashbuf;
780 size_t entries = l->entries;
783 * Skip initial speculative wild card hashs.
785 while (entries > 0U && next[l->length-1] != 0U) {
786 next += l->length;
787 entries--;
790 current = next;
791 while (entries-- > 1U) {
792 next += l->length;
793 if (next[l->length-1] != 0)
794 continue;
795 if (memcmp(current, next, l->length - 1) == 0)
796 return (ISC_TRUE);
797 current = next;
799 return (ISC_FALSE);
802 static const unsigned char *
803 hashlist_findnext(const hashlist_t *l,
804 const unsigned char hash[NSEC3_MAX_HASH_LENGTH])
806 size_t entries = l->entries;
807 const unsigned char *next = bsearch(hash, l->hashbuf, l->entries,
808 l->length, hashlist_comp);
809 INSIST(next != NULL);
811 do {
812 if (next < l->hashbuf + (l->entries - 1) * l->length)
813 next += l->length;
814 else
815 next = l->hashbuf;
816 if (next[l->length - 1] == 0)
817 break;
818 } while (entries-- > 1U);
819 INSIST(entries != 0U);
820 return (next);
823 static isc_boolean_t
824 hashlist_exists(const hashlist_t *l,
825 const unsigned char hash[NSEC3_MAX_HASH_LENGTH])
827 if (bsearch(hash, l->hashbuf, l->entries, l->length, hashlist_comp))
828 return (ISC_TRUE);
829 else
830 return (ISC_FALSE);
833 static void
834 addnowildcardhash(hashlist_t *l, /*const*/ dns_name_t *name,
835 unsigned int hashalg, unsigned int iterations,
836 const unsigned char *salt, size_t salt_len)
838 dns_fixedname_t fixed;
839 dns_name_t *wild;
840 dns_dbnode_t *node = NULL;
841 isc_result_t result;
842 char namestr[DNS_NAME_FORMATSIZE];
844 dns_fixedname_init(&fixed);
845 wild = dns_fixedname_name(&fixed);
847 result = dns_name_concatenate(dns_wildcardname, name, wild, NULL);
848 if (result == ISC_R_NOSPACE)
849 return;
850 check_result(result,"addnowildcardhash: dns_name_concatenate()");
852 result = dns_db_findnode(gdb, wild, ISC_FALSE, &node);
853 if (result == ISC_R_SUCCESS) {
854 dns_db_detachnode(gdb, &node);
855 return;
858 if (verbose) {
859 dns_name_format(wild, namestr, sizeof(namestr));
860 fprintf(stderr, "adding no-wildcardhash for %s\n", namestr);
863 hashlist_add_dns_name(l, wild, hashalg, iterations, salt, salt_len,
864 ISC_TRUE);
867 static void
868 opendb(const char *prefix, dns_name_t *name, dns_rdataclass_t rdclass,
869 dns_db_t **dbp)
871 char filename[PATH_MAX];
872 isc_buffer_t b;
873 isc_result_t result;
875 isc_buffer_init(&b, filename, sizeof(filename));
876 if (dsdir != NULL) {
877 /* allow room for a trailing slash */
878 if (strlen(dsdir) >= isc_buffer_availablelength(&b))
879 fatal("path '%s' is too long", dsdir);
880 isc_buffer_putstr(&b, dsdir);
881 if (dsdir[strlen(dsdir) - 1] != '/')
882 isc_buffer_putstr(&b, "/");
884 if (strlen(prefix) > isc_buffer_availablelength(&b))
885 fatal("path '%s' is too long", dsdir);
886 isc_buffer_putstr(&b, prefix);
887 result = dns_name_tofilenametext(name, ISC_FALSE, &b);
888 check_result(result, "dns_name_tofilenametext()");
889 if (isc_buffer_availablelength(&b) == 0) {
890 char namestr[DNS_NAME_FORMATSIZE];
891 dns_name_format(name, namestr, sizeof(namestr));
892 fatal("name '%s' is too long", namestr);
894 isc_buffer_putuint8(&b, 0);
896 result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone,
897 rdclass, 0, NULL, dbp);
898 check_result(result, "dns_db_create()");
900 result = dns_db_load3(*dbp, filename, inputformat, DNS_MASTER_HINT);
901 if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE)
902 dns_db_detach(dbp);
906 * Load the DS set for a child zone, if a dsset-* file can be found.
907 * If not, try to find a keyset-* file from an earlier version of
908 * dnssec-signzone, and build DS records from that.
910 static isc_result_t
911 loadds(dns_name_t *name, isc_uint32_t ttl, dns_rdataset_t *dsset) {
912 dns_db_t *db = NULL;
913 dns_dbversion_t *ver = NULL;
914 dns_dbnode_t *node = NULL;
915 isc_result_t result;
916 dns_rdataset_t keyset;
917 dns_rdata_t key, ds;
918 unsigned char dsbuf[DNS_DS_BUFFERSIZE];
919 dns_diff_t diff;
920 dns_difftuple_t *tuple = NULL;
922 opendb("dsset-", name, gclass, &db);
923 if (db != NULL) {
924 result = dns_db_findnode(db, name, ISC_FALSE, &node);
925 if (result == ISC_R_SUCCESS) {
926 dns_rdataset_init(dsset);
927 result = dns_db_findrdataset(db, node, NULL,
928 dns_rdatatype_ds, 0, 0,
929 dsset, NULL);
930 dns_db_detachnode(db, &node);
931 if (result == ISC_R_SUCCESS) {
932 vbprintf(2, "found DS records\n");
933 dsset->ttl = ttl;
934 dns_db_detach(&db);
935 return (result);
938 dns_db_detach(&db);
941 /* No DS records found; try again, looking for DNSKEY records */
942 opendb("keyset-", name, gclass, &db);
943 if (db == NULL) {
944 return (ISC_R_NOTFOUND);
947 result = dns_db_findnode(db, name, ISC_FALSE, &node);
948 if (result != ISC_R_SUCCESS) {
949 dns_db_detach(&db);
950 return (result);
953 dns_rdataset_init(&keyset);
954 result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_dnskey, 0, 0,
955 &keyset, NULL);
956 if (result != ISC_R_SUCCESS) {
957 dns_db_detachnode(db, &node);
958 dns_db_detach(&db);
959 return (result);
961 vbprintf(2, "found DNSKEY records\n");
963 result = dns_db_newversion(db, &ver);
964 check_result(result, "dns_db_newversion");
965 dns_diff_init(mctx, &diff);
967 for (result = dns_rdataset_first(&keyset);
968 result == ISC_R_SUCCESS;
969 result = dns_rdataset_next(&keyset))
971 dns_rdata_init(&key);
972 dns_rdata_init(&ds);
973 dns_rdataset_current(&keyset, &key);
974 result = dns_ds_buildrdata(name, &key, DNS_DSDIGEST_SHA1,
975 dsbuf, &ds);
976 check_result(result, "dns_ds_buildrdata");
978 result = dns_difftuple_create(mctx, DNS_DIFFOP_ADDRESIGN, name,
979 ttl, &ds, &tuple);
980 check_result(result, "dns_difftuple_create");
981 dns_diff_append(&diff, &tuple);
983 dns_rdata_reset(&ds);
984 result = dns_ds_buildrdata(name, &key, DNS_DSDIGEST_SHA256,
985 dsbuf, &ds);
986 check_result(result, "dns_ds_buildrdata");
988 result = dns_difftuple_create(mctx, DNS_DIFFOP_ADDRESIGN, name,
989 ttl, &ds, &tuple);
990 check_result(result, "dns_difftuple_create");
991 dns_diff_append(&diff, &tuple);
994 result = dns_diff_apply(&diff, db, ver);
995 check_result(result, "dns_diff_apply");
996 dns_diff_clear(&diff);
998 dns_db_closeversion(db, &ver, ISC_TRUE);
1000 result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_ds, 0, 0,
1001 dsset, NULL);
1002 check_result(result, "dns_db_findrdataset");
1004 dns_rdataset_disassociate(&keyset);
1005 dns_db_detachnode(db, &node);
1006 dns_db_detach(&db);
1007 return (result);
1010 static isc_boolean_t
1011 secure(dns_name_t *name, dns_dbnode_t *node) {
1012 dns_rdataset_t dsset;
1013 isc_result_t result;
1015 if (dns_name_equal(name, gorigin))
1016 return (ISC_FALSE);
1018 dns_rdataset_init(&dsset);
1019 result = dns_db_findrdataset(gdb, node, gversion, dns_rdatatype_ds,
1020 0, 0, &dsset, NULL);
1021 if (dns_rdataset_isassociated(&dsset))
1022 dns_rdataset_disassociate(&dsset);
1024 return (ISC_TF(result == ISC_R_SUCCESS));
1028 * Signs all records at a name.
1030 static void
1031 signname(dns_dbnode_t *node, dns_name_t *name) {
1032 isc_result_t result;
1033 dns_rdataset_t rdataset;
1034 dns_rdatasetiter_t *rdsiter;
1035 isc_boolean_t isdelegation = ISC_FALSE;
1036 dns_diff_t del, add;
1037 char namestr[DNS_NAME_FORMATSIZE];
1039 dns_rdataset_init(&rdataset);
1040 dns_name_format(name, namestr, sizeof(namestr));
1043 * Determine if this is a delegation point.
1045 if (is_delegation(gdb, gversion, gorigin, name, node, NULL))
1046 isdelegation = ISC_TRUE;
1049 * Now iterate through the rdatasets.
1051 dns_diff_init(mctx, &del);
1052 dns_diff_init(mctx, &add);
1053 rdsiter = NULL;
1054 result = dns_db_allrdatasets(gdb, node, gversion, 0, &rdsiter);
1055 check_result(result, "dns_db_allrdatasets()");
1056 result = dns_rdatasetiter_first(rdsiter);
1057 while (result == ISC_R_SUCCESS) {
1058 dns_rdatasetiter_current(rdsiter, &rdataset);
1060 /* If this is a RRSIG set, skip it. */
1061 if (rdataset.type == dns_rdatatype_rrsig)
1062 goto skip;
1065 * If this name is a delegation point, skip all records
1066 * except NSEC and DS sets. Otherwise check that there
1067 * isn't a DS record.
1069 if (isdelegation) {
1070 if (rdataset.type != nsec_datatype &&
1071 rdataset.type != dns_rdatatype_ds)
1072 goto skip;
1073 } else if (rdataset.type == dns_rdatatype_ds) {
1074 char namebuf[DNS_NAME_FORMATSIZE];
1075 dns_name_format(name, namebuf, sizeof(namebuf));
1076 fatal("'%s': found DS RRset without NS RRset\n",
1077 namebuf);
1080 signset(&del, &add, node, name, &rdataset);
1082 skip:
1083 dns_rdataset_disassociate(&rdataset);
1084 result = dns_rdatasetiter_next(rdsiter);
1086 if (result != ISC_R_NOMORE)
1087 fatal("rdataset iteration for name '%s' failed: %s",
1088 namestr, isc_result_totext(result));
1090 dns_rdatasetiter_destroy(&rdsiter);
1092 result = dns_diff_applysilently(&del, gdb, gversion);
1093 if (result != ISC_R_SUCCESS)
1094 fatal("failed to delete SIGs at node '%s': %s",
1095 namestr, isc_result_totext(result));
1097 result = dns_diff_applysilently(&add, gdb, gversion);
1098 if (result != ISC_R_SUCCESS)
1099 fatal("failed to add SIGs at node '%s': %s",
1100 namestr, isc_result_totext(result));
1102 dns_diff_clear(&del);
1103 dns_diff_clear(&add);
1106 static inline isc_boolean_t
1107 active_node(dns_dbnode_t *node) {
1108 dns_rdatasetiter_t *rdsiter = NULL;
1109 dns_rdatasetiter_t *rdsiter2 = NULL;
1110 isc_boolean_t active = ISC_FALSE;
1111 isc_result_t result;
1112 dns_rdataset_t rdataset;
1113 dns_rdatatype_t type;
1114 dns_rdatatype_t covers;
1115 isc_boolean_t found;
1117 dns_rdataset_init(&rdataset);
1118 result = dns_db_allrdatasets(gdb, node, gversion, 0, &rdsiter);
1119 check_result(result, "dns_db_allrdatasets()");
1120 result = dns_rdatasetiter_first(rdsiter);
1121 while (result == ISC_R_SUCCESS) {
1122 dns_rdatasetiter_current(rdsiter, &rdataset);
1123 if (rdataset.type != dns_rdatatype_nsec &&
1124 rdataset.type != dns_rdatatype_nsec3 &&
1125 rdataset.type != dns_rdatatype_rrsig)
1126 active = ISC_TRUE;
1127 dns_rdataset_disassociate(&rdataset);
1128 if (!active)
1129 result = dns_rdatasetiter_next(rdsiter);
1130 else
1131 result = ISC_R_NOMORE;
1133 if (result != ISC_R_NOMORE)
1134 fatal("rdataset iteration failed: %s",
1135 isc_result_totext(result));
1137 if (!active && nsec_datatype == dns_rdatatype_nsec) {
1139 * The node is empty of everything but NSEC / RRSIG records.
1141 for (result = dns_rdatasetiter_first(rdsiter);
1142 result == ISC_R_SUCCESS;
1143 result = dns_rdatasetiter_next(rdsiter)) {
1144 dns_rdatasetiter_current(rdsiter, &rdataset);
1145 result = dns_db_deleterdataset(gdb, node, gversion,
1146 rdataset.type,
1147 rdataset.covers);
1148 check_result(result, "dns_db_deleterdataset()");
1149 dns_rdataset_disassociate(&rdataset);
1151 if (result != ISC_R_NOMORE)
1152 fatal("rdataset iteration failed: %s",
1153 isc_result_totext(result));
1154 } else {
1156 * Delete RRSIGs for types that no longer exist.
1158 result = dns_db_allrdatasets(gdb, node, gversion, 0, &rdsiter2);
1159 check_result(result, "dns_db_allrdatasets()");
1160 for (result = dns_rdatasetiter_first(rdsiter);
1161 result == ISC_R_SUCCESS;
1162 result = dns_rdatasetiter_next(rdsiter)) {
1163 dns_rdatasetiter_current(rdsiter, &rdataset);
1164 type = rdataset.type;
1165 covers = rdataset.covers;
1166 dns_rdataset_disassociate(&rdataset);
1168 * Delete the NSEC chain if we are signing with
1169 * NSEC3.
1171 if (nsec_datatype == dns_rdatatype_nsec3 &&
1172 (type == dns_rdatatype_nsec ||
1173 covers == dns_rdatatype_nsec)) {
1174 result = dns_db_deleterdataset(gdb, node,
1175 gversion, type,
1176 covers);
1177 check_result(result,
1178 "dns_db_deleterdataset(nsec/rrsig)");
1179 continue;
1181 if (type != dns_rdatatype_rrsig)
1182 continue;
1183 found = ISC_FALSE;
1184 for (result = dns_rdatasetiter_first(rdsiter2);
1185 !found && result == ISC_R_SUCCESS;
1186 result = dns_rdatasetiter_next(rdsiter2)) {
1187 dns_rdatasetiter_current(rdsiter2, &rdataset);
1188 if (rdataset.type == covers)
1189 found = ISC_TRUE;
1190 dns_rdataset_disassociate(&rdataset);
1192 if (!found) {
1193 if (result != ISC_R_NOMORE)
1194 fatal("rdataset iteration failed: %s",
1195 isc_result_totext(result));
1196 result = dns_db_deleterdataset(gdb, node,
1197 gversion, type,
1198 covers);
1199 check_result(result,
1200 "dns_db_deleterdataset(rrsig)");
1201 } else if (result != ISC_R_NOMORE &&
1202 result != ISC_R_SUCCESS)
1203 fatal("rdataset iteration failed: %s",
1204 isc_result_totext(result));
1206 if (result != ISC_R_NOMORE)
1207 fatal("rdataset iteration failed: %s",
1208 isc_result_totext(result));
1209 dns_rdatasetiter_destroy(&rdsiter2);
1211 dns_rdatasetiter_destroy(&rdsiter);
1213 return (active);
1217 * Extracts the minimum TTL from the SOA record, and the SOA record's TTL.
1219 static void
1220 get_soa_ttls(void) {
1221 dns_rdataset_t soaset;
1222 dns_fixedname_t fname;
1223 dns_name_t *name;
1224 isc_result_t result;
1225 dns_rdata_t rdata = DNS_RDATA_INIT;
1227 dns_fixedname_init(&fname);
1228 name = dns_fixedname_name(&fname);
1229 dns_rdataset_init(&soaset);
1230 result = dns_db_find(gdb, gorigin, gversion, dns_rdatatype_soa,
1231 0, 0, NULL, name, &soaset, NULL);
1232 if (result != ISC_R_SUCCESS)
1233 fatal("failed to find an SOA at the zone apex: %s",
1234 isc_result_totext(result));
1236 result = dns_rdataset_first(&soaset);
1237 check_result(result, "dns_rdataset_first");
1238 dns_rdataset_current(&soaset, &rdata);
1239 zone_soa_min_ttl = dns_soa_getminimum(&rdata);
1240 soa_ttl = soaset.ttl;
1241 if (set_maxttl) {
1242 zone_soa_min_ttl = ISC_MIN(zone_soa_min_ttl, maxttl);
1243 soa_ttl = ISC_MIN(soa_ttl, maxttl);
1245 dns_rdataset_disassociate(&soaset);
1249 * Increment (or set if nonzero) the SOA serial
1251 static isc_result_t
1252 setsoaserial(isc_uint32_t serial) {
1253 isc_result_t result;
1254 dns_dbnode_t *node = NULL;
1255 dns_rdataset_t rdataset;
1256 dns_rdata_t rdata = DNS_RDATA_INIT;
1257 isc_uint32_t old_serial, new_serial;
1259 result = dns_db_getoriginnode(gdb, &node);
1260 if (result != ISC_R_SUCCESS)
1261 return result;
1263 dns_rdataset_init(&rdataset);
1265 result = dns_db_findrdataset(gdb, node, gversion,
1266 dns_rdatatype_soa, 0,
1267 0, &rdataset, NULL);
1268 if (result != ISC_R_SUCCESS)
1269 goto cleanup;
1271 result = dns_rdataset_first(&rdataset);
1272 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1274 dns_rdataset_current(&rdataset, &rdata);
1276 old_serial = dns_soa_getserial(&rdata);
1278 if (serial) {
1279 /* Set SOA serial to the value provided. */
1280 new_serial = serial;
1281 } else {
1282 /* Increment SOA serial using RFC 1982 arithmetics */
1283 new_serial = (old_serial + 1) & 0xFFFFFFFF;
1284 if (new_serial == 0)
1285 new_serial = 1;
1288 /* If the new serial is not likely to cause a zone transfer
1289 * (a/ixfr) from servers having the old serial, warn the user.
1291 * RFC1982 section 7 defines the maximum increment to be
1292 * (2^(32-1))-1. Using u_int32_t arithmetic, we can do a single
1293 * comparison. (5 - 6 == (2^32)-1, not negative-one)
1295 if (new_serial == old_serial ||
1296 (new_serial - old_serial) > 0x7fffffffU)
1297 fprintf(stderr, "%s: warning: Serial number not advanced, "
1298 "zone may not transfer\n", program);
1300 dns_soa_setserial(new_serial, &rdata);
1302 result = dns_db_deleterdataset(gdb, node, gversion,
1303 dns_rdatatype_soa, 0);
1304 check_result(result, "dns_db_deleterdataset");
1305 if (result != ISC_R_SUCCESS)
1306 goto cleanup;
1308 result = dns_db_addrdataset(gdb, node, gversion,
1309 0, &rdataset, 0, NULL);
1310 check_result(result, "dns_db_addrdataset");
1311 if (result != ISC_R_SUCCESS)
1312 goto cleanup;
1314 cleanup:
1315 dns_rdataset_disassociate(&rdataset);
1316 if (node != NULL)
1317 dns_db_detachnode(gdb, &node);
1318 dns_rdata_reset(&rdata);
1320 return (result);
1324 * Delete any RRSIG records at a node.
1326 static void
1327 cleannode(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node) {
1328 dns_rdatasetiter_t *rdsiter = NULL;
1329 dns_rdataset_t set;
1330 isc_result_t result, dresult;
1332 if (outputformat != dns_masterformat_text || !disable_zone_check)
1333 return;
1335 dns_rdataset_init(&set);
1336 result = dns_db_allrdatasets(db, node, version, 0, &rdsiter);
1337 check_result(result, "dns_db_allrdatasets");
1338 result = dns_rdatasetiter_first(rdsiter);
1339 while (result == ISC_R_SUCCESS) {
1340 isc_boolean_t destroy = ISC_FALSE;
1341 dns_rdatatype_t covers = 0;
1342 dns_rdatasetiter_current(rdsiter, &set);
1343 if (set.type == dns_rdatatype_rrsig) {
1344 covers = set.covers;
1345 destroy = ISC_TRUE;
1347 dns_rdataset_disassociate(&set);
1348 result = dns_rdatasetiter_next(rdsiter);
1349 if (destroy) {
1350 dresult = dns_db_deleterdataset(db, node, version,
1351 dns_rdatatype_rrsig,
1352 covers);
1353 check_result(dresult, "dns_db_deleterdataset");
1356 if (result != ISC_R_NOMORE)
1357 fatal("rdataset iteration failed: %s",
1358 isc_result_totext(result));
1359 dns_rdatasetiter_destroy(&rdsiter);
1363 * Set up the iterator and global state before starting the tasks.
1365 static void
1366 presign(void) {
1367 isc_result_t result;
1369 gdbiter = NULL;
1370 result = dns_db_createiterator(gdb, 0, &gdbiter);
1371 check_result(result, "dns_db_createiterator()");
1375 * Clean up the iterator and global state after the tasks complete.
1377 static void
1378 postsign(void) {
1379 dns_dbiterator_destroy(&gdbiter);
1383 * Sign the apex of the zone.
1384 * Note the origin may not be the first node if there are out of zone
1385 * records.
1387 static void
1388 signapex(void) {
1389 dns_dbnode_t *node = NULL;
1390 dns_fixedname_t fixed;
1391 dns_name_t *name;
1392 isc_result_t result;
1394 dns_fixedname_init(&fixed);
1395 name = dns_fixedname_name(&fixed);
1396 result = dns_dbiterator_seek(gdbiter, gorigin);
1397 check_result(result, "dns_dbiterator_seek()");
1398 result = dns_dbiterator_current(gdbiter, &node, name);
1399 check_dns_dbiterator_current(result);
1400 signname(node, name);
1401 dumpnode(name, node);
1402 cleannode(gdb, gversion, node);
1403 dns_db_detachnode(gdb, &node);
1404 result = dns_dbiterator_first(gdbiter);
1405 if (result == ISC_R_NOMORE)
1406 finished = ISC_TRUE;
1407 else if (result != ISC_R_SUCCESS)
1408 fatal("failure iterating database: %s",
1409 isc_result_totext(result));
1413 * Assigns a node to a worker thread. This is protected by the master task's
1414 * lock.
1416 static void
1417 assignwork(isc_task_t *task, isc_task_t *worker) {
1418 dns_fixedname_t *fname;
1419 dns_name_t *name;
1420 dns_dbnode_t *node;
1421 sevent_t *sevent;
1422 dns_rdataset_t nsec;
1423 isc_boolean_t found;
1424 isc_result_t result;
1425 static dns_name_t *zonecut = NULL; /* Protected by namelock. */
1426 static dns_fixedname_t fzonecut; /* Protected by namelock. */
1427 static unsigned int ended = 0; /* Protected by namelock. */
1429 if (shuttingdown)
1430 return;
1432 LOCK(&namelock);
1433 if (finished) {
1434 ended++;
1435 if (ended == ntasks) {
1436 isc_task_detach(&task);
1437 isc_app_shutdown();
1439 goto unlock;
1442 fname = isc_mem_get(mctx, sizeof(dns_fixedname_t));
1443 if (fname == NULL)
1444 fatal("out of memory");
1445 dns_fixedname_init(fname);
1446 name = dns_fixedname_name(fname);
1447 node = NULL;
1448 found = ISC_FALSE;
1449 while (!found) {
1450 result = dns_dbiterator_current(gdbiter, &node, name);
1451 check_dns_dbiterator_current(result);
1453 * The origin was handled by signapex().
1455 if (dns_name_equal(name, gorigin)) {
1456 dns_db_detachnode(gdb, &node);
1457 goto next;
1460 * Sort the zone data from the glue and out-of-zone data.
1461 * For NSEC zones nodes with zone data have NSEC records.
1462 * For NSEC3 zones the NSEC3 nodes are zone data but
1463 * outside of the zone name space. For the rest we need
1464 * to track the bottom of zone cuts.
1465 * Nodes which don't need to be signed are dumped here.
1467 dns_rdataset_init(&nsec);
1468 result = dns_db_findrdataset(gdb, node, gversion,
1469 nsec_datatype, 0, 0,
1470 &nsec, NULL);
1471 if (dns_rdataset_isassociated(&nsec))
1472 dns_rdataset_disassociate(&nsec);
1473 if (result == ISC_R_SUCCESS) {
1474 found = ISC_TRUE;
1475 } else if (nsec_datatype == dns_rdatatype_nsec3) {
1476 if (dns_name_issubdomain(name, gorigin) &&
1477 (zonecut == NULL ||
1478 !dns_name_issubdomain(name, zonecut))) {
1479 if (is_delegation(gdb, gversion, gorigin, name, node, NULL)) {
1480 dns_fixedname_init(&fzonecut);
1481 zonecut = dns_fixedname_name(&fzonecut);
1482 dns_name_copy(name, zonecut, NULL);
1483 if (!OPTOUT(nsec3flags) ||
1484 secure(name, node))
1485 found = ISC_TRUE;
1486 } else
1487 found = ISC_TRUE;
1491 if (!found) {
1492 dumpnode(name, node);
1493 dns_db_detachnode(gdb, &node);
1496 next:
1497 result = dns_dbiterator_next(gdbiter);
1498 if (result == ISC_R_NOMORE) {
1499 finished = ISC_TRUE;
1500 break;
1501 } else if (result != ISC_R_SUCCESS)
1502 fatal("failure iterating database: %s",
1503 isc_result_totext(result));
1505 if (!found) {
1506 ended++;
1507 if (ended == ntasks) {
1508 isc_task_detach(&task);
1509 isc_app_shutdown();
1511 isc_mem_put(mctx, fname, sizeof(dns_fixedname_t));
1512 goto unlock;
1514 sevent = (sevent_t *)
1515 isc_event_allocate(mctx, task, SIGNER_EVENT_WORK,
1516 sign, NULL, sizeof(sevent_t));
1517 if (sevent == NULL)
1518 fatal("failed to allocate event\n");
1520 sevent->node = node;
1521 sevent->fname = fname;
1522 isc_task_send(worker, ISC_EVENT_PTR(&sevent));
1523 unlock:
1524 UNLOCK(&namelock);
1528 * Start a worker task
1530 static void
1531 startworker(isc_task_t *task, isc_event_t *event) {
1532 isc_task_t *worker;
1534 worker = (isc_task_t *)event->ev_arg;
1535 assignwork(task, worker);
1536 isc_event_free(&event);
1540 * Write a node to the output file, and restart the worker task.
1542 static void
1543 writenode(isc_task_t *task, isc_event_t *event) {
1544 isc_task_t *worker;
1545 sevent_t *sevent = (sevent_t *)event;
1547 worker = (isc_task_t *)event->ev_sender;
1548 dumpnode(dns_fixedname_name(sevent->fname), sevent->node);
1549 cleannode(gdb, gversion, sevent->node);
1550 dns_db_detachnode(gdb, &sevent->node);
1551 isc_mem_put(mctx, sevent->fname, sizeof(dns_fixedname_t));
1552 assignwork(task, worker);
1553 isc_event_free(&event);
1557 * Sign a database node.
1559 static void
1560 sign(isc_task_t *task, isc_event_t *event) {
1561 dns_fixedname_t *fname;
1562 dns_dbnode_t *node;
1563 sevent_t *sevent, *wevent;
1565 sevent = (sevent_t *)event;
1566 node = sevent->node;
1567 fname = sevent->fname;
1568 isc_event_free(&event);
1570 signname(node, dns_fixedname_name(fname));
1571 wevent = (sevent_t *)
1572 isc_event_allocate(mctx, task, SIGNER_EVENT_WRITE,
1573 writenode, NULL, sizeof(sevent_t));
1574 if (wevent == NULL)
1575 fatal("failed to allocate event\n");
1576 wevent->node = node;
1577 wevent->fname = fname;
1578 isc_task_send(master, ISC_EVENT_PTR(&wevent));
1582 * Update / remove the DS RRset. Preserve RRSIG(DS) if possible.
1584 static void
1585 add_ds(dns_name_t *name, dns_dbnode_t *node, isc_uint32_t nsttl) {
1586 dns_rdataset_t dsset;
1587 dns_rdataset_t sigdsset;
1588 isc_result_t result;
1590 dns_rdataset_init(&dsset);
1591 dns_rdataset_init(&sigdsset);
1592 result = dns_db_findrdataset(gdb, node, gversion,
1593 dns_rdatatype_ds,
1594 0, 0, &dsset, &sigdsset);
1595 if (result == ISC_R_SUCCESS) {
1596 dns_rdataset_disassociate(&dsset);
1597 result = dns_db_deleterdataset(gdb, node, gversion,
1598 dns_rdatatype_ds, 0);
1599 check_result(result, "dns_db_deleterdataset");
1602 result = loadds(name, nsttl, &dsset);
1603 if (result == ISC_R_SUCCESS) {
1604 result = dns_db_addrdataset(gdb, node, gversion, 0,
1605 &dsset, 0, NULL);
1606 check_result(result, "dns_db_addrdataset");
1607 dns_rdataset_disassociate(&dsset);
1608 if (dns_rdataset_isassociated(&sigdsset))
1609 dns_rdataset_disassociate(&sigdsset);
1610 } else if (dns_rdataset_isassociated(&sigdsset)) {
1611 result = dns_db_deleterdataset(gdb, node, gversion,
1612 dns_rdatatype_rrsig,
1613 dns_rdatatype_ds);
1614 check_result(result, "dns_db_deleterdataset");
1615 dns_rdataset_disassociate(&sigdsset);
1620 * Remove records of the given type and their signatures.
1622 static void
1623 remove_records(dns_dbnode_t *node, dns_rdatatype_t which,
1624 isc_boolean_t checknsec)
1626 isc_result_t result;
1627 dns_rdatatype_t type, covers;
1628 dns_rdatasetiter_t *rdsiter = NULL;
1629 dns_rdataset_t rdataset;
1631 dns_rdataset_init(&rdataset);
1634 * Delete any records of the given type at the apex.
1636 result = dns_db_allrdatasets(gdb, node, gversion, 0, &rdsiter);
1637 check_result(result, "dns_db_allrdatasets()");
1638 for (result = dns_rdatasetiter_first(rdsiter);
1639 result == ISC_R_SUCCESS;
1640 result = dns_rdatasetiter_next(rdsiter)) {
1641 dns_rdatasetiter_current(rdsiter, &rdataset);
1642 type = rdataset.type;
1643 covers = rdataset.covers;
1644 dns_rdataset_disassociate(&rdataset);
1645 if (type == which || covers == which) {
1646 if (which == dns_rdatatype_nsec &&
1647 checknsec && !update_chain)
1648 fatal("Zone contains NSEC records. Use -u "
1649 "to update to NSEC3.");
1650 if (which == dns_rdatatype_nsec3param &&
1651 checknsec && !update_chain)
1652 fatal("Zone contains NSEC3 chains. Use -u "
1653 "to update to NSEC.");
1654 result = dns_db_deleterdataset(gdb, node, gversion,
1655 type, covers);
1656 check_result(result, "dns_db_deleterdataset()");
1657 continue;
1660 dns_rdatasetiter_destroy(&rdsiter);
1664 * Remove signatures covering the given type. If type == 0,
1665 * then remove all signatures, unless this is a delegation, in
1666 * which case remove all signatures except for DS or nsec_datatype
1668 static void
1669 remove_sigs(dns_dbnode_t *node, isc_boolean_t delegation,
1670 dns_rdatatype_t which)
1672 isc_result_t result;
1673 dns_rdatatype_t type, covers;
1674 dns_rdatasetiter_t *rdsiter = NULL;
1675 dns_rdataset_t rdataset;
1677 dns_rdataset_init(&rdataset);
1678 result = dns_db_allrdatasets(gdb, node, gversion, 0, &rdsiter);
1679 check_result(result, "dns_db_allrdatasets()");
1680 for (result = dns_rdatasetiter_first(rdsiter);
1681 result == ISC_R_SUCCESS;
1682 result = dns_rdatasetiter_next(rdsiter)) {
1683 dns_rdatasetiter_current(rdsiter, &rdataset);
1684 type = rdataset.type;
1685 covers = rdataset.covers;
1686 dns_rdataset_disassociate(&rdataset);
1688 if (type != dns_rdatatype_rrsig)
1689 continue;
1691 if (which == 0 && delegation &&
1692 (dns_rdatatype_atparent(covers) ||
1693 (nsec_datatype == dns_rdatatype_nsec &&
1694 covers == nsec_datatype)))
1695 continue;
1697 if (which != 0 && covers != which)
1698 continue;
1700 result = dns_db_deleterdataset(gdb, node, gversion,
1701 type, covers);
1702 check_result(result, "dns_db_deleterdataset()");
1704 dns_rdatasetiter_destroy(&rdsiter);
1708 * Generate NSEC records for the zone and remove NSEC3/NSEC3PARAM records.
1710 static void
1711 nsecify(void) {
1712 dns_dbiterator_t *dbiter = NULL;
1713 dns_dbnode_t *node = NULL, *nextnode = NULL;
1714 dns_fixedname_t fname, fnextname, fzonecut;
1715 dns_name_t *name, *nextname, *zonecut;
1716 dns_rdataset_t rdataset;
1717 dns_rdatasetiter_t *rdsiter = NULL;
1718 dns_rdatatype_t type, covers;
1719 isc_boolean_t done = ISC_FALSE;
1720 isc_result_t result;
1721 isc_uint32_t nsttl = 0;
1723 dns_rdataset_init(&rdataset);
1724 dns_fixedname_init(&fname);
1725 name = dns_fixedname_name(&fname);
1726 dns_fixedname_init(&fnextname);
1727 nextname = dns_fixedname_name(&fnextname);
1728 dns_fixedname_init(&fzonecut);
1729 zonecut = NULL;
1732 * Remove any NSEC3 chains.
1734 result = dns_db_createiterator(gdb, DNS_DB_NSEC3ONLY, &dbiter);
1735 check_result(result, "dns_db_createiterator()");
1736 for (result = dns_dbiterator_first(dbiter);
1737 result == ISC_R_SUCCESS;
1738 result = dns_dbiterator_next(dbiter)) {
1739 result = dns_dbiterator_current(dbiter, &node, name);
1740 check_dns_dbiterator_current(result);
1741 result = dns_db_allrdatasets(gdb, node, gversion, 0, &rdsiter);
1742 check_result(result, "dns_db_allrdatasets()");
1743 for (result = dns_rdatasetiter_first(rdsiter);
1744 result == ISC_R_SUCCESS;
1745 result = dns_rdatasetiter_next(rdsiter)) {
1746 dns_rdatasetiter_current(rdsiter, &rdataset);
1747 type = rdataset.type;
1748 covers = rdataset.covers;
1749 dns_rdataset_disassociate(&rdataset);
1750 result = dns_db_deleterdataset(gdb, node, gversion,
1751 type, covers);
1752 check_result(result,
1753 "dns_db_deleterdataset(nsec3param/rrsig)");
1755 dns_rdatasetiter_destroy(&rdsiter);
1756 dns_db_detachnode(gdb, &node);
1758 dns_dbiterator_destroy(&dbiter);
1760 result = dns_db_createiterator(gdb, DNS_DB_NONSEC3, &dbiter);
1761 check_result(result, "dns_db_createiterator()");
1763 result = dns_dbiterator_first(dbiter);
1764 check_result(result, "dns_dbiterator_first()");
1766 while (!done) {
1767 result = dns_dbiterator_current(dbiter, &node, name);
1768 check_dns_dbiterator_current(result);
1770 * Skip out-of-zone records.
1772 if (!dns_name_issubdomain(name, gorigin)) {
1773 result = dns_dbiterator_next(dbiter);
1774 if (result == ISC_R_NOMORE)
1775 done = ISC_TRUE;
1776 else
1777 check_result(result, "dns_dbiterator_next()");
1778 dns_db_detachnode(gdb, &node);
1779 continue;
1782 if (dns_name_equal(name, gorigin))
1783 remove_records(node, dns_rdatatype_nsec3param,
1784 ISC_TRUE);
1786 if (is_delegation(gdb, gversion, gorigin, name, node, &nsttl)) {
1787 zonecut = dns_fixedname_name(&fzonecut);
1788 dns_name_copy(name, zonecut, NULL);
1789 remove_sigs(node, ISC_TRUE, 0);
1790 if (generateds)
1791 add_ds(name, node, nsttl);
1794 result = dns_dbiterator_next(dbiter);
1795 nextnode = NULL;
1796 while (result == ISC_R_SUCCESS) {
1797 isc_boolean_t active = ISC_FALSE;
1798 result = dns_dbiterator_current(dbiter, &nextnode,
1799 nextname);
1800 check_dns_dbiterator_current(result);
1801 active = active_node(nextnode);
1802 if (!active) {
1803 dns_db_detachnode(gdb, &nextnode);
1804 result = dns_dbiterator_next(dbiter);
1805 continue;
1807 if (!dns_name_issubdomain(nextname, gorigin) ||
1808 (zonecut != NULL &&
1809 dns_name_issubdomain(nextname, zonecut)))
1811 remove_sigs(nextnode, ISC_FALSE, 0);
1812 remove_records(nextnode, dns_rdatatype_nsec,
1813 ISC_FALSE);
1814 dns_db_detachnode(gdb, &nextnode);
1815 result = dns_dbiterator_next(dbiter);
1816 continue;
1818 dns_db_detachnode(gdb, &nextnode);
1819 break;
1821 if (result == ISC_R_NOMORE) {
1822 dns_name_clone(gorigin, nextname);
1823 done = ISC_TRUE;
1824 } else if (result != ISC_R_SUCCESS)
1825 fatal("iterating through the database failed: %s",
1826 isc_result_totext(result));
1827 dns_dbiterator_pause(dbiter);
1828 result = dns_nsec_build(gdb, gversion, node, nextname,
1829 zone_soa_min_ttl);
1830 check_result(result, "dns_nsec_build()");
1831 dns_db_detachnode(gdb, &node);
1834 dns_dbiterator_destroy(&dbiter);
1837 static void
1838 addnsec3param(const unsigned char *salt, size_t salt_len,
1839 dns_iterations_t iterations)
1841 dns_dbnode_t *node = NULL;
1842 dns_rdata_nsec3param_t nsec3param;
1843 unsigned char nsec3parambuf[5 + 255];
1844 dns_rdatalist_t rdatalist;
1845 dns_rdataset_t rdataset;
1846 dns_rdata_t rdata = DNS_RDATA_INIT;
1847 isc_buffer_t b;
1848 isc_result_t result;
1850 dns_rdataset_init(&rdataset);
1852 nsec3param.common.rdclass = gclass;
1853 nsec3param.common.rdtype = dns_rdatatype_nsec3param;
1854 ISC_LINK_INIT(&nsec3param.common, link);
1855 nsec3param.mctx = NULL;
1856 nsec3param.flags = 0;
1857 nsec3param.hash = unknownalg ? DNS_NSEC3_UNKNOWNALG : dns_hash_sha1;
1858 nsec3param.iterations = iterations;
1859 nsec3param.salt_length = (unsigned char)salt_len;
1860 DE_CONST(salt, nsec3param.salt);
1862 isc_buffer_init(&b, nsec3parambuf, sizeof(nsec3parambuf));
1863 result = dns_rdata_fromstruct(&rdata, gclass,
1864 dns_rdatatype_nsec3param,
1865 &nsec3param, &b);
1866 check_result(result, "dns_rdata_fromstruct()");
1867 rdatalist.rdclass = rdata.rdclass;
1868 rdatalist.type = rdata.type;
1869 rdatalist.covers = 0;
1870 rdatalist.ttl = 0;
1871 ISC_LIST_INIT(rdatalist.rdata);
1872 ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
1873 result = dns_rdatalist_tordataset(&rdatalist, &rdataset);
1874 check_result(result, "dns_rdatalist_tordataset()");
1876 result = dns_db_findnode(gdb, gorigin, ISC_TRUE, &node);
1877 check_result(result, "dns_db_find(gorigin)");
1880 * Delete any current NSEC3PARAM records.
1882 result = dns_db_deleterdataset(gdb, node, gversion,
1883 dns_rdatatype_nsec3param, 0);
1884 if (result == DNS_R_UNCHANGED)
1885 result = ISC_R_SUCCESS;
1886 check_result(result, "dddnsec3param: dns_db_deleterdataset()");
1888 result = dns_db_addrdataset(gdb, node, gversion, 0, &rdataset,
1889 DNS_DBADD_MERGE, NULL);
1890 if (result == DNS_R_UNCHANGED)
1891 result = ISC_R_SUCCESS;
1892 check_result(result, "addnsec3param: dns_db_addrdataset()");
1893 dns_db_detachnode(gdb, &node);
1896 static void
1897 addnsec3(dns_name_t *name, dns_dbnode_t *node,
1898 const unsigned char *salt, size_t salt_len,
1899 unsigned int iterations, hashlist_t *hashlist,
1900 dns_ttl_t ttl)
1902 unsigned char hash[NSEC3_MAX_HASH_LENGTH];
1903 const unsigned char *nexthash;
1904 unsigned char nsec3buffer[DNS_NSEC3_BUFFERSIZE];
1905 dns_fixedname_t hashname;
1906 dns_rdatalist_t rdatalist;
1907 dns_rdataset_t rdataset;
1908 dns_rdata_t rdata = DNS_RDATA_INIT;
1909 isc_result_t result;
1910 dns_dbnode_t *nsec3node = NULL;
1911 char namebuf[DNS_NAME_FORMATSIZE];
1912 size_t hash_len;
1914 dns_name_format(name, namebuf, sizeof(namebuf));
1916 dns_fixedname_init(&hashname);
1917 dns_rdataset_init(&rdataset);
1919 dns_name_downcase(name, name, NULL);
1920 result = dns_nsec3_hashname(&hashname, hash, &hash_len,
1921 name, gorigin, dns_hash_sha1, iterations,
1922 salt, salt_len);
1923 check_result(result, "addnsec3: dns_nsec3_hashname()");
1924 nexthash = hashlist_findnext(hashlist, hash);
1925 result = dns_nsec3_buildrdata(gdb, gversion, node,
1926 unknownalg ?
1927 DNS_NSEC3_UNKNOWNALG : dns_hash_sha1,
1928 nsec3flags, iterations,
1929 salt, salt_len,
1930 nexthash, ISC_SHA1_DIGESTLENGTH,
1931 nsec3buffer, &rdata);
1932 check_result(result, "addnsec3: dns_nsec3_buildrdata()");
1933 rdatalist.rdclass = rdata.rdclass;
1934 rdatalist.type = rdata.type;
1935 rdatalist.covers = 0;
1936 rdatalist.ttl = ttl;
1937 ISC_LIST_INIT(rdatalist.rdata);
1938 ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
1939 result = dns_rdatalist_tordataset(&rdatalist, &rdataset);
1940 check_result(result, "dns_rdatalist_tordataset()");
1941 result = dns_db_findnsec3node(gdb, dns_fixedname_name(&hashname),
1942 ISC_TRUE, &nsec3node);
1943 check_result(result, "addnsec3: dns_db_findnode()");
1944 result = dns_db_addrdataset(gdb, nsec3node, gversion, 0, &rdataset,
1945 0, NULL);
1946 if (result == DNS_R_UNCHANGED)
1947 result = ISC_R_SUCCESS;
1948 check_result(result, "addnsec3: dns_db_addrdataset()");
1949 dns_db_detachnode(gdb, &nsec3node);
1953 * Clean out NSEC3 record and RRSIG(NSEC3) that are not in the hash list.
1955 * Extract the hash from the first label of 'name' then see if it
1956 * is in hashlist. If 'name' is not in the hashlist then delete the
1957 * any NSEC3 records which have the same parameters as the chain we
1958 * are building.
1960 * XXXMPA Should we also check that it of the form <hash>.<origin>?
1962 static void
1963 nsec3clean(dns_name_t *name, dns_dbnode_t *node,
1964 unsigned int hashalg, unsigned int iterations,
1965 const unsigned char *salt, size_t salt_len, hashlist_t *hashlist)
1967 dns_label_t label;
1968 dns_rdata_nsec3_t nsec3;
1969 dns_rdata_t rdata, delrdata;
1970 dns_rdatalist_t rdatalist;
1971 dns_rdataset_t rdataset, delrdataset;
1972 isc_boolean_t delete_rrsigs = ISC_FALSE;
1973 isc_buffer_t target;
1974 isc_result_t result;
1975 unsigned char hash[NSEC3_MAX_HASH_LENGTH + 1];
1976 isc_boolean_t exists;
1979 * Get the first label.
1981 dns_name_getlabel(name, 0, &label);
1984 * We want just the label contents.
1986 isc_region_consume(&label, 1);
1989 * Decode base32hex string.
1991 isc_buffer_init(&target, hash, sizeof(hash) - 1);
1992 result = isc_base32hex_decoderegion(&label, &target);
1993 if (result != ISC_R_SUCCESS)
1994 return;
1996 hash[isc_buffer_usedlength(&target)] = 0;
1998 exists = hashlist_exists(hashlist, hash);
2001 * Verify that the NSEC3 parameters match the current ones
2002 * otherwise we are dealing with a different NSEC3 chain.
2004 dns_rdataset_init(&rdataset);
2005 dns_rdataset_init(&delrdataset);
2007 result = dns_db_findrdataset(gdb, node, gversion, dns_rdatatype_nsec3,
2008 0, 0, &rdataset, NULL);
2009 if (result != ISC_R_SUCCESS)
2010 return;
2013 * Delete any NSEC3 records which are not part of the current
2014 * NSEC3 chain.
2016 for (result = dns_rdataset_first(&rdataset);
2017 result == ISC_R_SUCCESS;
2018 result = dns_rdataset_next(&rdataset)) {
2019 dns_rdata_init(&rdata);
2020 dns_rdataset_current(&rdataset, &rdata);
2021 result = dns_rdata_tostruct(&rdata, &nsec3, NULL);
2022 check_result(result, "dns_rdata_tostruct");
2023 if (exists && nsec3.hash == hashalg &&
2024 nsec3.iterations == iterations &&
2025 nsec3.salt_length == salt_len &&
2026 !memcmp(nsec3.salt, salt, salt_len))
2027 continue;
2028 rdatalist.rdclass = rdata.rdclass;
2029 rdatalist.type = rdata.type;
2030 rdatalist.covers = 0;
2031 if (set_maxttl)
2032 rdatalist.ttl = ISC_MIN(rdataset.ttl, maxttl);
2033 ISC_LIST_INIT(rdatalist.rdata);
2034 dns_rdata_init(&delrdata);
2035 dns_rdata_clone(&rdata, &delrdata);
2036 ISC_LIST_APPEND(rdatalist.rdata, &delrdata, link);
2037 result = dns_rdatalist_tordataset(&rdatalist, &delrdataset);
2038 check_result(result, "dns_rdatalist_tordataset()");
2039 result = dns_db_subtractrdataset(gdb, node, gversion,
2040 &delrdataset, 0, NULL);
2041 dns_rdataset_disassociate(&delrdataset);
2042 if (result != ISC_R_SUCCESS && result != DNS_R_NXRRSET)
2043 check_result(result, "dns_db_subtractrdataset(NSEC3)");
2044 delete_rrsigs = ISC_TRUE;
2046 dns_rdataset_disassociate(&rdataset);
2047 if (result != ISC_R_NOMORE)
2048 check_result(result, "dns_rdataset_first/next");
2050 if (!delete_rrsigs)
2051 return;
2053 * Delete the NSEC3 RRSIGs
2055 result = dns_db_deleterdataset(gdb, node, gversion,
2056 dns_rdatatype_rrsig,
2057 dns_rdatatype_nsec3);
2058 if (result != ISC_R_SUCCESS && result != DNS_R_UNCHANGED)
2059 check_result(result, "dns_db_deleterdataset(RRSIG(NSEC3))");
2062 static void
2063 rrset_cleanup(dns_name_t *name, dns_rdataset_t *rdataset,
2064 dns_diff_t *add, dns_diff_t *del)
2066 isc_result_t result;
2067 unsigned int count1 = 0;
2068 dns_rdataset_t tmprdataset;
2069 char namestr[DNS_NAME_FORMATSIZE];
2070 char typestr[TYPE_FORMATSIZE];
2072 dns_name_format(name, namestr, sizeof(namestr));
2073 type_format(rdataset->type, typestr, sizeof(typestr));
2075 dns_rdataset_init(&tmprdataset);
2076 for (result = dns_rdataset_first(rdataset);
2077 result == ISC_R_SUCCESS;
2078 result = dns_rdataset_next(rdataset)) {
2079 dns_rdata_t rdata1 = DNS_RDATA_INIT;
2080 unsigned int count2 = 0;
2082 count1++;
2083 dns_rdataset_current(rdataset, &rdata1);
2084 dns_rdataset_clone(rdataset, &tmprdataset);
2085 for (result = dns_rdataset_first(&tmprdataset);
2086 result == ISC_R_SUCCESS;
2087 result = dns_rdataset_next(&tmprdataset)) {
2088 dns_rdata_t rdata2 = DNS_RDATA_INIT;
2089 dns_difftuple_t *tuple = NULL;
2090 count2++;
2091 dns_rdataset_current(&tmprdataset, &rdata2);
2092 if (count1 < count2 &&
2093 dns_rdata_casecompare(&rdata1, &rdata2) == 0)
2095 vbprintf(2, "removing duplicate at %s/%s\n",
2096 namestr, typestr);
2097 result = dns_difftuple_create(mctx,
2098 DNS_DIFFOP_DELRESIGN,
2099 name, rdataset->ttl,
2100 &rdata2, &tuple);
2101 check_result(result, "dns_difftuple_create");
2102 dns_diff_append(del, &tuple);
2103 } else if (set_maxttl && rdataset->ttl > maxttl) {
2104 vbprintf(2, "reducing ttl of %s/%s "
2105 "from %d to %d\n",
2106 namestr, typestr,
2107 rdataset->ttl, maxttl);
2108 result = dns_difftuple_create(mctx,
2109 DNS_DIFFOP_DELRESIGN,
2110 name, rdataset->ttl,
2111 &rdata2, &tuple);
2112 check_result(result, "dns_difftuple_create");
2113 dns_diff_append(del, &tuple);
2114 tuple = NULL;
2115 result = dns_difftuple_create(mctx,
2116 DNS_DIFFOP_ADDRESIGN,
2117 name, maxttl,
2118 &rdata2, &tuple);
2119 check_result(result, "dns_difftuple_create");
2120 dns_diff_append(add, &tuple);
2123 dns_rdataset_disassociate(&tmprdataset);
2127 static void
2128 cleanup_zone(void) {
2129 isc_result_t result;
2130 dns_dbiterator_t *dbiter = NULL;
2131 dns_rdatasetiter_t *rdsiter = NULL;
2132 dns_diff_t add, del;
2133 dns_dbnode_t *node = NULL;
2134 dns_rdataset_t rdataset;
2135 dns_fixedname_t fname;
2136 dns_name_t *name;
2138 dns_diff_init(mctx, &add);
2139 dns_diff_init(mctx, &del);
2140 dns_fixedname_init(&fname);
2141 name = dns_fixedname_name(&fname);
2142 dns_rdataset_init(&rdataset);
2144 result = dns_db_createiterator(gdb, 0, &dbiter);
2145 check_result(result, "dns_db_createiterator()");
2147 for (result = dns_dbiterator_first(dbiter);
2148 result == ISC_R_SUCCESS;
2149 result = dns_dbiterator_next(dbiter)) {
2151 result = dns_dbiterator_current(dbiter, &node, name);
2152 check_dns_dbiterator_current(result);
2153 result = dns_db_allrdatasets(gdb, node, gversion, 0, &rdsiter);
2154 check_result(result, "dns_db_allrdatasets()");
2155 for (result = dns_rdatasetiter_first(rdsiter);
2156 result == ISC_R_SUCCESS;
2157 result = dns_rdatasetiter_next(rdsiter)) {
2158 dns_rdatasetiter_current(rdsiter, &rdataset);
2159 rrset_cleanup(name, &rdataset, &add, &del);
2160 dns_rdataset_disassociate(&rdataset);
2162 if (result != ISC_R_NOMORE)
2163 fatal("rdatasets iteration failed.");
2164 dns_rdatasetiter_destroy(&rdsiter);
2165 dns_db_detachnode(gdb, &node);
2167 if (result != ISC_R_NOMORE)
2168 fatal("zone iteration failed.");
2170 result = dns_diff_applysilently(&del, gdb, gversion);
2171 check_result(result, "dns_diff_applysilently");
2173 result = dns_diff_applysilently(&add, gdb, gversion);
2174 check_result(result, "dns_diff_applysilently");
2176 dns_diff_clear(&del);
2177 dns_diff_clear(&add);
2178 dns_dbiterator_destroy(&dbiter);
2182 * Generate NSEC3 records for the zone.
2184 static void
2185 nsec3ify(unsigned int hashalg, dns_iterations_t iterations,
2186 const unsigned char *salt, size_t salt_len, hashlist_t *hashlist)
2188 dns_dbiterator_t *dbiter = NULL;
2189 dns_dbnode_t *node = NULL, *nextnode = NULL;
2190 dns_fixedname_t fname, fnextname, fzonecut;
2191 dns_name_t *name, *nextname, *zonecut;
2192 dns_rdataset_t rdataset;
2193 int order;
2194 isc_boolean_t active;
2195 isc_boolean_t done = ISC_FALSE;
2196 isc_result_t result;
2197 isc_uint32_t nsttl = 0;
2198 unsigned int count, nlabels;
2200 dns_rdataset_init(&rdataset);
2201 dns_fixedname_init(&fname);
2202 name = dns_fixedname_name(&fname);
2203 dns_fixedname_init(&fnextname);
2204 nextname = dns_fixedname_name(&fnextname);
2205 dns_fixedname_init(&fzonecut);
2206 zonecut = NULL;
2209 * Walk the zone generating the hash names.
2211 result = dns_db_createiterator(gdb, DNS_DB_NONSEC3, &dbiter);
2212 check_result(result, "dns_db_createiterator()");
2214 result = dns_dbiterator_first(dbiter);
2215 check_result(result, "dns_dbiterator_first()");
2217 while (!done) {
2218 result = dns_dbiterator_current(dbiter, &node, name);
2219 check_dns_dbiterator_current(result);
2221 * Skip out-of-zone records.
2223 if (!dns_name_issubdomain(name, gorigin)) {
2224 result = dns_dbiterator_next(dbiter);
2225 if (result == ISC_R_NOMORE)
2226 done = ISC_TRUE;
2227 else
2228 check_result(result, "dns_dbiterator_next()");
2229 dns_db_detachnode(gdb, &node);
2230 continue;
2233 if (dns_name_equal(name, gorigin))
2234 remove_records(node, dns_rdatatype_nsec, ISC_TRUE);
2236 result = dns_dbiterator_next(dbiter);
2237 nextnode = NULL;
2238 while (result == ISC_R_SUCCESS) {
2239 result = dns_dbiterator_current(dbiter, &nextnode,
2240 nextname);
2241 check_dns_dbiterator_current(result);
2242 active = active_node(nextnode);
2243 if (!active) {
2244 dns_db_detachnode(gdb, &nextnode);
2245 result = dns_dbiterator_next(dbiter);
2246 continue;
2248 if (!dns_name_issubdomain(nextname, gorigin) ||
2249 (zonecut != NULL &&
2250 dns_name_issubdomain(nextname, zonecut))) {
2251 remove_sigs(nextnode, ISC_FALSE, 0);
2252 dns_db_detachnode(gdb, &nextnode);
2253 result = dns_dbiterator_next(dbiter);
2254 continue;
2256 if (is_delegation(gdb, gversion, gorigin,
2257 nextname, nextnode, &nsttl))
2259 zonecut = dns_fixedname_name(&fzonecut);
2260 dns_name_copy(nextname, zonecut, NULL);
2261 remove_sigs(nextnode, ISC_TRUE, 0);
2262 if (generateds)
2263 add_ds(nextname, nextnode, nsttl);
2264 if (OPTOUT(nsec3flags) &&
2265 !secure(nextname, nextnode)) {
2266 dns_db_detachnode(gdb, &nextnode);
2267 result = dns_dbiterator_next(dbiter);
2268 continue;
2271 dns_db_detachnode(gdb, &nextnode);
2272 break;
2274 if (result == ISC_R_NOMORE) {
2275 dns_name_copy(gorigin, nextname, NULL);
2276 done = ISC_TRUE;
2277 } else if (result != ISC_R_SUCCESS)
2278 fatal("iterating through the database failed: %s",
2279 isc_result_totext(result));
2280 dns_name_downcase(name, name, NULL);
2281 hashlist_add_dns_name(hashlist, name, hashalg, iterations,
2282 salt, salt_len, ISC_FALSE);
2283 dns_db_detachnode(gdb, &node);
2285 * Add hashs for empty nodes. Use closest encloser logic.
2286 * The closest encloser either has data or is a empty
2287 * node for another <name,nextname> span so we don't add
2288 * it here. Empty labels on nextname are within the span.
2290 dns_name_downcase(nextname, nextname, NULL);
2291 dns_name_fullcompare(name, nextname, &order, &nlabels);
2292 addnowildcardhash(hashlist, name, hashalg, iterations,
2293 salt, salt_len);
2294 count = dns_name_countlabels(nextname);
2295 while (count > nlabels + 1) {
2296 count--;
2297 dns_name_split(nextname, count, NULL, nextname);
2298 hashlist_add_dns_name(hashlist, nextname, hashalg,
2299 iterations, salt, salt_len,
2300 ISC_FALSE);
2301 addnowildcardhash(hashlist, nextname, hashalg,
2302 iterations, salt, salt_len);
2305 dns_dbiterator_destroy(&dbiter);
2308 * We have all the hashes now so we can sort them.
2310 hashlist_sort(hashlist);
2313 * Check for duplicate hashes. If found the salt needs to
2314 * be changed.
2316 if (hashlist_hasdup(hashlist))
2317 fatal("Duplicate hash detected. Pick a different salt.");
2320 * Generate the nsec3 records.
2322 zonecut = NULL;
2323 done = ISC_FALSE;
2325 addnsec3param(salt, salt_len, iterations);
2328 * Clean out NSEC3 records which don't match this chain.
2330 result = dns_db_createiterator(gdb, DNS_DB_NSEC3ONLY, &dbiter);
2331 check_result(result, "dns_db_createiterator()");
2333 for (result = dns_dbiterator_first(dbiter);
2334 result == ISC_R_SUCCESS;
2335 result = dns_dbiterator_next(dbiter)) {
2336 result = dns_dbiterator_current(dbiter, &node, name);
2337 check_dns_dbiterator_current(result);
2338 nsec3clean(name, node, hashalg, iterations, salt, salt_len,
2339 hashlist);
2340 dns_db_detachnode(gdb, &node);
2342 dns_dbiterator_destroy(&dbiter);
2345 * Generate / complete the new chain.
2347 result = dns_db_createiterator(gdb, DNS_DB_NONSEC3, &dbiter);
2348 check_result(result, "dns_db_createiterator()");
2350 result = dns_dbiterator_first(dbiter);
2351 check_result(result, "dns_dbiterator_first()");
2353 while (!done) {
2354 result = dns_dbiterator_current(dbiter, &node, name);
2355 check_dns_dbiterator_current(result);
2357 * Skip out-of-zone records.
2359 if (!dns_name_issubdomain(name, gorigin)) {
2360 result = dns_dbiterator_next(dbiter);
2361 if (result == ISC_R_NOMORE)
2362 done = ISC_TRUE;
2363 else
2364 check_result(result, "dns_dbiterator_next()");
2365 dns_db_detachnode(gdb, &node);
2366 continue;
2368 result = dns_dbiterator_next(dbiter);
2369 nextnode = NULL;
2370 while (result == ISC_R_SUCCESS) {
2371 result = dns_dbiterator_current(dbiter, &nextnode,
2372 nextname);
2373 check_dns_dbiterator_current(result);
2374 active = active_node(nextnode);
2375 if (!active) {
2376 dns_db_detachnode(gdb, &nextnode);
2377 result = dns_dbiterator_next(dbiter);
2378 continue;
2380 if (!dns_name_issubdomain(nextname, gorigin) ||
2381 (zonecut != NULL &&
2382 dns_name_issubdomain(nextname, zonecut))) {
2383 dns_db_detachnode(gdb, &nextnode);
2384 result = dns_dbiterator_next(dbiter);
2385 continue;
2387 if (is_delegation(gdb, gversion, gorigin,
2388 nextname, nextnode, NULL))
2390 zonecut = dns_fixedname_name(&fzonecut);
2391 dns_name_copy(nextname, zonecut, NULL);
2392 if (OPTOUT(nsec3flags) &&
2393 !secure(nextname, nextnode)) {
2394 dns_db_detachnode(gdb, &nextnode);
2395 result = dns_dbiterator_next(dbiter);
2396 continue;
2399 dns_db_detachnode(gdb, &nextnode);
2400 break;
2402 if (result == ISC_R_NOMORE) {
2403 dns_name_copy(gorigin, nextname, NULL);
2404 done = ISC_TRUE;
2405 } else if (result != ISC_R_SUCCESS)
2406 fatal("iterating through the database failed: %s",
2407 isc_result_totext(result));
2409 * We need to pause here to release the lock on the database.
2411 dns_dbiterator_pause(dbiter);
2412 addnsec3(name, node, salt, salt_len, iterations,
2413 hashlist, zone_soa_min_ttl);
2414 dns_db_detachnode(gdb, &node);
2416 * Add NSEC3's for empty nodes. Use closest encloser logic.
2418 dns_name_fullcompare(name, nextname, &order, &nlabels);
2419 count = dns_name_countlabels(nextname);
2420 while (count > nlabels + 1) {
2421 count--;
2422 dns_name_split(nextname, count, NULL, nextname);
2423 addnsec3(nextname, NULL, salt, salt_len,
2424 iterations, hashlist, zone_soa_min_ttl);
2427 dns_dbiterator_destroy(&dbiter);
2431 * Load the zone file from disk
2433 static void
2434 loadzone(char *file, char *origin, dns_rdataclass_t rdclass, dns_db_t **db) {
2435 isc_buffer_t b;
2436 int len;
2437 dns_fixedname_t fname;
2438 dns_name_t *name;
2439 isc_result_t result;
2441 len = strlen(origin);
2442 isc_buffer_init(&b, origin, len);
2443 isc_buffer_add(&b, len);
2445 dns_fixedname_init(&fname);
2446 name = dns_fixedname_name(&fname);
2447 result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
2448 if (result != ISC_R_SUCCESS)
2449 fatal("failed converting name '%s' to dns format: %s",
2450 origin, isc_result_totext(result));
2452 result = dns_db_create(mctx, "rbt", name, dns_dbtype_zone,
2453 rdclass, 0, NULL, db);
2454 check_result(result, "dns_db_create()");
2456 result = dns_db_load2(*db, file, inputformat);
2457 if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE)
2458 fatal("failed loading zone from '%s': %s",
2459 file, isc_result_totext(result));
2463 * Finds all public zone keys in the zone, and attempts to load the
2464 * private keys from disk.
2466 static void
2467 loadzonekeys(isc_boolean_t preserve_keys, isc_boolean_t load_public) {
2468 dns_dbnode_t *node;
2469 dns_dbversion_t *currentversion = NULL;
2470 isc_result_t result;
2471 dns_rdataset_t rdataset, keysigs, soasigs;
2473 node = NULL;
2474 result = dns_db_findnode(gdb, gorigin, ISC_FALSE, &node);
2475 if (result != ISC_R_SUCCESS)
2476 fatal("failed to find the zone's origin: %s",
2477 isc_result_totext(result));
2479 dns_db_currentversion(gdb, &currentversion);
2481 dns_rdataset_init(&rdataset);
2482 dns_rdataset_init(&soasigs);
2483 dns_rdataset_init(&keysigs);
2485 /* Make note of the keys which signed the SOA, if any */
2486 result = dns_db_findrdataset(gdb, node, currentversion,
2487 dns_rdatatype_soa, 0, 0,
2488 &rdataset, &soasigs);
2489 if (result != ISC_R_SUCCESS)
2490 goto cleanup;
2492 /* Preserve the TTL of the DNSKEY RRset, if any */
2493 dns_rdataset_disassociate(&rdataset);
2494 result = dns_db_findrdataset(gdb, node, currentversion,
2495 dns_rdatatype_dnskey, 0, 0,
2496 &rdataset, &keysigs);
2498 if (result != ISC_R_SUCCESS)
2499 goto cleanup;
2501 if (set_keyttl && keyttl != rdataset.ttl) {
2502 fprintf(stderr, "User-specified TTL %d conflicts "
2503 "with existing DNSKEY RRset TTL.\n",
2504 keyttl);
2505 fprintf(stderr, "Imported keys will use the RRSet "
2506 "TTL %d instead.\n",
2507 rdataset.ttl);
2509 keyttl = rdataset.ttl;
2511 /* Load keys corresponding to the existing DNSKEY RRset. */
2512 result = dns_dnssec_keylistfromrdataset(gorigin, directory, mctx,
2513 &rdataset, &keysigs, &soasigs,
2514 preserve_keys, load_public,
2515 &keylist);
2516 if (result != ISC_R_SUCCESS)
2517 fatal("failed to load the zone keys: %s",
2518 isc_result_totext(result));
2520 cleanup:
2521 if (dns_rdataset_isassociated(&rdataset))
2522 dns_rdataset_disassociate(&rdataset);
2523 if (dns_rdataset_isassociated(&keysigs))
2524 dns_rdataset_disassociate(&keysigs);
2525 if (dns_rdataset_isassociated(&soasigs))
2526 dns_rdataset_disassociate(&soasigs);
2527 dns_db_detachnode(gdb, &node);
2528 dns_db_closeversion(gdb, &currentversion, ISC_FALSE);
2531 static void
2532 loadexplicitkeys(char *keyfiles[], int n, isc_boolean_t setksk) {
2533 isc_result_t result;
2534 int i;
2536 for (i = 0; i < n; i++) {
2537 dns_dnsseckey_t *key = NULL;
2538 dst_key_t *newkey = NULL;
2540 result = dst_key_fromnamedfile(keyfiles[i], directory,
2541 DST_TYPE_PUBLIC |
2542 DST_TYPE_PRIVATE,
2543 mctx, &newkey);
2544 if (result != ISC_R_SUCCESS)
2545 fatal("cannot load dnskey %s: %s", keyfiles[i],
2546 isc_result_totext(result));
2548 if (!dns_name_equal(gorigin, dst_key_name(newkey)))
2549 fatal("key %s not at origin\n", keyfiles[i]);
2551 if (!dst_key_isprivate(newkey))
2552 fatal("cannot sign zone with non-private dnskey %s",
2553 keyfiles[i]);
2555 /* Skip any duplicates */
2556 for (key = ISC_LIST_HEAD(keylist);
2557 key != NULL;
2558 key = ISC_LIST_NEXT(key, link)) {
2559 if (dst_key_id(key->key) == dst_key_id(newkey) &&
2560 dst_key_alg(key->key) == dst_key_alg(newkey))
2561 break;
2564 if (key == NULL) {
2565 /* We haven't seen this key before */
2566 dns_dnsseckey_create(mctx, &newkey, &key);
2567 ISC_LIST_APPEND(keylist, key, link);
2568 key->source = dns_keysource_user;
2569 } else {
2570 dst_key_free(&key->key);
2571 key->key = newkey;
2574 key->force_publish = ISC_TRUE;
2575 key->force_sign = ISC_TRUE;
2577 if (setksk)
2578 key->ksk = ISC_TRUE;
2582 static void
2583 report(const char *format, ...) {
2584 va_list args;
2585 va_start(args, format);
2586 vfprintf(stderr, format, args);
2587 va_end(args);
2588 putc('\n', stderr);
2591 static void
2592 build_final_keylist(void) {
2593 isc_result_t result;
2594 dns_dbversion_t *ver = NULL;
2595 dns_diff_t diff;
2596 dns_dnsseckeylist_t matchkeys;
2597 char name[DNS_NAME_FORMATSIZE];
2600 * Find keys that match this zone in the key repository.
2602 ISC_LIST_INIT(matchkeys);
2603 result = dns_dnssec_findmatchingkeys(gorigin, directory,
2604 mctx, &matchkeys);
2605 if (result == ISC_R_NOTFOUND)
2606 result = ISC_R_SUCCESS;
2607 check_result(result, "dns_dnssec_findmatchingkeys");
2609 result = dns_db_newversion(gdb, &ver);
2610 check_result(result, "dns_db_newversion");
2612 dns_diff_init(mctx, &diff);
2615 * Update keylist with information from from the key repository.
2617 dns_dnssec_updatekeys(&keylist, &matchkeys, NULL, gorigin, keyttl,
2618 &diff, ignore_kskflag, mctx, report);
2620 dns_name_format(gorigin, name, sizeof(name));
2622 result = dns_diff_applysilently(&diff, gdb, ver);
2623 if (result != ISC_R_SUCCESS)
2624 fatal("failed to update DNSKEY RRset at node '%s': %s",
2625 name, isc_result_totext(result));
2627 dns_db_closeversion(gdb, &ver, ISC_TRUE);
2629 dns_diff_clear(&diff);
2632 static void
2633 warnifallksk(dns_db_t *db) {
2634 dns_dbversion_t *currentversion = NULL;
2635 dns_dbnode_t *node = NULL;
2636 dns_rdataset_t rdataset;
2637 dns_rdata_t rdata = DNS_RDATA_INIT;
2638 isc_result_t result;
2639 dns_rdata_dnskey_t dnskey;
2640 isc_boolean_t have_non_ksk = ISC_FALSE;
2642 dns_db_currentversion(db, &currentversion);
2644 result = dns_db_findnode(db, gorigin, ISC_FALSE, &node);
2645 if (result != ISC_R_SUCCESS)
2646 fatal("failed to find the zone's origin: %s",
2647 isc_result_totext(result));
2649 dns_rdataset_init(&rdataset);
2650 result = dns_db_findrdataset(db, node, currentversion,
2651 dns_rdatatype_dnskey, 0, 0, &rdataset,
2652 NULL);
2653 if (result != ISC_R_SUCCESS)
2654 fatal("failed to find keys at the zone apex: %s",
2655 isc_result_totext(result));
2656 result = dns_rdataset_first(&rdataset);
2657 check_result(result, "dns_rdataset_first");
2658 while (result == ISC_R_SUCCESS) {
2659 dns_rdata_reset(&rdata);
2660 dns_rdataset_current(&rdataset, &rdata);
2661 result = dns_rdata_tostruct(&rdata, &dnskey, NULL);
2662 check_result(result, "dns_rdata_tostruct");
2663 if ((dnskey.flags & DNS_KEYFLAG_KSK) == 0) {
2664 have_non_ksk = ISC_TRUE;
2665 result = ISC_R_NOMORE;
2666 } else
2667 result = dns_rdataset_next(&rdataset);
2668 dns_rdata_freestruct(&dnskey);
2670 dns_rdataset_disassociate(&rdataset);
2671 dns_db_detachnode(db, &node);
2672 dns_db_closeversion(db, &currentversion, ISC_FALSE);
2673 if (!have_non_ksk && !ignore_kskflag) {
2674 if (disable_zone_check)
2675 fprintf(stderr, "%s: warning: No non-KSK DNSKEY found; "
2676 "supply a ZSK or use '-z'.\n",
2677 program);
2678 else
2679 fatal("No non-KSK DNSKEY found; "
2680 "supply a ZSK or use '-z'.");
2684 static void
2685 set_nsec3params(isc_boolean_t update, isc_boolean_t set_salt,
2686 isc_boolean_t set_optout, isc_boolean_t set_iter)
2688 isc_result_t result;
2689 dns_dbversion_t *ver = NULL;
2690 dns_dbnode_t *node = NULL;
2691 dns_rdataset_t rdataset;
2692 dns_rdata_t rdata = DNS_RDATA_INIT;
2693 dns_rdata_nsec3_t nsec3;
2694 dns_fixedname_t fname;
2695 dns_name_t *hashname;
2696 unsigned char orig_salt[255];
2697 size_t orig_saltlen;
2698 dns_hash_t orig_hash;
2699 isc_uint16_t orig_iter;
2701 dns_db_currentversion(gdb, &ver);
2702 dns_rdataset_init(&rdataset);
2704 orig_saltlen = sizeof(orig_salt);
2705 result = dns_db_getnsec3parameters(gdb, ver, &orig_hash, NULL,
2706 &orig_iter, orig_salt,
2707 &orig_saltlen);
2708 if (result != ISC_R_SUCCESS)
2709 goto cleanup;
2711 nsec_datatype = dns_rdatatype_nsec3;
2713 if (!update && set_salt) {
2714 if (salt_length != orig_saltlen ||
2715 memcmp(saltbuf, orig_salt, salt_length) != 0)
2716 fatal("An NSEC3 chain exists with a different salt. "
2717 "Use -u to update it.");
2718 } else if (!set_salt) {
2719 salt_length = orig_saltlen;
2720 memmove(saltbuf, orig_salt, orig_saltlen);
2721 gsalt = saltbuf;
2724 if (!update && set_iter) {
2725 if (nsec3iter != orig_iter)
2726 fatal("An NSEC3 chain exists with different "
2727 "iterations. Use -u to update it.");
2728 } else if (!set_iter)
2729 nsec3iter = orig_iter;
2732 * Find an NSEC3 record to get the current OPTOUT value.
2733 * (This assumes all NSEC3 records agree.)
2736 dns_fixedname_init(&fname);
2737 hashname = dns_fixedname_name(&fname);
2738 result = dns_nsec3_hashname(&fname, NULL, NULL,
2739 gorigin, gorigin, dns_hash_sha1,
2740 orig_iter, orig_salt, orig_saltlen);
2741 check_result(result, "dns_nsec3_hashname");
2743 result = dns_db_findnsec3node(gdb, hashname, ISC_FALSE, &node);
2744 if (result != ISC_R_SUCCESS)
2745 goto cleanup;
2747 result = dns_db_findrdataset(gdb, node, ver, dns_rdatatype_nsec3,
2748 0, 0, &rdataset, NULL);
2749 if (result != ISC_R_SUCCESS)
2750 goto cleanup;
2752 result = dns_rdataset_first(&rdataset);
2753 check_result(result, "dns_rdataset_first");
2754 dns_rdataset_current(&rdataset, &rdata);
2755 result = dns_rdata_tostruct(&rdata, &nsec3, NULL);
2756 check_result(result, "dns_rdata_tostruct");
2758 if (!update && set_optout) {
2759 if (nsec3flags != nsec3.flags)
2760 fatal("An NSEC3 chain exists with%s OPTOUT. "
2761 "Use -u -%s to %s it.",
2762 OPTOUT(nsec3.flags) ? "" : "out",
2763 OPTOUT(nsec3.flags) ? "AA" : "A",
2764 OPTOUT(nsec3.flags) ? "clear" : "set");
2765 } else if (!set_optout)
2766 nsec3flags = nsec3.flags;
2768 dns_rdata_freestruct(&nsec3);
2770 cleanup:
2771 if (dns_rdataset_isassociated(&rdataset))
2772 dns_rdataset_disassociate(&rdataset);
2773 if (node != NULL)
2774 dns_db_detachnode(gdb, &node);
2775 dns_db_closeversion(gdb, &ver, ISC_FALSE);
2778 static void
2779 writeset(const char *prefix, dns_rdatatype_t type) {
2780 char *filename;
2781 char namestr[DNS_NAME_FORMATSIZE];
2782 dns_db_t *db = NULL;
2783 dns_dbversion_t *version = NULL;
2784 dns_diff_t diff;
2785 dns_difftuple_t *tuple = NULL;
2786 dns_fixedname_t fixed;
2787 dns_name_t *name;
2788 dns_rdata_t rdata, ds;
2789 isc_boolean_t have_ksk = ISC_FALSE;
2790 isc_boolean_t have_non_ksk = ISC_FALSE;
2791 isc_buffer_t b;
2792 isc_buffer_t namebuf;
2793 isc_region_t r;
2794 isc_result_t result;
2795 dns_dnsseckey_t *key, *tmpkey;
2796 unsigned char dsbuf[DNS_DS_BUFFERSIZE];
2797 unsigned char keybuf[DST_KEY_MAXSIZE];
2798 unsigned int filenamelen;
2799 const dns_master_style_t *style =
2800 (type == dns_rdatatype_dnskey) ? masterstyle : dsstyle;
2802 isc_buffer_init(&namebuf, namestr, sizeof(namestr));
2803 result = dns_name_tofilenametext(gorigin, ISC_FALSE, &namebuf);
2804 check_result(result, "dns_name_tofilenametext");
2805 isc_buffer_putuint8(&namebuf, 0);
2806 filenamelen = strlen(prefix) + strlen(namestr);
2807 if (dsdir != NULL)
2808 filenamelen += strlen(dsdir) + 1;
2809 filename = isc_mem_get(mctx, filenamelen + 1);
2810 if (filename == NULL)
2811 fatal("out of memory");
2812 if (dsdir != NULL)
2813 sprintf(filename, "%s/", dsdir);
2814 else
2815 filename[0] = 0;
2816 strcat(filename, prefix);
2817 strcat(filename, namestr);
2819 dns_diff_init(mctx, &diff);
2821 if (type == dns_rdatatype_dlv) {
2822 dns_name_t tname;
2823 unsigned int labels;
2825 dns_name_init(&tname, NULL);
2826 dns_fixedname_init(&fixed);
2827 name = dns_fixedname_name(&fixed);
2828 labels = dns_name_countlabels(gorigin);
2829 dns_name_getlabelsequence(gorigin, 0, labels - 1, &tname);
2830 result = dns_name_concatenate(&tname, dlv, name, NULL);
2831 check_result(result, "dns_name_concatenate");
2832 } else
2833 name = gorigin;
2835 for (key = ISC_LIST_HEAD(keylist);
2836 key != NULL;
2837 key = ISC_LIST_NEXT(key, link))
2839 if (REVOKE(key->key))
2840 continue;
2841 if (isksk(key)) {
2842 have_ksk = ISC_TRUE;
2843 have_non_ksk = ISC_FALSE;
2844 } else {
2845 have_ksk = ISC_FALSE;
2846 have_non_ksk = ISC_TRUE;
2848 for (tmpkey = ISC_LIST_HEAD(keylist);
2849 tmpkey != NULL;
2850 tmpkey = ISC_LIST_NEXT(tmpkey, link)) {
2851 if (dst_key_alg(key->key) != dst_key_alg(tmpkey->key))
2852 continue;
2853 if (REVOKE(tmpkey->key))
2854 continue;
2855 if (isksk(tmpkey))
2856 have_ksk = ISC_TRUE;
2857 else
2858 have_non_ksk = ISC_TRUE;
2860 if (have_ksk && have_non_ksk && !isksk(key))
2861 continue;
2862 dns_rdata_init(&rdata);
2863 dns_rdata_init(&ds);
2864 isc_buffer_init(&b, keybuf, sizeof(keybuf));
2865 result = dst_key_todns(key->key, &b);
2866 check_result(result, "dst_key_todns");
2867 isc_buffer_usedregion(&b, &r);
2868 dns_rdata_fromregion(&rdata, gclass, dns_rdatatype_dnskey, &r);
2869 if (type != dns_rdatatype_dnskey) {
2870 result = dns_ds_buildrdata(gorigin, &rdata,
2871 DNS_DSDIGEST_SHA1,
2872 dsbuf, &ds);
2873 check_result(result, "dns_ds_buildrdata");
2874 if (type == dns_rdatatype_dlv)
2875 ds.type = dns_rdatatype_dlv;
2876 result = dns_difftuple_create(mctx,
2877 DNS_DIFFOP_ADDRESIGN,
2878 name, 0, &ds, &tuple);
2879 check_result(result, "dns_difftuple_create");
2880 dns_diff_append(&diff, &tuple);
2882 dns_rdata_reset(&ds);
2883 result = dns_ds_buildrdata(gorigin, &rdata,
2884 DNS_DSDIGEST_SHA256,
2885 dsbuf, &ds);
2886 check_result(result, "dns_ds_buildrdata");
2887 if (type == dns_rdatatype_dlv)
2888 ds.type = dns_rdatatype_dlv;
2889 result = dns_difftuple_create(mctx,
2890 DNS_DIFFOP_ADDRESIGN,
2891 name, 0, &ds, &tuple);
2893 } else
2894 result = dns_difftuple_create(mctx,
2895 DNS_DIFFOP_ADDRESIGN,
2896 gorigin, zone_soa_min_ttl,
2897 &rdata, &tuple);
2898 check_result(result, "dns_difftuple_create");
2899 dns_diff_append(&diff, &tuple);
2902 result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone,
2903 gclass, 0, NULL, &db);
2904 check_result(result, "dns_db_create");
2906 result = dns_db_newversion(db, &version);
2907 check_result(result, "dns_db_newversion");
2909 result = dns_diff_apply(&diff, db, version);
2910 check_result(result, "dns_diff_apply");
2911 dns_diff_clear(&diff);
2913 result = dns_master_dump(mctx, db, version, style, filename);
2914 check_result(result, "dns_master_dump");
2916 isc_mem_put(mctx, filename, filenamelen + 1);
2918 dns_db_closeversion(db, &version, ISC_FALSE);
2919 dns_db_detach(&db);
2922 static void
2923 print_time(FILE *fp) {
2924 time_t currenttime;
2926 if (outputformat != dns_masterformat_text)
2927 return;
2929 currenttime = time(NULL);
2930 fprintf(fp, "; File written on %s", ctime(&currenttime));
2933 static void
2934 print_version(FILE *fp) {
2935 if (outputformat != dns_masterformat_text)
2936 return;
2938 fprintf(fp, "; dnssec_signzone version " VERSION "\n");
2941 ISC_PLATFORM_NORETURN_PRE static void
2942 usage(void) ISC_PLATFORM_NORETURN_POST;
2944 static void
2945 usage(void) {
2946 fprintf(stderr, "Usage:\n");
2947 fprintf(stderr, "\t%s [options] zonefile [keys]\n", program);
2949 fprintf(stderr, "\n");
2951 fprintf(stderr, "Version: %s\n", VERSION);
2953 fprintf(stderr, "Options: (default value in parenthesis) \n");
2954 fprintf(stderr, "\t-S:\tsmart signing: automatically finds key files\n"
2955 "\t\tfor the zone and determines how they are to "
2956 "be used\n");
2957 fprintf(stderr, "\t-K directory:\n");
2958 fprintf(stderr, "\t\tdirectory to find key files (.)\n");
2959 fprintf(stderr, "\t-d directory:\n");
2960 fprintf(stderr, "\t\tdirectory to find dsset-* files (.)\n");
2961 fprintf(stderr, "\t-g:\t");
2962 fprintf(stderr, "update DS records based on child zones' "
2963 "dsset-* files\n");
2964 fprintf(stderr, "\t-s [YYYYMMDDHHMMSS|+offset]:\n");
2965 fprintf(stderr, "\t\tRRSIG start time "
2966 "- absolute|offset (now - 1 hour)\n");
2967 fprintf(stderr, "\t-e [YYYYMMDDHHMMSS|+offset|\"now\"+offset]:\n");
2968 fprintf(stderr, "\t\tRRSIG end time "
2969 "- absolute|from start|from now "
2970 "(now + 30 days)\n");
2971 fprintf(stderr, "\t-X [YYYYMMDDHHMMSS|+offset|\"now\"+offset]:\n");
2972 fprintf(stderr, "\t\tDNSKEY RRSIG end "
2973 "- absolute|from start|from now "
2974 "(matches -e)\n");
2975 fprintf(stderr, "\t-i interval:\n");
2976 fprintf(stderr, "\t\tcycle interval - resign "
2977 "if < interval from end ( (end-start)/4 )\n");
2978 fprintf(stderr, "\t-j jitter:\n");
2979 fprintf(stderr, "\t\trandomize signature end time up to jitter seconds\n");
2980 fprintf(stderr, "\t-v debuglevel (0)\n");
2981 fprintf(stderr, "\t-V:\tprint version information\n");
2982 fprintf(stderr, "\t-o origin:\n");
2983 fprintf(stderr, "\t\tzone origin (name of zonefile)\n");
2984 fprintf(stderr, "\t-f outfile:\n");
2985 fprintf(stderr, "\t\tfile the signed zone is written in "
2986 "(zonefile + .signed)\n");
2987 fprintf(stderr, "\t-I format:\n");
2988 fprintf(stderr, "\t\tfile format of input zonefile (text)\n");
2989 fprintf(stderr, "\t-O format:\n");
2990 fprintf(stderr, "\t\tfile format of signed zone file (text)\n");
2991 fprintf(stderr, "\t-N format:\n");
2992 fprintf(stderr, "\t\tsoa serial format of signed zone file (keep)\n");
2993 fprintf(stderr, "\t-D:\n");
2994 fprintf(stderr, "\t\toutput only DNSSEC-related records\n");
2995 fprintf(stderr, "\t-r randomdev:\n");
2996 fprintf(stderr, "\t\ta file containing random data\n");
2997 fprintf(stderr, "\t-a:\t");
2998 fprintf(stderr, "verify generated signatures\n");
2999 fprintf(stderr, "\t-c class (IN)\n");
3000 fprintf(stderr, "\t-E engine:\n");
3001 #if defined(PKCS11CRYPTO)
3002 fprintf(stderr, "\t\tpath to PKCS#11 provider library "
3003 "(default is %s)\n", PK11_LIB_LOCATION);
3004 #elif defined(USE_PKCS11)
3005 fprintf(stderr, "\t\tname of an OpenSSL engine to use "
3006 "(default is \"pkcs11\")\n");
3007 #else
3008 fprintf(stderr, "\t\tname of an OpenSSL engine to use\n");
3009 #endif
3010 fprintf(stderr, "\t-p:\t");
3011 fprintf(stderr, "use pseudorandom data (faster but less secure)\n");
3012 fprintf(stderr, "\t-P:\t");
3013 fprintf(stderr, "disable post-sign verification\n");
3014 fprintf(stderr, "\t-Q:\t");
3015 fprintf(stderr, "remove signatures from keys that are no "
3016 "longer active\n");
3017 fprintf(stderr, "\t-R:\t");
3018 fprintf(stderr, "remove signatures from keys that no longer exist\n");
3019 fprintf(stderr, "\t-T TTL:\tTTL for newly added DNSKEYs\n");
3020 fprintf(stderr, "\t-t:\t");
3021 fprintf(stderr, "print statistics\n");
3022 fprintf(stderr, "\t-u:\t");
3023 fprintf(stderr, "update or replace an existing NSEC/NSEC3 chain\n");
3024 fprintf(stderr, "\t-x:\tsign DNSKEY record with KSKs only, not ZSKs\n");
3025 fprintf(stderr, "\t-z:\tsign all records with KSKs\n");
3026 fprintf(stderr, "\t-C:\tgenerate a keyset file, for compatibility\n"
3027 "\t\twith older versions of dnssec-signzone -g\n");
3028 fprintf(stderr, "\t-n ncpus (number of cpus present)\n");
3029 fprintf(stderr, "\t-k key_signing_key\n");
3030 fprintf(stderr, "\t-l lookasidezone\n");
3031 fprintf(stderr, "\t-3 NSEC3 salt\n");
3032 fprintf(stderr, "\t-H NSEC3 iterations (10)\n");
3033 fprintf(stderr, "\t-A NSEC3 optout\n");
3035 fprintf(stderr, "\n");
3037 fprintf(stderr, "Signing Keys: ");
3038 fprintf(stderr, "(default: all zone keys that have private keys)\n");
3039 fprintf(stderr, "\tkeyfile (Kname+alg+tag)\n");
3041 exit(0);
3044 static void
3045 removetempfile(void) {
3046 if (removefile)
3047 isc_file_remove(tempfile);
3050 static void
3051 print_stats(isc_time_t *timer_start, isc_time_t *timer_finish,
3052 isc_time_t *sign_start, isc_time_t *sign_finish)
3054 isc_uint64_t time_us; /* Time in microseconds */
3055 isc_uint64_t time_ms; /* Time in milliseconds */
3056 isc_uint64_t sig_ms; /* Signatures per millisecond */
3057 FILE *out = output_stdout ? stderr : stdout;
3059 fprintf(out, "Signatures generated: %10d\n", nsigned);
3060 fprintf(out, "Signatures retained: %10d\n", nretained);
3061 fprintf(out, "Signatures dropped: %10d\n", ndropped);
3062 fprintf(out, "Signatures successfully verified: %10d\n", nverified);
3063 fprintf(out, "Signatures unsuccessfully "
3064 "verified: %10d\n", nverifyfailed);
3066 time_us = isc_time_microdiff(sign_finish, sign_start);
3067 time_ms = time_us / 1000;
3068 fprintf(out, "Signing time in seconds: %7u.%03u\n",
3069 (unsigned int) (time_ms / 1000),
3070 (unsigned int) (time_ms % 1000));
3071 if (time_us > 0) {
3072 sig_ms = ((isc_uint64_t)nsigned * 1000000000) / time_us;
3073 fprintf(out, "Signatures per second: %7u.%03u\n",
3074 (unsigned int) sig_ms / 1000,
3075 (unsigned int) sig_ms % 1000);
3078 time_us = isc_time_microdiff(timer_finish, timer_start);
3079 time_ms = time_us / 1000;
3080 fprintf(out, "Runtime in seconds: %7u.%03u\n",
3081 (unsigned int) (time_ms / 1000),
3082 (unsigned int) (time_ms % 1000));
3086 main(int argc, char *argv[]) {
3087 int i, ch;
3088 char *startstr = NULL, *endstr = NULL, *classname = NULL;
3089 char *dnskey_endstr = NULL;
3090 char *origin = NULL, *file = NULL, *output = NULL;
3091 char *inputformatstr = NULL, *outputformatstr = NULL;
3092 char *serialformatstr = NULL;
3093 char *dskeyfile[MAXDSKEYS];
3094 int ndskeys = 0;
3095 char *endp;
3096 isc_time_t timer_start, timer_finish;
3097 isc_time_t sign_start, sign_finish;
3098 dns_dnsseckey_t *key;
3099 isc_result_t result;
3100 isc_log_t *log = NULL;
3101 isc_boolean_t pseudorandom = ISC_FALSE;
3102 #ifdef USE_PKCS11
3103 const char *engine = PKCS11_ENGINE;
3104 #else
3105 const char *engine = NULL;
3106 #endif
3107 unsigned int eflags;
3108 isc_boolean_t free_output = ISC_FALSE;
3109 int tempfilelen = 0;
3110 dns_rdataclass_t rdclass;
3111 isc_task_t **tasks = NULL;
3112 isc_buffer_t b;
3113 int len;
3114 hashlist_t hashlist;
3115 isc_boolean_t make_keyset = ISC_FALSE;
3116 isc_boolean_t set_salt = ISC_FALSE;
3117 isc_boolean_t set_optout = ISC_FALSE;
3118 isc_boolean_t set_iter = ISC_FALSE;
3119 isc_boolean_t nonsecify = ISC_FALSE;
3121 /* Unused letters: Bb G J q Yy (and F is reserved). */
3122 #define CMDLINE_FLAGS \
3123 "3:AaCc:Dd:E:e:f:FghH:i:I:j:K:k:L:l:m:M:n:N:o:O:PpQRr:s:ST:tuUv:VX:xzZ:"
3126 * Process memory debugging argument first.
3128 while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) {
3129 switch (ch) {
3130 case 'm':
3131 if (strcasecmp(isc_commandline_argument, "record") == 0)
3132 isc_mem_debugging |= ISC_MEM_DEBUGRECORD;
3133 if (strcasecmp(isc_commandline_argument, "trace") == 0)
3134 isc_mem_debugging |= ISC_MEM_DEBUGTRACE;
3135 if (strcasecmp(isc_commandline_argument, "usage") == 0)
3136 isc_mem_debugging |= ISC_MEM_DEBUGUSAGE;
3137 if (strcasecmp(isc_commandline_argument, "size") == 0)
3138 isc_mem_debugging |= ISC_MEM_DEBUGSIZE;
3139 if (strcasecmp(isc_commandline_argument, "mctx") == 0)
3140 isc_mem_debugging |= ISC_MEM_DEBUGCTX;
3141 break;
3142 default:
3143 break;
3146 isc_commandline_reset = ISC_TRUE;
3148 masterstyle = &dns_master_style_explicitttl;
3150 check_result(isc_app_start(), "isc_app_start");
3152 result = isc_mem_create(0, 0, &mctx);
3153 if (result != ISC_R_SUCCESS)
3154 fatal("out of memory");
3156 #ifdef PKCS11CRYPTO
3157 pk11_result_register();
3158 #endif
3159 dns_result_register();
3161 isc_commandline_errprint = ISC_FALSE;
3163 while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) {
3164 switch (ch) {
3165 case '3':
3166 set_salt = ISC_TRUE;
3167 nsec_datatype = dns_rdatatype_nsec3;
3168 if (strcmp(isc_commandline_argument, "-") != 0) {
3169 isc_buffer_t target;
3170 char *sarg;
3172 sarg = isc_commandline_argument;
3173 isc_buffer_init(&target, saltbuf,
3174 sizeof(saltbuf));
3175 result = isc_hex_decodestring(sarg, &target);
3176 check_result(result,
3177 "isc_hex_decodestring(salt)");
3178 salt_length = isc_buffer_usedlength(&target);
3180 break;
3182 case 'A':
3183 set_optout = ISC_TRUE;
3184 if (OPTOUT(nsec3flags))
3185 nsec3flags &= ~DNS_NSEC3FLAG_OPTOUT;
3186 else
3187 nsec3flags |= DNS_NSEC3FLAG_OPTOUT;
3188 break;
3190 case 'a':
3191 tryverify = ISC_TRUE;
3192 break;
3194 case 'C':
3195 make_keyset = ISC_TRUE;
3196 break;
3198 case 'c':
3199 classname = isc_commandline_argument;
3200 break;
3202 case 'd':
3203 dsdir = isc_commandline_argument;
3204 if (strlen(dsdir) == 0U)
3205 fatal("DS directory must be non-empty string");
3206 result = try_dir(dsdir);
3207 if (result != ISC_R_SUCCESS)
3208 fatal("cannot open directory %s: %s",
3209 dsdir, isc_result_totext(result));
3210 break;
3212 case 'D':
3213 output_dnssec_only = ISC_TRUE;
3214 break;
3216 case 'E':
3217 engine = isc_commandline_argument;
3218 break;
3220 case 'e':
3221 endstr = isc_commandline_argument;
3222 break;
3224 case 'f':
3225 output = isc_commandline_argument;
3226 if (strcmp(output, "-") == 0)
3227 output_stdout = ISC_TRUE;
3228 break;
3230 case 'g':
3231 generateds = ISC_TRUE;
3232 break;
3234 case 'H':
3235 set_iter = ISC_TRUE;
3236 nsec3iter = strtoul(isc_commandline_argument, &endp, 0);
3237 if (*endp != '\0')
3238 fatal("iterations must be numeric");
3239 if (nsec3iter > 0xffffU)
3240 fatal("iterations too big");
3241 break;
3243 case 'I':
3244 inputformatstr = isc_commandline_argument;
3245 break;
3247 case 'i':
3248 endp = NULL;
3249 cycle = strtol(isc_commandline_argument, &endp, 0);
3250 if (*endp != '\0' || cycle < 0)
3251 fatal("cycle period must be numeric and "
3252 "positive");
3253 break;
3255 case 'j':
3256 endp = NULL;
3257 jitter = strtol(isc_commandline_argument, &endp, 0);
3258 if (*endp != '\0' || jitter < 0)
3259 fatal("jitter must be numeric and positive");
3260 break;
3262 case 'K':
3263 directory = isc_commandline_argument;
3264 break;
3266 case 'k':
3267 if (ndskeys == MAXDSKEYS)
3268 fatal("too many key-signing keys specified");
3269 dskeyfile[ndskeys++] = isc_commandline_argument;
3270 break;
3272 case 'L':
3273 snset = ISC_TRUE;
3274 endp = NULL;
3275 serialnum = strtol(isc_commandline_argument, &endp, 0);
3276 if (*endp != '\0') {
3277 fprintf(stderr, "source serial number "
3278 "must be numeric");
3279 exit(1);
3281 break;
3283 case 'l':
3284 len = strlen(isc_commandline_argument);
3285 isc_buffer_init(&b, isc_commandline_argument, len);
3286 isc_buffer_add(&b, len);
3288 dns_fixedname_init(&dlv_fixed);
3289 dlv = dns_fixedname_name(&dlv_fixed);
3290 result = dns_name_fromtext(dlv, &b, dns_rootname, 0,
3291 NULL);
3292 check_result(result, "dns_name_fromtext(dlv)");
3293 break;
3295 case 'M':
3296 endp = NULL;
3297 set_maxttl = ISC_TRUE;
3298 maxttl = strtol(isc_commandline_argument, &endp, 0);
3299 if (*endp != '\0') {
3300 fprintf(stderr, "maximum TTL "
3301 "must be numeric");
3302 exit(1);
3304 break;
3306 case 'm':
3307 break;
3309 case 'N':
3310 serialformatstr = isc_commandline_argument;
3311 break;
3313 case 'n':
3314 endp = NULL;
3315 ntasks = strtol(isc_commandline_argument, &endp, 0);
3316 if (*endp != '\0' || ntasks > ISC_INT32_MAX)
3317 fatal("number of cpus must be numeric");
3318 break;
3320 case 'O':
3321 outputformatstr = isc_commandline_argument;
3322 break;
3324 case 'o':
3325 origin = isc_commandline_argument;
3326 break;
3328 case 'P':
3329 disable_zone_check = ISC_TRUE;
3330 break;
3332 case 'p':
3333 pseudorandom = ISC_TRUE;
3334 break;
3336 case 'Q':
3337 remove_inactkeysigs = ISC_TRUE;
3338 break;
3340 case 'R':
3341 remove_orphansigs = ISC_TRUE;
3342 break;
3344 case 'r':
3345 setup_entropy(mctx, isc_commandline_argument, &ectx);
3346 break;
3348 case 'S':
3349 smartsign = ISC_TRUE;
3350 break;
3352 case 's':
3353 startstr = isc_commandline_argument;
3354 break;
3356 case 'T':
3357 endp = NULL;
3358 set_keyttl = ISC_TRUE;
3359 keyttl = strtottl(isc_commandline_argument);
3360 break;
3362 case 't':
3363 printstats = ISC_TRUE;
3364 break;
3366 case 'U': /* Undocumented for testing only. */
3367 unknownalg = ISC_TRUE;
3368 break;
3370 case 'u':
3371 update_chain = ISC_TRUE;
3372 break;
3374 case 'v':
3375 endp = NULL;
3376 verbose = strtol(isc_commandline_argument, &endp, 0);
3377 if (*endp != '\0')
3378 fatal("verbose level must be numeric");
3379 break;
3381 case 'X':
3382 dnskey_endstr = isc_commandline_argument;
3383 break;
3385 case 'x':
3386 keyset_kskonly = ISC_TRUE;
3387 break;
3389 case 'z':
3390 ignore_kskflag = ISC_TRUE;
3391 break;
3393 case 'F':
3394 /* Reserved for FIPS mode */
3395 /* FALLTHROUGH */
3396 case '?':
3397 if (isc_commandline_option != '?')
3398 fprintf(stderr, "%s: invalid argument -%c\n",
3399 program, isc_commandline_option);
3400 /* FALLTHROUGH */
3401 case 'h':
3402 /* Does not return. */
3403 usage();
3405 case 'V':
3406 /* Does not return. */
3407 version(program);
3409 case 'Z': /* Undocumented test options */
3410 if (!strcmp(isc_commandline_argument, "nonsecify"))
3411 nonsecify = ISC_TRUE;
3412 break;
3414 default:
3415 fprintf(stderr, "%s: unhandled option -%c\n",
3416 program, isc_commandline_option);
3417 exit(1);
3421 if (ectx == NULL)
3422 setup_entropy(mctx, NULL, &ectx);
3423 eflags = ISC_ENTROPY_BLOCKING;
3424 if (!pseudorandom)
3425 eflags |= ISC_ENTROPY_GOODONLY;
3427 result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE);
3428 if (result != ISC_R_SUCCESS)
3429 fatal("could not create hash context");
3431 result = dst_lib_init2(mctx, ectx, engine, eflags);
3432 if (result != ISC_R_SUCCESS)
3433 fatal("could not initialize dst: %s",
3434 isc_result_totext(result));
3435 isc_stdtime_get(&now);
3437 if (startstr != NULL) {
3438 starttime = strtotime(startstr, now, now, NULL);
3439 } else
3440 starttime = now - 3600; /* Allow for some clock skew. */
3442 if (endstr != NULL)
3443 endtime = strtotime(endstr, now, starttime, NULL);
3444 else
3445 endtime = starttime + (30 * 24 * 60 * 60);
3447 if (dnskey_endstr != NULL) {
3448 dnskey_endtime = strtotime(dnskey_endstr, now, starttime,
3449 NULL);
3450 if (endstr != NULL && dnskey_endtime == endtime)
3451 fprintf(stderr, "WARNING: -e and -X were both set, "
3452 "but have identical values.\n");
3453 } else
3454 dnskey_endtime = endtime;
3456 if (cycle == -1)
3457 cycle = (endtime - starttime) / 4;
3459 if (ntasks == 0)
3460 ntasks = isc_os_ncpus() * 2;
3461 vbprintf(4, "using %d cpus\n", ntasks);
3463 rdclass = strtoclass(classname);
3465 if (directory == NULL)
3466 directory = ".";
3468 setup_logging(mctx, &log);
3470 argc -= isc_commandline_index;
3471 argv += isc_commandline_index;
3473 if (argc < 1)
3474 usage();
3476 file = argv[0];
3478 argc -= 1;
3479 argv += 1;
3481 if (origin == NULL)
3482 origin = file;
3484 if (output == NULL) {
3485 free_output = ISC_TRUE;
3486 output = isc_mem_allocate(mctx,
3487 strlen(file) + strlen(".signed") + 1);
3488 if (output == NULL)
3489 fatal("out of memory");
3490 sprintf(output, "%s.signed", file);
3493 if (inputformatstr != NULL) {
3494 if (strcasecmp(inputformatstr, "text") == 0)
3495 inputformat = dns_masterformat_text;
3496 else if (strcasecmp(inputformatstr, "map") == 0)
3497 inputformat = dns_masterformat_map;
3498 else if (strcasecmp(inputformatstr, "raw") == 0)
3499 inputformat = dns_masterformat_raw;
3500 else if (strncasecmp(inputformatstr, "raw=", 4) == 0) {
3501 inputformat = dns_masterformat_raw;
3502 fprintf(stderr,
3503 "WARNING: input format version ignored\n");
3504 } else
3505 fatal("unknown file format: %s", inputformatstr);
3509 if (outputformatstr != NULL) {
3510 if (strcasecmp(outputformatstr, "text") == 0) {
3511 outputformat = dns_masterformat_text;
3512 } else if (strcasecmp(outputformatstr, "full") == 0) {
3513 outputformat = dns_masterformat_text;
3514 masterstyle = &dns_master_style_full;
3515 } else if (strcasecmp(outputformatstr, "map") == 0) {
3516 outputformat = dns_masterformat_map;
3517 } else if (strcasecmp(outputformatstr, "raw") == 0) {
3518 outputformat = dns_masterformat_raw;
3519 } else if (strncasecmp(outputformatstr, "raw=", 4) == 0) {
3520 char *end;
3521 outputformat = dns_masterformat_raw;
3523 outputformat = dns_masterformat_raw;
3524 rawversion = strtol(outputformatstr + 4, &end, 10);
3525 if (end == outputformatstr + 4 || *end != '\0' ||
3526 rawversion > 1U) {
3527 fprintf(stderr,
3528 "unknown raw format version\n");
3529 exit(1);
3531 } else
3532 fatal("unknown file format: %s", outputformatstr);
3535 if (serialformatstr != NULL) {
3536 if (strcasecmp(serialformatstr, "keep") == 0)
3537 serialformat = SOA_SERIAL_KEEP;
3538 else if (strcasecmp(serialformatstr, "increment") == 0 ||
3539 strcasecmp(serialformatstr, "incr") == 0)
3540 serialformat = SOA_SERIAL_INCREMENT;
3541 else if (strcasecmp(serialformatstr, "unixtime") == 0)
3542 serialformat = SOA_SERIAL_UNIXTIME;
3543 else
3544 fatal("unknown soa serial format: %s",
3545 serialformatstr);
3548 if (output_dnssec_only && outputformat != dns_masterformat_text)
3549 fatal("option -D can only be used with \"-O text\"");
3551 if (output_dnssec_only && serialformat != SOA_SERIAL_KEEP)
3552 fatal("option -D can only be used with \"-N keep\"");
3554 if (output_dnssec_only && set_maxttl)
3555 fatal("option -D cannot be used with -M");
3557 result = dns_master_stylecreate(&dsstyle, DNS_STYLEFLAG_NO_TTL,
3558 0, 24, 0, 0, 0, 8, mctx);
3559 check_result(result, "dns_master_stylecreate");
3561 gdb = NULL;
3562 TIME_NOW(&timer_start);
3563 loadzone(file, origin, rdclass, &gdb);
3564 gorigin = dns_db_origin(gdb);
3565 gclass = dns_db_class(gdb);
3566 get_soa_ttls();
3568 if (set_maxttl && set_keyttl && keyttl > maxttl) {
3569 fprintf(stderr, "%s: warning: Specified key TTL %d "
3570 "exceeds maximum zone TTL; reducing to %d\n",
3571 program, keyttl, maxttl);
3572 keyttl = maxttl;
3575 if (!set_keyttl)
3576 keyttl = soa_ttl;
3579 * Check for any existing NSEC3 parameters in the zone,
3580 * and use them as defaults if -u was not specified.
3582 if (update_chain && !set_optout && !set_iter && !set_salt)
3583 nsec_datatype = dns_rdatatype_nsec;
3584 else
3585 set_nsec3params(update_chain, set_salt, set_optout, set_iter);
3588 * We need to do this early on, as we start messing with the list
3589 * of keys rather early.
3591 ISC_LIST_INIT(keylist);
3592 isc_rwlock_init(&keylist_lock, 0, 0);
3595 * Fill keylist with:
3596 * 1) Keys listed in the DNSKEY set that have
3597 * private keys associated, *if* no keys were
3598 * set on the command line.
3599 * 2) ZSKs set on the command line
3600 * 3) KSKs set on the command line
3601 * 4) Any keys remaining in the DNSKEY set which
3602 * do not have private keys associated and were
3603 * not specified on the command line.
3605 if (argc == 0 || smartsign)
3606 loadzonekeys(!smartsign, ISC_FALSE);
3607 loadexplicitkeys(argv, argc, ISC_FALSE);
3608 loadexplicitkeys(dskeyfile, ndskeys, ISC_TRUE);
3609 loadzonekeys(!smartsign, ISC_TRUE);
3612 * If we're doing smart signing, look in the key repository for
3613 * key files with metadata, and merge them with the keylist
3614 * we have now.
3616 if (smartsign)
3617 build_final_keylist();
3619 /* Now enumerate the key list */
3620 for (key = ISC_LIST_HEAD(keylist);
3621 key != NULL;
3622 key = ISC_LIST_NEXT(key, link)) {
3623 key->index = keycount++;
3626 if (keycount == 0) {
3627 if (disable_zone_check)
3628 fprintf(stderr, "%s: warning: No keys specified "
3629 "or found\n", program);
3630 else
3631 fatal("No signing keys specified or found.");
3632 nokeys = ISC_TRUE;
3635 warnifallksk(gdb);
3637 if (IS_NSEC3) {
3638 unsigned int max;
3639 isc_boolean_t answer;
3641 hash_length = dns_nsec3_hashlength(dns_hash_sha1);
3642 hashlist_init(&hashlist, dns_db_nodecount(gdb) * 2,
3643 hash_length);
3644 result = dns_nsec_nseconly(gdb, gversion, &answer);
3645 if (result == ISC_R_NOTFOUND)
3646 fprintf(stderr, "%s: warning: NSEC3 generation "
3647 "requested with no DNSKEY; ignoring\n",
3648 program);
3649 else if (result != ISC_R_SUCCESS)
3650 check_result(result, "dns_nsec_nseconly");
3651 else if (answer)
3652 fatal("NSEC3 generation requested with "
3653 "NSEC-only DNSKEY");
3655 result = dns_nsec3_maxiterations(gdb, NULL, mctx, &max);
3656 check_result(result, "dns_nsec3_maxiterations()");
3657 if (nsec3iter > max)
3658 fatal("NSEC3 iterations too big for weakest DNSKEY "
3659 "strength. Maximum iterations allowed %u.", max);
3662 gversion = NULL;
3663 result = dns_db_newversion(gdb, &gversion);
3664 check_result(result, "dns_db_newversion()");
3666 switch (serialformat) {
3667 case SOA_SERIAL_INCREMENT:
3668 setsoaserial(0);
3669 break;
3670 case SOA_SERIAL_UNIXTIME:
3671 setsoaserial(now);
3672 break;
3673 case SOA_SERIAL_KEEP:
3674 default:
3675 /* do nothing */
3676 break;
3679 /* Remove duplicates and cap TTLs at maxttl */
3680 cleanup_zone();
3682 if (!nonsecify) {
3683 if (IS_NSEC3)
3684 nsec3ify(dns_hash_sha1, nsec3iter, gsalt, salt_length,
3685 &hashlist);
3686 else
3687 nsecify();
3690 if (!nokeys) {
3691 writeset("dsset-", dns_rdatatype_ds);
3692 if (make_keyset)
3693 writeset("keyset-", dns_rdatatype_dnskey);
3694 if (dlv != NULL) {
3695 writeset("dlvset-", dns_rdatatype_dlv);
3699 if (output_stdout) {
3700 outfp = stdout;
3701 if (outputformatstr == NULL)
3702 masterstyle = &dns_master_style_full;
3703 } else {
3704 tempfilelen = strlen(output) + 20;
3705 tempfile = isc_mem_get(mctx, tempfilelen);
3706 if (tempfile == NULL)
3707 fatal("out of memory");
3709 result = isc_file_mktemplate(output, tempfile, tempfilelen);
3710 check_result(result, "isc_file_mktemplate");
3712 if (outputformat == dns_masterformat_text)
3713 result = isc_file_openunique(tempfile, &outfp);
3714 else
3715 result = isc_file_bopenunique(tempfile, &outfp);
3716 if (result != ISC_R_SUCCESS)
3717 fatal("failed to open temporary output file: %s",
3718 isc_result_totext(result));
3719 removefile = ISC_TRUE;
3720 setfatalcallback(&removetempfile);
3723 print_time(outfp);
3724 print_version(outfp);
3726 result = isc_taskmgr_create(mctx, ntasks, 0, &taskmgr);
3727 if (result != ISC_R_SUCCESS)
3728 fatal("failed to create task manager: %s",
3729 isc_result_totext(result));
3731 master = NULL;
3732 result = isc_task_create(taskmgr, 0, &master);
3733 if (result != ISC_R_SUCCESS)
3734 fatal("failed to create task: %s", isc_result_totext(result));
3736 tasks = isc_mem_get(mctx, ntasks * sizeof(isc_task_t *));
3737 if (tasks == NULL)
3738 fatal("out of memory");
3739 for (i = 0; i < (int)ntasks; i++) {
3740 tasks[i] = NULL;
3741 result = isc_task_create(taskmgr, 0, &tasks[i]);
3742 if (result != ISC_R_SUCCESS)
3743 fatal("failed to create task: %s",
3744 isc_result_totext(result));
3747 RUNTIME_CHECK(isc_mutex_init(&namelock) == ISC_R_SUCCESS);
3748 if (printstats)
3749 RUNTIME_CHECK(isc_mutex_init(&statslock) == ISC_R_SUCCESS);
3751 presign();
3752 TIME_NOW(&sign_start);
3753 signapex();
3754 if (!finished) {
3756 * There is more work to do. Spread it out over multiple
3757 * processors if possible.
3759 for (i = 0; i < (int)ntasks; i++) {
3760 result = isc_app_onrun(mctx, master, startworker,
3761 tasks[i]);
3762 if (result != ISC_R_SUCCESS)
3763 fatal("failed to start task: %s",
3764 isc_result_totext(result));
3766 (void)isc_app_run();
3767 if (!finished)
3768 fatal("process aborted by user");
3769 } else
3770 isc_task_detach(&master);
3771 shuttingdown = ISC_TRUE;
3772 for (i = 0; i < (int)ntasks; i++)
3773 isc_task_detach(&tasks[i]);
3774 isc_taskmgr_destroy(&taskmgr);
3775 isc_mem_put(mctx, tasks, ntasks * sizeof(isc_task_t *));
3776 postsign();
3777 TIME_NOW(&sign_finish);
3779 if (!disable_zone_check)
3780 verifyzone(gdb, gversion, gorigin, mctx,
3781 ignore_kskflag, keyset_kskonly);
3783 if (outputformat != dns_masterformat_text) {
3784 dns_masterrawheader_t header;
3785 dns_master_initrawheader(&header);
3786 if (rawversion == 0U)
3787 header.flags = DNS_MASTERRAW_COMPAT;
3788 else if (snset) {
3789 header.flags = DNS_MASTERRAW_SOURCESERIALSET;
3790 header.sourceserial = serialnum;
3792 result = dns_master_dumptostream3(mctx, gdb, gversion,
3793 masterstyle, outputformat,
3794 &header, outfp);
3795 check_result(result, "dns_master_dumptostream3");
3798 DESTROYLOCK(&namelock);
3799 if (printstats)
3800 DESTROYLOCK(&statslock);
3802 if (!output_stdout) {
3803 result = isc_stdio_close(outfp);
3804 check_result(result, "isc_stdio_close");
3805 removefile = ISC_FALSE;
3807 result = isc_file_rename(tempfile, output);
3808 if (result != ISC_R_SUCCESS)
3809 fatal("failed to rename temp file to %s: %s",
3810 output, isc_result_totext(result));
3812 printf("%s\n", output);
3815 dns_db_closeversion(gdb, &gversion, ISC_FALSE);
3816 dns_db_detach(&gdb);
3818 while (!ISC_LIST_EMPTY(keylist)) {
3819 key = ISC_LIST_HEAD(keylist);
3820 ISC_LIST_UNLINK(keylist, key, link);
3821 dns_dnsseckey_destroy(mctx, &key);
3824 if (tempfilelen != 0)
3825 isc_mem_put(mctx, tempfile, tempfilelen);
3827 if (free_output)
3828 isc_mem_free(mctx, output);
3830 dns_master_styledestroy(&dsstyle, mctx);
3832 cleanup_logging(&log);
3833 dst_lib_destroy();
3834 isc_hash_destroy();
3835 cleanup_entropy(&ectx);
3836 dns_name_destroy();
3837 if (verbose > 10)
3838 isc_mem_stats(mctx, stdout);
3839 isc_mem_destroy(&mctx);
3841 (void) isc_app_finish();
3843 if (printstats) {
3844 TIME_NOW(&timer_finish);
3845 print_stats(&timer_start, &timer_finish,
3846 &sign_start, &sign_finish);
3849 return (0);