2 * Portions Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
3 * Portions Copyright (C) 1999-2001, 2003 Internet Software Consortium.
4 * Portions Copyright (C) 1995-2000 by Network Associates, Inc.
6 * Permission to use, copy, modify, and 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.139.2.5 2004/04/15 02:16:24 marka Exp $ */
27 #include <isc/commandline.h>
28 #include <isc/entropy.h>
29 #include <isc/event.h>
32 #include <isc/mutex.h>
34 #include <isc/stdio.h>
35 #include <isc/string.h>
41 #include <dns/dbiterator.h>
43 #include <dns/dnssec.h>
44 #include <dns/fixedname.h>
45 #include <dns/keyvalues.h>
47 #include <dns/master.h>
48 #include <dns/masterdump.h>
50 #include <dns/rdata.h>
51 #include <dns/rdataset.h>
52 #include <dns/rdataclass.h>
53 #include <dns/rdatasetiter.h>
54 #include <dns/rdatastruct.h>
55 #include <dns/rdatatype.h>
56 #include <dns/result.h>
57 #include <dns/secalg.h>
61 #include <dst/result.h>
63 #include "dnssectool.h"
65 const char *program = "dnssec-signzone";
70 typedef struct signer_key_struct signer_key_t;
72 struct signer_key_struct {
74 isc_boolean_t isdefault;
75 unsigned int position;
76 ISC_LINK(signer_key_t) link;
79 #define SIGNER_EVENTCLASS ISC_EVENTCLASS(0x4453)
80 #define SIGNER_EVENT_WRITE (SIGNER_EVENTCLASS + 0)
81 #define SIGNER_EVENT_WORK (SIGNER_EVENTCLASS + 1)
83 typedef struct signer_event sevent_t;
85 ISC_EVENT_COMMON(sevent_t);
86 dns_fixedname_t *fname;
87 dns_fixedname_t *fnextname;
91 static ISC_LIST(signer_key_t) keylist;
92 static unsigned int keycount = 0;
93 static isc_stdtime_t starttime = 0, endtime = 0, now;
94 static int cycle = -1;
95 static isc_boolean_t tryverify = ISC_FALSE;
96 static isc_boolean_t printstats = ISC_FALSE;
97 static isc_mem_t *mctx = NULL;
98 static isc_entropy_t *ectx = NULL;
99 static dns_ttl_t zonettl;
101 static char *tempfile = NULL;
102 static const dns_master_style_t *masterstyle;
103 static unsigned int nsigned = 0, nretained = 0, ndropped = 0;
104 static unsigned int nverified = 0, nverifyfailed = 0;
105 static const char *directory;
106 static isc_mutex_t namelock, statslock;
107 static isc_taskmgr_t *taskmgr = NULL;
108 static dns_db_t *gdb; /* The database */
109 static dns_dbversion_t *gversion; /* The database version */
110 static dns_dbiterator_t *gdbiter; /* The database iterator */
111 static dns_name_t *gorigin; /* The database origin */
112 static dns_dbnode_t *gnode = NULL; /* The "current" database node */
113 static dns_name_t *lastzonecut;
114 static isc_task_t *master = NULL;
115 static unsigned int ntasks = 0;
116 static isc_boolean_t shuttingdown = ISC_FALSE, finished = ISC_FALSE;
117 static unsigned int assigned = 0, completed = 0;
118 static isc_boolean_t nokeys = ISC_FALSE;
119 static isc_boolean_t removefile = ISC_FALSE;
121 #define INCSTAT(counter) \
125 UNLOCK(&statslock); \
129 sign(isc_task_t *task, isc_event_t *event);
133 set_bit(unsigned char *array, unsigned int index, unsigned int bit) {
134 unsigned int shift, mask;
136 shift = 7 - (index % 8);
140 array[index / 8] |= mask;
142 array[index / 8] &= (~mask & 0xFF);
145 static signer_key_t *
146 newkeystruct(dst_key_t *dstkey, isc_boolean_t isdefault) {
149 key = isc_mem_get(mctx, sizeof(signer_key_t));
151 fatal("out of memory");
153 key->isdefault = isdefault;
154 key->position = keycount++;
155 ISC_LINK_INIT(key, link);
160 signwithkey(dns_name_t *name, dns_rdataset_t *rdataset, dns_rdata_t *rdata,
161 dst_key_t *key, isc_buffer_t *b)
165 result = dns_dnssec_sign(name, rdataset, key, &starttime, &endtime,
167 isc_entropy_stopcallbacksources(ectx);
168 if (result != ISC_R_SUCCESS) {
169 char keystr[KEY_FORMATSIZE];
170 key_format(key, keystr, sizeof keystr);
171 fatal("key '%s' failed to sign data: %s",
172 keystr, isc_result_totext(result));
177 result = dns_dnssec_verify(name, rdataset, key,
178 ISC_TRUE, mctx, rdata);
179 if (result == ISC_R_SUCCESS) {
180 vbprintf(3, "\tsignature verified\n");
183 vbprintf(3, "\tsignature failed to verify\n");
184 INCSTAT(nverifyfailed);
189 static inline isc_boolean_t
190 issigningkey(signer_key_t *key) {
191 return (key->isdefault);
194 static inline isc_boolean_t
195 iszonekey(signer_key_t *key) {
196 return (ISC_TF(dns_name_equal(dst_key_name(key->key), gorigin) &&
197 dst_key_iszonekey(key->key)));
201 * Finds the key that generated a SIG, if possible. First look at the keys
202 * that we've loaded already, and then see if there's a key on disk.
204 static signer_key_t *
205 keythatsigned(dns_rdata_sig_t *sig) {
207 dst_key_t *pubkey = NULL, *privkey = NULL;
210 key = ISC_LIST_HEAD(keylist);
211 while (key != NULL) {
212 if (sig->keyid == dst_key_id(key->key) &&
213 sig->algorithm == dst_key_alg(key->key) &&
214 dns_name_equal(&sig->signer, dst_key_name(key->key)))
216 key = ISC_LIST_NEXT(key, link);
219 result = dst_key_fromfile(&sig->signer, sig->keyid, sig->algorithm,
220 DST_TYPE_PUBLIC, NULL, mctx, &pubkey);
221 if (result != ISC_R_SUCCESS)
224 result = dst_key_fromfile(&sig->signer, sig->keyid, sig->algorithm,
225 DST_TYPE_PUBLIC | DST_TYPE_PRIVATE,
226 NULL, mctx, &privkey);
227 if (result == ISC_R_SUCCESS) {
228 dst_key_free(&pubkey);
229 key = newkeystruct(privkey, ISC_FALSE);
231 key = newkeystruct(pubkey, ISC_FALSE);
232 ISC_LIST_APPEND(keylist, key, link);
237 * Check to see if we expect to find a key at this name. If we see a SIG
238 * and can't find the signing key that we expect to find, we drop the sig.
239 * I'm not sure if this is completely correct, but it seems to work.
242 expecttofindkey(dns_name_t *name) {
243 unsigned int options = DNS_DBFIND_NOWILD;
244 dns_fixedname_t fname;
246 char namestr[DNS_NAME_FORMATSIZE];
248 dns_fixedname_init(&fname);
249 result = dns_db_find(gdb, name, gversion, dns_rdatatype_key, options,
250 0, NULL, dns_fixedname_name(&fname), NULL, NULL);
256 case DNS_R_DELEGATION:
261 dns_name_format(name, namestr, sizeof namestr);
262 fatal("failure looking for '%s KEY' in database: %s",
263 namestr, isc_result_totext(result));
264 return (ISC_FALSE); /* removes a warning */
267 static inline isc_boolean_t
268 setverifies(dns_name_t *name, dns_rdataset_t *set, signer_key_t *key,
272 result = dns_dnssec_verify(name, set, key->key, ISC_FALSE, mctx, sig);
273 if (result == ISC_R_SUCCESS) {
277 INCSTAT(nverifyfailed);
283 * Signs a set. Goes through contortions to decide if each SIG should
284 * be dropped or retained, and then determines if any new SIGs need to
288 signset(dns_diff_t *diff, dns_dbnode_t *node, dns_name_t *name,
291 dns_rdataset_t sigset;
292 dns_rdata_t sigrdata = DNS_RDATA_INIT;
296 isc_boolean_t nosigs = ISC_FALSE;
297 isc_boolean_t *wassignedby, *nowsignedby;
299 dns_difftuple_t *tuple;
302 char namestr[DNS_NAME_FORMATSIZE];
303 char typestr[TYPE_FORMATSIZE];
304 char sigstr[SIG_FORMATSIZE];
306 dns_name_format(name, namestr, sizeof namestr);
307 type_format(set->type, typestr, sizeof typestr);
309 ttl = ISC_MIN(set->ttl, endtime - starttime);
311 dns_rdataset_init(&sigset);
312 result = dns_db_findrdataset(gdb, node, gversion, dns_rdatatype_sig,
313 set->type, 0, &sigset, NULL);
314 if (result == ISC_R_NOTFOUND) {
315 result = ISC_R_SUCCESS;
318 if (result != ISC_R_SUCCESS)
319 fatal("failed while looking for '%s SIG %s': %s",
320 namestr, typestr, isc_result_totext(result));
322 vbprintf(1, "%s/%s:\n", namestr, typestr);
324 arraysize = keycount;
326 arraysize += dns_rdataset_count(&sigset);
327 wassignedby = isc_mem_get(mctx, arraysize * sizeof(isc_boolean_t));
328 nowsignedby = isc_mem_get(mctx, arraysize * sizeof(isc_boolean_t));
329 if (wassignedby == NULL || nowsignedby == NULL)
330 fatal("out of memory");
332 for (i = 0; i < arraysize; i++)
333 wassignedby[i] = nowsignedby[i] = ISC_FALSE;
336 result = ISC_R_NOMORE;
338 result = dns_rdataset_first(&sigset);
340 while (result == ISC_R_SUCCESS) {
341 isc_boolean_t expired, future;
342 isc_boolean_t keep = ISC_FALSE, resign = ISC_FALSE;
344 dns_rdataset_current(&sigset, &sigrdata);
346 result = dns_rdata_tostruct(&sigrdata, &sig, NULL);
347 check_result(result, "dns_rdata_tostruct");
349 expired = ISC_TF(now + cycle > sig.timeexpire);
350 future = ISC_TF(now < sig.timesigned);
352 key = keythatsigned(&sig);
353 sig_format(&sig, sigstr, sizeof sigstr);
355 if (sig.timesigned > sig.timeexpire) {
356 /* sig is dropped and not replaced */
357 vbprintf(2, "\tsig by %s dropped - "
358 "invalid validity period\n",
360 } else if (key == NULL && !future &&
361 expecttofindkey(&sig.signer))
363 /* sig is dropped and not replaced */
364 vbprintf(2, "\tsig by %s dropped - "
365 "private key not found\n",
367 } else if (key == NULL || future) {
368 vbprintf(2, "\tsig by %s %s - key not found\n",
369 expired ? "retained" : "dropped", sigstr);
372 } else if (issigningkey(key)) {
373 if (!expired && setverifies(name, set, key, &sigrdata))
375 vbprintf(2, "\tsig by %s retained\n", sigstr);
377 wassignedby[key->position] = ISC_TRUE;
378 nowsignedby[key->position] = ISC_TRUE;
380 vbprintf(2, "\tsig by %s dropped - %s\n",
382 expired ? "expired" :
384 wassignedby[key->position] = ISC_TRUE;
387 } else if (iszonekey(key)) {
388 if (!expired && setverifies(name, set, key, &sigrdata))
390 vbprintf(2, "\tsig by %s retained\n", sigstr);
392 wassignedby[key->position] = ISC_TRUE;
393 nowsignedby[key->position] = ISC_TRUE;
395 vbprintf(2, "\tsig by %s dropped - %s\n",
397 expired ? "expired" :
399 wassignedby[key->position] = ISC_TRUE;
401 } else if (!expired) {
402 vbprintf(2, "\tsig by %s retained\n", sigstr);
405 vbprintf(2, "\tsig by %s expired\n", sigstr);
409 nowsignedby[key->position] = ISC_TRUE;
413 result = dns_difftuple_create(mctx, DNS_DIFFOP_DEL,
416 check_result(result, "dns_difftuple_create");
417 dns_diff_append(diff, &tuple);
423 dns_rdata_t trdata = DNS_RDATA_INIT;
424 unsigned char array[BUFSIZE];
425 char keystr[KEY_FORMATSIZE];
427 key_format(key->key, keystr, sizeof keystr);
428 vbprintf(1, "\tresigning with key %s\n", keystr);
429 isc_buffer_init(&b, array, sizeof(array));
430 signwithkey(name, set, &trdata, key->key, &b);
431 nowsignedby[key->position] = ISC_TRUE;
433 result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD,
436 check_result(result, "dns_difftuple_create");
437 dns_diff_append(diff, &tuple);
440 dns_rdata_reset(&sigrdata);
441 dns_rdata_freestruct(&sig);
442 result = dns_rdataset_next(&sigset);
444 if (result == ISC_R_NOMORE)
445 result = ISC_R_SUCCESS;
447 check_result(result, "dns_rdataset_first/next");
448 if (dns_rdataset_isassociated(&sigset))
449 dns_rdataset_disassociate(&sigset);
451 key = ISC_LIST_HEAD(keylist);
452 while (key != NULL) {
453 if (key->isdefault && !nowsignedby[key->position]) {
455 dns_rdata_t trdata = DNS_RDATA_INIT;
456 unsigned char array[BUFSIZE];
457 char keystr[KEY_FORMATSIZE];
459 key_format(key->key, keystr, sizeof keystr);
460 vbprintf(1, "\tsigning with key %s\n", keystr);
461 isc_buffer_init(&b, array, sizeof(array));
462 signwithkey(name, set, &trdata, key->key, &b);
464 result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD,
467 check_result(result, "dns_difftuple_create");
468 dns_diff_append(diff, &tuple);
470 key = ISC_LIST_NEXT(key, link);
473 isc_mem_put(mctx, wassignedby, arraysize * sizeof(isc_boolean_t));
474 isc_mem_put(mctx, nowsignedby, arraysize * sizeof(isc_boolean_t));
477 /* Determine if a KEY set contains a null key */
479 hasnullkey(dns_rdataset_t *rdataset) {
481 dns_rdata_t rdata = DNS_RDATA_INIT;
482 isc_boolean_t found = ISC_FALSE;
484 result = dns_rdataset_first(rdataset);
485 while (result == ISC_R_SUCCESS) {
486 dst_key_t *key = NULL;
488 dns_rdata_reset(&rdata);
489 dns_rdataset_current(rdataset, &rdata);
490 result = dns_dnssec_keyfromrdata(dns_rootname,
492 if (result != ISC_R_SUCCESS)
493 fatal("could not convert KEY into internal format: %s",
494 isc_result_totext(result));
495 if (dst_key_isnullkey(key))
498 if (found == ISC_TRUE)
500 result = dns_rdataset_next(rdataset);
502 if (result != ISC_R_NOMORE)
503 fatal("failure looking for null keys");
508 opendb(const char *prefix, dns_name_t *name, dns_rdataclass_t rdclass,
515 isc_buffer_init(&b, filename, sizeof(filename));
516 if (directory != NULL) {
517 isc_buffer_putstr(&b, directory);
518 if (directory[strlen(directory) - 1] != '/')
519 isc_buffer_putstr(&b, "/");
521 isc_buffer_putstr(&b, prefix);
522 result = dns_name_tofilenametext(name, ISC_FALSE, &b);
523 check_result(result, "dns_name_tofilenametext()");
524 if (isc_buffer_availablelength(&b) == 0) {
525 char namestr[DNS_NAME_FORMATSIZE];
526 dns_name_format(name, namestr, sizeof namestr);
527 fatal("name '%s' is too long", namestr);
529 isc_buffer_putuint8(&b, 0);
531 result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone,
532 rdclass, 0, NULL, dbp);
533 check_result(result, "dns_db_create()");
535 result = dns_db_load(*dbp, filename);
536 if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE)
541 * Looks for signatures of the zone keys by the parent, and imports them
545 importparentsig(dns_diff_t *diff, dns_name_t *name, dns_rdataset_t *set) {
546 dns_db_t *newdb = NULL;
547 dns_dbnode_t *newnode = NULL;
548 dns_rdataset_t newset, sigset;
549 dns_rdata_t rdata = DNS_RDATA_INIT, newrdata = DNS_RDATA_INIT;
552 dns_rdataset_init(&newset);
553 dns_rdataset_init(&sigset);
555 opendb("signedkey-", name, dns_db_class(gdb), &newdb);
559 result = dns_db_findnode(newdb, name, ISC_FALSE, &newnode);
560 if (result != ISC_R_SUCCESS)
562 result = dns_db_findrdataset(newdb, newnode, NULL, dns_rdatatype_key,
563 0, 0, &newset, &sigset);
564 if (result != ISC_R_SUCCESS)
567 if (!dns_rdataset_isassociated(&newset) ||
568 !dns_rdataset_isassociated(&sigset))
571 if (dns_rdataset_count(set) != dns_rdataset_count(&newset)) {
572 result = DNS_R_BADDB;
576 result = dns_rdataset_first(set);
577 check_result(result, "dns_rdataset_first()");
578 for (; result == ISC_R_SUCCESS; result = dns_rdataset_next(set)) {
579 dns_rdataset_current(set, &rdata);
580 result = dns_rdataset_first(&newset);
581 check_result(result, "dns_rdataset_first()");
583 result == ISC_R_SUCCESS;
584 result = dns_rdataset_next(&newset))
586 dns_rdataset_current(&newset, &newrdata);
587 if (dns_rdata_compare(&rdata, &newrdata) == 0)
589 dns_rdata_reset(&newrdata);
591 dns_rdata_reset(&newrdata);
592 dns_rdata_reset(&rdata);
593 if (result != ISC_R_SUCCESS)
596 if (result != ISC_R_NOMORE)
599 vbprintf(2, "found the parent's signature of our zone key\n");
601 result = dns_rdataset_first(&sigset);
602 while (result == ISC_R_SUCCESS) {
603 dns_difftuple_t *tuple = NULL;
605 dns_rdataset_current(&sigset, &rdata);
606 result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD, name,
607 sigset.ttl, &rdata, &tuple);
608 check_result(result, "dns_difftuple_create");
609 dns_diff_append(diff, &tuple);
610 result = dns_rdataset_next(&sigset);
611 dns_rdata_reset(&rdata);
613 if (result == ISC_R_NOMORE)
614 result = ISC_R_SUCCESS;
617 if (dns_rdataset_isassociated(&newset))
618 dns_rdataset_disassociate(&newset);
619 if (dns_rdataset_isassociated(&sigset))
620 dns_rdataset_disassociate(&sigset);
622 dns_db_detachnode(newdb, &newnode);
624 dns_db_detach(&newdb);
625 if (result != ISC_R_SUCCESS)
626 fatal("zone signedkey file is invalid or does not match zone");
630 * Looks for our signatures of child keys. If present, inform the caller.
633 haschildkey(dns_name_t *name) {
634 dns_db_t *newdb = NULL;
635 dns_dbnode_t *newnode = NULL;
636 dns_rdataset_t set, sigset;
637 dns_rdata_t sigrdata = DNS_RDATA_INIT;
639 isc_boolean_t found = ISC_FALSE;
643 dns_rdataset_init(&set);
644 dns_rdataset_init(&sigset);
646 opendb("signedkey-", name, dns_db_class(gdb), &newdb);
650 result = dns_db_findnode(newdb, name, ISC_FALSE, &newnode);
651 if (result != ISC_R_SUCCESS)
653 result = dns_db_findrdataset(newdb, newnode, NULL, dns_rdatatype_key,
654 0, 0, &set, &sigset);
655 if (result != ISC_R_SUCCESS)
658 if (!dns_rdataset_isassociated(&set) ||
659 !dns_rdataset_isassociated(&sigset))
662 result = dns_rdataset_first(&sigset);
663 check_result(result, "dns_rdataset_first()");
664 dns_rdata_init(&sigrdata);
665 for (; result == ISC_R_SUCCESS; result = dns_rdataset_next(&sigset)) {
666 dns_rdataset_current(&sigset, &sigrdata);
667 result = dns_rdata_tostruct(&sigrdata, &sig, NULL);
668 if (result != ISC_R_SUCCESS)
670 key = keythatsigned(&sig);
671 dns_rdata_freestruct(&sig);
673 char namestr[DNS_NAME_FORMATSIZE];
674 dns_name_format(name, namestr, sizeof namestr);
676 "creating KEY from signedkey file for %s: "
678 namestr, isc_result_totext(result));
681 result = dns_dnssec_verify(name, &set, key->key,
682 ISC_FALSE, mctx, &sigrdata);
683 if (result == ISC_R_SUCCESS) {
687 char namestr[DNS_NAME_FORMATSIZE];
688 dns_name_format(name, namestr, sizeof namestr);
690 "verifying SIG in signedkey file for %s: %s\n",
691 namestr, isc_result_totext(result));
693 dns_rdata_reset(&sigrdata);
697 if (dns_rdataset_isassociated(&set))
698 dns_rdataset_disassociate(&set);
699 if (dns_rdataset_isassociated(&sigset))
700 dns_rdataset_disassociate(&sigset);
702 dns_db_detachnode(newdb, &newnode);
704 dns_db_detach(&newdb);
710 * There probably should be a dns_nxt_setbit, but it can get complicated if
711 * the length of the bit set needs to be increased. In this case, since the
712 * NXT bit is set and both SIG and KEY are less than NXT, the easy way works.
715 nxt_setbit(dns_rdataset_t *rdataset, dns_rdatatype_t type) {
717 dns_rdata_t rdata = DNS_RDATA_INIT;
720 result = dns_rdataset_first(rdataset);
721 check_result(result, "dns_rdataset_first()");
722 dns_rdataset_current(rdataset, &rdata);
723 result = dns_rdata_tostruct(&rdata, &nxt, NULL);
724 check_result(result, "dns_rdata_tostruct");
725 set_bit(nxt.typebits, type, 1);
726 dns_rdata_freestruct(&nxt);
730 createnullkey(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
733 unsigned char keydata[4];
734 dns_rdata_t keyrdata = DNS_RDATA_INIT;
737 dns_difftuple_t *tuple = NULL;
740 char namestr[DNS_NAME_FORMATSIZE];
742 dns_name_format(name, namestr, sizeof namestr);
743 vbprintf(2, "adding null key at %s\n", namestr);
745 key.common.rdclass = dns_db_class(db);
746 key.common.rdtype = dns_rdatatype_key;
747 ISC_LINK_INIT(&key.common, link);
749 key.flags = DNS_KEYTYPE_NOKEY | DNS_KEYOWNER_ZONE;
750 key.protocol = DNS_KEYPROTO_DNSSEC;
751 key.algorithm = DNS_KEYALG_DSA;
754 isc_buffer_init(&b, keydata, sizeof keydata);
755 result = dns_rdata_fromstruct(&keyrdata, dns_db_class(db),
756 dns_rdatatype_key, &key, &b);
757 if (result != ISC_R_SUCCESS)
758 fatal("failed to build null key");
760 dns_diff_init(mctx, &diff);
762 result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD, name, ttl,
764 check_result(result, "dns_difftuple_create");
766 dns_diff_append(&diff, &tuple);
768 result = dns_diff_apply(&diff, db, version);
769 check_result(result, "dns_diff_apply");
771 dns_diff_clear(&diff);
775 * Signs all records at a name. This mostly just signs each set individually,
776 * but also adds the SIG bit to any NXTs generated earlier, deals with
777 * parent/child KEY signatures, and handles other exceptional cases.
780 signname(dns_dbnode_t *node, dns_name_t *name) {
782 dns_rdataset_t rdataset;
783 dns_rdatasetiter_t *rdsiter;
784 isc_boolean_t isdelegation = ISC_FALSE;
785 isc_boolean_t childkey = ISC_FALSE;
786 static int warnwild = 0;
787 isc_boolean_t atorigin;
788 isc_boolean_t neednullkey = ISC_FALSE;
791 if (dns_name_iswildcard(name)) {
792 char namestr[DNS_NAME_FORMATSIZE];
793 dns_name_format(name, namestr, sizeof namestr);
794 if (warnwild++ == 0) {
795 fprintf(stderr, "%s: warning: BIND 9 doesn't properly "
796 "handle wildcards in secure zones:\n",
798 fprintf(stderr, "\t- wildcard nonexistence proof is "
799 "not generated by the server\n");
800 fprintf(stderr, "\t- wildcard nonexistence proof is "
801 "not required by the resolver\n");
803 fprintf(stderr, "%s: warning: wildcard name seen: %s\n",
807 atorigin = dns_name_equal(name, gorigin);
810 * If this is not the origin, determine if it's a delegation point.
813 dns_rdataset_t nsset;
815 dns_rdataset_init(&nsset);
816 result = dns_db_findrdataset(gdb, node, gversion,
817 dns_rdatatype_ns, 0, 0, &nsset,
819 /* Is this a delegation point? */
820 if (result == ISC_R_SUCCESS) {
821 isdelegation = ISC_TRUE;
822 dns_rdataset_disassociate(&nsset);
827 * If this is a delegation point, determine if we need to generate
831 dns_rdataset_t keyset;
832 dns_ttl_t nullkeyttl;
834 childkey = haschildkey(name);
835 neednullkey = ISC_TRUE;
836 nullkeyttl = zonettl;
838 dns_rdataset_init(&keyset);
839 result = dns_db_findrdataset(gdb, node, gversion,
840 dns_rdatatype_key, 0, 0, &keyset,
842 if (result == ISC_R_SUCCESS && childkey) {
843 char namestr[DNS_NAME_FORMATSIZE];
844 dns_name_format(name, namestr, sizeof namestr);
845 if (hasnullkey(&keyset)) {
846 fatal("%s has both a signedkey file and "
847 "null keys in the zone. Aborting.",
850 vbprintf(2, "child key for %s found\n", namestr);
851 neednullkey = ISC_FALSE;
852 dns_rdataset_disassociate(&keyset);
854 else if (result == ISC_R_SUCCESS) {
855 if (hasnullkey(&keyset))
856 neednullkey = ISC_FALSE;
857 nullkeyttl = keyset.ttl;
858 dns_rdataset_disassociate(&keyset);
859 } else if (childkey) {
860 char namestr[DNS_NAME_FORMATSIZE];
861 dns_name_format(name, namestr, sizeof namestr);
862 vbprintf(2, "child key for %s found\n", namestr);
863 neednullkey = ISC_FALSE;
867 createnullkey(gdb, gversion, name, nullkeyttl);
871 * Now iterate through the rdatasets.
873 dns_diff_init(mctx, &diff);
874 dns_rdataset_init(&rdataset);
876 result = dns_db_allrdatasets(gdb, node, gversion, 0, &rdsiter);
877 check_result(result, "dns_db_allrdatasets()");
878 result = dns_rdatasetiter_first(rdsiter);
879 while (result == ISC_R_SUCCESS) {
880 dns_rdatasetiter_current(rdsiter, &rdataset);
882 /* If this is a SIG set, skip it. */
883 if (rdataset.type == dns_rdatatype_sig)
887 * If this is a KEY set at the apex, look for a signedkey file.
889 if (atorigin && rdataset.type == dns_rdatatype_key) {
890 importparentsig(&diff, name, &rdataset);
895 * If this name is a delegation point, skip all records
896 * except an NXT set a KEY set containing a null key.
899 if (!(rdataset.type == dns_rdatatype_nxt ||
900 (rdataset.type == dns_rdatatype_key &&
901 hasnullkey(&rdataset))))
905 if (rdataset.type == dns_rdatatype_nxt) {
907 nxt_setbit(&rdataset, dns_rdatatype_sig);
909 nxt_setbit(&rdataset, dns_rdatatype_key);
912 signset(&diff, node, name, &rdataset);
915 dns_rdataset_disassociate(&rdataset);
916 result = dns_rdatasetiter_next(rdsiter);
918 if (result != ISC_R_NOMORE) {
919 char namestr[DNS_NAME_FORMATSIZE];
920 dns_name_format(name, namestr, sizeof namestr);
921 fatal("rdataset iteration for name '%s' failed: %s",
922 namestr, isc_result_totext(result));
924 dns_rdatasetiter_destroy(&rdsiter);
926 result = dns_diff_apply(&diff, gdb, gversion);
927 if (result != ISC_R_SUCCESS) {
928 char namestr[DNS_NAME_FORMATSIZE];
929 dns_name_format(name, namestr, sizeof namestr);
930 fatal("failed to add SIGs at node '%s': %s",
931 namestr, isc_result_totext(result));
933 dns_diff_clear(&diff);
936 static inline isc_boolean_t
937 active_node(dns_dbnode_t *node) {
938 dns_rdatasetiter_t *rdsiter;
939 isc_boolean_t active = ISC_FALSE;
941 dns_rdataset_t rdataset;
943 dns_rdataset_init(&rdataset);
945 result = dns_db_allrdatasets(gdb, node, gversion, 0, &rdsiter);
946 check_result(result, "dns_db_allrdatasets()");
947 result = dns_rdatasetiter_first(rdsiter);
948 while (result == ISC_R_SUCCESS) {
949 dns_rdatasetiter_current(rdsiter, &rdataset);
950 if (rdataset.type != dns_rdatatype_nxt)
952 dns_rdataset_disassociate(&rdataset);
954 result = dns_rdatasetiter_next(rdsiter);
956 result = ISC_R_NOMORE;
958 if (result != ISC_R_NOMORE)
959 fatal("rdataset iteration failed: %s",
960 isc_result_totext(result));
961 dns_rdatasetiter_destroy(&rdsiter);
965 * Make sure there is no NXT record for this node.
967 result = dns_db_deleterdataset(gdb, node, gversion,
968 dns_rdatatype_nxt, 0);
969 if (result == DNS_R_UNCHANGED)
970 result = ISC_R_SUCCESS;
971 check_result(result, "dns_db_deleterdataset");
977 static inline isc_result_t
978 next_active(dns_name_t *name, dns_dbnode_t **nodep) {
980 isc_boolean_t active;
984 result = dns_dbiterator_current(gdbiter, nodep, name);
985 if (result == ISC_R_SUCCESS) {
986 active = active_node(*nodep);
988 dns_db_detachnode(gdb, nodep);
989 result = dns_dbiterator_next(gdbiter);
992 } while (result == ISC_R_SUCCESS && !active);
997 static inline isc_result_t
998 next_nonglue(dns_name_t *name, dns_dbnode_t **nodep, dns_name_t *origin,
1001 isc_result_t result;
1004 result = next_active(name, nodep);
1005 if (result == ISC_R_SUCCESS) {
1006 if (dns_name_issubdomain(name, origin) &&
1008 !dns_name_issubdomain(name, lastcut)))
1009 return (ISC_R_SUCCESS);
1010 result = dns_master_dumpnodetostream(mctx, gdb,
1014 check_result(result, "dns_master_dumpnodetostream");
1015 dns_db_detachnode(gdb, nodep);
1016 result = dns_dbiterator_next(gdbiter);
1018 } while (result == ISC_R_SUCCESS);
1023 * Extracts the TTL from the SOA.
1027 dns_rdataset_t soaset;
1028 dns_fixedname_t fname;
1030 isc_result_t result;
1033 dns_fixedname_init(&fname);
1034 name = dns_fixedname_name(&fname);
1035 dns_rdataset_init(&soaset);
1036 result = dns_db_find(gdb, gorigin, gversion, dns_rdatatype_soa,
1037 0, 0, NULL, name, &soaset, NULL);
1038 if (result != ISC_R_SUCCESS) {
1039 char namestr[DNS_NAME_FORMATSIZE];
1040 dns_name_format(name, namestr, sizeof namestr);
1041 fatal("failed to find '%s SOA' in the zone: %s",
1042 namestr, isc_result_totext(result));
1045 dns_rdataset_disassociate(&soaset);
1050 * Delete any SIG records at a node.
1053 cleannode(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node) {
1054 dns_rdatasetiter_t *rdsiter = NULL;
1056 isc_result_t result, dresult;
1058 dns_rdataset_init(&set);
1059 result = dns_db_allrdatasets(db, node, version, 0, &rdsiter);
1060 check_result(result, "dns_db_allrdatasets");
1061 result = dns_rdatasetiter_first(rdsiter);
1062 while (result == ISC_R_SUCCESS) {
1063 isc_boolean_t destroy = ISC_FALSE;
1064 dns_rdatatype_t covers = 0;
1065 dns_rdatasetiter_current(rdsiter, &set);
1066 if (set.type == dns_rdatatype_sig) {
1067 covers = set.covers;
1070 dns_rdataset_disassociate(&set);
1071 result = dns_rdatasetiter_next(rdsiter);
1073 dresult = dns_db_deleterdataset(db, node, version,
1076 check_result(dresult, "dns_db_deleterdataset");
1079 if (result != ISC_R_NOMORE)
1080 fatal("rdataset iteration failed: %s",
1081 isc_result_totext(result));
1082 dns_rdatasetiter_destroy(&rdsiter);
1086 * Set up the iterator and global state before starting the tasks.
1090 isc_result_t result;
1093 result = dns_db_createiterator(gdb, ISC_FALSE, &gdbiter);
1094 check_result(result, "dns_db_createiterator()");
1096 result = dns_dbiterator_first(gdbiter);
1097 check_result(result, "dns_dbiterator_first()");
1106 * Clean up the iterator and global state after the tasks complete.
1110 if (lastzonecut != NULL) {
1111 dns_name_free(lastzonecut, mctx);
1112 isc_mem_put(mctx, lastzonecut, sizeof(dns_name_t));
1114 dns_dbiterator_destroy(&gdbiter);
1118 * Find the next name to nxtify & sign
1121 getnextname(dns_name_t *name, dns_name_t *nextname, dns_dbnode_t **nodep) {
1122 isc_result_t result;
1123 dns_dbnode_t *nextnode, *curnode;
1127 if (shuttingdown || finished) {
1128 result = ISC_R_NOMORE;
1130 dns_db_detachnode(gdb, &gnode);
1134 if (gnode == NULL) {
1135 dns_fixedname_t ftname;
1138 dns_fixedname_init(&ftname);
1139 tname = dns_fixedname_name(&ftname);
1141 result = next_nonglue(tname, &gnode, gorigin, lastzonecut);
1142 if (result != ISC_R_SUCCESS)
1143 fatal("failed to iterate through the zone");
1148 dns_dbiterator_current(gdbiter, &curnode, name);
1149 if (!dns_name_equal(name, gorigin)) {
1150 dns_rdatasetiter_t *rdsiter = NULL;
1153 dns_rdataset_init(&set);
1154 result = dns_db_allrdatasets(gdb, curnode, gversion, 0,
1156 check_result(result, "dns_db_allrdatasets");
1157 result = dns_rdatasetiter_first(rdsiter);
1158 while (result == ISC_R_SUCCESS) {
1159 dns_rdatasetiter_current(rdsiter, &set);
1160 if (set.type == dns_rdatatype_ns) {
1161 dns_rdataset_disassociate(&set);
1164 dns_rdataset_disassociate(&set);
1165 result = dns_rdatasetiter_next(rdsiter);
1167 if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE)
1168 fatal("rdataset iteration failed: %s",
1169 isc_result_totext(result));
1170 if (result == ISC_R_SUCCESS) {
1171 if (lastzonecut != NULL)
1172 dns_name_free(lastzonecut, mctx);
1174 lastzonecut = isc_mem_get(mctx,
1175 sizeof(dns_name_t));
1176 if (lastzonecut == NULL)
1177 fatal("out of memory");
1179 dns_name_init(lastzonecut, NULL);
1180 result = dns_name_dup(name, mctx, lastzonecut);
1181 check_result(result, "dns_name_dup()");
1183 dns_rdatasetiter_destroy(&rdsiter);
1185 result = dns_dbiterator_next(gdbiter);
1186 if (result == ISC_R_SUCCESS)
1187 result = next_nonglue(nextname, &nextnode, gorigin,
1189 if (result == ISC_R_NOMORE) {
1190 dns_name_clone(gorigin, nextname);
1191 finished = ISC_TRUE;
1192 result = ISC_R_SUCCESS;
1193 } else if (result != ISC_R_SUCCESS)
1194 fatal("iterating through the database failed: %s",
1195 isc_result_totext(result));
1196 dns_db_detachnode(gdb, &curnode);
1207 * Assigns a node to a worker thread. This is protected by the master task's
1211 assignwork(isc_task_t *task, isc_task_t *worker) {
1212 dns_fixedname_t *fname, *fnextname;
1215 isc_result_t result;
1217 fname = isc_mem_get(mctx, sizeof(dns_fixedname_t));
1218 fnextname = isc_mem_get(mctx, sizeof(dns_fixedname_t));
1219 if (fname == NULL || fnextname == NULL)
1220 fatal("out of memory");
1221 dns_fixedname_init(fname);
1222 dns_fixedname_init(fnextname);
1224 result = getnextname(dns_fixedname_name(fname),
1225 dns_fixedname_name(fnextname), &node);
1226 if (result == ISC_R_NOMORE) {
1227 isc_mem_put(mctx, fname, sizeof(dns_fixedname_t));
1228 isc_mem_put(mctx, fnextname, sizeof(dns_fixedname_t));
1229 if (assigned == completed) {
1230 isc_task_detach(&task);
1235 sevent = (sevent_t *)
1236 isc_event_allocate(mctx, task, SIGNER_EVENT_WORK,
1237 sign, NULL, sizeof(sevent_t));
1239 fatal("failed to allocate event\n");
1241 sevent->node = node;
1242 sevent->fname = fname;
1243 sevent->fnextname = fnextname;
1244 isc_task_send(worker, ISC_EVENT_PTR(&sevent));
1249 * Start a worker task
1252 startworker(isc_task_t *task, isc_event_t *event) {
1255 worker = (isc_task_t *)event->ev_arg;
1256 assignwork(task, worker);
1257 isc_event_free(&event);
1261 * Write a node to the output file, and restart the worker task.
1264 writenode(isc_task_t *task, isc_event_t *event) {
1265 isc_result_t result;
1267 sevent_t *sevent = (sevent_t *)event;
1270 worker = (isc_task_t *)event->ev_sender;
1271 result = dns_master_dumpnodetostream(mctx, gdb, gversion,
1273 dns_fixedname_name(sevent->fname),
1275 check_result(result, "dns_master_dumpnodetostream");
1276 cleannode(gdb, gversion, sevent->node);
1277 dns_db_detachnode(gdb, &sevent->node);
1278 isc_mem_put(mctx, sevent->fname, sizeof(dns_fixedname_t));
1279 assignwork(task, worker);
1280 isc_event_free(&event);
1284 * Sign and nxtify a database node.
1287 sign(isc_task_t *task, isc_event_t *event) {
1288 dns_fixedname_t *fname, *fnextname;
1290 sevent_t *sevent, *wevent;
1291 isc_result_t result;
1293 sevent = (sevent_t *)event;
1294 node = sevent->node;
1295 fname = sevent->fname;
1296 fnextname = sevent->fnextname;
1297 isc_event_free(&event);
1299 result = dns_nxt_build(gdb, gversion, node,
1300 dns_fixedname_name(fnextname), zonettl);
1301 check_result(result, "dns_nxt_build()");
1302 isc_mem_put(mctx, fnextname, sizeof(dns_fixedname_t));
1303 signname(node, dns_fixedname_name(fname));
1304 wevent = (sevent_t *)
1305 isc_event_allocate(mctx, task, SIGNER_EVENT_WRITE,
1306 writenode, NULL, sizeof(sevent_t));
1308 fatal("failed to allocate event\n");
1309 wevent->node = node;
1310 wevent->fname = fname;
1311 isc_task_send(master, ISC_EVENT_PTR(&wevent));
1315 * Load the zone file from disk
1318 loadzone(char *file, char *origin, dns_rdataclass_t rdclass, dns_db_t **db) {
1321 dns_fixedname_t fname;
1323 isc_result_t result;
1325 len = strlen(origin);
1326 isc_buffer_init(&b, origin, len);
1327 isc_buffer_add(&b, len);
1329 dns_fixedname_init(&fname);
1330 name = dns_fixedname_name(&fname);
1331 result = dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL);
1332 if (result != ISC_R_SUCCESS)
1333 fatal("failed converting name '%s' to dns format: %s",
1334 origin, isc_result_totext(result));
1336 result = dns_db_create(mctx, "rbt", name, dns_dbtype_zone,
1337 rdclass, 0, NULL, db);
1338 check_result(result, "dns_db_create()");
1340 result = dns_db_load(*db, file);
1341 if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE)
1342 fatal("failed loading zone from '%s': %s",
1343 file, isc_result_totext(result));
1347 * Finds all public zone keys in the zone, and attempts to load the
1348 * private keys from disk.
1351 loadzonekeys(dns_db_t *db) {
1353 dns_dbversion_t *currentversion;
1354 isc_result_t result;
1355 dst_key_t *keys[20];
1356 unsigned int nkeys, i;
1358 currentversion = NULL;
1359 dns_db_currentversion(db, ¤tversion);
1362 result = dns_db_findnode(db, gorigin, ISC_FALSE, &node);
1363 if (result != ISC_R_SUCCESS)
1364 fatal("failed to find the zone's origin: %s",
1365 isc_result_totext(result));
1367 result = dns_dnssec_findzonekeys(db, currentversion, node, gorigin,
1368 mctx, 20, keys, &nkeys);
1369 if (result == ISC_R_NOTFOUND)
1370 result = ISC_R_SUCCESS;
1371 if (result != ISC_R_SUCCESS)
1372 fatal("failed to find the zone keys: %s",
1373 isc_result_totext(result));
1375 for (i = 0; i < nkeys; i++) {
1378 key = newkeystruct(keys[i], ISC_FALSE);
1379 ISC_LIST_APPEND(keylist, key, link);
1381 dns_db_detachnode(db, &node);
1382 dns_db_closeversion(db, ¤tversion, ISC_FALSE);
1386 * Finds all public zone keys in the zone.
1389 loadzonepubkeys(dns_db_t *db) {
1390 dns_dbversion_t *currentversion = NULL;
1391 dns_dbnode_t *node = NULL;
1392 dns_rdataset_t rdataset;
1393 dns_rdata_t rdata = DNS_RDATA_INIT;
1396 isc_result_t result;
1398 dns_db_currentversion(db, ¤tversion);
1400 result = dns_db_findnode(db, gorigin, ISC_FALSE, &node);
1401 if (result != ISC_R_SUCCESS)
1402 fatal("failed to find the zone's origin: %s",
1403 isc_result_totext(result));
1405 dns_rdataset_init(&rdataset);
1406 result = dns_db_findrdataset(db, node, currentversion,
1407 dns_rdatatype_key, 0, 0, &rdataset, NULL);
1408 if (result != ISC_R_SUCCESS)
1409 fatal("failed to find keys at the zone apex: %s",
1410 isc_result_totext(result));
1411 result = dns_rdataset_first(&rdataset);
1412 check_result(result, "dns_rdataset_first");
1413 while (result == ISC_R_SUCCESS) {
1415 dns_rdata_reset(&rdata);
1416 dns_rdataset_current(&rdataset, &rdata);
1417 result = dns_dnssec_keyfromrdata(gorigin, &rdata, mctx,
1419 if (result != ISC_R_SUCCESS)
1421 if (!dst_key_iszonekey(pubkey)) {
1422 dst_key_free(&pubkey);
1426 key = newkeystruct(pubkey, ISC_FALSE);
1427 ISC_LIST_APPEND(keylist, key, link);
1429 result = dns_rdataset_next(&rdataset);
1431 dns_rdataset_disassociate(&rdataset);
1432 dns_db_detachnode(db, &node);
1433 dns_db_closeversion(db, ¤tversion, ISC_FALSE);
1437 print_time(FILE *fp) {
1440 currenttime = time(NULL);
1441 fprintf(fp, "; File written on %s", ctime(¤ttime));
1445 print_version(FILE *fp) {
1446 fprintf(fp, "; dnssec_signzone version " VERSION "\n");
1451 fprintf(stderr, "Usage:\n");
1452 fprintf(stderr, "\t%s [options] zonefile [keys]\n", program);
1454 fprintf(stderr, "\n");
1456 fprintf(stderr, "Options: (default value in parenthesis) \n");
1457 fprintf(stderr, "\t-c class (IN)\n");
1458 fprintf(stderr, "\t-d directory\n");
1459 fprintf(stderr, "\t\tdirectory to find signedkey files (.)\n");
1460 fprintf(stderr, "\t-s YYYYMMDDHHMMSS|+offset:\n");
1461 fprintf(stderr, "\t\tSIG start time - absolute|offset (now)\n");
1462 fprintf(stderr, "\t-e YYYYMMDDHHMMSS|+offset|\"now\"+offset]:\n");
1463 fprintf(stderr, "\t\tSIG end time - absolute|from start|from now "
1464 "(now + 30 days)\n");
1465 fprintf(stderr, "\t-i interval:\n");
1466 fprintf(stderr, "\t\tcycle interval - resign "
1467 "if < interval from end ( (end-start)/4 )\n");
1468 fprintf(stderr, "\t-v debuglevel (0)\n");
1469 fprintf(stderr, "\t-o origin:\n");
1470 fprintf(stderr, "\t\tzone origin (name of zonefile)\n");
1471 fprintf(stderr, "\t-f outfile:\n");
1472 fprintf(stderr, "\t\tfile the signed zone is written in "
1473 "(zonefile + .signed)\n");
1474 fprintf(stderr, "\t-r randomdev:\n");
1475 fprintf(stderr, "\t\ta file containing random data\n");
1476 fprintf(stderr, "\t-a:\t");
1477 fprintf(stderr, "verify generated signatures\n");
1478 fprintf(stderr, "\t-p:\t");
1479 fprintf(stderr, "use pseudorandom data (faster but less secure)\n");
1480 fprintf(stderr, "\t-t:\t");
1481 fprintf(stderr, "print statistics\n");
1482 fprintf(stderr, "\t-n ncpus (number of cpus present)\n");
1484 fprintf(stderr, "\n");
1486 fprintf(stderr, "Signing Keys: ");
1487 fprintf(stderr, "(default: all zone keys that have private keys)\n");
1488 fprintf(stderr, "\tkeyfile (Kname+alg+tag)\n");
1491 "WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING\n"
1493 "WARNING This version of dnssec-signzone produces zones that are WARNING\n"
1494 "WARNING incompatible with the forthcoming DS based DNSSEC WARNING\n"
1495 "WARNING standard. WARNING\n"
1497 "WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING\n");
1503 removetempfile(void) {
1505 isc_file_remove(tempfile);
1509 main(int argc, char *argv[]) {
1511 char *startstr = NULL, *endstr = NULL, *classname = NULL;
1512 char *origin = NULL, *file = NULL, *output = NULL;
1513 char *randomfile = NULL;
1515 isc_time_t timer_start, timer_finish;
1517 isc_result_t result;
1518 isc_log_t *log = NULL;
1519 isc_boolean_t pseudorandom = ISC_FALSE;
1520 unsigned int eflags;
1521 isc_boolean_t free_output = ISC_FALSE;
1523 dns_rdataclass_t rdclass;
1525 isc_task_t **tasks = NULL;
1526 masterstyle = &dns_master_style_explicitttl;
1528 check_result(isc_app_start(), "isc_app_start");
1530 result = isc_mem_create(0, 0, &mctx);
1531 if (result != ISC_R_SUCCESS)
1532 fatal("out of memory");
1534 dns_result_register();
1536 while ((ch = isc_commandline_parse(argc, argv,
1537 "c:s:e:i:v:o:f:ahpr:td:n:"))
1541 classname = isc_commandline_argument;
1545 startstr = isc_commandline_argument;
1549 endstr = isc_commandline_argument;
1554 cycle = strtol(isc_commandline_argument, &endp, 0);
1555 if (*endp != '\0' || cycle < 0)
1556 fatal("cycle period must be numeric and "
1561 pseudorandom = ISC_TRUE;
1565 randomfile = isc_commandline_argument;
1570 verbose = strtol(isc_commandline_argument, &endp, 0);
1572 fatal("verbose level must be numeric");
1576 origin = isc_commandline_argument;
1580 output = isc_commandline_argument;
1584 tryverify = ISC_TRUE;
1588 printstats = ISC_TRUE;
1592 directory = isc_commandline_argument;
1597 ntasks = strtol(isc_commandline_argument, &endp, 0);
1598 if (*endp != '\0' || ntasks > ISC_INT32_MAX)
1599 fatal("number of cpus must be numeric");
1611 "WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING\n"
1613 "WARNING This version of dnssec-signzone produces zones that are WARNING\n"
1614 "WARNING incompatible with the forth coming DS based DNSSEC WARNING\n"
1615 "WARNING standard. WARNING\n"
1617 "WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING\n");
1620 setup_entropy(mctx, randomfile, &ectx);
1621 eflags = ISC_ENTROPY_BLOCKING;
1623 eflags |= ISC_ENTROPY_GOODONLY;
1624 result = dst_lib_init(mctx, ectx, eflags);
1625 if (result != ISC_R_SUCCESS)
1626 fatal("could not initialize dst");
1628 isc_stdtime_get(&now);
1630 if (startstr != NULL)
1631 starttime = strtotime(startstr, now, now);
1636 endtime = strtotime(endstr, now, starttime);
1638 endtime = starttime + (30 * 24 * 60 * 60);
1641 cycle = (endtime - starttime) / 4;
1644 ntasks = isc_os_ncpus();
1645 vbprintf(4, "using %d cpus\n", ntasks);
1648 if (classname != NULL) {
1650 r.length = strlen(classname);
1651 result = dns_rdataclass_fromtext(&rdclass, &r);
1652 if (result != ISC_R_SUCCESS)
1653 fatal("unknown class %s",classname);
1655 rdclass = dns_rdataclass_in;
1657 setup_logging(verbose, mctx, &log);
1659 argc -= isc_commandline_index;
1660 argv += isc_commandline_index;
1670 if (output == NULL) {
1671 free_output = ISC_TRUE;
1672 output = isc_mem_allocate(mctx,
1673 strlen(file) + strlen(".signed") + 1);
1675 fatal("out of memory");
1676 sprintf(output, "%s.signed", file);
1683 isc_time_now(&timer_start);
1684 loadzone(file, origin, rdclass, &gdb);
1685 gorigin = dns_db_origin(gdb);
1687 ISC_LIST_INIT(keylist);
1694 key = ISC_LIST_HEAD(keylist);
1695 while (key != NULL) {
1696 key->isdefault = ISC_TRUE;
1697 key = ISC_LIST_NEXT(key, link);
1700 for (i = 0; i < argc; i++) {
1701 dst_key_t *newkey = NULL;
1703 result = dst_key_fromnamedfile(argv[i],
1707 if (result != ISC_R_SUCCESS)
1708 fatal("cannot load key %s: %s", argv[i],
1709 isc_result_totext(result));
1711 key = ISC_LIST_HEAD(keylist);
1712 while (key != NULL) {
1713 dst_key_t *dkey = key->key;
1714 if (dst_key_id(dkey) == dst_key_id(newkey) &&
1715 dst_key_alg(dkey) == dst_key_alg(newkey) &&
1716 dns_name_equal(dst_key_name(dkey),
1717 dst_key_name(newkey)))
1719 key->isdefault = ISC_TRUE;
1720 if (!dst_key_isprivate(dkey))
1721 fatal("cannot sign zone with "
1722 "non-private key %s",
1726 key = ISC_LIST_NEXT(key, link);
1729 key = newkeystruct(newkey, ISC_TRUE);
1730 ISC_LIST_APPEND(keylist, key, link);
1732 dst_key_free(&newkey);
1735 loadzonepubkeys(gdb);
1738 if (ISC_LIST_EMPTY(keylist)) {
1739 fprintf(stderr, "%s: warning: No keys specified or found\n",
1745 result = dns_db_newversion(gdb, &gversion);
1746 check_result(result, "dns_db_newversion()");
1748 tempfilelen = strlen(output) + 20;
1749 tempfile = isc_mem_get(mctx, tempfilelen);
1750 if (tempfile == NULL)
1751 fatal("out of memory");
1753 result = isc_file_mktemplate(output, tempfile, tempfilelen);
1754 check_result(result, "isc_file_mktemplate");
1757 result = isc_file_openunique(tempfile, &fp);
1758 if (result != ISC_R_SUCCESS)
1759 fatal("failed to open temporary output file: %s",
1760 isc_result_totext(result));
1761 removefile = ISC_TRUE;
1762 setfatalcallback(&removetempfile);
1767 result = isc_taskmgr_create(mctx, ntasks, 0, &taskmgr);
1768 if (result != ISC_R_SUCCESS)
1769 fatal("failed to create task manager: %s",
1770 isc_result_totext(result));
1773 result = isc_task_create(taskmgr, 0, &master);
1774 if (result != ISC_R_SUCCESS)
1775 fatal("failed to create task: %s", isc_result_totext(result));
1777 tasks = isc_mem_get(mctx, ntasks * sizeof(isc_task_t *));
1779 fatal("out of memory");
1780 for (i = 0; i < (int)ntasks; i++) {
1782 result = isc_task_create(taskmgr, 0, &tasks[i]);
1783 if (result != ISC_R_SUCCESS)
1784 fatal("failed to create task: %s",
1785 isc_result_totext(result));
1786 result = isc_app_onrun(mctx, master, startworker, tasks[i]);
1787 if (result != ISC_R_SUCCESS)
1788 fatal("failed to start task: %s",
1789 isc_result_totext(result));
1792 RUNTIME_CHECK(isc_mutex_init(&namelock) == ISC_R_SUCCESS);
1794 RUNTIME_CHECK(isc_mutex_init(&statslock) == ISC_R_SUCCESS);
1797 (void)isc_app_run();
1799 fatal("process aborted by user");
1800 shuttingdown = ISC_TRUE;
1801 for (i = 0; i < (int)ntasks; i++)
1802 isc_task_detach(&tasks[i]);
1803 isc_taskmgr_destroy(&taskmgr);
1804 isc_mem_put(mctx, tasks, ntasks * sizeof(isc_task_t *));
1807 result = isc_stdio_close(fp);
1808 check_result(result, "isc_stdio_close");
1809 removefile = ISC_FALSE;
1811 result = isc_file_rename(tempfile, output);
1812 if (result != ISC_R_SUCCESS)
1813 fatal("failed to rename temp file to %s: %s\n",
1814 output, isc_result_totext(result));
1816 DESTROYLOCK(&namelock);
1818 DESTROYLOCK(&statslock);
1820 printf("%s\n", output);
1822 dns_db_closeversion(gdb, &gversion, ISC_FALSE);
1824 dns_db_detach(&gdb);
1826 while (!ISC_LIST_EMPTY(keylist)) {
1827 key = ISC_LIST_HEAD(keylist);
1828 ISC_LIST_UNLINK(keylist, key, link);
1829 dst_key_free(&key->key);
1830 isc_mem_put(mctx, key, sizeof(signer_key_t));
1833 isc_mem_put(mctx, tempfile, tempfilelen);
1836 isc_mem_free(mctx, output);
1838 cleanup_logging(&log);
1840 cleanup_entropy(&ectx);
1842 isc_mem_stats(mctx, stdout);
1843 isc_mem_destroy(&mctx);
1845 (void) isc_app_finish();
1848 isc_uint64_t runtime_us; /* Runtime in microseconds */
1849 isc_uint64_t runtime_ms; /* Runtime in milliseconds */
1850 isc_uint64_t sig_ms; /* Signatures per millisecond */
1852 isc_time_now(&timer_finish);
1854 runtime_us = isc_time_microdiff(&timer_finish, &timer_start);
1856 printf("Signatures generated: %10d\n",
1858 printf("Signatures retained: %10d\n",
1860 printf("Signatures dropped: %10d\n",
1862 printf("Signatures successfully verified: %10d\n",
1864 printf("Signatures unsuccessfully verified: %10d\n",
1866 runtime_ms = runtime_us / 1000;
1867 printf("Runtime in seconds: %7u.%03u\n",
1868 (unsigned int) (runtime_ms / 1000),
1869 (unsigned int) (runtime_ms % 1000));
1870 if (runtime_us > 0) {
1871 sig_ms = ((isc_uint64_t)nsigned * 1000000000) /
1873 printf("Signatures per second: %7u.%03u\n",
1874 (unsigned int) sig_ms / 1000,
1875 (unsigned int) sig_ms % 1000);