📄 dnssec-signzone.c
字号:
/* * Portions Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (C) 1999-2003 Internet Software Consortium. * Portions Copyright (C) 1995-2000 by Network Associates, Inc. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *//* $Id: dnssec-signzone.c,v 1.139.2.2.4.16 2004/08/28 06:25:29 marka Exp $ */#include <config.h>#include <stdlib.h>#include <time.h>#include <isc/app.h>#include <isc/commandline.h>#include <isc/entropy.h>#include <isc/event.h>#include <isc/file.h>#include <isc/mem.h>#include <isc/mutex.h>#include <isc/os.h>#include <isc/print.h>#include <isc/serial.h>#include <isc/stdio.h>#include <isc/string.h>#include <isc/task.h>#include <isc/util.h>#include <isc/time.h>#include <dns/db.h>#include <dns/dbiterator.h>#include <dns/diff.h>#include <dns/dnssec.h>#include <dns/ds.h>#include <dns/fixedname.h>#include <dns/keyvalues.h>#include <dns/log.h>#include <dns/master.h>#include <dns/masterdump.h>#include <dns/nsec.h>#include <dns/rdata.h>#include <dns/rdataset.h>#include <dns/rdataclass.h>#include <dns/rdatasetiter.h>#include <dns/rdatastruct.h>#include <dns/rdatatype.h>#include <dns/result.h>#include <dns/time.h>#include <dst/dst.h>#include "dnssectool.h"const char *program = "dnssec-signzone";int verbose;#define BUFSIZE 2048#define MAXDSKEYS 8typedef struct signer_key_struct signer_key_t;struct signer_key_struct { dst_key_t *key; isc_boolean_t issigningkey; isc_boolean_t isdsk; isc_boolean_t isksk; unsigned int position; ISC_LINK(signer_key_t) link;};#define SIGNER_EVENTCLASS ISC_EVENTCLASS(0x4453)#define SIGNER_EVENT_WRITE (SIGNER_EVENTCLASS + 0)#define SIGNER_EVENT_WORK (SIGNER_EVENTCLASS + 1)typedef struct signer_event sevent_t;struct signer_event { ISC_EVENT_COMMON(sevent_t); dns_fixedname_t *fname; dns_dbnode_t *node;};static ISC_LIST(signer_key_t) keylist;static unsigned int keycount = 0;static isc_stdtime_t starttime = 0, endtime = 0, now;static int cycle = -1;static isc_boolean_t tryverify = ISC_FALSE;static isc_boolean_t printstats = ISC_FALSE;static isc_mem_t *mctx = NULL;static isc_entropy_t *ectx = NULL;static dns_ttl_t zonettl;static FILE *fp;static char *tempfile = NULL;static const dns_master_style_t *masterstyle;static unsigned int nsigned = 0, nretained = 0, ndropped = 0;static unsigned int nverified = 0, nverifyfailed = 0;static const char *directory;static isc_mutex_t namelock, statslock;static isc_taskmgr_t *taskmgr = NULL;static dns_db_t *gdb; /* The database */static dns_dbversion_t *gversion; /* The database version */static dns_dbiterator_t *gdbiter; /* The database iterator */static dns_rdataclass_t gclass; /* The class */static dns_name_t *gorigin; /* The database origin */static isc_task_t *master = NULL;static unsigned int ntasks = 0;static isc_boolean_t shuttingdown = ISC_FALSE, finished = ISC_FALSE;static unsigned int assigned = 0, completed = 0;static isc_boolean_t nokeys = ISC_FALSE;static isc_boolean_t removefile = ISC_FALSE;static isc_boolean_t generateds = ISC_FALSE;static isc_boolean_t ignoreksk = ISC_FALSE;static dns_name_t *dlv = NULL;static dns_fixedname_t dlv_fixed;static dns_master_style_t *dsstyle = NULL;#define INCSTAT(counter) \ if (printstats) { \ LOCK(&statslock); \ counter++; \ UNLOCK(&statslock); \ }static voidsign(isc_task_t *task, isc_event_t *event);static inline voidset_bit(unsigned char *array, unsigned int index, unsigned int bit) { unsigned int shift, mask; shift = 7 - (index % 8); mask = 1 << shift; if (bit != 0) array[index / 8] |= mask; else array[index / 8] &= (~mask & 0xFF);}static voiddumpnode(dns_name_t *name, dns_dbnode_t *node) { isc_result_t result; result = dns_master_dumpnodetostream(mctx, gdb, gversion, node, name, masterstyle, fp); check_result(result, "dns_master_dumpnodetostream");}static voiddumpdb(dns_db_t *db) { dns_dbiterator_t *dbiter = NULL; dns_dbnode_t *node; dns_fixedname_t fname; dns_name_t *name; isc_result_t result; dbiter = NULL; result = dns_db_createiterator(db, ISC_FALSE, &dbiter); check_result(result, "dns_db_createiterator()"); dns_fixedname_init(&fname); name = dns_fixedname_name(&fname); node = NULL; for (result = dns_dbiterator_first(dbiter); result == ISC_R_SUCCESS; result = dns_dbiterator_next(dbiter)) { result = dns_dbiterator_current(dbiter, &node, name); check_result(result, "dns_dbiterator_current()"); dumpnode(name, node); dns_db_detachnode(db, &node); } if (result != ISC_R_NOMORE) fatal("iterating database: %s", isc_result_totext(result)); dns_dbiterator_destroy(&dbiter);}static signer_key_t *newkeystruct(dst_key_t *dstkey, isc_boolean_t signwithkey) { signer_key_t *key; key = isc_mem_get(mctx, sizeof(signer_key_t)); if (key == NULL) fatal("out of memory"); key->key = dstkey; if ((dst_key_flags(dstkey) & DNS_KEYFLAG_KSK) != 0) { key->issigningkey = signwithkey; key->isksk = ISC_TRUE; key->isdsk = ISC_FALSE; } else { key->issigningkey = signwithkey; key->isksk = ISC_FALSE; key->isdsk = ISC_TRUE; } key->position = keycount++; ISC_LINK_INIT(key, link); return (key);}static voidsignwithkey(dns_name_t *name, dns_rdataset_t *rdataset, dns_rdata_t *rdata, dst_key_t *key, isc_buffer_t *b){ isc_result_t result; result = dns_dnssec_sign(name, rdataset, key, &starttime, &endtime, mctx, b, rdata); isc_entropy_stopcallbacksources(ectx); if (result != ISC_R_SUCCESS) { char keystr[KEY_FORMATSIZE]; key_format(key, keystr, sizeof(keystr)); fatal("dnskey '%s' failed to sign data: %s", keystr, isc_result_totext(result)); } INCSTAT(nsigned); if (tryverify) { result = dns_dnssec_verify(name, rdataset, key, ISC_TRUE, mctx, rdata); if (result == ISC_R_SUCCESS) { vbprintf(3, "\tsignature verified\n"); INCSTAT(nverified); } else { vbprintf(3, "\tsignature failed to verify\n"); INCSTAT(nverifyfailed); } }}static inline isc_boolean_tissigningkey(signer_key_t *key) { return (key->issigningkey);}static inline isc_boolean_tiszonekey(signer_key_t *key) { return (ISC_TF(dns_name_equal(dst_key_name(key->key), gorigin) && dst_key_iszonekey(key->key)));}/* * Finds the key that generated a RRSIG, if possible. First look at the keys * that we've loaded already, and then see if there's a key on disk. */static signer_key_t *keythatsigned(dns_rdata_rrsig_t *rrsig) { isc_result_t result; dst_key_t *pubkey = NULL, *privkey = NULL; signer_key_t *key; key = ISC_LIST_HEAD(keylist); while (key != NULL) { if (rrsig->keyid == dst_key_id(key->key) && rrsig->algorithm == dst_key_alg(key->key) && dns_name_equal(&rrsig->signer, dst_key_name(key->key))) return key; key = ISC_LIST_NEXT(key, link); } result = dst_key_fromfile(&rrsig->signer, rrsig->keyid, rrsig->algorithm, DST_TYPE_PUBLIC, NULL, mctx, &pubkey); if (result != ISC_R_SUCCESS) return (NULL); result = dst_key_fromfile(&rrsig->signer, rrsig->keyid, rrsig->algorithm, DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, NULL, mctx, &privkey); if (result == ISC_R_SUCCESS) { dst_key_free(&pubkey); key = newkeystruct(privkey, ISC_FALSE); } else key = newkeystruct(pubkey, ISC_FALSE); ISC_LIST_APPEND(keylist, key, link); return (key);}/* * Check to see if we expect to find a key at this name. If we see a RRSIG * and can't find the signing key that we expect to find, we drop the rrsig. * I'm not sure if this is completely correct, but it seems to work. */static isc_boolean_texpecttofindkey(dns_name_t *name) { unsigned int options = DNS_DBFIND_NOWILD; dns_fixedname_t fname; isc_result_t result; char namestr[DNS_NAME_FORMATSIZE]; dns_fixedname_init(&fname); result = dns_db_find(gdb, name, gversion, dns_rdatatype_dnskey, options, 0, NULL, dns_fixedname_name(&fname), NULL, NULL); switch (result) { case ISC_R_SUCCESS: case DNS_R_NXDOMAIN: case DNS_R_NXRRSET: return (ISC_TRUE); case DNS_R_DELEGATION: case DNS_R_CNAME: case DNS_R_DNAME: return (ISC_FALSE); } dns_name_format(name, namestr, sizeof(namestr)); fatal("failure looking for '%s DNSKEY' in database: %s", namestr, isc_result_totext(result)); return (ISC_FALSE); /* removes a warning */}static inline isc_boolean_tsetverifies(dns_name_t *name, dns_rdataset_t *set, signer_key_t *key, dns_rdata_t *rrsig){ isc_result_t result; result = dns_dnssec_verify(name, set, key->key, ISC_FALSE, mctx, rrsig); if (result == ISC_R_SUCCESS) { INCSTAT(nverified); return (ISC_TRUE); } else { INCSTAT(nverifyfailed); return (ISC_FALSE); }}/* * Signs a set. Goes through contortions to decide if each RRSIG should * be dropped or retained, and then determines if any new SIGs need to * be generated. */static voidsignset(dns_diff_t *del, dns_diff_t *add, dns_dbnode_t *node, dns_name_t *name, dns_rdataset_t *set){ dns_rdataset_t sigset; dns_rdata_t sigrdata = DNS_RDATA_INIT; dns_rdata_rrsig_t rrsig; signer_key_t *key; isc_result_t result; isc_boolean_t nosigs = ISC_FALSE; isc_boolean_t *wassignedby, *nowsignedby; int arraysize; dns_difftuple_t *tuple; dns_ttl_t ttl; int i; char namestr[DNS_NAME_FORMATSIZE]; char typestr[TYPE_FORMATSIZE]; char sigstr[SIG_FORMATSIZE]; dns_name_format(name, namestr, sizeof(namestr)); type_format(set->type, typestr, sizeof(typestr)); ttl = ISC_MIN(set->ttl, endtime - starttime); dns_rdataset_init(&sigset); result = dns_db_findrdataset(gdb, node, gversion, dns_rdatatype_rrsig, set->type, 0, &sigset, NULL); if (result == ISC_R_NOTFOUND) { result = ISC_R_SUCCESS; nosigs = ISC_TRUE; } if (result != ISC_R_SUCCESS) fatal("failed while looking for '%s RRSIG %s': %s", namestr, typestr, isc_result_totext(result)); vbprintf(1, "%s/%s:\n", namestr, typestr); arraysize = keycount; if (!nosigs) arraysize += dns_rdataset_count(&sigset); wassignedby = isc_mem_get(mctx, arraysize * sizeof(isc_boolean_t)); nowsignedby = isc_mem_get(mctx, arraysize * sizeof(isc_boolean_t)); if (wassignedby == NULL || nowsignedby == NULL) fatal("out of memory"); for (i = 0; i < arraysize; i++) wassignedby[i] = nowsignedby[i] = ISC_FALSE; if (nosigs) result = ISC_R_NOMORE; else result = dns_rdataset_first(&sigset); while (result == ISC_R_SUCCESS) { isc_boolean_t expired, future; isc_boolean_t keep = ISC_FALSE, resign = ISC_FALSE; dns_rdataset_current(&sigset, &sigrdata); result = dns_rdata_tostruct(&sigrdata, &rrsig, NULL); check_result(result, "dns_rdata_tostruct"); future = isc_serial_lt(now, rrsig.timesigned); key = keythatsigned(&rrsig); sig_format(&rrsig, sigstr, sizeof(sigstr)); if (key != NULL && issigningkey(key)) expired = isc_serial_gt(now + cycle, rrsig.timeexpire); else expired = isc_serial_gt(now, rrsig.timeexpire); if (isc_serial_gt(rrsig.timesigned, rrsig.timeexpire)) { /* rrsig is dropped and not replaced */ vbprintf(2, "\trrsig by %s dropped - " "invalid validity period\n", sigstr); } else if (key == NULL && !future && expecttofindkey(&rrsig.signer)) { /* rrsig is dropped and not replaced */ vbprintf(2, "\trrsig by %s dropped - " "private dnskey not found\n", sigstr); } else if (key == NULL || future) { vbprintf(2, "\trrsig by %s %s - dnskey not found\n", expired ? "retained" : "dropped", sigstr); if (!expired) keep = ISC_TRUE; } else if (issigningkey(key)) { if (!expired && setverifies(name, set, key, &sigrdata)) { vbprintf(2, "\trrsig by %s retained\n", sigstr); keep = ISC_TRUE; wassignedby[key->position] = ISC_TRUE; nowsignedby[key->position] = ISC_TRUE; } else { vbprintf(2, "\trrsig by %s dropped - %s\n", sigstr, expired ? "expired" : "failed to verify"); wassignedby[key->position] = ISC_TRUE; resign = ISC_TRUE; } } else if (iszonekey(key)) { if (!expired && setverifies(name, set, key, &sigrdata)) { vbprintf(2, "\trrsig by %s retained\n", sigstr); keep = ISC_TRUE; wassignedby[key->position] = ISC_TRUE; nowsignedby[key->position] = ISC_TRUE; } else { vbprintf(2, "\trrsig by %s dropped - %s\n", sigstr, expired ? "expired" : "failed to verify"); wassignedby[key->position] = ISC_TRUE; } } else if (!expired) { vbprintf(2, "\trrsig by %s retained\n", sigstr); keep = ISC_TRUE; } else { vbprintf(2, "\trrsig by %s expired\n", sigstr); } if (keep) { nowsignedby[key->position] = ISC_TRUE; INCSTAT(nretained); if (sigset.ttl != ttl) { vbprintf(2, "\tfixing ttl %s\n", sigstr); tuple = NULL; result = dns_difftuple_create(mctx, DNS_DIFFOP_DEL, name, sigset.ttl, &sigrdata, &tuple); check_result(result, "dns_difftuple_create"); dns_diff_append(del, &tuple); result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD, name, ttl, &sigrdata, &tuple); check_result(result, "dns_difftuple_create"); dns_diff_append(add, &tuple); } } else { tuple = NULL; result = dns_difftuple_create(mctx, DNS_DIFFOP_DEL, name, sigset.ttl, &sigrdata, &tuple); check_result(result, "dns_difftuple_create"); dns_diff_append(del, &tuple); INCSTAT(ndropped); } if (resign) { isc_buffer_t b; dns_rdata_t trdata = DNS_RDATA_INIT; unsigned char array[BUFSIZE]; char keystr[KEY_FORMATSIZE]; INSIST(!keep); key_format(key->key, keystr, sizeof(keystr)); vbprintf(1, "\tresigning with dnskey %s\n", keystr); isc_buffer_init(&b, array, sizeof(array)); signwithkey(name, set, &trdata, key->key, &b); nowsignedby[key->position] = ISC_TRUE; tuple = NULL; result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD, name, ttl, &trdata, &tuple); check_result(result, "dns_difftuple_create"); dns_diff_append(add, &tuple); } dns_rdata_reset(&sigrdata); dns_rdata_freestruct(&rrsig); result = dns_rdataset_next(&sigset); } if (result == ISC_R_NOMORE) result = ISC_R_SUCCESS;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -