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