turns printfs back on
[freebsd-src/fkvm-freebsd.git] / contrib / bind9 / bin / dnssec / dnssec-signzone.c
blob46cd4a74dfe24cc1a5ef0e9e346a8694829aa1a4
1 /*
2 * Portions Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
3 * Portions Copyright (C) 1999-2003 Internet Software Consortium.
4 * Portions Copyright (C) 1995-2000 by Network Associates, Inc.
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
11 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE
13 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
16 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 /* $Id: dnssec-signzone.c,v 1.177.18.24 2007/08/28 07:20:00 tbox Exp $ */
21 /*! \file */
23 #include <config.h>
25 #include <stdlib.h>
26 #include <time.h>
28 #include <isc/app.h>
29 #include <isc/commandline.h>
30 #include <isc/entropy.h>
31 #include <isc/event.h>
32 #include <isc/file.h>
33 #include <isc/hash.h>
34 #include <isc/mem.h>
35 #include <isc/mutex.h>
36 #include <isc/os.h>
37 #include <isc/print.h>
38 #include <isc/random.h>
39 #include <isc/serial.h>
40 #include <isc/stdio.h>
41 #include <isc/string.h>
42 #include <isc/task.h>
43 #include <isc/util.h>
44 #include <isc/time.h>
46 #include <dns/db.h>
47 #include <dns/dbiterator.h>
48 #include <dns/diff.h>
49 #include <dns/dnssec.h>
50 #include <dns/ds.h>
51 #include <dns/fixedname.h>
52 #include <dns/keyvalues.h>
53 #include <dns/log.h>
54 #include <dns/master.h>
55 #include <dns/masterdump.h>
56 #include <dns/nsec.h>
57 #include <dns/rdata.h>
58 #include <dns/rdataset.h>
59 #include <dns/rdataclass.h>
60 #include <dns/rdatasetiter.h>
61 #include <dns/rdatastruct.h>
62 #include <dns/rdatatype.h>
63 #include <dns/result.h>
64 #include <dns/soa.h>
65 #include <dns/time.h>
67 #include <dst/dst.h>
69 #include "dnssectool.h"
71 const char *program = "dnssec-signzone";
72 int verbose;
74 #define BUFSIZE 2048
75 #define MAXDSKEYS 8
77 typedef struct signer_key_struct signer_key_t;
79 struct signer_key_struct {
80 dst_key_t *key;
81 isc_boolean_t issigningkey;
82 isc_boolean_t isdsk;
83 isc_boolean_t isksk;
84 unsigned int position;
85 ISC_LINK(signer_key_t) link;
88 #define SIGNER_EVENTCLASS ISC_EVENTCLASS(0x4453)
89 #define SIGNER_EVENT_WRITE (SIGNER_EVENTCLASS + 0)
90 #define SIGNER_EVENT_WORK (SIGNER_EVENTCLASS + 1)
92 #define SOA_SERIAL_KEEP 0
93 #define SOA_SERIAL_INCREMENT 1
94 #define SOA_SERIAL_UNIXTIME 2
96 typedef struct signer_event sevent_t;
97 struct signer_event {
98 ISC_EVENT_COMMON(sevent_t);
99 dns_fixedname_t *fname;
100 dns_dbnode_t *node;
103 static ISC_LIST(signer_key_t) keylist;
104 static unsigned int keycount = 0;
105 static isc_stdtime_t starttime = 0, endtime = 0, now;
106 static int cycle = -1;
107 static int jitter = 0;
108 static isc_boolean_t tryverify = ISC_FALSE;
109 static isc_boolean_t printstats = ISC_FALSE;
110 static isc_mem_t *mctx = NULL;
111 static isc_entropy_t *ectx = NULL;
112 static dns_ttl_t zonettl;
113 static FILE *fp;
114 static char *tempfile = NULL;
115 static const dns_master_style_t *masterstyle;
116 static dns_masterformat_t inputformat = dns_masterformat_text;
117 static dns_masterformat_t outputformat = dns_masterformat_text;
118 static unsigned int nsigned = 0, nretained = 0, ndropped = 0;
119 static unsigned int nverified = 0, nverifyfailed = 0;
120 static const char *directory;
121 static isc_mutex_t namelock, statslock;
122 static isc_taskmgr_t *taskmgr = NULL;
123 static dns_db_t *gdb; /* The database */
124 static dns_dbversion_t *gversion; /* The database version */
125 static dns_dbiterator_t *gdbiter; /* The database iterator */
126 static dns_rdataclass_t gclass; /* The class */
127 static dns_name_t *gorigin; /* The database origin */
128 static isc_task_t *master = NULL;
129 static unsigned int ntasks = 0;
130 static isc_boolean_t shuttingdown = ISC_FALSE, finished = ISC_FALSE;
131 static unsigned int assigned = 0, completed = 0;
132 static isc_boolean_t nokeys = ISC_FALSE;
133 static isc_boolean_t removefile = ISC_FALSE;
134 static isc_boolean_t generateds = ISC_FALSE;
135 static isc_boolean_t ignoreksk = ISC_FALSE;
136 static dns_name_t *dlv = NULL;
137 static dns_fixedname_t dlv_fixed;
138 static dns_master_style_t *dsstyle = NULL;
139 static unsigned int serialformat = SOA_SERIAL_KEEP;
141 #define INCSTAT(counter) \
142 if (printstats) { \
143 LOCK(&statslock); \
144 counter++; \
145 UNLOCK(&statslock); \
148 static void
149 sign(isc_task_t *task, isc_event_t *event);
152 static inline void
153 set_bit(unsigned char *array, unsigned int index, unsigned int bit) {
154 unsigned int shift, mask;
156 shift = 7 - (index % 8);
157 mask = 1 << shift;
159 if (bit != 0)
160 array[index / 8] |= mask;
161 else
162 array[index / 8] &= (~mask & 0xFF);
165 static void
166 dumpnode(dns_name_t *name, dns_dbnode_t *node) {
167 isc_result_t result;
169 if (outputformat != dns_masterformat_text)
170 return;
171 result = dns_master_dumpnodetostream(mctx, gdb, gversion, node, name,
172 masterstyle, fp);
173 check_result(result, "dns_master_dumpnodetostream");
176 static signer_key_t *
177 newkeystruct(dst_key_t *dstkey, isc_boolean_t signwithkey) {
178 signer_key_t *key;
180 key = isc_mem_get(mctx, sizeof(signer_key_t));
181 if (key == NULL)
182 fatal("out of memory");
183 key->key = dstkey;
184 if ((dst_key_flags(dstkey) & DNS_KEYFLAG_KSK) != 0) {
185 key->issigningkey = signwithkey;
186 key->isksk = ISC_TRUE;
187 key->isdsk = ISC_FALSE;
188 } else {
189 key->issigningkey = signwithkey;
190 key->isksk = ISC_FALSE;
191 key->isdsk = ISC_TRUE;
193 key->position = keycount++;
194 ISC_LINK_INIT(key, link);
195 return (key);
198 static void
199 signwithkey(dns_name_t *name, dns_rdataset_t *rdataset, dns_rdata_t *rdata,
200 dst_key_t *key, isc_buffer_t *b)
202 isc_result_t result;
203 isc_stdtime_t jendtime;
205 jendtime = (jitter != 0) ? isc_random_jitter(endtime, jitter) : endtime;
206 result = dns_dnssec_sign(name, rdataset, key, &starttime, &jendtime,
207 mctx, b, rdata);
208 isc_entropy_stopcallbacksources(ectx);
209 if (result != ISC_R_SUCCESS) {
210 char keystr[KEY_FORMATSIZE];
211 key_format(key, keystr, sizeof(keystr));
212 fatal("dnskey '%s' failed to sign data: %s",
213 keystr, isc_result_totext(result));
215 INCSTAT(nsigned);
217 if (tryverify) {
218 result = dns_dnssec_verify(name, rdataset, key,
219 ISC_TRUE, mctx, rdata);
220 if (result == ISC_R_SUCCESS) {
221 vbprintf(3, "\tsignature verified\n");
222 INCSTAT(nverified);
223 } else {
224 vbprintf(3, "\tsignature failed to verify\n");
225 INCSTAT(nverifyfailed);
230 static inline isc_boolean_t
231 issigningkey(signer_key_t *key) {
232 return (key->issigningkey);
235 static inline isc_boolean_t
236 iszonekey(signer_key_t *key) {
237 return (ISC_TF(dns_name_equal(dst_key_name(key->key), gorigin) &&
238 dst_key_iszonekey(key->key)));
242 * Finds the key that generated a RRSIG, if possible. First look at the keys
243 * that we've loaded already, and then see if there's a key on disk.
245 static signer_key_t *
246 keythatsigned(dns_rdata_rrsig_t *rrsig) {
247 isc_result_t result;
248 dst_key_t *pubkey = NULL, *privkey = NULL;
249 signer_key_t *key;
251 key = ISC_LIST_HEAD(keylist);
252 while (key != NULL) {
253 if (rrsig->keyid == dst_key_id(key->key) &&
254 rrsig->algorithm == dst_key_alg(key->key) &&
255 dns_name_equal(&rrsig->signer, dst_key_name(key->key)))
256 return key;
257 key = ISC_LIST_NEXT(key, link);
260 result = dst_key_fromfile(&rrsig->signer, rrsig->keyid,
261 rrsig->algorithm, DST_TYPE_PUBLIC,
262 NULL, mctx, &pubkey);
263 if (result != ISC_R_SUCCESS)
264 return (NULL);
266 result = dst_key_fromfile(&rrsig->signer, rrsig->keyid,
267 rrsig->algorithm,
268 DST_TYPE_PUBLIC | DST_TYPE_PRIVATE,
269 NULL, mctx, &privkey);
270 if (result == ISC_R_SUCCESS) {
271 dst_key_free(&pubkey);
272 key = newkeystruct(privkey, ISC_FALSE);
273 } else
274 key = newkeystruct(pubkey, ISC_FALSE);
275 ISC_LIST_APPEND(keylist, key, link);
276 return (key);
280 * Check to see if we expect to find a key at this name. If we see a RRSIG
281 * and can't find the signing key that we expect to find, we drop the rrsig.
282 * I'm not sure if this is completely correct, but it seems to work.
284 static isc_boolean_t
285 expecttofindkey(dns_name_t *name) {
286 unsigned int options = DNS_DBFIND_NOWILD;
287 dns_fixedname_t fname;
288 isc_result_t result;
289 char namestr[DNS_NAME_FORMATSIZE];
291 dns_fixedname_init(&fname);
292 result = dns_db_find(gdb, name, gversion, dns_rdatatype_dnskey, options,
293 0, NULL, dns_fixedname_name(&fname), NULL, NULL);
294 switch (result) {
295 case ISC_R_SUCCESS:
296 case DNS_R_NXDOMAIN:
297 case DNS_R_NXRRSET:
298 return (ISC_TRUE);
299 case DNS_R_DELEGATION:
300 case DNS_R_CNAME:
301 case DNS_R_DNAME:
302 return (ISC_FALSE);
304 dns_name_format(name, namestr, sizeof(namestr));
305 fatal("failure looking for '%s DNSKEY' in database: %s",
306 namestr, isc_result_totext(result));
307 return (ISC_FALSE); /* removes a warning */
310 static inline isc_boolean_t
311 setverifies(dns_name_t *name, dns_rdataset_t *set, signer_key_t *key,
312 dns_rdata_t *rrsig)
314 isc_result_t result;
315 result = dns_dnssec_verify(name, set, key->key, ISC_FALSE, mctx, rrsig);
316 if (result == ISC_R_SUCCESS) {
317 INCSTAT(nverified);
318 return (ISC_TRUE);
319 } else {
320 INCSTAT(nverifyfailed);
321 return (ISC_FALSE);
326 * Signs a set. Goes through contortions to decide if each RRSIG should
327 * be dropped or retained, and then determines if any new SIGs need to
328 * be generated.
330 static void
331 signset(dns_diff_t *del, dns_diff_t *add, dns_dbnode_t *node, dns_name_t *name,
332 dns_rdataset_t *set)
334 dns_rdataset_t sigset;
335 dns_rdata_t sigrdata = DNS_RDATA_INIT;
336 dns_rdata_rrsig_t rrsig;
337 signer_key_t *key;
338 isc_result_t result;
339 isc_boolean_t nosigs = ISC_FALSE;
340 isc_boolean_t *wassignedby, *nowsignedby;
341 int arraysize;
342 dns_difftuple_t *tuple;
343 dns_ttl_t ttl;
344 int i;
345 char namestr[DNS_NAME_FORMATSIZE];
346 char typestr[TYPE_FORMATSIZE];
347 char sigstr[SIG_FORMATSIZE];
349 dns_name_format(name, namestr, sizeof(namestr));
350 type_format(set->type, typestr, sizeof(typestr));
352 ttl = ISC_MIN(set->ttl, endtime - starttime);
354 dns_rdataset_init(&sigset);
355 result = dns_db_findrdataset(gdb, node, gversion, dns_rdatatype_rrsig,
356 set->type, 0, &sigset, NULL);
357 if (result == ISC_R_NOTFOUND) {
358 result = ISC_R_SUCCESS;
359 nosigs = ISC_TRUE;
361 if (result != ISC_R_SUCCESS)
362 fatal("failed while looking for '%s RRSIG %s': %s",
363 namestr, typestr, isc_result_totext(result));
365 vbprintf(1, "%s/%s:\n", namestr, typestr);
367 arraysize = keycount;
368 if (!nosigs)
369 arraysize += dns_rdataset_count(&sigset);
370 wassignedby = isc_mem_get(mctx, arraysize * sizeof(isc_boolean_t));
371 nowsignedby = isc_mem_get(mctx, arraysize * sizeof(isc_boolean_t));
372 if (wassignedby == NULL || nowsignedby == NULL)
373 fatal("out of memory");
375 for (i = 0; i < arraysize; i++)
376 wassignedby[i] = nowsignedby[i] = ISC_FALSE;
378 if (nosigs)
379 result = ISC_R_NOMORE;
380 else
381 result = dns_rdataset_first(&sigset);
383 while (result == ISC_R_SUCCESS) {
384 isc_boolean_t expired, future;
385 isc_boolean_t keep = ISC_FALSE, resign = ISC_FALSE;
387 dns_rdataset_current(&sigset, &sigrdata);
389 result = dns_rdata_tostruct(&sigrdata, &rrsig, NULL);
390 check_result(result, "dns_rdata_tostruct");
392 future = isc_serial_lt(now, rrsig.timesigned);
394 key = keythatsigned(&rrsig);
395 sig_format(&rrsig, sigstr, sizeof(sigstr));
396 if (key != NULL && issigningkey(key))
397 expired = isc_serial_gt(now + cycle, rrsig.timeexpire);
398 else
399 expired = isc_serial_gt(now, rrsig.timeexpire);
401 if (isc_serial_gt(rrsig.timesigned, rrsig.timeexpire)) {
402 /* rrsig is dropped and not replaced */
403 vbprintf(2, "\trrsig by %s dropped - "
404 "invalid validity period\n",
405 sigstr);
406 } else if (key == NULL && !future &&
407 expecttofindkey(&rrsig.signer))
409 /* rrsig is dropped and not replaced */
410 vbprintf(2, "\trrsig by %s dropped - "
411 "private dnskey not found\n",
412 sigstr);
413 } else if (key == NULL || future) {
414 vbprintf(2, "\trrsig by %s %s - dnskey not found\n",
415 expired ? "retained" : "dropped", sigstr);
416 if (!expired)
417 keep = ISC_TRUE;
418 } else if (issigningkey(key)) {
419 if (!expired && setverifies(name, set, key, &sigrdata))
421 vbprintf(2, "\trrsig by %s retained\n", sigstr);
422 keep = ISC_TRUE;
423 wassignedby[key->position] = ISC_TRUE;
424 nowsignedby[key->position] = ISC_TRUE;
425 } else {
426 vbprintf(2, "\trrsig by %s dropped - %s\n",
427 sigstr,
428 expired ? "expired" :
429 "failed to verify");
430 wassignedby[key->position] = ISC_TRUE;
431 resign = ISC_TRUE;
433 } else if (iszonekey(key)) {
434 if (!expired && setverifies(name, set, key, &sigrdata))
436 vbprintf(2, "\trrsig by %s retained\n", sigstr);
437 keep = ISC_TRUE;
438 wassignedby[key->position] = ISC_TRUE;
439 nowsignedby[key->position] = ISC_TRUE;
440 } else {
441 vbprintf(2, "\trrsig by %s dropped - %s\n",
442 sigstr,
443 expired ? "expired" :
444 "failed to verify");
445 wassignedby[key->position] = ISC_TRUE;
447 } else if (!expired) {
448 vbprintf(2, "\trrsig by %s retained\n", sigstr);
449 keep = ISC_TRUE;
450 } else {
451 vbprintf(2, "\trrsig by %s expired\n", sigstr);
454 if (keep) {
455 nowsignedby[key->position] = ISC_TRUE;
456 INCSTAT(nretained);
457 if (sigset.ttl != ttl) {
458 vbprintf(2, "\tfixing ttl %s\n", sigstr);
459 tuple = NULL;
460 result = dns_difftuple_create(mctx,
461 DNS_DIFFOP_DEL,
462 name, sigset.ttl,
463 &sigrdata,
464 &tuple);
465 check_result(result, "dns_difftuple_create");
466 dns_diff_append(del, &tuple);
467 result = dns_difftuple_create(mctx,
468 DNS_DIFFOP_ADD,
469 name, ttl,
470 &sigrdata,
471 &tuple);
472 check_result(result, "dns_difftuple_create");
473 dns_diff_append(add, &tuple);
475 } else {
476 tuple = NULL;
477 result = dns_difftuple_create(mctx, DNS_DIFFOP_DEL,
478 name, sigset.ttl,
479 &sigrdata, &tuple);
480 check_result(result, "dns_difftuple_create");
481 dns_diff_append(del, &tuple);
482 INCSTAT(ndropped);
485 if (resign) {
486 isc_buffer_t b;
487 dns_rdata_t trdata = DNS_RDATA_INIT;
488 unsigned char array[BUFSIZE];
489 char keystr[KEY_FORMATSIZE];
491 INSIST(!keep);
493 key_format(key->key, keystr, sizeof(keystr));
494 vbprintf(1, "\tresigning with dnskey %s\n", keystr);
495 isc_buffer_init(&b, array, sizeof(array));
496 signwithkey(name, set, &trdata, key->key, &b);
497 nowsignedby[key->position] = ISC_TRUE;
498 tuple = NULL;
499 result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD,
500 name, ttl, &trdata,
501 &tuple);
502 check_result(result, "dns_difftuple_create");
503 dns_diff_append(add, &tuple);
506 dns_rdata_reset(&sigrdata);
507 dns_rdata_freestruct(&rrsig);
508 result = dns_rdataset_next(&sigset);
510 if (result == ISC_R_NOMORE)
511 result = ISC_R_SUCCESS;
513 check_result(result, "dns_rdataset_first/next");
514 if (dns_rdataset_isassociated(&sigset))
515 dns_rdataset_disassociate(&sigset);
517 for (key = ISC_LIST_HEAD(keylist);
518 key != NULL;
519 key = ISC_LIST_NEXT(key, link))
521 isc_buffer_t b;
522 dns_rdata_t trdata;
523 unsigned char array[BUFSIZE];
524 char keystr[KEY_FORMATSIZE];
526 if (nowsignedby[key->position])
527 continue;
529 if (!key->issigningkey)
530 continue;
531 if (!(ignoreksk || key->isdsk ||
532 (key->isksk &&
533 set->type == dns_rdatatype_dnskey &&
534 dns_name_equal(name, gorigin))))
535 continue;
537 key_format(key->key, keystr, sizeof(keystr));
538 vbprintf(1, "\tsigning with dnskey %s\n", keystr);
539 dns_rdata_init(&trdata);
540 isc_buffer_init(&b, array, sizeof(array));
541 signwithkey(name, set, &trdata, key->key, &b);
542 tuple = NULL;
543 result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD, name,
544 ttl, &trdata, &tuple);
545 check_result(result, "dns_difftuple_create");
546 dns_diff_append(add, &tuple);
549 isc_mem_put(mctx, wassignedby, arraysize * sizeof(isc_boolean_t));
550 isc_mem_put(mctx, nowsignedby, arraysize * sizeof(isc_boolean_t));
553 static void
554 opendb(const char *prefix, dns_name_t *name, dns_rdataclass_t rdclass,
555 dns_db_t **dbp)
557 char filename[256];
558 isc_buffer_t b;
559 isc_result_t result;
561 isc_buffer_init(&b, filename, sizeof(filename));
562 if (directory != NULL) {
563 isc_buffer_putstr(&b, directory);
564 if (directory[strlen(directory) - 1] != '/')
565 isc_buffer_putstr(&b, "/");
567 isc_buffer_putstr(&b, prefix);
568 result = dns_name_tofilenametext(name, ISC_FALSE, &b);
569 check_result(result, "dns_name_tofilenametext()");
570 if (isc_buffer_availablelength(&b) == 0) {
571 char namestr[DNS_NAME_FORMATSIZE];
572 dns_name_format(name, namestr, sizeof(namestr));
573 fatal("name '%s' is too long", namestr);
575 isc_buffer_putuint8(&b, 0);
577 result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone,
578 rdclass, 0, NULL, dbp);
579 check_result(result, "dns_db_create()");
581 result = dns_db_load(*dbp, filename);
582 if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE)
583 dns_db_detach(dbp);
587 * Loads the key set for a child zone, if there is one, and builds DS records.
589 static isc_result_t
590 loadds(dns_name_t *name, isc_uint32_t ttl, dns_rdataset_t *dsset) {
591 dns_db_t *db = NULL;
592 dns_dbversion_t *ver = NULL;
593 dns_dbnode_t *node = NULL;
594 isc_result_t result;
595 dns_rdataset_t keyset;
596 dns_rdata_t key, ds;
597 unsigned char dsbuf[DNS_DS_BUFFERSIZE];
598 dns_diff_t diff;
599 dns_difftuple_t *tuple = NULL;
601 opendb("keyset-", name, gclass, &db);
602 if (db == NULL)
603 return (ISC_R_NOTFOUND);
605 result = dns_db_findnode(db, name, ISC_FALSE, &node);
606 if (result != ISC_R_SUCCESS) {
607 dns_db_detach(&db);
608 return (DNS_R_BADDB);
610 dns_rdataset_init(&keyset);
611 result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_dnskey, 0, 0,
612 &keyset, NULL);
613 if (result != ISC_R_SUCCESS) {
614 dns_db_detachnode(db, &node);
615 dns_db_detach(&db);
616 return (result);
619 vbprintf(2, "found DNSKEY records\n");
621 result = dns_db_newversion(db, &ver);
622 check_result(result, "dns_db_newversion");
624 dns_diff_init(mctx, &diff);
626 for (result = dns_rdataset_first(&keyset);
627 result == ISC_R_SUCCESS;
628 result = dns_rdataset_next(&keyset))
630 dns_rdata_init(&key);
631 dns_rdata_init(&ds);
632 dns_rdataset_current(&keyset, &key);
633 result = dns_ds_buildrdata(name, &key, DNS_DSDIGEST_SHA1,
634 dsbuf, &ds);
635 check_result(result, "dns_ds_buildrdata");
637 result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD, name,
638 ttl, &ds, &tuple);
639 check_result(result, "dns_difftuple_create");
640 dns_diff_append(&diff, &tuple);
642 dns_rdata_reset(&ds);
643 result = dns_ds_buildrdata(name, &key, DNS_DSDIGEST_SHA256,
644 dsbuf, &ds);
645 check_result(result, "dns_ds_buildrdata");
647 result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD, name,
648 ttl, &ds, &tuple);
649 check_result(result, "dns_difftuple_create");
650 dns_diff_append(&diff, &tuple);
652 result = dns_diff_apply(&diff, db, ver);
653 check_result(result, "dns_diff_apply");
654 dns_diff_clear(&diff);
656 dns_db_closeversion(db, &ver, ISC_TRUE);
658 result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_ds, 0, 0,
659 dsset, NULL);
660 check_result(result, "dns_db_findrdataset");
662 dns_rdataset_disassociate(&keyset);
663 dns_db_detachnode(db, &node);
664 dns_db_detach(&db);
665 return (result);
668 static isc_boolean_t
669 nsec_setbit(dns_name_t *name, dns_rdataset_t *rdataset, dns_rdatatype_t type,
670 unsigned int val)
672 isc_result_t result;
673 dns_rdata_t rdata = DNS_RDATA_INIT;
674 dns_rdata_nsec_t nsec;
675 unsigned int newlen;
676 unsigned char bitmap[8192 + 512];
677 unsigned char nsecdata[8192 + 512 + DNS_NAME_MAXWIRE];
678 isc_boolean_t answer = ISC_FALSE;
679 unsigned int i, len, window;
680 int octet;
682 result = dns_rdataset_first(rdataset);
683 check_result(result, "dns_rdataset_first()");
684 dns_rdataset_current(rdataset, &rdata);
685 result = dns_rdata_tostruct(&rdata, &nsec, NULL);
686 check_result(result, "dns_rdata_tostruct");
688 INSIST(nsec.len <= sizeof(bitmap));
690 newlen = 0;
692 memset(bitmap, 0, sizeof(bitmap));
693 for (i = 0; i < nsec.len; i += len) {
694 INSIST(i + 2 <= nsec.len);
695 window = nsec.typebits[i];
696 len = nsec.typebits[i+1];
697 i += 2;
698 INSIST(len > 0 && len <= 32);
699 INSIST(i + len <= nsec.len);
700 memmove(&bitmap[window * 32 + 512], &nsec.typebits[i], len);
702 set_bit(bitmap + 512, type, val);
703 for (window = 0; window < 256; window++) {
704 for (octet = 31; octet >= 0; octet--)
705 if (bitmap[window * 32 + 512 + octet] != 0)
706 break;
707 if (octet < 0)
708 continue;
709 bitmap[newlen] = window;
710 bitmap[newlen + 1] = octet + 1;
711 newlen += 2;
713 * Overlapping move.
715 memmove(&bitmap[newlen], &bitmap[window * 32 + 512], octet + 1);
716 newlen += octet + 1;
718 if (newlen != nsec.len ||
719 memcmp(nsec.typebits, bitmap, newlen) != 0) {
720 dns_rdata_t newrdata = DNS_RDATA_INIT;
721 isc_buffer_t b;
722 dns_diff_t diff;
723 dns_difftuple_t *tuple = NULL;
725 dns_diff_init(mctx, &diff);
726 result = dns_difftuple_create(mctx, DNS_DIFFOP_DEL, name,
727 rdataset->ttl, &rdata, &tuple);
728 check_result(result, "dns_difftuple_create");
729 dns_diff_append(&diff, &tuple);
731 nsec.typebits = bitmap;
732 nsec.len = newlen;
733 isc_buffer_init(&b, nsecdata, sizeof(nsecdata));
734 result = dns_rdata_fromstruct(&newrdata, rdata.rdclass,
735 dns_rdatatype_nsec, &nsec,
736 &b);
737 check_result(result, "dns_rdata_fromstruct");
739 result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD,
740 name, rdataset->ttl,
741 &newrdata, &tuple);
742 check_result(result, "dns_difftuple_create");
743 dns_diff_append(&diff, &tuple);
744 result = dns_diff_apply(&diff, gdb, gversion);
745 check_result(result, "dns_difftuple_apply");
746 dns_diff_clear(&diff);
747 answer = ISC_TRUE;
749 dns_rdata_freestruct(&nsec);
750 return (answer);
753 static isc_boolean_t
754 delegation(dns_name_t *name, dns_dbnode_t *node, isc_uint32_t *ttlp) {
755 dns_rdataset_t nsset;
756 isc_result_t result;
758 if (dns_name_equal(name, gorigin))
759 return (ISC_FALSE);
761 dns_rdataset_init(&nsset);
762 result = dns_db_findrdataset(gdb, node, gversion, dns_rdatatype_ns,
763 0, 0, &nsset, NULL);
764 if (dns_rdataset_isassociated(&nsset)) {
765 if (ttlp != NULL)
766 *ttlp = nsset.ttl;
767 dns_rdataset_disassociate(&nsset);
770 return (ISC_TF(result == ISC_R_SUCCESS));
774 * Signs all records at a name. This mostly just signs each set individually,
775 * but also adds the RRSIG bit to any NSECs generated earlier, deals with
776 * parent/child KEY signatures, and handles other exceptional cases.
778 static void
779 signname(dns_dbnode_t *node, dns_name_t *name) {
780 isc_result_t result;
781 dns_rdataset_t rdataset;
782 dns_rdatasetiter_t *rdsiter;
783 isc_boolean_t isdelegation = ISC_FALSE;
784 isc_boolean_t hasds = ISC_FALSE;
785 isc_boolean_t changed = ISC_FALSE;
786 dns_diff_t del, add;
787 char namestr[DNS_NAME_FORMATSIZE];
788 isc_uint32_t nsttl = 0;
790 dns_name_format(name, namestr, sizeof(namestr));
793 * Determine if this is a delegation point.
795 if (delegation(name, node, &nsttl))
796 isdelegation = ISC_TRUE;
799 * If this is a delegation point, look for a DS set.
801 if (isdelegation) {
802 dns_rdataset_t dsset;
803 dns_rdataset_t sigdsset;
805 dns_rdataset_init(&dsset);
806 dns_rdataset_init(&sigdsset);
807 result = dns_db_findrdataset(gdb, node, gversion,
808 dns_rdatatype_ds,
809 0, 0, &dsset, &sigdsset);
810 if (result == ISC_R_SUCCESS) {
811 dns_rdataset_disassociate(&dsset);
812 if (generateds) {
813 result = dns_db_deleterdataset(gdb, node,
814 gversion,
815 dns_rdatatype_ds,
817 check_result(result, "dns_db_deleterdataset");
818 } else
819 hasds = ISC_TRUE;
821 if (generateds) {
822 result = loadds(name, nsttl, &dsset);
823 if (result == ISC_R_SUCCESS) {
824 result = dns_db_addrdataset(gdb, node,
825 gversion, 0,
826 &dsset, 0, NULL);
827 check_result(result, "dns_db_addrdataset");
828 hasds = ISC_TRUE;
829 dns_rdataset_disassociate(&dsset);
830 if (dns_rdataset_isassociated(&sigdsset))
831 dns_rdataset_disassociate(&sigdsset);
832 } else if (dns_rdataset_isassociated(&sigdsset)) {
833 result = dns_db_deleterdataset(gdb, node,
834 gversion,
835 dns_rdatatype_rrsig,
836 dns_rdatatype_ds);
837 check_result(result, "dns_db_deleterdataset");
838 dns_rdataset_disassociate(&sigdsset);
840 } else if (dns_rdataset_isassociated(&sigdsset))
841 dns_rdataset_disassociate(&sigdsset);
845 * Make sure that NSEC bits are appropriately set.
847 dns_rdataset_init(&rdataset);
848 RUNTIME_CHECK(dns_db_findrdataset(gdb, node, gversion,
849 dns_rdatatype_nsec, 0, 0, &rdataset,
850 NULL) == ISC_R_SUCCESS);
851 if (!nokeys)
852 changed = nsec_setbit(name, &rdataset, dns_rdatatype_rrsig, 1);
853 if (changed) {
854 dns_rdataset_disassociate(&rdataset);
855 RUNTIME_CHECK(dns_db_findrdataset(gdb, node, gversion,
856 dns_rdatatype_nsec, 0, 0,
857 &rdataset,
858 NULL) == ISC_R_SUCCESS);
860 if (hasds)
861 (void)nsec_setbit(name, &rdataset, dns_rdatatype_ds, 1);
862 else
863 (void)nsec_setbit(name, &rdataset, dns_rdatatype_ds, 0);
864 dns_rdataset_disassociate(&rdataset);
867 * Now iterate through the rdatasets.
869 dns_diff_init(mctx, &del);
870 dns_diff_init(mctx, &add);
871 rdsiter = NULL;
872 result = dns_db_allrdatasets(gdb, node, gversion, 0, &rdsiter);
873 check_result(result, "dns_db_allrdatasets()");
874 result = dns_rdatasetiter_first(rdsiter);
875 while (result == ISC_R_SUCCESS) {
876 dns_rdatasetiter_current(rdsiter, &rdataset);
878 /* If this is a RRSIG set, skip it. */
879 if (rdataset.type == dns_rdatatype_rrsig)
880 goto skip;
883 * If this name is a delegation point, skip all records
884 * except NSEC and DS sets. Otherwise check that there
885 * isn't a DS record.
887 if (isdelegation) {
888 if (rdataset.type != dns_rdatatype_nsec &&
889 rdataset.type != dns_rdatatype_ds)
890 goto skip;
891 } else if (rdataset.type == dns_rdatatype_ds) {
892 char namebuf[DNS_NAME_FORMATSIZE];
893 dns_name_format(name, namebuf, sizeof(namebuf));
894 fatal("'%s': found DS RRset without NS RRset\n",
895 namebuf);
898 signset(&del, &add, node, name, &rdataset);
900 skip:
901 dns_rdataset_disassociate(&rdataset);
902 result = dns_rdatasetiter_next(rdsiter);
904 if (result != ISC_R_NOMORE)
905 fatal("rdataset iteration for name '%s' failed: %s",
906 namestr, isc_result_totext(result));
908 dns_rdatasetiter_destroy(&rdsiter);
910 result = dns_diff_applysilently(&del, gdb, gversion);
911 if (result != ISC_R_SUCCESS)
912 fatal("failed to delete SIGs at node '%s': %s",
913 namestr, isc_result_totext(result));
915 result = dns_diff_applysilently(&add, gdb, gversion);
916 if (result != ISC_R_SUCCESS)
917 fatal("failed to add SIGs at node '%s': %s",
918 namestr, isc_result_totext(result));
920 dns_diff_clear(&del);
921 dns_diff_clear(&add);
924 static inline isc_boolean_t
925 active_node(dns_dbnode_t *node) {
926 dns_rdatasetiter_t *rdsiter = NULL;
927 dns_rdatasetiter_t *rdsiter2 = NULL;
928 isc_boolean_t active = ISC_FALSE;
929 isc_result_t result;
930 dns_rdataset_t rdataset;
931 dns_rdatatype_t type;
932 dns_rdatatype_t covers;
933 isc_boolean_t found;
935 dns_rdataset_init(&rdataset);
936 result = dns_db_allrdatasets(gdb, node, gversion, 0, &rdsiter);
937 check_result(result, "dns_db_allrdatasets()");
938 result = dns_rdatasetiter_first(rdsiter);
939 while (result == ISC_R_SUCCESS) {
940 dns_rdatasetiter_current(rdsiter, &rdataset);
941 if (rdataset.type != dns_rdatatype_nsec &&
942 rdataset.type != dns_rdatatype_rrsig)
943 active = ISC_TRUE;
944 dns_rdataset_disassociate(&rdataset);
945 if (!active)
946 result = dns_rdatasetiter_next(rdsiter);
947 else
948 result = ISC_R_NOMORE;
950 if (result != ISC_R_NOMORE)
951 fatal("rdataset iteration failed: %s",
952 isc_result_totext(result));
954 if (!active) {
956 * The node is empty of everything but NSEC / RRSIG records.
958 for (result = dns_rdatasetiter_first(rdsiter);
959 result == ISC_R_SUCCESS;
960 result = dns_rdatasetiter_next(rdsiter)) {
961 dns_rdatasetiter_current(rdsiter, &rdataset);
962 result = dns_db_deleterdataset(gdb, node, gversion,
963 rdataset.type,
964 rdataset.covers);
965 check_result(result, "dns_db_deleterdataset()");
966 dns_rdataset_disassociate(&rdataset);
968 if (result != ISC_R_NOMORE)
969 fatal("rdataset iteration failed: %s",
970 isc_result_totext(result));
971 } else {
973 * Delete RRSIGs for types that no longer exist.
975 result = dns_db_allrdatasets(gdb, node, gversion, 0, &rdsiter2);
976 check_result(result, "dns_db_allrdatasets()");
977 for (result = dns_rdatasetiter_first(rdsiter);
978 result == ISC_R_SUCCESS;
979 result = dns_rdatasetiter_next(rdsiter)) {
980 dns_rdatasetiter_current(rdsiter, &rdataset);
981 type = rdataset.type;
982 covers = rdataset.covers;
983 dns_rdataset_disassociate(&rdataset);
984 if (type != dns_rdatatype_rrsig)
985 continue;
986 found = ISC_FALSE;
987 for (result = dns_rdatasetiter_first(rdsiter2);
988 !found && result == ISC_R_SUCCESS;
989 result = dns_rdatasetiter_next(rdsiter2)) {
990 dns_rdatasetiter_current(rdsiter2, &rdataset);
991 if (rdataset.type == covers)
992 found = ISC_TRUE;
993 dns_rdataset_disassociate(&rdataset);
995 if (!found) {
996 if (result != ISC_R_NOMORE)
997 fatal("rdataset iteration failed: %s",
998 isc_result_totext(result));
999 result = dns_db_deleterdataset(gdb, node,
1000 gversion, type,
1001 covers);
1002 check_result(result,
1003 "dns_db_deleterdataset(rrsig)");
1004 } else if (result != ISC_R_NOMORE &&
1005 result != ISC_R_SUCCESS)
1006 fatal("rdataset iteration failed: %s",
1007 isc_result_totext(result));
1009 if (result != ISC_R_NOMORE)
1010 fatal("rdataset iteration failed: %s",
1011 isc_result_totext(result));
1012 dns_rdatasetiter_destroy(&rdsiter2);
1014 dns_rdatasetiter_destroy(&rdsiter);
1016 return (active);
1020 * Extracts the TTL from the SOA.
1022 static dns_ttl_t
1023 soattl(void) {
1024 dns_rdataset_t soaset;
1025 dns_fixedname_t fname;
1026 dns_name_t *name;
1027 isc_result_t result;
1028 dns_ttl_t ttl;
1029 dns_rdata_t rdata = DNS_RDATA_INIT;
1030 dns_rdata_soa_t soa;
1032 dns_fixedname_init(&fname);
1033 name = dns_fixedname_name(&fname);
1034 dns_rdataset_init(&soaset);
1035 result = dns_db_find(gdb, gorigin, gversion, dns_rdatatype_soa,
1036 0, 0, NULL, name, &soaset, NULL);
1037 if (result != ISC_R_SUCCESS)
1038 fatal("failed to find an SOA at the zone apex: %s",
1039 isc_result_totext(result));
1041 result = dns_rdataset_first(&soaset);
1042 check_result(result, "dns_rdataset_first");
1043 dns_rdataset_current(&soaset, &rdata);
1044 result = dns_rdata_tostruct(&rdata, &soa, NULL);
1045 check_result(result, "dns_rdata_tostruct");
1046 ttl = soa.minimum;
1047 dns_rdataset_disassociate(&soaset);
1048 return (ttl);
1052 * Increment (or set if nonzero) the SOA serial
1054 static isc_result_t
1055 setsoaserial(isc_uint32_t serial) {
1056 isc_result_t result;
1057 dns_dbnode_t *node = NULL;
1058 dns_rdataset_t rdataset;
1059 dns_rdata_t rdata = DNS_RDATA_INIT;
1060 isc_uint32_t old_serial, new_serial;
1062 result = dns_db_getoriginnode(gdb, &node);
1063 if (result != ISC_R_SUCCESS)
1064 return result;
1066 dns_rdataset_init(&rdataset);
1068 result = dns_db_findrdataset(gdb, node, gversion,
1069 dns_rdatatype_soa, 0,
1070 0, &rdataset, NULL);
1071 if (result != ISC_R_SUCCESS)
1072 goto cleanup;
1074 result = dns_rdataset_first(&rdataset);
1075 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1077 dns_rdataset_current(&rdataset, &rdata);
1079 old_serial = dns_soa_getserial(&rdata);
1081 if (serial) {
1082 /* Set SOA serial to the value provided. */
1083 new_serial = serial;
1084 } else {
1085 /* Increment SOA serial using RFC 1982 arithmetics */
1086 new_serial = (old_serial + 1) & 0xFFFFFFFF;
1087 if (new_serial == 0)
1088 new_serial = 1;
1091 /* If the new serial is not likely to cause a zone transfer
1092 * (a/ixfr) from servers having the old serial, warn the user.
1094 * RFC1982 section 7 defines the maximum increment to be
1095 * (2^(32-1))-1. Using u_int32_t arithmetic, we can do a single
1096 * comparison. (5 - 6 == (2^32)-1, not negative-one)
1098 if (new_serial == old_serial ||
1099 (new_serial - old_serial) > 0x7fffffffU)
1100 fprintf(stderr, "%s: warning: Serial number not advanced, "
1101 "zone may not transfer\n", program);
1103 dns_soa_setserial(new_serial, &rdata);
1105 result = dns_db_deleterdataset(gdb, node, gversion,
1106 dns_rdatatype_soa, 0);
1107 check_result(result, "dns_db_deleterdataset");
1108 if (result != ISC_R_SUCCESS)
1109 goto cleanup;
1111 result = dns_db_addrdataset(gdb, node, gversion,
1112 0, &rdataset, 0, NULL);
1113 check_result(result, "dns_db_addrdataset");
1114 if (result != ISC_R_SUCCESS)
1115 goto cleanup;
1117 cleanup:
1118 dns_rdataset_disassociate(&rdataset);
1119 if (node != NULL)
1120 dns_db_detachnode(gdb, &node);
1121 dns_rdata_reset(&rdata);
1123 return (result);
1127 * Delete any RRSIG records at a node.
1129 static void
1130 cleannode(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node) {
1131 dns_rdatasetiter_t *rdsiter = NULL;
1132 dns_rdataset_t set;
1133 isc_result_t result, dresult;
1135 if (outputformat != dns_masterformat_text)
1136 return;
1138 dns_rdataset_init(&set);
1139 result = dns_db_allrdatasets(db, node, version, 0, &rdsiter);
1140 check_result(result, "dns_db_allrdatasets");
1141 result = dns_rdatasetiter_first(rdsiter);
1142 while (result == ISC_R_SUCCESS) {
1143 isc_boolean_t destroy = ISC_FALSE;
1144 dns_rdatatype_t covers = 0;
1145 dns_rdatasetiter_current(rdsiter, &set);
1146 if (set.type == dns_rdatatype_rrsig) {
1147 covers = set.covers;
1148 destroy = ISC_TRUE;
1150 dns_rdataset_disassociate(&set);
1151 result = dns_rdatasetiter_next(rdsiter);
1152 if (destroy) {
1153 dresult = dns_db_deleterdataset(db, node, version,
1154 dns_rdatatype_rrsig,
1155 covers);
1156 check_result(dresult, "dns_db_deleterdataset");
1159 if (result != ISC_R_NOMORE)
1160 fatal("rdataset iteration failed: %s",
1161 isc_result_totext(result));
1162 dns_rdatasetiter_destroy(&rdsiter);
1166 * Set up the iterator and global state before starting the tasks.
1168 static void
1169 presign(void) {
1170 isc_result_t result;
1172 gdbiter = NULL;
1173 result = dns_db_createiterator(gdb, ISC_FALSE, &gdbiter);
1174 check_result(result, "dns_db_createiterator()");
1176 result = dns_dbiterator_first(gdbiter);
1177 check_result(result, "dns_dbiterator_first()");
1181 * Clean up the iterator and global state after the tasks complete.
1183 static void
1184 postsign(void) {
1185 dns_dbiterator_destroy(&gdbiter);
1189 * Sign the apex of the zone.
1191 static void
1192 signapex(void) {
1193 dns_dbnode_t *node = NULL;
1194 dns_fixedname_t fixed;
1195 dns_name_t *name;
1196 isc_result_t result;
1198 dns_fixedname_init(&fixed);
1199 name = dns_fixedname_name(&fixed);
1200 result = dns_dbiterator_current(gdbiter, &node, name);
1201 check_result(result, "dns_dbiterator_current()");
1202 signname(node, name);
1203 dumpnode(name, node);
1204 cleannode(gdb, gversion, node);
1205 dns_db_detachnode(gdb, &node);
1206 result = dns_dbiterator_next(gdbiter);
1207 if (result == ISC_R_NOMORE)
1208 finished = ISC_TRUE;
1209 else if (result != ISC_R_SUCCESS)
1210 fatal("failure iterating database: %s",
1211 isc_result_totext(result));
1215 * Assigns a node to a worker thread. This is protected by the master task's
1216 * lock.
1218 static void
1219 assignwork(isc_task_t *task, isc_task_t *worker) {
1220 dns_fixedname_t *fname;
1221 dns_name_t *name;
1222 dns_dbnode_t *node;
1223 sevent_t *sevent;
1224 dns_rdataset_t nsec;
1225 isc_boolean_t found;
1226 isc_result_t result;
1228 if (shuttingdown)
1229 return;
1231 if (finished) {
1232 if (assigned == completed) {
1233 isc_task_detach(&task);
1234 isc_app_shutdown();
1236 return;
1239 fname = isc_mem_get(mctx, sizeof(dns_fixedname_t));
1240 if (fname == NULL)
1241 fatal("out of memory");
1242 dns_fixedname_init(fname);
1243 name = dns_fixedname_name(fname);
1244 node = NULL;
1245 found = ISC_FALSE;
1246 LOCK(&namelock);
1247 while (!found) {
1248 result = dns_dbiterator_current(gdbiter, &node, name);
1249 if (result != ISC_R_SUCCESS)
1250 fatal("failure iterating database: %s",
1251 isc_result_totext(result));
1252 dns_rdataset_init(&nsec);
1253 result = dns_db_findrdataset(gdb, node, gversion,
1254 dns_rdatatype_nsec, 0, 0,
1255 &nsec, NULL);
1256 if (result == ISC_R_SUCCESS)
1257 found = ISC_TRUE;
1258 else
1259 dumpnode(name, node);
1260 if (dns_rdataset_isassociated(&nsec))
1261 dns_rdataset_disassociate(&nsec);
1262 if (!found)
1263 dns_db_detachnode(gdb, &node);
1265 result = dns_dbiterator_next(gdbiter);
1266 if (result == ISC_R_NOMORE) {
1267 finished = ISC_TRUE;
1268 break;
1269 } else if (result != ISC_R_SUCCESS)
1270 fatal("failure iterating database: %s",
1271 isc_result_totext(result));
1273 UNLOCK(&namelock);
1274 if (!found) {
1275 if (assigned == completed) {
1276 isc_task_detach(&task);
1277 isc_app_shutdown();
1279 isc_mem_put(mctx, fname, sizeof(dns_fixedname_t));
1280 return;
1282 sevent = (sevent_t *)
1283 isc_event_allocate(mctx, task, SIGNER_EVENT_WORK,
1284 sign, NULL, sizeof(sevent_t));
1285 if (sevent == NULL)
1286 fatal("failed to allocate event\n");
1288 sevent->node = node;
1289 sevent->fname = fname;
1290 isc_task_send(worker, ISC_EVENT_PTR(&sevent));
1291 assigned++;
1295 * Start a worker task
1297 static void
1298 startworker(isc_task_t *task, isc_event_t *event) {
1299 isc_task_t *worker;
1301 worker = (isc_task_t *)event->ev_arg;
1302 assignwork(task, worker);
1303 isc_event_free(&event);
1307 * Write a node to the output file, and restart the worker task.
1309 static void
1310 writenode(isc_task_t *task, isc_event_t *event) {
1311 isc_task_t *worker;
1312 sevent_t *sevent = (sevent_t *)event;
1314 completed++;
1315 worker = (isc_task_t *)event->ev_sender;
1316 dumpnode(dns_fixedname_name(sevent->fname), sevent->node);
1317 cleannode(gdb, gversion, sevent->node);
1318 dns_db_detachnode(gdb, &sevent->node);
1319 isc_mem_put(mctx, sevent->fname, sizeof(dns_fixedname_t));
1320 assignwork(task, worker);
1321 isc_event_free(&event);
1325 * Sign a database node.
1327 static void
1328 sign(isc_task_t *task, isc_event_t *event) {
1329 dns_fixedname_t *fname;
1330 dns_dbnode_t *node;
1331 sevent_t *sevent, *wevent;
1333 sevent = (sevent_t *)event;
1334 node = sevent->node;
1335 fname = sevent->fname;
1336 isc_event_free(&event);
1338 signname(node, dns_fixedname_name(fname));
1339 wevent = (sevent_t *)
1340 isc_event_allocate(mctx, task, SIGNER_EVENT_WRITE,
1341 writenode, NULL, sizeof(sevent_t));
1342 if (wevent == NULL)
1343 fatal("failed to allocate event\n");
1344 wevent->node = node;
1345 wevent->fname = fname;
1346 isc_task_send(master, ISC_EVENT_PTR(&wevent));
1350 * Generate NSEC records for the zone.
1352 static void
1353 nsecify(void) {
1354 dns_dbiterator_t *dbiter = NULL;
1355 dns_dbnode_t *node = NULL, *nextnode = NULL;
1356 dns_fixedname_t fname, fnextname, fzonecut;
1357 dns_name_t *name, *nextname, *zonecut;
1358 isc_boolean_t done = ISC_FALSE;
1359 isc_result_t result;
1361 dns_fixedname_init(&fname);
1362 name = dns_fixedname_name(&fname);
1363 dns_fixedname_init(&fnextname);
1364 nextname = dns_fixedname_name(&fnextname);
1365 dns_fixedname_init(&fzonecut);
1366 zonecut = NULL;
1368 result = dns_db_createiterator(gdb, ISC_FALSE, &dbiter);
1369 check_result(result, "dns_db_createiterator()");
1371 result = dns_dbiterator_first(dbiter);
1372 check_result(result, "dns_dbiterator_first()");
1374 while (!done) {
1375 dns_dbiterator_current(dbiter, &node, name);
1376 if (delegation(name, node, NULL)) {
1377 zonecut = dns_fixedname_name(&fzonecut);
1378 dns_name_copy(name, zonecut, NULL);
1380 result = dns_dbiterator_next(dbiter);
1381 nextnode = NULL;
1382 while (result == ISC_R_SUCCESS) {
1383 isc_boolean_t active = ISC_FALSE;
1384 result = dns_dbiterator_current(dbiter, &nextnode,
1385 nextname);
1386 if (result != ISC_R_SUCCESS)
1387 break;
1388 active = active_node(nextnode);
1389 if (!active) {
1390 dns_db_detachnode(gdb, &nextnode);
1391 result = dns_dbiterator_next(dbiter);
1392 continue;
1394 if (!dns_name_issubdomain(nextname, gorigin) ||
1395 (zonecut != NULL &&
1396 dns_name_issubdomain(nextname, zonecut)))
1398 dns_db_detachnode(gdb, &nextnode);
1399 result = dns_dbiterator_next(dbiter);
1400 continue;
1402 dns_db_detachnode(gdb, &nextnode);
1403 break;
1405 if (result == ISC_R_NOMORE) {
1406 dns_name_clone(gorigin, nextname);
1407 done = ISC_TRUE;
1408 } else if (result != ISC_R_SUCCESS)
1409 fatal("iterating through the database failed: %s",
1410 isc_result_totext(result));
1411 result = dns_nsec_build(gdb, gversion, node, nextname,
1412 zonettl);
1413 check_result(result, "dns_nsec_build()");
1414 dns_db_detachnode(gdb, &node);
1417 dns_dbiterator_destroy(&dbiter);
1421 * Load the zone file from disk
1423 static void
1424 loadzone(char *file, char *origin, dns_rdataclass_t rdclass, dns_db_t **db) {
1425 isc_buffer_t b;
1426 int len;
1427 dns_fixedname_t fname;
1428 dns_name_t *name;
1429 isc_result_t result;
1431 len = strlen(origin);
1432 isc_buffer_init(&b, origin, len);
1433 isc_buffer_add(&b, len);
1435 dns_fixedname_init(&fname);
1436 name = dns_fixedname_name(&fname);
1437 result = dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL);
1438 if (result != ISC_R_SUCCESS)
1439 fatal("failed converting name '%s' to dns format: %s",
1440 origin, isc_result_totext(result));
1442 result = dns_db_create(mctx, "rbt", name, dns_dbtype_zone,
1443 rdclass, 0, NULL, db);
1444 check_result(result, "dns_db_create()");
1446 result = dns_db_load2(*db, file, inputformat);
1447 if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE)
1448 fatal("failed loading zone from '%s': %s",
1449 file, isc_result_totext(result));
1453 * Finds all public zone keys in the zone, and attempts to load the
1454 * private keys from disk.
1456 static void
1457 loadzonekeys(dns_db_t *db) {
1458 dns_dbnode_t *node;
1459 dns_dbversion_t *currentversion;
1460 isc_result_t result;
1461 dst_key_t *keys[20];
1462 unsigned int nkeys, i;
1464 currentversion = NULL;
1465 dns_db_currentversion(db, &currentversion);
1467 node = NULL;
1468 result = dns_db_findnode(db, gorigin, ISC_FALSE, &node);
1469 if (result != ISC_R_SUCCESS)
1470 fatal("failed to find the zone's origin: %s",
1471 isc_result_totext(result));
1473 result = dns_dnssec_findzonekeys(db, currentversion, node, gorigin,
1474 mctx, 20, keys, &nkeys);
1475 if (result == ISC_R_NOTFOUND)
1476 result = ISC_R_SUCCESS;
1477 if (result != ISC_R_SUCCESS)
1478 fatal("failed to find the zone keys: %s",
1479 isc_result_totext(result));
1481 for (i = 0; i < nkeys; i++) {
1482 signer_key_t *key;
1484 key = newkeystruct(keys[i], dst_key_isprivate(keys[i]));
1485 ISC_LIST_APPEND(keylist, key, link);
1487 dns_db_detachnode(db, &node);
1488 dns_db_closeversion(db, &currentversion, ISC_FALSE);
1492 * Finds all public zone keys in the zone.
1494 static void
1495 loadzonepubkeys(dns_db_t *db) {
1496 dns_dbversion_t *currentversion = NULL;
1497 dns_dbnode_t *node = NULL;
1498 dns_rdataset_t rdataset;
1499 dns_rdata_t rdata = DNS_RDATA_INIT;
1500 dst_key_t *pubkey;
1501 signer_key_t *key;
1502 isc_result_t result;
1504 dns_db_currentversion(db, &currentversion);
1506 result = dns_db_findnode(db, gorigin, ISC_FALSE, &node);
1507 if (result != ISC_R_SUCCESS)
1508 fatal("failed to find the zone's origin: %s",
1509 isc_result_totext(result));
1511 dns_rdataset_init(&rdataset);
1512 result = dns_db_findrdataset(db, node, currentversion,
1513 dns_rdatatype_dnskey, 0, 0, &rdataset, NULL);
1514 if (result != ISC_R_SUCCESS)
1515 fatal("failed to find keys at the zone apex: %s",
1516 isc_result_totext(result));
1517 result = dns_rdataset_first(&rdataset);
1518 check_result(result, "dns_rdataset_first");
1519 while (result == ISC_R_SUCCESS) {
1520 pubkey = NULL;
1521 dns_rdata_reset(&rdata);
1522 dns_rdataset_current(&rdataset, &rdata);
1523 result = dns_dnssec_keyfromrdata(gorigin, &rdata, mctx,
1524 &pubkey);
1525 if (result != ISC_R_SUCCESS)
1526 goto next;
1527 if (!dst_key_iszonekey(pubkey)) {
1528 dst_key_free(&pubkey);
1529 goto next;
1532 key = newkeystruct(pubkey, ISC_FALSE);
1533 ISC_LIST_APPEND(keylist, key, link);
1534 next:
1535 result = dns_rdataset_next(&rdataset);
1537 dns_rdataset_disassociate(&rdataset);
1538 dns_db_detachnode(db, &node);
1539 dns_db_closeversion(db, &currentversion, ISC_FALSE);
1542 static void
1543 warnifallksk(dns_db_t *db) {
1544 dns_dbversion_t *currentversion = NULL;
1545 dns_dbnode_t *node = NULL;
1546 dns_rdataset_t rdataset;
1547 dns_rdata_t rdata = DNS_RDATA_INIT;
1548 isc_result_t result;
1549 dns_rdata_key_t key;
1550 isc_boolean_t have_non_ksk = ISC_FALSE;
1552 dns_db_currentversion(db, &currentversion);
1554 result = dns_db_findnode(db, gorigin, ISC_FALSE, &node);
1555 if (result != ISC_R_SUCCESS)
1556 fatal("failed to find the zone's origin: %s",
1557 isc_result_totext(result));
1559 dns_rdataset_init(&rdataset);
1560 result = dns_db_findrdataset(db, node, currentversion,
1561 dns_rdatatype_dnskey, 0, 0, &rdataset, NULL);
1562 if (result != ISC_R_SUCCESS)
1563 fatal("failed to find keys at the zone apex: %s",
1564 isc_result_totext(result));
1565 result = dns_rdataset_first(&rdataset);
1566 check_result(result, "dns_rdataset_first");
1567 while (result == ISC_R_SUCCESS) {
1568 dns_rdata_reset(&rdata);
1569 dns_rdataset_current(&rdataset, &rdata);
1570 result = dns_rdata_tostruct(&rdata, &key, NULL);
1571 check_result(result, "dns_rdata_tostruct");
1572 if ((key.flags & DNS_KEYFLAG_KSK) == 0) {
1573 have_non_ksk = ISC_TRUE;
1574 result = ISC_R_NOMORE;
1575 } else
1576 result = dns_rdataset_next(&rdataset);
1578 dns_rdataset_disassociate(&rdataset);
1579 dns_db_detachnode(db, &node);
1580 dns_db_closeversion(db, &currentversion, ISC_FALSE);
1581 if (!have_non_ksk && !ignoreksk)
1582 fprintf(stderr, "%s: warning: No non-KSK dnskey found. "
1583 "Supply non-KSK dnskey or use '-z'.\n",
1584 program);
1587 static void
1588 writeset(const char *prefix, dns_rdatatype_t type) {
1589 char *filename;
1590 char namestr[DNS_NAME_FORMATSIZE];
1591 dns_db_t *db = NULL;
1592 dns_dbversion_t *version = NULL;
1593 dns_diff_t diff;
1594 dns_difftuple_t *tuple = NULL;
1595 dns_fixedname_t fixed;
1596 dns_name_t *name;
1597 dns_rdata_t rdata, ds;
1598 isc_boolean_t have_ksk = ISC_FALSE;
1599 isc_boolean_t have_non_ksk = ISC_FALSE;
1600 isc_buffer_t b;
1601 isc_buffer_t namebuf;
1602 isc_region_t r;
1603 isc_result_t result;
1604 signer_key_t *key;
1605 unsigned char dsbuf[DNS_DS_BUFFERSIZE];
1606 unsigned char keybuf[DST_KEY_MAXSIZE];
1607 unsigned int filenamelen;
1608 const dns_master_style_t *style =
1609 (type == dns_rdatatype_dnskey) ? masterstyle : dsstyle;
1611 isc_buffer_init(&namebuf, namestr, sizeof(namestr));
1612 result = dns_name_tofilenametext(gorigin, ISC_FALSE, &namebuf);
1613 check_result(result, "dns_name_tofilenametext");
1614 isc_buffer_putuint8(&namebuf, 0);
1615 filenamelen = strlen(prefix) + strlen(namestr);
1616 if (directory != NULL)
1617 filenamelen += strlen(directory) + 1;
1618 filename = isc_mem_get(mctx, filenamelen + 1);
1619 if (filename == NULL)
1620 fatal("out of memory");
1621 if (directory != NULL)
1622 sprintf(filename, "%s/", directory);
1623 else
1624 filename[0] = 0;
1625 strcat(filename, prefix);
1626 strcat(filename, namestr);
1628 dns_diff_init(mctx, &diff);
1630 for (key = ISC_LIST_HEAD(keylist);
1631 key != NULL;
1632 key = ISC_LIST_NEXT(key, link))
1633 if (!key->isksk) {
1634 have_non_ksk = ISC_TRUE;
1635 break;
1638 for (key = ISC_LIST_HEAD(keylist);
1639 key != NULL;
1640 key = ISC_LIST_NEXT(key, link))
1641 if (key->isksk) {
1642 have_ksk = ISC_TRUE;
1643 break;
1646 if (type == dns_rdatatype_dlv) {
1647 dns_name_t tname;
1648 unsigned int labels;
1650 dns_name_init(&tname, NULL);
1651 dns_fixedname_init(&fixed);
1652 name = dns_fixedname_name(&fixed);
1653 labels = dns_name_countlabels(gorigin);
1654 dns_name_getlabelsequence(gorigin, 0, labels - 1, &tname);
1655 result = dns_name_concatenate(&tname, dlv, name, NULL);
1656 check_result(result, "dns_name_concatenate");
1657 } else
1658 name = gorigin;
1660 for (key = ISC_LIST_HEAD(keylist);
1661 key != NULL;
1662 key = ISC_LIST_NEXT(key, link))
1664 if (have_ksk && have_non_ksk && !key->isksk)
1665 continue;
1666 dns_rdata_init(&rdata);
1667 dns_rdata_init(&ds);
1668 isc_buffer_init(&b, keybuf, sizeof(keybuf));
1669 result = dst_key_todns(key->key, &b);
1670 check_result(result, "dst_key_todns");
1671 isc_buffer_usedregion(&b, &r);
1672 dns_rdata_fromregion(&rdata, gclass, dns_rdatatype_dnskey, &r);
1673 if (type != dns_rdatatype_dnskey) {
1674 result = dns_ds_buildrdata(gorigin, &rdata,
1675 DNS_DSDIGEST_SHA1,
1676 dsbuf, &ds);
1677 check_result(result, "dns_ds_buildrdata");
1678 if (type == dns_rdatatype_dlv)
1679 ds.type = dns_rdatatype_dlv;
1680 result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD,
1681 name, 0, &ds, &tuple);
1682 check_result(result, "dns_difftuple_create");
1683 dns_diff_append(&diff, &tuple);
1685 dns_rdata_reset(&ds);
1686 result = dns_ds_buildrdata(gorigin, &rdata,
1687 DNS_DSDIGEST_SHA256,
1688 dsbuf, &ds);
1689 check_result(result, "dns_ds_buildrdata");
1690 if (type == dns_rdatatype_dlv)
1691 ds.type = dns_rdatatype_dlv;
1692 result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD,
1693 name, 0, &ds, &tuple);
1695 } else
1696 result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD,
1697 gorigin, zonettl,
1698 &rdata, &tuple);
1699 check_result(result, "dns_difftuple_create");
1700 dns_diff_append(&diff, &tuple);
1703 result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone,
1704 gclass, 0, NULL, &db);
1705 check_result(result, "dns_db_create");
1707 result = dns_db_newversion(db, &version);
1708 check_result(result, "dns_db_newversion");
1710 result = dns_diff_apply(&diff, db, version);
1711 check_result(result, "dns_diff_apply");
1712 dns_diff_clear(&diff);
1714 result = dns_master_dump(mctx, db, version, style, filename);
1715 check_result(result, "dns_master_dump");
1717 isc_mem_put(mctx, filename, filenamelen + 1);
1719 dns_db_closeversion(db, &version, ISC_FALSE);
1720 dns_db_detach(&db);
1723 static void
1724 print_time(FILE *fp) {
1725 time_t currenttime;
1727 if (outputformat != dns_masterformat_text)
1728 return;
1730 currenttime = time(NULL);
1731 fprintf(fp, "; File written on %s", ctime(&currenttime));
1734 static void
1735 print_version(FILE *fp) {
1736 if (outputformat != dns_masterformat_text)
1737 return;
1739 fprintf(fp, "; dnssec_signzone version " VERSION "\n");
1742 static void
1743 usage(void) {
1744 fprintf(stderr, "Usage:\n");
1745 fprintf(stderr, "\t%s [options] zonefile [keys]\n", program);
1747 fprintf(stderr, "\n");
1749 fprintf(stderr, "Version: %s\n", VERSION);
1751 fprintf(stderr, "Options: (default value in parenthesis) \n");
1752 fprintf(stderr, "\t-c class (IN)\n");
1753 fprintf(stderr, "\t-d directory\n");
1754 fprintf(stderr, "\t\tdirectory to find keyset files (.)\n");
1755 fprintf(stderr, "\t-g:\t");
1756 fprintf(stderr, "generate DS records from keyset files\n");
1757 fprintf(stderr, "\t-s [YYYYMMDDHHMMSS|+offset]:\n");
1758 fprintf(stderr, "\t\tRRSIG start time - absolute|offset (now - 1 hour)\n");
1759 fprintf(stderr, "\t-e [YYYYMMDDHHMMSS|+offset|\"now\"+offset]:\n");
1760 fprintf(stderr, "\t\tRRSIG end time - absolute|from start|from now "
1761 "(now + 30 days)\n");
1762 fprintf(stderr, "\t-i interval:\n");
1763 fprintf(stderr, "\t\tcycle interval - resign "
1764 "if < interval from end ( (end-start)/4 )\n");
1765 fprintf(stderr, "\t-j jitter:\n");
1766 fprintf(stderr, "\t\trandomize signature end time up to jitter seconds\n");
1767 fprintf(stderr, "\t-v debuglevel (0)\n");
1768 fprintf(stderr, "\t-o origin:\n");
1769 fprintf(stderr, "\t\tzone origin (name of zonefile)\n");
1770 fprintf(stderr, "\t-f outfile:\n");
1771 fprintf(stderr, "\t\tfile the signed zone is written in "
1772 "(zonefile + .signed)\n");
1773 fprintf(stderr, "\t-I format:\n");
1774 fprintf(stderr, "\t\tfile format of input zonefile (text)\n");
1775 fprintf(stderr, "\t-O format:\n");
1776 fprintf(stderr, "\t\tfile format of signed zone file (text)\n");
1777 fprintf(stderr, "\t-N format:\n");
1778 fprintf(stderr, "\t\tsoa serial format of signed zone file (keep)\n");
1779 fprintf(stderr, "\t-r randomdev:\n");
1780 fprintf(stderr, "\t\ta file containing random data\n");
1781 fprintf(stderr, "\t-a:\t");
1782 fprintf(stderr, "verify generated signatures\n");
1783 fprintf(stderr, "\t-p:\t");
1784 fprintf(stderr, "use pseudorandom data (faster but less secure)\n");
1785 fprintf(stderr, "\t-t:\t");
1786 fprintf(stderr, "print statistics\n");
1787 fprintf(stderr, "\t-n ncpus (number of cpus present)\n");
1788 fprintf(stderr, "\t-k key_signing_key\n");
1789 fprintf(stderr, "\t-l lookasidezone\n");
1790 fprintf(stderr, "\t-z:\t");
1791 fprintf(stderr, "ignore KSK flag in DNSKEYs");
1793 fprintf(stderr, "\n");
1795 fprintf(stderr, "Signing Keys: ");
1796 fprintf(stderr, "(default: all zone keys that have private keys)\n");
1797 fprintf(stderr, "\tkeyfile (Kname+alg+tag)\n");
1798 exit(0);
1801 static void
1802 removetempfile(void) {
1803 if (removefile)
1804 isc_file_remove(tempfile);
1807 static void
1808 print_stats(isc_time_t *timer_start, isc_time_t *timer_finish) {
1809 isc_uint64_t runtime_us; /* Runtime in microseconds */
1810 isc_uint64_t runtime_ms; /* Runtime in milliseconds */
1811 isc_uint64_t sig_ms; /* Signatures per millisecond */
1813 runtime_us = isc_time_microdiff(timer_finish, timer_start);
1815 printf("Signatures generated: %10d\n", nsigned);
1816 printf("Signatures retained: %10d\n", nretained);
1817 printf("Signatures dropped: %10d\n", ndropped);
1818 printf("Signatures successfully verified: %10d\n", nverified);
1819 printf("Signatures unsuccessfully verified: %10d\n", nverifyfailed);
1820 runtime_ms = runtime_us / 1000;
1821 printf("Runtime in seconds: %7u.%03u\n",
1822 (unsigned int) (runtime_ms / 1000),
1823 (unsigned int) (runtime_ms % 1000));
1824 if (runtime_us > 0) {
1825 sig_ms = ((isc_uint64_t)nsigned * 1000000000) / runtime_us;
1826 printf("Signatures per second: %7u.%03u\n",
1827 (unsigned int) sig_ms / 1000,
1828 (unsigned int) sig_ms % 1000);
1833 main(int argc, char *argv[]) {
1834 int i, ch;
1835 char *startstr = NULL, *endstr = NULL, *classname = NULL;
1836 char *origin = NULL, *file = NULL, *output = NULL;
1837 char *inputformatstr = NULL, *outputformatstr = NULL;
1838 char *serialformatstr = NULL;
1839 char *dskeyfile[MAXDSKEYS];
1840 int ndskeys = 0;
1841 char *endp;
1842 isc_time_t timer_start, timer_finish;
1843 signer_key_t *key;
1844 isc_result_t result;
1845 isc_log_t *log = NULL;
1846 isc_boolean_t pseudorandom = ISC_FALSE;
1847 unsigned int eflags;
1848 isc_boolean_t free_output = ISC_FALSE;
1849 int tempfilelen;
1850 dns_rdataclass_t rdclass;
1851 isc_task_t **tasks = NULL;
1852 isc_buffer_t b;
1853 int len;
1855 masterstyle = &dns_master_style_explicitttl;
1857 check_result(isc_app_start(), "isc_app_start");
1859 result = isc_mem_create(0, 0, &mctx);
1860 if (result != ISC_R_SUCCESS)
1861 fatal("out of memory");
1863 dns_result_register();
1865 while ((ch = isc_commandline_parse(argc, argv,
1866 "ac:d:e:f:ghi:I:j:k:l:n:N:o:O:pr:s:Stv:z"))
1867 != -1) {
1868 switch (ch) {
1869 case 'a':
1870 tryverify = ISC_TRUE;
1871 break;
1873 case 'c':
1874 classname = isc_commandline_argument;
1875 break;
1877 case 'd':
1878 directory = isc_commandline_argument;
1879 break;
1881 case 'e':
1882 endstr = isc_commandline_argument;
1883 break;
1885 case 'f':
1886 output = isc_commandline_argument;
1887 break;
1889 case 'g':
1890 generateds = ISC_TRUE;
1891 break;
1893 case 'h':
1894 default:
1895 usage();
1896 break;
1898 case 'i':
1899 endp = NULL;
1900 cycle = strtol(isc_commandline_argument, &endp, 0);
1901 if (*endp != '\0' || cycle < 0)
1902 fatal("cycle period must be numeric and "
1903 "positive");
1904 break;
1906 case 'I':
1907 inputformatstr = isc_commandline_argument;
1908 break;
1910 case 'j':
1911 endp = NULL;
1912 jitter = strtol(isc_commandline_argument, &endp, 0);
1913 if (*endp != '\0' || jitter < 0)
1914 fatal("jitter must be numeric and positive");
1915 break;
1917 case 'l':
1918 dns_fixedname_init(&dlv_fixed);
1919 len = strlen(isc_commandline_argument);
1920 isc_buffer_init(&b, isc_commandline_argument, len);
1921 isc_buffer_add(&b, len);
1923 dns_fixedname_init(&dlv_fixed);
1924 dlv = dns_fixedname_name(&dlv_fixed);
1925 result = dns_name_fromtext(dlv, &b, dns_rootname,
1926 ISC_FALSE, NULL);
1927 check_result(result, "dns_name_fromtext(dlv)");
1928 break;
1930 case 'k':
1931 if (ndskeys == MAXDSKEYS)
1932 fatal("too many key-signing keys specified");
1933 dskeyfile[ndskeys++] = isc_commandline_argument;
1934 break;
1936 case 'n':
1937 endp = NULL;
1938 ntasks = strtol(isc_commandline_argument, &endp, 0);
1939 if (*endp != '\0' || ntasks > ISC_INT32_MAX)
1940 fatal("number of cpus must be numeric");
1941 break;
1943 case 'N':
1944 serialformatstr = isc_commandline_argument;
1945 break;
1947 case 'o':
1948 origin = isc_commandline_argument;
1949 break;
1951 case 'O':
1952 outputformatstr = isc_commandline_argument;
1953 break;
1955 case 'p':
1956 pseudorandom = ISC_TRUE;
1957 break;
1959 case 'r':
1960 setup_entropy(mctx, isc_commandline_argument, &ectx);
1961 break;
1963 case 's':
1964 startstr = isc_commandline_argument;
1965 break;
1967 case 'S':
1968 /* This is intentionally undocumented */
1969 /* -S: simple output style */
1970 masterstyle = &dns_master_style_simple;
1971 break;
1973 case 't':
1974 printstats = ISC_TRUE;
1975 break;
1977 case 'v':
1978 endp = NULL;
1979 verbose = strtol(isc_commandline_argument, &endp, 0);
1980 if (*endp != '\0')
1981 fatal("verbose level must be numeric");
1982 break;
1984 case 'z':
1985 ignoreksk = ISC_TRUE;
1986 break;
1990 if (ectx == NULL)
1991 setup_entropy(mctx, NULL, &ectx);
1992 eflags = ISC_ENTROPY_BLOCKING;
1993 if (!pseudorandom)
1994 eflags |= ISC_ENTROPY_GOODONLY;
1996 result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE);
1997 if (result != ISC_R_SUCCESS)
1998 fatal("could not create hash context");
2000 result = dst_lib_init(mctx, ectx, eflags);
2001 if (result != ISC_R_SUCCESS)
2002 fatal("could not initialize dst");
2004 isc_stdtime_get(&now);
2006 if (startstr != NULL)
2007 starttime = strtotime(startstr, now, now);
2008 else
2009 starttime = now - 3600; /* Allow for some clock skew. */
2011 if (endstr != NULL)
2012 endtime = strtotime(endstr, now, starttime);
2013 else
2014 endtime = starttime + (30 * 24 * 60 * 60);
2016 if (cycle == -1)
2017 cycle = (endtime - starttime) / 4;
2019 if (ntasks == 0)
2020 ntasks = isc_os_ncpus();
2021 vbprintf(4, "using %d cpus\n", ntasks);
2023 rdclass = strtoclass(classname);
2025 setup_logging(verbose, mctx, &log);
2027 argc -= isc_commandline_index;
2028 argv += isc_commandline_index;
2030 if (argc < 1)
2031 usage();
2033 file = argv[0];
2035 argc -= 1;
2036 argv += 1;
2038 if (origin == NULL)
2039 origin = file;
2041 if (output == NULL) {
2042 free_output = ISC_TRUE;
2043 output = isc_mem_allocate(mctx,
2044 strlen(file) + strlen(".signed") + 1);
2045 if (output == NULL)
2046 fatal("out of memory");
2047 sprintf(output, "%s.signed", file);
2050 if (inputformatstr != NULL) {
2051 if (strcasecmp(inputformatstr, "text") == 0)
2052 inputformat = dns_masterformat_text;
2053 else if (strcasecmp(inputformatstr, "raw") == 0)
2054 inputformat = dns_masterformat_raw;
2055 else
2056 fatal("unknown file format: %s\n", inputformatstr);
2059 if (outputformatstr != NULL) {
2060 if (strcasecmp(outputformatstr, "text") == 0)
2061 outputformat = dns_masterformat_text;
2062 else if (strcasecmp(outputformatstr, "raw") == 0)
2063 outputformat = dns_masterformat_raw;
2064 else
2065 fatal("unknown file format: %s\n", outputformatstr);
2068 if (serialformatstr != NULL) {
2069 if (strcasecmp(serialformatstr, "keep") == 0)
2070 serialformat = SOA_SERIAL_KEEP;
2071 else if (strcasecmp(serialformatstr, "increment") == 0 ||
2072 strcasecmp(serialformatstr, "incr") == 0)
2073 serialformat = SOA_SERIAL_INCREMENT;
2074 else if (strcasecmp(serialformatstr, "unixtime") == 0)
2075 serialformat = SOA_SERIAL_UNIXTIME;
2076 else
2077 fatal("unknown soa serial format: %s\n", serialformatstr);
2080 result = dns_master_stylecreate(&dsstyle, DNS_STYLEFLAG_NO_TTL,
2081 0, 24, 0, 0, 0, 8, mctx);
2082 check_result(result, "dns_master_stylecreate");
2085 gdb = NULL;
2086 TIME_NOW(&timer_start);
2087 loadzone(file, origin, rdclass, &gdb);
2088 gorigin = dns_db_origin(gdb);
2089 gclass = dns_db_class(gdb);
2090 zonettl = soattl();
2092 ISC_LIST_INIT(keylist);
2094 if (argc == 0) {
2095 loadzonekeys(gdb);
2096 } else {
2097 for (i = 0; i < argc; i++) {
2098 dst_key_t *newkey = NULL;
2100 result = dst_key_fromnamedfile(argv[i],
2101 DST_TYPE_PUBLIC |
2102 DST_TYPE_PRIVATE,
2103 mctx, &newkey);
2104 if (result != ISC_R_SUCCESS)
2105 fatal("cannot load dnskey %s: %s", argv[i],
2106 isc_result_totext(result));
2108 key = ISC_LIST_HEAD(keylist);
2109 while (key != NULL) {
2110 dst_key_t *dkey = key->key;
2111 if (dst_key_id(dkey) == dst_key_id(newkey) &&
2112 dst_key_alg(dkey) == dst_key_alg(newkey) &&
2113 dns_name_equal(dst_key_name(dkey),
2114 dst_key_name(newkey)))
2116 if (!dst_key_isprivate(dkey))
2117 fatal("cannot sign zone with "
2118 "non-private dnskey %s",
2119 argv[i]);
2120 break;
2122 key = ISC_LIST_NEXT(key, link);
2124 if (key == NULL) {
2125 key = newkeystruct(newkey, ISC_TRUE);
2126 ISC_LIST_APPEND(keylist, key, link);
2127 } else
2128 dst_key_free(&newkey);
2131 loadzonepubkeys(gdb);
2134 for (i = 0; i < ndskeys; i++) {
2135 dst_key_t *newkey = NULL;
2137 result = dst_key_fromnamedfile(dskeyfile[i],
2138 DST_TYPE_PUBLIC |
2139 DST_TYPE_PRIVATE,
2140 mctx, &newkey);
2141 if (result != ISC_R_SUCCESS)
2142 fatal("cannot load dnskey %s: %s", dskeyfile[i],
2143 isc_result_totext(result));
2145 key = ISC_LIST_HEAD(keylist);
2146 while (key != NULL) {
2147 dst_key_t *dkey = key->key;
2148 if (dst_key_id(dkey) == dst_key_id(newkey) &&
2149 dst_key_alg(dkey) == dst_key_alg(newkey) &&
2150 dns_name_equal(dst_key_name(dkey),
2151 dst_key_name(newkey)))
2153 /* Override key flags. */
2154 key->issigningkey = ISC_TRUE;
2155 key->isksk = ISC_TRUE;
2156 key->isdsk = ISC_FALSE;
2157 dst_key_free(&dkey);
2158 key->key = newkey;
2159 break;
2161 key = ISC_LIST_NEXT(key, link);
2163 if (key == NULL) {
2164 /* Override dnskey flags. */
2165 key = newkeystruct(newkey, ISC_TRUE);
2166 key->isksk = ISC_TRUE;
2167 key->isdsk = ISC_FALSE;
2168 ISC_LIST_APPEND(keylist, key, link);
2172 if (ISC_LIST_EMPTY(keylist)) {
2173 fprintf(stderr, "%s: warning: No keys specified or found\n",
2174 program);
2175 nokeys = ISC_TRUE;
2178 warnifallksk(gdb);
2180 gversion = NULL;
2181 result = dns_db_newversion(gdb, &gversion);
2182 check_result(result, "dns_db_newversion()");
2184 switch (serialformat) {
2185 case SOA_SERIAL_INCREMENT:
2186 setsoaserial(0);
2187 break;
2188 case SOA_SERIAL_UNIXTIME:
2189 setsoaserial(now);
2190 break;
2191 case SOA_SERIAL_KEEP:
2192 default:
2193 /* do nothing */
2194 break;
2197 nsecify();
2199 if (!nokeys) {
2200 writeset("keyset-", dns_rdatatype_dnskey);
2201 writeset("dsset-", dns_rdatatype_ds);
2202 if (dlv != NULL) {
2203 writeset("dlvset-", dns_rdatatype_dlv);
2207 tempfilelen = strlen(output) + 20;
2208 tempfile = isc_mem_get(mctx, tempfilelen);
2209 if (tempfile == NULL)
2210 fatal("out of memory");
2212 result = isc_file_mktemplate(output, tempfile, tempfilelen);
2213 check_result(result, "isc_file_mktemplate");
2215 fp = NULL;
2216 result = isc_file_openunique(tempfile, &fp);
2217 if (result != ISC_R_SUCCESS)
2218 fatal("failed to open temporary output file: %s",
2219 isc_result_totext(result));
2220 removefile = ISC_TRUE;
2221 setfatalcallback(&removetempfile);
2223 print_time(fp);
2224 print_version(fp);
2226 result = isc_taskmgr_create(mctx, ntasks, 0, &taskmgr);
2227 if (result != ISC_R_SUCCESS)
2228 fatal("failed to create task manager: %s",
2229 isc_result_totext(result));
2231 master = NULL;
2232 result = isc_task_create(taskmgr, 0, &master);
2233 if (result != ISC_R_SUCCESS)
2234 fatal("failed to create task: %s", isc_result_totext(result));
2236 tasks = isc_mem_get(mctx, ntasks * sizeof(isc_task_t *));
2237 if (tasks == NULL)
2238 fatal("out of memory");
2239 for (i = 0; i < (int)ntasks; i++) {
2240 tasks[i] = NULL;
2241 result = isc_task_create(taskmgr, 0, &tasks[i]);
2242 if (result != ISC_R_SUCCESS)
2243 fatal("failed to create task: %s",
2244 isc_result_totext(result));
2247 RUNTIME_CHECK(isc_mutex_init(&namelock) == ISC_R_SUCCESS);
2248 if (printstats)
2249 RUNTIME_CHECK(isc_mutex_init(&statslock) == ISC_R_SUCCESS);
2251 presign();
2252 signapex();
2253 if (!finished) {
2255 * There is more work to do. Spread it out over multiple
2256 * processors if possible.
2258 for (i = 0; i < (int)ntasks; i++) {
2259 result = isc_app_onrun(mctx, master, startworker,
2260 tasks[i]);
2261 if (result != ISC_R_SUCCESS)
2262 fatal("failed to start task: %s",
2263 isc_result_totext(result));
2265 (void)isc_app_run();
2266 if (!finished)
2267 fatal("process aborted by user");
2268 } else
2269 isc_task_detach(&master);
2270 shuttingdown = ISC_TRUE;
2271 for (i = 0; i < (int)ntasks; i++)
2272 isc_task_detach(&tasks[i]);
2273 isc_taskmgr_destroy(&taskmgr);
2274 isc_mem_put(mctx, tasks, ntasks * sizeof(isc_task_t *));
2275 postsign();
2277 if (outputformat != dns_masterformat_text) {
2278 result = dns_master_dumptostream2(mctx, gdb, gversion,
2279 masterstyle, outputformat,
2280 fp);
2281 check_result(result, "dns_master_dumptostream2");
2284 result = isc_stdio_close(fp);
2285 check_result(result, "isc_stdio_close");
2286 removefile = ISC_FALSE;
2288 result = isc_file_rename(tempfile, output);
2289 if (result != ISC_R_SUCCESS)
2290 fatal("failed to rename temp file to %s: %s\n",
2291 output, isc_result_totext(result));
2293 DESTROYLOCK(&namelock);
2294 if (printstats)
2295 DESTROYLOCK(&statslock);
2297 printf("%s\n", output);
2299 dns_db_closeversion(gdb, &gversion, ISC_FALSE);
2300 dns_db_detach(&gdb);
2302 while (!ISC_LIST_EMPTY(keylist)) {
2303 key = ISC_LIST_HEAD(keylist);
2304 ISC_LIST_UNLINK(keylist, key, link);
2305 dst_key_free(&key->key);
2306 isc_mem_put(mctx, key, sizeof(signer_key_t));
2309 isc_mem_put(mctx, tempfile, tempfilelen);
2311 if (free_output)
2312 isc_mem_free(mctx, output);
2314 dns_master_styledestroy(&dsstyle, mctx);
2316 cleanup_logging(&log);
2317 dst_lib_destroy();
2318 isc_hash_destroy();
2319 cleanup_entropy(&ectx);
2320 dns_name_destroy();
2321 if (verbose > 10)
2322 isc_mem_stats(mctx, stdout);
2323 isc_mem_destroy(&mctx);
2325 (void) isc_app_finish();
2327 if (printstats) {
2328 TIME_NOW(&timer_finish);
2329 print_stats(&timer_start, &timer_finish);
2332 return (0);