📄 dnssec-signzone.c
字号:
/* * Portions Copyright (C) 1999-2001, 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 INTERNET SOFTWARE CONSORTIUM AND * NETWORK ASSOCIATES DISCLAIM ALL WARRANTIES WITH REGARD TO THIS * SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE CONSORTIUM OR NETWORK * ASSOCIATES 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 2003/03/06 04:38:13 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/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/fixedname.h>#include <dns/keyvalues.h>#include <dns/log.h>#include <dns/master.h>#include <dns/masterdump.h>#include <dns/nxt.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/secalg.h>#include <dns/time.h>#include <dst/dst.h>#include <dst/result.h>#include "dnssectool.h"const char *program = "dnssec-signzone";int verbose;#define BUFSIZE 2048typedef struct signer_key_struct signer_key_t;struct signer_key_struct { dst_key_t *key; isc_boolean_t isdefault; 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_fixedname_t *fnextname; 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_name_t *gorigin; /* The database origin */static dns_dbnode_t *gnode = NULL; /* The "current" database node */static dns_name_t *lastzonecut;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;#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 signer_key_t *newkeystruct(dst_key_t *dstkey, isc_boolean_t isdefault) { signer_key_t *key; key = isc_mem_get(mctx, sizeof(signer_key_t)); if (key == NULL) fatal("out of memory"); key->key = dstkey; key->isdefault = isdefault; 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("key '%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->isdefault);}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 SIG, 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_sig_t *sig) { isc_result_t result; dst_key_t *pubkey = NULL, *privkey = NULL; signer_key_t *key; key = ISC_LIST_HEAD(keylist); while (key != NULL) { if (sig->keyid == dst_key_id(key->key) && sig->algorithm == dst_key_alg(key->key) && dns_name_equal(&sig->signer, dst_key_name(key->key))) return key; key = ISC_LIST_NEXT(key, link); } result = dst_key_fromfile(&sig->signer, sig->keyid, sig->algorithm, DST_TYPE_PUBLIC, NULL, mctx, &pubkey); if (result != ISC_R_SUCCESS) return (NULL); result = dst_key_fromfile(&sig->signer, sig->keyid, sig->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 SIG * and can't find the signing key that we expect to find, we drop the sig. * 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_key, 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 KEY' 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 *sig){ isc_result_t result; result = dns_dnssec_verify(name, set, key->key, ISC_FALSE, mctx, sig); 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 SIG should * be dropped or retained, and then determines if any new SIGs need to * be generated. */static voidsignset(dns_diff_t *diff, 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_sig_t sig; 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_sig, 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 SIG %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, &sig, NULL); check_result(result, "dns_rdata_tostruct"); expired = ISC_TF(now + cycle > sig.timeexpire); future = ISC_TF(now < sig.timesigned); key = keythatsigned(&sig); sig_format(&sig, sigstr, sizeof sigstr); if (sig.timesigned > sig.timeexpire) { /* sig is dropped and not replaced */ vbprintf(2, "\tsig by %s dropped - " "invalid validity period\n", sigstr); } else if (key == NULL && !future && expecttofindkey(&sig.signer)) { /* sig is dropped and not replaced */ vbprintf(2, "\tsig by %s dropped - " "private key not found\n", sigstr); } else if (key == NULL || future) { vbprintf(2, "\tsig by %s %s - key 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, "\tsig by %s retained\n", sigstr); keep = ISC_TRUE; wassignedby[key->position] = ISC_TRUE; nowsignedby[key->position] = ISC_TRUE; } else { vbprintf(2, "\tsig 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, "\tsig by %s retained\n", sigstr); keep = ISC_TRUE; wassignedby[key->position] = ISC_TRUE; nowsignedby[key->position] = ISC_TRUE; } else { vbprintf(2, "\tsig by %s dropped - %s\n", sigstr, expired ? "expired" : "failed to verify"); wassignedby[key->position] = ISC_TRUE; } } else if (!expired) { vbprintf(2, "\tsig by %s retained\n", sigstr); keep = ISC_TRUE; } else { vbprintf(2, "\tsig by %s expired\n", sigstr); } if (keep) { nowsignedby[key->position] = ISC_TRUE; INCSTAT(nretained); } 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(diff, &tuple); INCSTAT(ndropped); } if (resign) { isc_buffer_t b; dns_rdata_t trdata = DNS_RDATA_INIT; unsigned char array[BUFSIZE]; char keystr[KEY_FORMATSIZE]; key_format(key->key, keystr, sizeof keystr); vbprintf(1, "\tresigning with key %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(diff, &tuple); } dns_rdata_reset(&sigrdata); dns_rdata_freestruct(&sig); result = dns_rdataset_next(&sigset); } if (result == ISC_R_NOMORE) result = ISC_R_SUCCESS; check_result(result, "dns_rdataset_first/next"); if (dns_rdataset_isassociated(&sigset)) dns_rdataset_disassociate(&sigset); key = ISC_LIST_HEAD(keylist); while (key != NULL) { if (key->isdefault && !nowsignedby[key->position]) { isc_buffer_t b; dns_rdata_t trdata = DNS_RDATA_INIT; unsigned char array[BUFSIZE]; char keystr[KEY_FORMATSIZE]; key_format(key->key, keystr, sizeof keystr); vbprintf(1, "\tsigning with key %s\n", keystr); isc_buffer_init(&b, array, sizeof(array)); signwithkey(name, set, &trdata, key->key, &b); tuple = NULL; result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD, name, ttl, &trdata, &tuple); check_result(result, "dns_difftuple_create"); dns_diff_append(diff, &tuple); } key = ISC_LIST_NEXT(key, link);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -