📄 validator.c
字号:
/* * Copyright (C) 2000-2002 Internet Software Consortium. * * 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 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL * INTERNET SOFTWARE CONSORTIUM 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: validator.c,v 1.91.2.5 2002/08/05 06:57:12 marka Exp $ */#include <config.h>#include <isc/mem.h>#include <isc/print.h>#include <isc/task.h>#include <isc/util.h>#include <dns/db.h>#include <dns/dnssec.h>#include <dns/events.h>#include <dns/keytable.h>#include <dns/log.h>#include <dns/message.h>#include <dns/nxt.h>#include <dns/rdata.h>#include <dns/rdatastruct.h>#include <dns/rdataset.h>#include <dns/rdatatype.h>#include <dns/resolver.h>#include <dns/result.h>#include <dns/validator.h>#include <dns/view.h>#define VALIDATOR_MAGIC ISC_MAGIC('V', 'a', 'l', '?')#define VALID_VALIDATOR(v) ISC_MAGIC_VALID(v, VALIDATOR_MAGIC)#define VALATTR_SHUTDOWN 0x01#define VALATTR_FOUNDNONEXISTENCE 0x02#define VALATTR_TRIEDVERIFY 0x04#define SHUTDOWN(v) (((v)->attributes & VALATTR_SHUTDOWN) != 0)static voidnullkeyvalidated(isc_task_t *task, isc_event_t *event);static inline isc_boolean_tcontainsnullkey(dns_validator_t *val, dns_rdataset_t *rdataset);static inline isc_result_tget_dst_key(dns_validator_t *val, dns_rdata_sig_t *siginfo, dns_rdataset_t *rdataset);static inline isc_result_tvalidate(dns_validator_t *val, isc_boolean_t resume);static inline isc_result_tnxtvalidate(dns_validator_t *val, isc_boolean_t resume);static inline isc_result_tproveunsecure(dns_validator_t *val, isc_boolean_t resume);static voidvalidator_log(dns_validator_t *val, int level, const char *fmt, ...) ISC_FORMAT_PRINTF(3, 4);static voidvalidator_done(dns_validator_t *val, isc_result_t result) { isc_task_t *task; if (val->event == NULL) return; /* * Caller must be holding the lock. */ val->event->result = result; task = val->event->ev_sender; val->event->ev_sender = val; val->event->ev_type = DNS_EVENT_VALIDATORDONE; val->event->ev_action = val->action; val->event->ev_arg = val->arg; isc_task_sendanddetach(&task, (isc_event_t **)&val->event);}static voidauth_nonpending(dns_message_t *message) { isc_result_t result; dns_name_t *name; dns_rdataset_t *rdataset; for (result = dns_message_firstname(message, DNS_SECTION_AUTHORITY); result == ISC_R_SUCCESS; result = dns_message_nextname(message, DNS_SECTION_AUTHORITY)) { name = NULL; dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name); for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) { if (rdataset->trust == dns_trust_pending) rdataset->trust = dns_trust_authauthority; } }}static voidfetch_callback_validator(isc_task_t *task, isc_event_t *event) { dns_fetchevent_t *devent; dns_validator_t *val; dns_rdataset_t *rdataset; isc_result_t result; isc_result_t eresult; UNUSED(task); INSIST(event->ev_type == DNS_EVENT_FETCHDONE); devent = (dns_fetchevent_t *)event; val = devent->ev_arg; rdataset = &val->frdataset; eresult = devent->result; isc_event_free(&event); dns_resolver_destroyfetch(&val->fetch); if (SHUTDOWN(val)) { dns_validator_destroy(&val); return; } if (val->event == NULL) { validator_log(val, ISC_LOG_DEBUG(3), "fetch_callback_validator: event == NULL"); return; } validator_log(val, ISC_LOG_DEBUG(3), "in fetch_callback_validator"); LOCK(&val->lock); if (eresult == ISC_R_SUCCESS) { validator_log(val, ISC_LOG_DEBUG(3), "keyset with trust %d", rdataset->trust); /* * Only extract the dst key if the keyset is secure. */ if (rdataset->trust >= dns_trust_secure) { result = get_dst_key(val, val->siginfo, rdataset); if (result == ISC_R_SUCCESS) val->keyset = &val->frdataset; } result = validate(val, ISC_TRUE); if (result != DNS_R_WAIT) { validator_done(val, result); goto out; } } else { validator_log(val, ISC_LOG_DEBUG(3), "fetch_callback_validator: got %s", dns_result_totext(eresult)); validator_done(val, DNS_R_NOVALIDKEY); } out: UNLOCK(&val->lock); /* * Free stuff from the event. */ if (dns_rdataset_isassociated(&val->frdataset) && val->keyset != &val->frdataset) dns_rdataset_disassociate(&val->frdataset); if (dns_rdataset_isassociated(&val->fsigrdataset)) dns_rdataset_disassociate(&val->fsigrdataset);}static voidfetch_callback_nullkey(isc_task_t *task, isc_event_t *event) { dns_fetchevent_t *devent; dns_validator_t *val; dns_rdataset_t *rdataset, *sigrdataset; isc_result_t result; isc_result_t eresult; UNUSED(task); INSIST(event->ev_type == DNS_EVENT_FETCHDONE); devent = (dns_fetchevent_t *)event; val = devent->ev_arg; rdataset = &val->frdataset; sigrdataset = &val->fsigrdataset; eresult = devent->result; dns_resolver_destroyfetch(&val->fetch); if (SHUTDOWN(val)) { dns_validator_destroy(&val); isc_event_free(&event); return; } if (val->event == NULL) { validator_log(val, ISC_LOG_DEBUG(3), "fetch_callback_nullkey: event == NULL"); isc_event_free(&event); return; } validator_log(val, ISC_LOG_DEBUG(3), "in fetch_callback_nullkey"); LOCK(&val->lock); if (eresult == ISC_R_SUCCESS) { if (!containsnullkey(val, rdataset)) { /* * No null key. */ validator_log(val, ISC_LOG_DEBUG(3), "found a keyset, no null key"); result = proveunsecure(val, ISC_TRUE); if (result != DNS_R_WAIT) validator_done(val, result); else { /* * Don't free rdataset & sigrdataset, since * they'll be freed in nullkeyvalidated. */ isc_event_free(&event); UNLOCK(&val->lock); return; } } else { validator_log(val, ISC_LOG_DEBUG(3), "found a keyset with a null key"); if (rdataset->trust >= dns_trust_secure) { validator_log(val, ISC_LOG_DEBUG(3), "insecurity proof succeeded"); val->event->rdataset->trust = dns_trust_answer; validator_done(val, ISC_R_SUCCESS); } else if (!dns_rdataset_isassociated(sigrdataset)) { validator_log(val, ISC_LOG_DEBUG(3), "insecurity proof failed"); validator_done(val, DNS_R_NOTINSECURE); } else { dns_name_t *tname; tname = dns_fixedname_name(&devent->foundname); result = dns_validator_create(val->view, tname, dns_rdatatype_key, rdataset, sigrdataset, NULL, 0, val->task, nullkeyvalidated, val, &val->keyvalidator); if (result != ISC_R_SUCCESS) validator_done(val, result); /* * Don't free rdataset & sigrdataset, since * they'll be freed in nullkeyvalidated. */ isc_event_free(&event); UNLOCK(&val->lock); return; } } } else if (eresult == DNS_R_NCACHENXDOMAIN || eresult == DNS_R_NCACHENXRRSET || eresult == DNS_R_NXDOMAIN || eresult == DNS_R_NXRRSET) { /* * No keys. */ validator_log(val, ISC_LOG_DEBUG(3), "no keys found"); result = proveunsecure(val, ISC_TRUE); if (result != DNS_R_WAIT) validator_done(val, result); } else { validator_log(val, ISC_LOG_DEBUG(3), "fetch_callback_nullkey: got %s", dns_result_totext(eresult)); validator_done(val, DNS_R_NOVALIDKEY); } UNLOCK(&val->lock); /* * Free stuff from the event. */ if (dns_rdataset_isassociated(&val->frdataset)) dns_rdataset_disassociate(&val->frdataset); if (dns_rdataset_isassociated(&val->fsigrdataset)) dns_rdataset_disassociate(&val->fsigrdataset); isc_event_free(&event);}static voidkeyvalidated(isc_task_t *task, isc_event_t *event) { dns_validatorevent_t *devent; dns_validator_t *val; isc_result_t result; isc_result_t eresult; UNUSED(task); INSIST(event->ev_type == DNS_EVENT_VALIDATORDONE); devent = (dns_validatorevent_t *)event; val = devent->ev_arg; eresult = devent->result; isc_event_free(&event); if (SHUTDOWN(val)) { dns_validator_destroy(&val); return; } if (val->event == NULL) return; validator_log(val, ISC_LOG_DEBUG(3), "in keyvalidated"); LOCK(&val->lock); if (eresult == ISC_R_SUCCESS) { validator_log(val, ISC_LOG_DEBUG(3), "keyset with trust %d", val->frdataset.trust); /* * Only extract the dst key if the keyset is secure. */ if (val->frdataset.trust >= dns_trust_secure) (void) get_dst_key(val, val->siginfo, &val->frdataset); result = validate(val, ISC_TRUE); if (result != DNS_R_WAIT) { validator_done(val, result); goto out; } } else { validator_log(val, ISC_LOG_DEBUG(3), "keyvalidated: got %s", dns_result_totext(eresult)); validator_done(val, eresult); } out: UNLOCK(&val->lock); dns_validator_destroy(&val->keyvalidator); /* * Free stuff from the event. */ if (dns_rdataset_isassociated(&val->frdataset)) dns_rdataset_disassociate(&val->frdataset); if (dns_rdataset_isassociated(&val->fsigrdataset)) dns_rdataset_disassociate(&val->fsigrdataset);}static isc_boolean_tnxtprovesnonexistence(dns_validator_t *val, dns_name_t *nxtname, dns_rdataset_t *nxtset, dns_rdataset_t *signxtset){ int order; dns_rdata_t rdata = DNS_RDATA_INIT; isc_boolean_t isnxdomain; isc_result_t result; INSIST(DNS_MESSAGE_VALID(val->event->message)); if (val->event->message->rcode == dns_rcode_nxdomain) isnxdomain = ISC_TRUE; else isnxdomain = ISC_FALSE; result = dns_rdataset_first(nxtset); if (result != ISC_R_SUCCESS) { validator_log(val, ISC_LOG_DEBUG(3), "failure processing NXT set"); return (ISC_FALSE); } dns_rdataset_current(nxtset, &rdata); validator_log(val, ISC_LOG_DEBUG(3), "looking for relevant nxt"); order = dns_name_compare(val->event->name, nxtname); if (order == 0) { /* * The names are the same. Look for the type present bit. */ if (isnxdomain) { validator_log(val, ISC_LOG_DEBUG(3), "NXT record seen at nonexistent name"); return (ISC_FALSE); } if (val->event->type >= 128) { validator_log(val, ISC_LOG_DEBUG(3), "invalid type %d", val->event->type); return (ISC_FALSE); } if (dns_nxt_typepresent(&rdata, val->event->type)) { validator_log(val, ISC_LOG_DEBUG(3), "type should not be present"); return (ISC_FALSE); } validator_log(val, ISC_LOG_DEBUG(3), "nxt bitmask ok"); } else if (order > 0) { dns_rdata_nxt_t nxt; /* * The NXT owner name is less than the nonexistent name. */ if (!isnxdomain) { validator_log(val, ISC_LOG_DEBUG(3), "missing NXT record at name"); return (ISC_FALSE); } if (dns_name_issubdomain(val->event->name, nxtname) && dns_nxt_typepresent(&rdata, dns_rdatatype_ns) && !dns_nxt_typepresent(&rdata, dns_rdatatype_soa)) { /* * This NXT record is from somewhere higher in * the DNS, and at the parent of a delegation. * It can not be legitimately used here. */ validator_log(val, ISC_LOG_DEBUG(3), "ignoring parent nxt"); return (ISC_FALSE); } result = dns_rdata_tostruct(&rdata, &nxt, NULL); if (result != ISC_R_SUCCESS) return (ISC_FALSE); dns_rdata_reset(&rdata); order = dns_name_compare(val->event->name, &nxt.next); if (order >= 0) { /* * The NXT next name is less than the nonexistent * name. This is only ok if the next name is the zone * name. */ dns_rdata_sig_t siginfo; result = dns_rdataset_first(signxtset); if (result != ISC_R_SUCCESS) { validator_log(val, ISC_LOG_DEBUG(3), "failure processing SIG NXT set"); dns_rdata_freestruct(&nxt); return (ISC_FALSE); } dns_rdataset_current(signxtset, &rdata); result = dns_rdata_tostruct(&rdata, &siginfo, NULL); if (result != ISC_R_SUCCESS) { validator_log(val, ISC_LOG_DEBUG(3), "failure processing SIG NXT set"); dns_rdata_freestruct(&nxt); return (ISC_FALSE); } if (!dns_name_equal(&siginfo.signer, &nxt.next)) { validator_log(val, ISC_LOG_DEBUG(3), "next name is not greater"); dns_rdata_freestruct(&nxt); return (ISC_FALSE); } validator_log(val, ISC_LOG_DEBUG(3), "nxt points to zone apex, ok"); } dns_rdata_freestruct(&nxt); validator_log(val, ISC_LOG_DEBUG(3), "nxt range ok"); } else { validator_log(val, ISC_LOG_DEBUG(3), "nxt owner name is not less"); /* * The NXT owner name is greater than the supposedly * nonexistent name. This NXT is irrelevant. */ return (ISC_FALSE); } return (ISC_TRUE);}static voidauthvalidated(isc_task_t *task, isc_event_t *event) { dns_validatorevent_t *devent; dns_validator_t *val; dns_rdataset_t *rdataset, *sigrdataset; isc_result_t result; isc_result_t eresult; UNUSED(task); INSIST(event->ev_type == DNS_EVENT_VALIDATORDONE); devent = (dns_validatorevent_t *)event; rdataset = devent->rdataset; sigrdataset = devent->sigrdataset; val = devent->ev_arg; eresult = devent->result; dns_validator_destroy(&val->authvalidator); if (SHUTDOWN(val)) { dns_validator_destroy(&val); return; } if (val->event == NULL) return; validator_log(val, ISC_LOG_DEBUG(3), "in authvalidated"); LOCK(&val->lock); if (eresult != ISC_R_SUCCESS) { validator_log(val, ISC_LOG_DEBUG(3), "authvalidated: got %s", dns_result_totext(eresult)); result = nxtvalidate(val, ISC_TRUE); if (result != DNS_R_WAIT) validator_done(val, result); } else { if (rdataset->type == dns_rdatatype_nxt && nxtprovesnonexistence(val, devent->name, rdataset, sigrdataset)) val->attributes |= VALATTR_FOUNDNONEXISTENCE; result = nxtvalidate(val, ISC_TRUE); if (result != DNS_R_WAIT) validator_done(val, result); } UNLOCK(&val->lock); /* * Free stuff from the event. */ isc_event_free(&event);}static voidnegauthvalidated(isc_task_t *task, isc_event_t *event) { dns_validatorevent_t *devent; dns_validator_t *val; isc_result_t eresult; UNUSED(task); INSIST(event->ev_type == DNS_EVENT_VALIDATORDONE); devent = (dns_validatorevent_t *)event; val = devent->ev_arg; eresult = devent->result; isc_event_free(&event); dns_validator_destroy(&val->authvalidator); if (SHUTDOWN(val)) { dns_validator_destroy(&val); return; } if (val->event == NULL) return; validator_log(val, ISC_LOG_DEBUG(3), "in negauthvalidated"); LOCK(&val->lock); if (eresult == ISC_R_SUCCESS) { val->attributes |= VALATTR_FOUNDNONEXISTENCE; validator_log(val, ISC_LOG_DEBUG(3), "nonexistence proof found"); auth_nonpending(val->event->message); validator_done(val, ISC_R_SUCCESS); } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -