diff options
Diffstat (limited to 'lib/dns')
94 files changed, 3460 insertions, 855 deletions
diff --git a/lib/dns/Makefile.in b/lib/dns/Makefile.in index b712ab1cd874e..a3e3e9a4e86ac 100644 --- a/lib/dns/Makefile.in +++ b/lib/dns/Makefile.in @@ -55,6 +55,8 @@ DSTOBJS = @DST_EXTRA_OBJS@ @OPENSSLLINKOBJS@ \ dst_api.@O@ dst_lib.@O@ dst_parse.@O@ dst_result.@O@ \ gssapi_link.@O@ gssapictx.@O@ hmac_link.@O@ key.@O@ +RRLOBJS = rrl.@O@ + # Alphabetically DNSOBJS = acache.@O@ acl.@O@ adb.@O@ byaddr.@O@ \ cache.@O@ callbacks.@O@ clientinfo.@O@ compress.@O@ \ @@ -67,14 +69,14 @@ DNSOBJS = acache.@O@ acl.@O@ adb.@O@ byaddr.@O@ \ portlist.@O@ private.@O@ \ rbt.@O@ rbtdb.@O@ rbtdb64.@O@ rcode.@O@ rdata.@O@ \ rdatalist.@O@ rdataset.@O@ rdatasetiter.@O@ rdataslab.@O@ \ - request.@O@ resolver.@O@ result.@O@ rootns.@O@ rpz.@O@ \ - rriterator.@O@ sdb.@O@ \ + request.@O@ resolver.@O@ result.@O@ rootns.@O@ \ + rpz.@O@ rriterator.@O@ sdb.@O@ \ sdlz.@O@ soa.@O@ ssu.@O@ ssu_external.@O@ \ stats.@O@ tcpmsg.@O@ time.@O@ timer.@O@ tkey.@O@ \ tsec.@O@ tsig.@O@ ttl.@O@ update.@O@ validator.@O@ \ version.@O@ view.@O@ xfrin.@O@ zone.@O@ zonekey.@O@ zt.@O@ -OBJS= ${DNSOBJS} ${OTHEROBJS} ${DSTOBJS} +OBJS= ${DNSOBJS} ${OTHEROBJS} ${DSTOBJS} @RRLLINKOBJS@ # Alphabetically OPENSSLGOSTLINKSRCS = opensslgost_link.c @@ -101,7 +103,9 @@ DNSSRCS = acache.c acl.c adb.c byaddr.c \ tsec.c tsig.c ttl.c update.c validator.c \ version.c view.c xfrin.c zone.c zonekey.c zt.c ${OTHERSRCS} -SRCS = ${DSTSRCS} ${DNSSRCS} +RRLSRCS = rrl.c + +SRCS = ${DSTSRCS} ${DNSSRCS} @RRLLINKSRCS@ SUBDIRS = include TARGETS = include/dns/enumtype.h include/dns/enumclass.h \ diff --git a/lib/dns/acache.c b/lib/dns/acache.c index 6df9b98386353..d3d28f8561710 100644 --- a/lib/dns/acache.c +++ b/lib/dns/acache.c @@ -1669,13 +1669,14 @@ dns_acache_cancelentry(dns_acacheentry_t *entry) { REQUIRE(DNS_ACACHEENTRY_VALID(entry)); acache = entry->acache; - callback_active = ISC_TF(entry->cbarg != NULL); INSIST(DNS_ACACHE_VALID(entry->acache)); LOCK(&acache->lock); ACACHE_LOCK(&acache->entrylocks[entry->locknum], isc_rwlocktype_write); + callback_active = ISC_TF(entry->cbarg != NULL); + /* * Release dependencies stored in this entry as much as possible. * The main link cannot be released, since the acache object has diff --git a/lib/dns/acl.c b/lib/dns/acl.c index 3221d30c2b52a..dbc6f9cb4f3af 100644 --- a/lib/dns/acl.c +++ b/lib/dns/acl.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2009, 2011, 2013 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009, 2011, 2013, 2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -291,8 +291,8 @@ dns_acl_merge(dns_acl_t *dest, dns_acl_t *source, isc_boolean_t pos) return (ISC_R_NOMEMORY); /* Copy in the original elements */ - memcpy(newmem, dest->elements, - dest->length * sizeof(dns_aclelement_t)); + memmove(newmem, dest->elements, + dest->length * sizeof(dns_aclelement_t)); /* Release the memory for the old elements array */ isc_mem_put(dest->mctx, dest->elements, diff --git a/lib/dns/adb.c b/lib/dns/adb.c index ef7875dcb46ba..10d51bc441433 100644 --- a/lib/dns/adb.c +++ b/lib/dns/adb.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2013 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -852,12 +852,12 @@ import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset, dns_rdataset_current(rdataset, &rdata); if (rdtype == dns_rdatatype_a) { INSIST(rdata.length == 4); - memcpy(&ina.s_addr, rdata.data, 4); + memmove(&ina.s_addr, rdata.data, 4); isc_sockaddr_fromin(&sockaddr, &ina, 0); hookhead = &adbname->v4; } else { INSIST(rdata.length == 16); - memcpy(in6a.s6_addr, rdata.data, 16); + memmove(in6a.s6_addr, rdata.data, 16); isc_sockaddr_fromin6(&sockaddr, &in6a, 0); hookhead = &adbname->v6; } diff --git a/lib/dns/api b/lib/dns/api index a8881101f4e1a..cc5437d0be7b5 100644 --- a/lib/dns/api +++ b/lib/dns/api @@ -4,6 +4,6 @@ # 9.8: 80-89, 120-129 # 9.9: 90-109 # 9.9-sub: 130-139 -LIBINTERFACE = 99 -LIBREVISION = 1 -LIBAGE = 0 +LIBINTERFACE = 102 +LIBREVISION = 2 +LIBAGE = 2 diff --git a/lib/dns/client.c b/lib/dns/client.c index fc551cf9dfe57..cee4fb268d71a 100644 --- a/lib/dns/client.c +++ b/lib/dns/client.c @@ -249,13 +249,14 @@ static isc_result_t send_update(updatectx_t *uctx); static isc_result_t getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr, isc_socketmgr_t *socketmgr, isc_taskmgr_t *taskmgr, - isc_boolean_t is_shared, dns_dispatch_t **dispp) + isc_boolean_t is_shared, dns_dispatch_t **dispp, + isc_sockaddr_t *localaddr) { unsigned int attrs, attrmask; - isc_sockaddr_t sa; dns_dispatch_t *disp; unsigned buffersize, maxbuffers, maxrequests, buckets, increment; isc_result_t result; + isc_sockaddr_t anyaddr; attrs = 0; attrs |= DNS_DISPATCHATTR_UDP; @@ -275,7 +276,10 @@ getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr, attrmask |= DNS_DISPATCHATTR_IPV4; attrmask |= DNS_DISPATCHATTR_IPV6; - isc_sockaddr_anyofpf(&sa, family); + if (localaddr == NULL) { + localaddr = &anyaddr; + isc_sockaddr_anyofpf(localaddr, family); + } buffersize = 4096; maxbuffers = is_shared ? 1000 : 8; @@ -285,7 +289,7 @@ getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr, disp = NULL; result = dns_dispatch_getudp(dispatchmgr, socketmgr, - taskmgr, &sa, + taskmgr, localaddr, buffersize, maxbuffers, maxrequests, buckets, increment, attrs, attrmask, &disp); @@ -422,6 +426,19 @@ dns_client_createx(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr, unsigned int options, dns_client_t **clientp) { + isc_result_t result; + result = dns_client_createx2(mctx, actx, taskmgr, socketmgr, timermgr, + options, clientp, NULL, NULL); + return (result); +} + +isc_result_t +dns_client_createx2(isc_mem_t *mctx, isc_appctx_t *actx, + isc_taskmgr_t *taskmgr, isc_socketmgr_t *socketmgr, + isc_timermgr_t *timermgr, unsigned int options, + dns_client_t **clientp, isc_sockaddr_t *localaddr4, + isc_sockaddr_t *localaddr6) +{ dns_client_t *client; isc_result_t result; dns_dispatchmgr_t *dispatchmgr = NULL; @@ -460,17 +477,27 @@ dns_client_createx(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, goto cleanup; client->dispatchmgr = dispatchmgr; - /* TODO: whether to use dispatch v4 or v6 should be configurable */ + /* + * If only one address family is specified, use it. + * If neither family is specified, or if both are, use both. + */ client->dispatchv4 = NULL; + if (localaddr4 != NULL || localaddr6 == NULL) { + result = getudpdispatch(AF_INET, dispatchmgr, socketmgr, + taskmgr, ISC_TRUE, + &dispatchv4, localaddr4); + if (result == ISC_R_SUCCESS) + client->dispatchv4 = dispatchv4; + } + client->dispatchv6 = NULL; - result = getudpdispatch(AF_INET, dispatchmgr, socketmgr, - taskmgr, ISC_TRUE, &dispatchv4); - if (result == ISC_R_SUCCESS) - client->dispatchv4 = dispatchv4; - result = getudpdispatch(AF_INET6, dispatchmgr, socketmgr, - taskmgr, ISC_TRUE, &dispatchv6); - if (result == ISC_R_SUCCESS) - client->dispatchv6 = dispatchv6; + if (localaddr6 != NULL || localaddr4 == NULL) { + result = getudpdispatch(AF_INET6, dispatchmgr, socketmgr, + taskmgr, ISC_TRUE, + &dispatchv6, localaddr6); + if (result == ISC_R_SUCCESS) + client->dispatchv6 = dispatchv6; + } /* We need at least one of the dispatchers */ if (dispatchv4 == NULL && dispatchv6 == NULL) { @@ -1094,11 +1121,23 @@ client_resfind(resctx_t *rctx, dns_fetchevent_t *event) { UNLOCK(&rctx->lock); } + +static void +suspend(isc_task_t *task, isc_event_t *event) { + isc_appctx_t *actx = event->ev_arg; + + UNUSED(task); + + isc_app_ctxsuspend(actx); + isc_event_free(&event); +} + static void resolve_done(isc_task_t *task, isc_event_t *event) { resarg_t *resarg = event->ev_arg; dns_clientresevent_t *rev = (dns_clientresevent_t *)event; dns_name_t *name; + isc_result_t result; UNUSED(task); @@ -1117,8 +1156,16 @@ resolve_done(isc_task_t *task, isc_event_t *event) { if (!resarg->canceled) { UNLOCK(&resarg->lock); - /* Exit from the internal event loop */ - isc_app_ctxsuspend(resarg->actx); + /* + * We may or may not be running. isc__appctx_onrun will + * fail if we are currently running otherwise we post a + * action to call isc_app_ctxsuspend when we do start + * running. + */ + result = isc_app_ctxonrun(resarg->actx, resarg->client->mctx, + task, suspend, resarg->actx); + if (result == ISC_R_ALREADYRUNNING) + isc_app_ctxsuspend(resarg->actx); } else { /* * We have already exited from the loop (due to some @@ -1310,9 +1357,8 @@ dns_client_startresolve(dns_client_t *client, dns_name_t *name, ISC_LIST_APPEND(client->resctxs, rctx, link); UNLOCK(&client->lock); - client_resfind(rctx, NULL); - *transp = (dns_clientrestrans_t *)rctx; + client_resfind(rctx, NULL); return (ISC_R_SUCCESS); diff --git a/lib/dns/diff.c b/lib/dns/diff.c index ff60d462f3727..4517dade38dc8 100644 --- a/lib/dns/diff.c +++ b/lib/dns/diff.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007-2009, 2011, 2013 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007-2009, 2011, 2013, 2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -79,7 +79,7 @@ dns_difftuple_create(isc_mem_t *mctx, datap = (unsigned char *)(t + 1); - memcpy(datap, name->ndata, name->length); + memmove(datap, name->ndata, name->length); dns_name_init(&t->name, NULL); dns_name_clone(name, &t->name); t->name.ndata = datap; @@ -87,7 +87,7 @@ dns_difftuple_create(isc_mem_t *mctx, t->ttl = ttl; - memcpy(datap, rdata->data, rdata->length); + memmove(datap, rdata->data, rdata->length); dns_rdata_init(&t->rdata); dns_rdata_clone(rdata, &t->rdata); t->rdata.data = datap; @@ -379,15 +379,6 @@ diff_apply(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver, diff->resign); dns_db_setsigningtime(db, modified, resign); - if (diff->resign == 0 && - (op == DNS_DIFFOP_ADDRESIGN || - op == DNS_DIFFOP_DELRESIGN)) - isc_log_write( - DIFF_COMMON_LOGARGS, - ISC_LOG_WARNING, - "resign requested " - "with 0 resign " - "interval"); } } else if (result == DNS_R_UNCHANGED) { /* diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index 5063914a9b296..7af8e644b1971 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2009, 2011-2013 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009, 2011-2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -706,8 +706,8 @@ destroy_disp_ok(dns_dispatch_t *disp) /* * Called when refcount reaches 0 (and safe to destroy). * - * The dispatcher must not be locked. - * The manager must be locked. + * The dispatcher must be locked. + * The manager must not be locked. */ static void destroy_disp(isc_task_t *task, isc_event_t *event) { @@ -778,6 +778,7 @@ port_search(dns_dispatch_t *disp, in_port_t port) { static dispportentry_t * new_portentry(dns_dispatch_t *disp, in_port_t port) { dispportentry_t *portentry; + dns_qid_t *qid; REQUIRE(disp->port_table != NULL); @@ -786,10 +787,13 @@ new_portentry(dns_dispatch_t *disp, in_port_t port) { return (portentry); portentry->port = port; - portentry->refs = 0; + portentry->refs = 1; ISC_LINK_INIT(portentry, link); + qid = DNS_QID(disp); + LOCK(&qid->lock); ISC_LIST_APPEND(disp->port_table[port % DNS_DISPATCH_PORTTABLESIZE], portentry, link); + UNLOCK(&qid->lock); return (portentry); } @@ -800,7 +804,6 @@ new_portentry(dns_dispatch_t *disp, in_port_t port) { static void deref_portentry(dns_dispatch_t *disp, dispportentry_t **portentryp) { dispportentry_t *portentry = *portentryp; - isc_boolean_t unlink = ISC_FALSE; dns_qid_t *qid; REQUIRE(disp->port_table != NULL); @@ -809,15 +812,14 @@ deref_portentry(dns_dispatch_t *disp, dispportentry_t **portentryp) { qid = DNS_QID(disp); LOCK(&qid->lock); portentry->refs--; - unlink = ISC_TF(portentry->refs == 0); - UNLOCK(&qid->lock); - if (unlink) { + if (portentry->refs == 0) { ISC_LIST_UNLINK(disp->port_table[portentry->port % DNS_DISPATCH_PORTTABLESIZE], portentry, link); isc_mempool_put(disp->portpool, portentry); } + UNLOCK(&qid->lock); *portentryp = NULL; } @@ -832,6 +834,7 @@ socket_search(dns_qid_t *qid, isc_sockaddr_t *dest, in_port_t port, { dispsocket_t *dispsock; + REQUIRE(VALID_QID(qid)); REQUIRE(bucket < qid->qid_nbuckets); dispsock = ISC_LIST_HEAD(qid->sock_table[bucket]); @@ -938,8 +941,11 @@ get_dispsocket(dns_dispatch_t *disp, isc_sockaddr_t *dest, result = ISC_R_NOMEMORY; break; } + } else { + LOCK(&qid->lock); + portentry->refs++; + UNLOCK(&qid->lock); } - portentry->refs++; break; } else if (result == ISC_R_NOPERM) { char buf[ISC_SOCKADDR_FORMATSIZE]; @@ -1076,6 +1082,7 @@ entry_search(dns_qid_t *qid, isc_sockaddr_t *dest, dns_messageid_t id, { dns_dispentry_t *res; + REQUIRE(VALID_QID(qid)); REQUIRE(bucket < qid->qid_nbuckets); res = ISC_LIST_HEAD(qid->qid_table[bucket]); @@ -1428,8 +1435,8 @@ udp_recv(isc_event_t *ev_in, dns_dispatch_t *disp, dispsocket_t *dispsock) { } /* - * If both dispatches are bound to an address then fail as - * the addresses can't be equal (enforced by the IP stack). + * If each dispatch is bound to a different address + * then fail. * * Note under Linux a packet can be sent out via IPv4 socket * and the response be received via a IPv6 socket. @@ -1444,7 +1451,8 @@ udp_recv(isc_event_t *ev_in, dns_dispatch_t *disp, dispsocket_t *dispsock) { } isc_sockaddr_anyofpf(&a1, isc_sockaddr_pf(&resp->disp->local)); isc_sockaddr_anyofpf(&a2, isc_sockaddr_pf(&disp->local)); - if (!isc_sockaddr_eqaddr(&a1, &resp->disp->local) && + if (!isc_sockaddr_eqaddr(&disp->local, &resp->disp->local) && + !isc_sockaddr_eqaddr(&a1, &resp->disp->local) && !isc_sockaddr_eqaddr(&a2, &disp->local)) { free_buffer(disp, ev->region.base, ev->region.length); goto unlock; @@ -2647,8 +2655,7 @@ dispatch_allocate(dns_dispatchmgr_t *mgr, unsigned int maxrequests, * MUST be unlocked, and not used by anything. */ static void -dispatch_free(dns_dispatch_t **dispp) -{ +dispatch_free(dns_dispatch_t **dispp) { dns_dispatch_t *disp; dns_dispatchmgr_t *mgr; int i; @@ -3311,17 +3318,17 @@ dns_dispatch_addresponse2(dns_dispatch_t *disp, isc_sockaddr_t *dest, */ LOCK(&qid->lock); id = (dns_messageid_t)dispatch_random(DISP_ARC4CTX(disp)); - bucket = dns_hash(qid, dest, id, localport); ok = ISC_FALSE; - for (i = 0; i < 64; i++) { + i = 0; + do { + bucket = dns_hash(qid, dest, id, localport); if (entry_search(qid, dest, id, localport, bucket) == NULL) { ok = ISC_TRUE; break; } id += qid->qid_increment; id &= 0x0000ffff; - bucket = dns_hash(qid, dest, id, localport); - } + } while (i++ < 64); UNLOCK(&qid->lock); if (!ok) { @@ -3331,9 +3338,9 @@ dns_dispatch_addresponse2(dns_dispatch_t *disp, isc_sockaddr_t *dest, res = isc_mempool_get(disp->mgr->rpool); if (res == NULL) { - UNLOCK(&disp->lock); if (dispsocket != NULL) destroy_dispsocket(disp, &dispsocket); + UNLOCK(&disp->lock); return (ISC_R_NOMEMORY); } @@ -3708,7 +3715,7 @@ dns_dispatch_importrecv(dns_dispatch_t *disp, isc_event_t *event) { isc_event_free(ISC_EVENT_PTR(&newsevent)); return; } - memcpy(buf, sevent->region.base, sevent->n); + memmove(buf, sevent->region.base, sevent->n); newsevent->region.base = buf; newsevent->region.length = disp->mgr->buffersize; newsevent->n = sevent->n; diff --git a/lib/dns/dns64.c b/lib/dns/dns64.c index 78eff579a2bac..7d47c66933b54 100644 --- a/lib/dns/dns64.c +++ b/lib/dns/dns64.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010, 2011 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2010, 2011, 2014 Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -83,10 +83,10 @@ dns_dns64_create(isc_mem_t *mctx, isc_netaddr_t *prefix, if (new == NULL) return (ISC_R_NOMEMORY); memset(new->bits, 0, sizeof(new->bits)); - memcpy(new->bits, prefix->type.in6.s6_addr, prefixlen / 8); + memmove(new->bits, prefix->type.in6.s6_addr, prefixlen / 8); if (suffix != NULL) - memcpy(new->bits + nbytes, suffix->type.in6.s6_addr + nbytes, - 16 - nbytes); + memmove(new->bits + nbytes, suffix->type.in6.s6_addr + nbytes, + 16 - nbytes); new->clients = NULL; if (clients != NULL) dns_acl_attach(clients, &new->clients); @@ -155,7 +155,7 @@ dns_dns64_aaaafroma(const dns_dns64_t *dns64, const isc_netaddr_t *reqaddr, struct in_addr ina; isc_netaddr_t netaddr; - memcpy(&ina.s_addr, a, 4); + memmove(&ina.s_addr, a, 4); isc_netaddr_fromin(&netaddr, &ina); result = dns_acl_match(&netaddr, NULL, dns64->mapped, env, &match, NULL); @@ -168,7 +168,7 @@ dns_dns64_aaaafroma(const dns_dns64_t *dns64, const isc_netaddr_t *reqaddr, nbytes = dns64->prefixlen / 8; INSIST(nbytes <= 12); /* Copy prefix. */ - memcpy(aaaa, dns64->bits, nbytes); + memmove(aaaa, dns64->bits, nbytes); /* Bits 64-71 are zeros. draft-ietf-behave-address-format-04 */ if (nbytes == 8) aaaa[nbytes++] = 0; @@ -180,7 +180,7 @@ dns_dns64_aaaafroma(const dns_dns64_t *dns64, const isc_netaddr_t *reqaddr, aaaa[nbytes++] = 0; } /* Copy suffix. */ - memcpy(aaaa + nbytes, dns64->bits + nbytes, 16 - nbytes); + memmove(aaaa + nbytes, dns64->bits + nbytes, 16 - nbytes); return (ISC_R_SUCCESS); } @@ -268,7 +268,7 @@ dns_dns64_aaaaok(const dns_dns64_t *dns64, const isc_netaddr_t *reqaddr, if (aaaaok == NULL || !aaaaok[i]) { dns_rdataset_current(rdataset, &rdata); - memcpy(&in6.s6_addr, rdata.data, 16); + memmove(&in6.s6_addr, rdata.data, 16); isc_netaddr_fromin6(&netaddr, &in6); result = dns_acl_match(&netaddr, NULL, diff --git a/lib/dns/dnssec.c b/lib/dns/dnssec.c index d00c99b4124c0..d7addc681430a 100644 --- a/lib/dns/dnssec.c +++ b/lib/dns/dnssec.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -295,7 +295,7 @@ dns_dnssec_sign(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, * Create an envelope for each rdata: <name|type|class|ttl>. */ isc_buffer_init(&envbuf, data, sizeof(data)); - memcpy(data, r.base, r.length); + memmove(data, r.base, r.length); isc_buffer_add(&envbuf, r.length); isc_buffer_putuint16(&envbuf, set->type); isc_buffer_putuint16(&envbuf, set->rdclass); @@ -501,10 +501,10 @@ dns_dnssec_verify3(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, if (labels - sig.labels > 0) { isc_buffer_putuint8(&envbuf, 1); isc_buffer_putuint8(&envbuf, '*'); - memcpy(data + 2, r.base, r.length); + memmove(data + 2, r.base, r.length); } else - memcpy(data, r.base, r.length); + memmove(data, r.base, r.length); isc_buffer_add(&envbuf, r.length); isc_buffer_putuint16(&envbuf, set->type); isc_buffer_putuint16(&envbuf, set->rdclass); @@ -609,8 +609,8 @@ dns_dnssec_verify(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, return (result); } -static isc_boolean_t -key_active(dst_key_t *key, isc_stdtime_t now) { +isc_boolean_t +dns_dnssec_keyactive(dst_key_t *key, isc_stdtime_t now) { isc_result_t result; isc_stdtime_t publish, active, revoke, inactive, delete; isc_boolean_t pubset = ISC_FALSE, actset = ISC_FALSE; @@ -684,6 +684,7 @@ dns_dnssec_findzonekeys2(dns_db_t *db, dns_dbversion_t *ver, isc_stdtime_get(&now); *nkeys = 0; + memset(keys, 0, sizeof(*keys) * maxkeys); dns_rdataset_init(&rdataset); RETERR(dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey, 0, 0, &rdataset, NULL)); @@ -763,7 +764,8 @@ dns_dnssec_findzonekeys2(dns_db_t *db, dns_dbversion_t *ver, /* * If a key is marked inactive, skip it */ - if (!key_active(keys[count], now)) { + if (!dns_dnssec_keyactive(keys[count], now)) { + dst_key_setinactive(pubkey, ISC_TRUE); dst_key_free(&keys[count]); keys[count] = pubkey; pubkey = NULL; @@ -1038,14 +1040,14 @@ dns_dnssec_verifymessage(isc_buffer_t *source, dns_message_t *msg, /* * Extract the header. */ - memcpy(header, source_r.base, DNS_MESSAGE_HEADERLEN); + memmove(header, source_r.base, DNS_MESSAGE_HEADERLEN); /* * Decrement the additional field counter. */ - memcpy(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2); + memmove(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2); addcount = htons((isc_uint16_t)(ntohs(addcount) - 1)); - memcpy(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2); + memmove(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2); /* * Digest the modified header. @@ -1311,9 +1313,9 @@ dns_dnssec_findmatchingkeys(dns_name_t *origin, const char *directory, isc_dir_t dir; dns_dnsseckey_t *key = NULL; dst_key_t *dstkey = NULL; - char namebuf[DNS_NAME_FORMATSIZE], *p; + char namebuf[DNS_NAME_FORMATSIZE]; isc_buffer_t b; - unsigned int len; + unsigned int len, i; isc_stdtime_t now; REQUIRE(keylist != NULL); @@ -1333,49 +1335,62 @@ dns_dnssec_findmatchingkeys(dns_name_t *origin, const char *directory, isc_stdtime_get(&now); while (isc_dir_read(&dir) == ISC_R_SUCCESS) { - if (dir.entry.name[0] == 'K' && - dir.entry.length > len + 1 && - dir.entry.name[len + 1] == '+' && - strncasecmp(dir.entry.name + 1, namebuf, len) == 0) { - p = strrchr(dir.entry.name, '.'); - if (p != NULL && strcmp(p, ".private") != 0) - continue; + if (dir.entry.name[0] != 'K' || + dir.entry.length < len + 1 || + dir.entry.name[len + 1] != '+' || + strncasecmp(dir.entry.name + 1, namebuf, len) != 0) + continue; - dstkey = NULL; - result = dst_key_fromnamedfile(dir.entry.name, - directory, - DST_TYPE_PUBLIC | - DST_TYPE_PRIVATE, - mctx, &dstkey); - - if (result != ISC_R_SUCCESS) { - isc_log_write(dns_lctx, - DNS_LOGCATEGORY_GENERAL, - DNS_LOGMODULE_DNSSEC, - ISC_LOG_WARNING, - "dns_dnssec_findmatchingkeys: " - "error reading key file %s: %s", - dir.entry.name, - isc_result_totext(result)); + for (i = len + 1 + 1; i < dir.entry.length ; i++) + if (dir.entry.name[i] < '0' || dir.entry.name[i] > '9') + break; + + if (i == len + 1 + 1 || i >= dir.entry.length || + dir.entry.name[i] != '+') + continue; + + for (i++ ; i < dir.entry.length ; i++) + if (dir.entry.name[i] < '0' || dir.entry.name[i] > '9') + break; + + if (strcmp(dir.entry.name + i, ".private") != 0) continue; - } - RETERR(dns_dnsseckey_create(mctx, &dstkey, &key)); - key->source = dns_keysource_repository; - get_hints(key, now); + dstkey = NULL; + result = dst_key_fromnamedfile(dir.entry.name, + directory, + DST_TYPE_PUBLIC | + DST_TYPE_PRIVATE, + mctx, &dstkey); - if (key->legacy) { - dns_dnsseckey_destroy(mctx, &key); - } else { - ISC_LIST_APPEND(list, key, link); - key = NULL; - } + if (result != ISC_R_SUCCESS) { + isc_log_write(dns_lctx, + DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_DNSSEC, + ISC_LOG_WARNING, + "dns_dnssec_findmatchingkeys: " + "error reading key file %s: %s", + dir.entry.name, + isc_result_totext(result)); + continue; + } + + RETERR(dns_dnsseckey_create(mctx, &dstkey, &key)); + key->source = dns_keysource_repository; + get_hints(key, now); + + if (key->legacy) { + dns_dnsseckey_destroy(mctx, &key); + } else { + ISC_LIST_APPEND(list, key, link); + key = NULL; } } - if (!ISC_LIST_EMPTY(list)) + if (!ISC_LIST_EMPTY(list)) { + result = ISC_R_SUCCESS; ISC_LIST_APPENDLIST(*keylist, list, link); - else + } else result = ISC_R_NOTFOUND; failure: @@ -1793,7 +1808,13 @@ dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys, for (key2 = ISC_LIST_HEAD(*keys); key2 != NULL; key2 = ISC_LIST_NEXT(key2, link)) { - if (dst_key_pubcompare(key1->key, key2->key, + int f1 = dst_key_flags(key1->key); + int f2 = dst_key_flags(key2->key); + int nr1 = f1 & ~DNS_KEYFLAG_REVOKE; + int nr2 = f2 & ~DNS_KEYFLAG_REVOKE; + if (nr1 == nr2 && + dst_key_alg(key1->key) == dst_key_alg(key2->key) && + dst_key_pubcompare(key1->key, key2->key, ISC_TRUE)) { int r1, r2; r1 = dst_key_flags(key1->key) & diff --git a/lib/dns/dst_api.c b/lib/dns/dst_api.c index 98607246effcf..6416273760470 100644 --- a/lib/dns/dst_api.c +++ b/lib/dns/dst_api.c @@ -443,6 +443,16 @@ dst_key_tofile(const dst_key_t *key, int type, const char *directory) { return (ISC_R_SUCCESS); } +void +dst_key_setexternal(dst_key_t *key, isc_boolean_t value) { + key->external = value; +} + +isc_boolean_t +dst_key_isexternal(dst_key_t *key) { + return (key->external); +} + isc_result_t dst_key_fromfile(dns_name_t *name, dns_keytag_t id, unsigned int alg, int type, const char *directory, @@ -1349,10 +1359,27 @@ get_key_struct(dns_name_t *name, unsigned int alg, key->times[i] = 0; key->timeset[i] = ISC_FALSE; } + key->inactive = ISC_FALSE; key->magic = KEY_MAGIC; return (key); } +isc_boolean_t +dst_key_inactive(const dst_key_t *key) { + + REQUIRE(VALID_KEY(key)); + + return (key->inactive); +} + +void +dst_key_setinactive(dst_key_t *key, isc_boolean_t inactive) { + + REQUIRE(VALID_KEY(key)); + + key->inactive = inactive; +} + /*% * Reads a public key from disk */ diff --git a/lib/dns/dst_internal.h b/lib/dns/dst_internal.h index c3e8e29a46e8e..49ca424e5b990 100644 --- a/lib/dns/dst_internal.h +++ b/lib/dns/dst_internal.h @@ -1,5 +1,5 @@ /* - * Portions Copyright (C) 2004-2012 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 2004-2013 Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (C) 2000-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -126,6 +126,9 @@ struct dst_key { isc_boolean_t timeset[DST_MAX_TIMES + 1]; /*%< data set? */ isc_stdtime_t nums[DST_MAX_NUMERIC + 1]; /*%< numeric metadata */ isc_boolean_t numset[DST_MAX_NUMERIC + 1]; /*%< data set? */ + isc_boolean_t inactive; /*%< private key not present as it is + inactive */ + isc_boolean_t external; /*%< external key */ int fmt_major; /*%< private key format, major version */ int fmt_minor; /*%< private key format, minor version */ diff --git a/lib/dns/dst_parse.c b/lib/dns/dst_parse.c index ca43cb3d12414..2b950d5a3b9cf 100644 --- a/lib/dns/dst_parse.c +++ b/lib/dns/dst_parse.c @@ -1,5 +1,5 @@ /* - * Portions Copyright (C) 2004-2012 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 2004-2013 Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -178,14 +178,18 @@ find_numericdata(const char *s) { } static int -check_rsa(const dst_private_t *priv) { +check_rsa(const dst_private_t *priv, isc_boolean_t external) { int i, j; isc_boolean_t have[RSA_NTAGS]; isc_boolean_t ok; unsigned int mask; + if (external) + return ((priv->nelements == 0) ? 0 : -1); + for (i = 0; i < RSA_NTAGS; i++) have[i] = ISC_FALSE; + for (j = 0; j < priv->nelements; j++) { for (i = 0; i < RSA_NTAGS; i++) if (priv->elements[j].tag == TAG(DST_ALG_RSAMD5, i)) @@ -231,10 +235,15 @@ check_dh(const dst_private_t *priv) { } static int -check_dsa(const dst_private_t *priv) { +check_dsa(const dst_private_t *priv, isc_boolean_t external) { int i, j; + + if (external) + return ((priv->nelements == 0)? 0 : -1); + if (priv->nelements != DSA_NTAGS) return (-1); + for (i = 0; i < DSA_NTAGS; i++) { for (j = 0; j < priv->nelements; j++) if (priv->elements[j].tag == TAG(DST_ALG_DSA, i)) @@ -246,7 +255,11 @@ check_dsa(const dst_private_t *priv) { } static int -check_gost(const dst_private_t *priv) { +check_gost(const dst_private_t *priv, isc_boolean_t external) { + + if (external) + return ((priv->nelements == 0)? 0 : -1); + if (priv->nelements != GOST_NTAGS) return (-1); if (priv->elements[0].tag != TAG(DST_ALG_ECCGOST, 0)) @@ -255,7 +268,11 @@ check_gost(const dst_private_t *priv) { } static int -check_ecdsa(const dst_private_t *priv) { +check_ecdsa(const dst_private_t *priv, isc_boolean_t external) { + + if (external) + return ((priv->nelements == 0) ? 0 : -1); + if (priv->nelements != ECDSA_NTAGS) return (-1); if (priv->elements[0].tag != TAG(DST_ALG_ECDSA256, 0)) @@ -309,7 +326,7 @@ check_hmac_sha(const dst_private_t *priv, unsigned int ntags, static int check_data(const dst_private_t *priv, const unsigned int alg, - isc_boolean_t old) + isc_boolean_t old, isc_boolean_t external) { /* XXXVIX this switch statement is too sparse to gen a jump table. */ switch (alg) { @@ -318,17 +335,17 @@ check_data(const dst_private_t *priv, const unsigned int alg, case DST_ALG_NSEC3RSASHA1: case DST_ALG_RSASHA256: case DST_ALG_RSASHA512: - return (check_rsa(priv)); + return (check_rsa(priv, external)); case DST_ALG_DH: return (check_dh(priv)); case DST_ALG_DSA: case DST_ALG_NSEC3DSA: - return (check_dsa(priv)); + return (check_dsa(priv, external)); case DST_ALG_ECCGOST: - return (check_gost(priv)); + return (check_gost(priv, external)); case DST_ALG_ECDSA256: case DST_ALG_ECDSA384: - return (check_ecdsa(priv)); + return (check_ecdsa(priv, external)); case DST_ALG_HMACMD5: return (check_hmac_md5(priv, old)); case DST_ALG_HMACSHA1: @@ -372,6 +389,7 @@ dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex, unsigned int opt = ISC_LEXOPT_EOL; isc_stdtime_t when; isc_result_t ret; + isc_boolean_t external = ISC_FALSE; REQUIRE(priv != NULL); @@ -470,6 +488,11 @@ dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex, goto fail; } + if (strcmp(DST_AS_STR(token), "External:") == 0) { + external = ISC_TRUE; + goto next; + } + /* Numeric metadata */ tag = find_numericdata(DST_AS_STR(token)); if (tag >= 0) { @@ -534,8 +557,14 @@ dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex, READLINE(lex, opt, &token); data = NULL; } + done: - check = check_data(priv, alg, ISC_TRUE); + if (external && priv->nelements != 0) { + ret = DST_R_INVALIDPRIVATEKEY; + goto fail; + } + + check = check_data(priv, alg, ISC_TRUE, external); if (check < 0) { ret = DST_R_INVALIDPRIVATEKEY; goto fail; @@ -544,6 +573,8 @@ dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex, goto fail; } + key->external = external; + return (ISC_R_SUCCESS); fail: @@ -573,7 +604,7 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv, REQUIRE(priv != NULL); - ret = check_data(priv, dst_key_alg(key), ISC_FALSE); + ret = check_data(priv, dst_key_alg(key), ISC_FALSE, key->external); if (ret < 0) return (DST_R_INVALIDPRIVATEKEY); else if (ret != ISC_R_SUCCESS) @@ -691,6 +722,9 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv, fprintf(fp, "%s %.*s\n", s, (int)r.length, r.base); } + if (key->external) + fprintf(fp, "External:\n"); + /* Add the metadata tags */ if (major > 1 || (major == 1 && minor >= 3)) { for (i = 0; i < NUMERIC_NTAGS; i++) { @@ -706,14 +740,14 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv, isc_buffer_init(&b, buffer, sizeof(buffer)); result = dns_time32_totext(when, &b); - if (result != ISC_R_SUCCESS) { + if (result != ISC_R_SUCCESS) { fclose(fp); return (DST_R_INVALIDPRIVATEKEY); - } + } isc_buffer_usedregion(&b, &r); - fprintf(fp, "%s %.*s\n", timetags[i], (int)r.length, + fprintf(fp, "%s %.*s\n", timetags[i], (int)r.length, r.base); } } diff --git a/lib/dns/dst_result.c b/lib/dns/dst_result.c index 297e809cc9453..e9f7b06ab2521 100644 --- a/lib/dns/dst_result.c +++ b/lib/dns/dst_result.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007, 2008, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2008, 2012, 2013 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -35,7 +35,7 @@ static const char *text[DST_R_NRESULTS] = { "illegal operation for a null key", /*%< 3 */ "public key is invalid", /*%< 4 */ "private key is invalid", /*%< 5 */ - "UNUSED6", /*%< 6 */ + "external key", /*%< 6 */ "error occurred writing key to disk", /*%< 7 */ "invalid algorithm specific parameter", /*%< 8 */ "UNUSED9", /*%< 9 */ diff --git a/lib/dns/gen.c b/lib/dns/gen.c index 6b533dd23f9c7..b934c9990fb3f 100644 --- a/lib/dns/gen.c +++ b/lib/dns/gen.c @@ -309,7 +309,8 @@ find_typename(int type) { static void insert_into_typenames(int type, const char *typename, const char *attr) { struct ttnam *ttn = NULL; - int c, i, n; + size_t c; + int i, n; char tmp[256]; INSIST(strlen(typename) < TYPECLASSBUF); @@ -485,7 +486,7 @@ sd(int rdclass, const char *classname, const char *dirname, char filetype) { static unsigned int HASH(char *string) { - unsigned int n; + size_t n; unsigned char a, b; n = strlen(string); @@ -779,6 +780,14 @@ main(int argc, char **argv) { ttn = find_typename(i); if (ttn == NULL) continue; + /* + * Remove KEYDATA (65533) from the type to memonic + * translation as it is internal use only. This + * stops the tools from displaying KEYDATA instead + * of TYPE65533. + */ + if (i == 65533U) + continue; fprintf(stdout, "\tcase %u: return " "(str_totext(\"%s\", target)); \\\n", i, upper(ttn->typename)); diff --git a/lib/dns/gssapi_link.c b/lib/dns/gssapi_link.c index 5ad81cd80ced3..2927b676d3665 100644 --- a/lib/dns/gssapi_link.c +++ b/lib/dns/gssapi_link.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009, 2011-2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -47,7 +47,7 @@ #define GBUFFER_TO_REGION(gb, r) \ do { \ - (r).length = (gb).length; \ + (r).length = (unsigned int)(gb).length; \ (r).base = (gb).value; \ } while (0) @@ -180,7 +180,7 @@ gssapi_sign(dst_context_t *dctx, isc_buffer_t *sig) { * Copy the output into our buffer space, and release the gssapi * allocated space. */ - isc_buffer_putmem(sig, gsig.value, gsig.length); + isc_buffer_putmem(sig, gsig.value, (unsigned int)gsig.length); if (gsig.length != 0U) gss_release_buffer(&minor, &gsig); @@ -216,7 +216,7 @@ gssapi_verify(dst_context_t *dctx, const isc_region_t *sig) { buf = isc_mem_allocate(dst__memory_pool, sig->length); if (buf == NULL) return (ISC_R_FAILURE); - memcpy(buf, sig->base, sig->length); + memmove(buf, sig->base, sig->length); r.base = buf; r.length = sig->length; REGION_TO_GBUFFER(r, gsig); @@ -286,7 +286,7 @@ gssapi_destroy(dst_key_t *key) { static isc_result_t gssapi_restore(dst_key_t *key, const char *keystr) { OM_uint32 major, minor; - size_t len; + unsigned int len; isc_buffer_t *b = NULL; isc_region_t r; gss_buffer_desc gssbuffer; @@ -346,13 +346,13 @@ gssapi_dump(dst_key_t *key, isc_mem_t *mctx, char **buffer, int *length) { gss_release_buffer(&minor, &gssbuffer); return (ISC_R_NOMEMORY); } - isc_buffer_init(&b, buf, len); + isc_buffer_init(&b, buf, (unsigned int)len); GBUFFER_TO_REGION(gssbuffer, r); result = isc_base64_totext(&r, 0, "", &b); RUNTIME_CHECK(result == ISC_R_SUCCESS); gss_release_buffer(&minor, &gssbuffer); *buffer = buf; - *length = len; + *length = (int)len; return (ISC_R_SUCCESS); } diff --git a/lib/dns/gssapictx.c b/lib/dns/gssapictx.c index a8c5900e6d14a..d4209d378a76e 100644 --- a/lib/dns/gssapictx.c +++ b/lib/dns/gssapictx.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2013 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -68,8 +68,12 @@ * always use one. If we're not using our own SPNEGO implementation, * we include SPNEGO's OID. */ -#if defined(GSSAPI) +#ifdef GSSAPI +#ifdef WIN32 +#include <krb5/krb5.h> +#else #include ISC_PLATFORM_KRB5HEADER +#endif static unsigned char krb5_mech_oid_bytes[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02 @@ -103,7 +107,7 @@ static gss_OID_set_desc mech_oid_set = { #define GBUFFER_TO_REGION(gb, r) \ do { \ - (r).length = (gb).length; \ + (r).length = (unsigned int)(gb).length; \ (r).base = (gb).value; \ } while (0) @@ -252,12 +256,12 @@ dst_gssapi_acquirecred(dns_name_t *name, isc_boolean_t initiate, gss_cred_id_t *cred) { #ifdef GSSAPI + isc_result_t result; isc_buffer_t namebuf; gss_name_t gname; gss_buffer_desc gnamebuf; unsigned char array[DNS_NAME_MAXTEXT + 1]; OM_uint32 gret, minor; - gss_OID_set mechs; OM_uint32 lifetime; gss_cred_usage_t usage; char buf[1024]; @@ -304,16 +308,17 @@ dst_gssapi_acquirecred(dns_name_t *name, isc_boolean_t initiate, usage = GSS_C_ACCEPT; gret = gss_acquire_cred(&minor, gname, GSS_C_INDEFINITE, - &mech_oid_set, - usage, cred, &mechs, &lifetime); + &mech_oid_set, usage, cred, NULL, &lifetime); if (gret != GSS_S_COMPLETE) { gss_log(3, "failed to acquire %s credentials for %s: %s", initiate ? "initiate" : "accept", (gname != NULL) ? (char *)gnamebuf.value : "?", gss_error_tostring(gret, minor, buf, sizeof(buf))); - check_config((char *)array); - return (ISC_R_FAILURE); + if (gname != NULL) + check_config((char *)array); + result = ISC_R_FAILURE; + goto cleanup; } gss_log(4, "acquired %s credentials for %s", @@ -321,8 +326,18 @@ dst_gssapi_acquirecred(dns_name_t *name, isc_boolean_t initiate, (gname != NULL) ? (char *)gnamebuf.value : "?"); log_cred(*cred); + result = ISC_R_SUCCESS; - return (ISC_R_SUCCESS); +cleanup: + if (gname != NULL) { + gret = gss_release_name(&minor, &gname); + if (gret != GSS_S_COMPLETE) + gss_log(3, "failed gss_release_name: %s", + gss_error_tostring(gret, minor, buf, + sizeof(buf))); + } + + return (result); #else REQUIRE(cred != NULL && *cred == NULL); @@ -620,7 +635,6 @@ dst_gssapi_initctx(dns_name_t *name, isc_buffer_t *intoken, RETERR(isc_buffer_copyregion(outtoken, &r)); (void)gss_release_buffer(&minor, &gouttoken); } - (void)gss_release_name(&minor, &gname); if (gret == GSS_S_COMPLETE) result = ISC_R_SUCCESS; @@ -628,6 +642,7 @@ dst_gssapi_initctx(dns_name_t *name, isc_buffer_t *intoken, result = DNS_R_CONTINUE; out: + (void)gss_release_name(&minor, &gname); return (result); #else UNUSED(name); @@ -669,7 +684,7 @@ dst_gssapi_acceptctx(gss_cred_id_t cred, context = *ctxout; if (gssapi_keytab != NULL) { -#ifdef ISC_PLATFORM_GSSAPI_KRB5_HEADER +#if defined(ISC_PLATFORM_GSSAPI_KRB5_HEADER) || defined(WIN32) gret = gsskrb5_register_acceptor_identity(gssapi_keytab); if (gret != GSS_S_COMPLETE) { gss_log(3, "failed " @@ -730,7 +745,8 @@ dst_gssapi_acceptctx(gss_cred_id_t cred, } if (gouttoken.length > 0U) { - RETERR(isc_buffer_allocate(mctx, outtoken, gouttoken.length)); + RETERR(isc_buffer_allocate(mctx, outtoken, + (unsigned int)gouttoken.length)); GBUFFER_TO_REGION(gouttoken, r); RETERR(isc_buffer_copyregion(*outtoken, &r)); (void)gss_release_buffer(&minor, &gouttoken); diff --git a/lib/dns/hmac_link.c b/lib/dns/hmac_link.c index 256abb6eb475e..d99c5fb00f42c 100644 --- a/lib/dns/hmac_link.c +++ b/lib/dns/hmac_link.c @@ -1,5 +1,5 @@ /* - * Portions Copyright (C) 2004-2012 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 2004-2014 Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -42,6 +42,7 @@ #include <isc/md5.h> #include <isc/sha1.h> #include <isc/mem.h> +#include <isc/safe.h> #include <isc/string.h> #include <isc/util.h> @@ -138,7 +139,7 @@ hmacmd5_compare(const dst_key_t *key1, const dst_key_t *key2) { else if (hkey1 == NULL || hkey2 == NULL) return (ISC_FALSE); - if (memcmp(hkey1->key, hkey2->key, ISC_SHA1_BLOCK_LENGTH) == 0) + if (isc_safe_memcmp(hkey1->key, hkey2->key, ISC_SHA1_BLOCK_LENGTH)) return (ISC_TRUE); else return (ISC_FALSE); @@ -227,9 +228,8 @@ hmacmd5_fromdns(dst_key_t *key, isc_buffer_t *data) { isc_md5_update(&md5ctx, r.base, r.length); isc_md5_final(&md5ctx, hkey->key); keylen = ISC_MD5_DIGESTLENGTH; - } - else { - memcpy(hkey->key, r.base, r.length); + } else { + memmove(hkey->key, r.base, r.length); keylen = r.length; } @@ -415,7 +415,7 @@ hmacsha1_compare(const dst_key_t *key1, const dst_key_t *key2) { else if (hkey1 == NULL || hkey2 == NULL) return (ISC_FALSE); - if (memcmp(hkey1->key, hkey2->key, ISC_SHA1_BLOCK_LENGTH) == 0) + if (isc_safe_memcmp(hkey1->key, hkey2->key, ISC_SHA1_BLOCK_LENGTH)) return (ISC_TRUE); else return (ISC_FALSE); @@ -504,9 +504,8 @@ hmacsha1_fromdns(dst_key_t *key, isc_buffer_t *data) { isc_sha1_update(&sha1ctx, r.base, r.length); isc_sha1_final(&sha1ctx, hkey->key); keylen = ISC_SHA1_DIGESTLENGTH; - } - else { - memcpy(hkey->key, r.base, r.length); + } else { + memmove(hkey->key, r.base, r.length); keylen = r.length; } @@ -692,7 +691,7 @@ hmacsha224_compare(const dst_key_t *key1, const dst_key_t *key2) { else if (hkey1 == NULL || hkey2 == NULL) return (ISC_FALSE); - if (memcmp(hkey1->key, hkey2->key, ISC_SHA224_BLOCK_LENGTH) == 0) + if (isc_safe_memcmp(hkey1->key, hkey2->key, ISC_SHA224_BLOCK_LENGTH)) return (ISC_TRUE); else return (ISC_FALSE); @@ -783,9 +782,8 @@ hmacsha224_fromdns(dst_key_t *key, isc_buffer_t *data) { isc_sha224_update(&sha224ctx, r.base, r.length); isc_sha224_final(hkey->key, &sha224ctx); keylen = ISC_SHA224_DIGESTLENGTH; - } - else { - memcpy(hkey->key, r.base, r.length); + } else { + memmove(hkey->key, r.base, r.length); keylen = r.length; } @@ -971,7 +969,7 @@ hmacsha256_compare(const dst_key_t *key1, const dst_key_t *key2) { else if (hkey1 == NULL || hkey2 == NULL) return (ISC_FALSE); - if (memcmp(hkey1->key, hkey2->key, ISC_SHA256_BLOCK_LENGTH) == 0) + if (isc_safe_memcmp(hkey1->key, hkey2->key, ISC_SHA256_BLOCK_LENGTH)) return (ISC_TRUE); else return (ISC_FALSE); @@ -1062,9 +1060,8 @@ hmacsha256_fromdns(dst_key_t *key, isc_buffer_t *data) { isc_sha256_update(&sha256ctx, r.base, r.length); isc_sha256_final(hkey->key, &sha256ctx); keylen = ISC_SHA256_DIGESTLENGTH; - } - else { - memcpy(hkey->key, r.base, r.length); + } else { + memmove(hkey->key, r.base, r.length); keylen = r.length; } @@ -1250,7 +1247,7 @@ hmacsha384_compare(const dst_key_t *key1, const dst_key_t *key2) { else if (hkey1 == NULL || hkey2 == NULL) return (ISC_FALSE); - if (memcmp(hkey1->key, hkey2->key, ISC_SHA384_BLOCK_LENGTH) == 0) + if (isc_safe_memcmp(hkey1->key, hkey2->key, ISC_SHA384_BLOCK_LENGTH)) return (ISC_TRUE); else return (ISC_FALSE); @@ -1341,9 +1338,8 @@ hmacsha384_fromdns(dst_key_t *key, isc_buffer_t *data) { isc_sha384_update(&sha384ctx, r.base, r.length); isc_sha384_final(hkey->key, &sha384ctx); keylen = ISC_SHA384_DIGESTLENGTH; - } - else { - memcpy(hkey->key, r.base, r.length); + } else { + memmove(hkey->key, r.base, r.length); keylen = r.length; } @@ -1529,7 +1525,7 @@ hmacsha512_compare(const dst_key_t *key1, const dst_key_t *key2) { else if (hkey1 == NULL || hkey2 == NULL) return (ISC_FALSE); - if (memcmp(hkey1->key, hkey2->key, ISC_SHA512_BLOCK_LENGTH) == 0) + if (isc_safe_memcmp(hkey1->key, hkey2->key, ISC_SHA512_BLOCK_LENGTH)) return (ISC_TRUE); else return (ISC_FALSE); @@ -1620,9 +1616,8 @@ hmacsha512_fromdns(dst_key_t *key, isc_buffer_t *data) { isc_sha512_update(&sha512ctx, r.base, r.length); isc_sha512_final(hkey->key, &sha512ctx); keylen = ISC_SHA512_DIGESTLENGTH; - } - else { - memcpy(hkey->key, r.base, r.length); + } else { + memmove(hkey->key, r.base, r.length); keylen = r.length; } diff --git a/lib/dns/include/dns/Makefile.in b/lib/dns/include/dns/Makefile.in index 1a69f2c814f42..6ff682f70d372 100644 --- a/lib/dns/include/dns/Makefile.in +++ b/lib/dns/include/dns/Makefile.in @@ -1,4 +1,4 @@ -# Copyright (C) 2004, 2007-2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") +# Copyright (C) 2004, 2007-2009, 2011, 2012, 2014 Internet Systems Consortium, Inc. ("ISC") # Copyright (C) 1998-2003 Internet Software Consortium. # # Permission to use, copy, modify, and/or distribute this software for any @@ -22,7 +22,8 @@ top_srcdir = @top_srcdir@ @BIND9_VERSION@ HEADERS = acl.h adb.h byaddr.h cache.h callbacks.h cert.h compress.h \ - clientinfo.h db.h dbiterator.h dbtable.h diff.h dispatch.h \ + client.h clientinfo.h compress.h \ + db.h dbiterator.h dbtable.h diff.h dispatch.h \ dlz.h dnssec.h ds.h events.h fixedname.h iptable.h journal.h \ keyflags.h keytable.h keyvalues.h lib.h log.h \ master.h masterdump.h message.h name.h ncache.h nsec.h \ @@ -30,7 +31,7 @@ HEADERS = acl.h adb.h byaddr.h cache.h callbacks.h cert.h compress.h \ rdata.h rdataclass.h rdatalist.h rdataset.h rdatasetiter.h \ rdataslab.h rdatatype.h request.h resolver.h result.h \ rootns.h rpz.h sdb.h sdlz.h secalg.h secproto.h soa.h ssu.h \ - tcpmsg.h time.h tkey.h tsig.h ttl.h types.h \ + tcpmsg.h time.h tkey.h tsec.h tsig.h ttl.h types.h \ validator.h version.h view.h xfrin.h zone.h zonekey.h zt.h GENHEADERS = enumclass.h enumtype.h rdatastruct.h diff --git a/lib/dns/include/dns/client.h b/lib/dns/include/dns/client.h index d21dff788ddea..41baa0d6b9d35 100644 --- a/lib/dns/include/dns/client.h +++ b/lib/dns/include/dns/client.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2009, 2013 Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -149,6 +149,13 @@ isc_result_t dns_client_createx(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr, unsigned int options, dns_client_t **clientp); + +isc_result_t +dns_client_createx2(isc_mem_t *mctx, isc_appctx_t *actx, + isc_taskmgr_t *taskmgr, isc_socketmgr_t *socketmgr, + isc_timermgr_t *timermgr, unsigned int options, + dns_client_t **clientp, + isc_sockaddr_t *localaddr4, isc_sockaddr_t *localaddr6); /*%< * Create a DNS client. These functions create a new client object with * minimal internal resources such as the default 'view' for the IN class and @@ -161,6 +168,12 @@ dns_client_createx(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, * dns_client_create() is expected to be used by an application that only needs * simple synchronous services or by a thread-based application. * + * dns_client_createx2 takes two additional parameters, 'localaddr4' and + * 'localaddr6', to specify the local address to use for each family. If + * both are set to NULL, then wildcard addresses will be used for both + * families. If only one is NULL, then the other address will be used + * as the local address, and the other protocol family will not be used. + * * If the DNS_CLIENTCREATEOPT_USECACHE flag is set in 'options', * dns_client_create(x) will create a cache database with the view. * diff --git a/lib/dns/include/dns/dnssec.h b/lib/dns/include/dns/dnssec.h index e443f91b635b8..7202d99b5da94 100644 --- a/lib/dns/include/dns/dnssec.h +++ b/lib/dns/include/dns/dnssec.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007, 2009-2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009-2013 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -174,6 +174,7 @@ dns_dnssec_findzonekeys(dns_db_t *db, dns_dbversion_t *ver, dns_dbnode_t *node, dns_name_t *name, isc_mem_t *mctx, unsigned int maxkeys, dst_key_t **keys, unsigned int *nkeys); + isc_result_t dns_dnssec_findzonekeys2(dns_db_t *db, dns_dbversion_t *ver, dns_dbnode_t *node, dns_name_t *name, @@ -186,6 +187,20 @@ dns_dnssec_findzonekeys2(dns_db_t *db, dns_dbversion_t *ver, */ /*@}*/ +isc_boolean_t +dns_dnssec_keyactive(dst_key_t *key, isc_stdtime_t now); +/*%< + * + * Returns ISC_TRUE if 'key' is active as of the time specified + * in 'now' (i.e., if the activation date has passed, inactivation or + * deletion date has not yet been reached, and the key is not revoked + * -- or if it is a legacy key without metadata). Otherwise returns + * ISC_FALSE. + * + * Requires: + *\li 'key' is a valid key + */ + isc_result_t dns_dnssec_signmessage(dns_message_t *msg, dst_key_t *key); /*%< diff --git a/lib/dns/include/dns/log.h b/lib/dns/include/dns/log.h index 3c4df8a45003a..e8c8c105473e9 100644 --- a/lib/dns/include/dns/log.h +++ b/lib/dns/include/dns/log.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007, 2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009, 2011-2013 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -43,6 +43,7 @@ LIBDNS_EXTERNAL_DATA extern isc_logmodule_t dns_modules[]; #define DNS_LOGCATEGORY_DELEGATION_ONLY (&dns_categories[10]) #define DNS_LOGCATEGORY_EDNS_DISABLED (&dns_categories[11]) #define DNS_LOGCATEGORY_RPZ (&dns_categories[12]) +#define DNS_LOGCATEGORY_RRL (&dns_categories[13]) /* Backwards compatibility. */ #define DNS_LOGCATEGORY_GENERAL ISC_LOGCATEGORY_GENERAL diff --git a/lib/dns/include/dns/master.h b/lib/dns/include/dns/master.h index 896c6e95ecd31..4362789c3e0fc 100644 --- a/lib/dns/include/dns/master.h +++ b/lib/dns/include/dns/master.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009, 2011-2013 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -57,6 +57,7 @@ #define DNS_MASTER_RESIGN 0x00002000 #define DNS_MASTER_KEY 0x00004000 /*%< Loading a key zone master file. */ +#define DNS_MASTER_NOTTL 0x00008000 /*%< Don't require ttl. */ ISC_LANG_BEGINDECLS diff --git a/lib/dns/include/dns/masterdump.h b/lib/dns/include/dns/masterdump.h index 8631248cc2eee..092c61b974bff 100644 --- a/lib/dns/include/dns/masterdump.h +++ b/lib/dns/include/dns/masterdump.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008, 2011 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2008, 2011, 2013 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -148,6 +148,11 @@ LIBDNS_EXTERNAL_DATA extern const dns_master_style_t dns_master_style_simple; */ LIBDNS_EXTERNAL_DATA extern const dns_master_style_t dns_master_style_debug; +/*% + * The style used for dumping "key" zones. + */ +LIBDNS_EXTERNAL_DATA extern const dns_master_style_t dns_master_style_keyzone; + /*** *** Functions ***/ diff --git a/lib/dns/include/dns/message.h b/lib/dns/include/dns/message.h index a6862faab633a..6b2f39fc95835 100644 --- a/lib/dns/include/dns/message.h +++ b/lib/dns/include/dns/message.h @@ -105,6 +105,7 @@ /*%< EDNS0 extended OPT codes */ #define DNS_OPT_NSID 0x0003 /*%< NSID opt code */ +#define DNS_OPT_CLIENT_SUBNET 0x0008 /*%< client subnet opt code */ #define DNS_MESSAGE_REPLYPRESERVE (DNS_MESSAGEFLAG_RD|DNS_MESSAGEFLAG_CD) #define DNS_MESSAGEEXTFLAG_REPLYPRESERVE (DNS_MESSAGEEXTFLAG_DO) diff --git a/lib/dns/include/dns/nsec3.h b/lib/dns/include/dns/nsec3.h index e4a22868a2db7..a4be9687dca1a 100644 --- a/lib/dns/include/dns/nsec3.h +++ b/lib/dns/include/dns/nsec3.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2008-2013 Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -43,7 +43,7 @@ /* * Test "unknown" algorithm. Is mapped to dns_hash_sha1. */ -#define DNS_NSEC3_UNKNOWNALG 245U +#define DNS_NSEC3_UNKNOWNALG ((dns_hash_t)245U) ISC_LANG_BEGINDECLS diff --git a/lib/dns/include/dns/rdata.h b/lib/dns/include/dns/rdata.h index 89ecaf8006966..b9531a579284a 100644 --- a/lib/dns/include/dns/rdata.h +++ b/lib/dns/include/dns/rdata.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009, 2011-2013 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -171,6 +171,9 @@ struct dns_rdata { #define DNS_STYLEFLAG_COMMENT 0x00000002U #define DNS_STYLEFLAG_RRCOMMENT 0x00000004U +/*% Output KEYDATA in human readable format. */ +#define DNS_STYLEFLAG_KEYDATA 0x00000008U + #define DNS_RDATA_DOWNCASE DNS_NAME_DOWNCASE #define DNS_RDATA_CHECKNAMES DNS_NAME_CHECKNAMES #define DNS_RDATA_CHECKNAMESFAIL DNS_NAME_CHECKNAMESFAIL diff --git a/lib/dns/include/dns/rrl.h b/lib/dns/include/dns/rrl.h new file mode 100644 index 0000000000000..ef6b72b4280d2 --- /dev/null +++ b/lib/dns/include/dns/rrl.h @@ -0,0 +1,278 @@ +/* + * Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 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. + */ + + +#ifndef DNS_RRL_H +#define DNS_RRL_H 1 + +/* + * Rate limit DNS responses. + */ + +#include <isc/lang.h> + +#include <dns/fixedname.h> +#include <dns/rdata.h> +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + + +/* + * Memory allocation or other failures. + */ +#define DNS_RRL_LOG_FAIL ISC_LOG_WARNING +/* + * dropped or slipped responses. + */ +#define DNS_RRL_LOG_DROP ISC_LOG_INFO +/* + * Major events in dropping or slipping. + */ +#define DNS_RRL_LOG_DEBUG1 ISC_LOG_DEBUG(3) +/* + * Limit computations. + */ +#define DNS_RRL_LOG_DEBUG2 ISC_LOG_DEBUG(4) +/* + * Even less interesting. + */ +#define DNS_RRL_LOG_DEBUG3 ISC_LOG_DEBUG(9) + + +#define DNS_RRL_LOG_ERR_LEN 64 +#define DNS_RRL_LOG_BUF_LEN (sizeof("would continue limiting") + \ + DNS_RRL_LOG_ERR_LEN + \ + sizeof(" responses to ") + \ + ISC_NETADDR_FORMATSIZE + \ + sizeof("/128 for IN ") + \ + DNS_RDATATYPE_FORMATSIZE + \ + DNS_NAME_FORMATSIZE) + + +typedef struct dns_rrl_hash dns_rrl_hash_t; + +/* + * Response types. + */ +typedef enum { + DNS_RRL_RTYPE_FREE = 0, + DNS_RRL_RTYPE_QUERY, + DNS_RRL_RTYPE_REFERRAL, + DNS_RRL_RTYPE_NODATA, + DNS_RRL_RTYPE_NXDOMAIN, + DNS_RRL_RTYPE_ERROR, + DNS_RRL_RTYPE_ALL, + DNS_RRL_RTYPE_TCP, +} dns_rrl_rtype_t; + +/* + * A rate limit bucket key. + * This should be small to limit the total size of the database. + * The hash of the qname should be wide enough to make the probability + * of collisions among requests from a single IP address block less than 50%. + * We need a 32-bit hash value for 10000 qps (e.g. random qnames forged + * by attacker) to collide with legitimate qnames from the target with + * probability at most 1%. + */ +#define DNS_RRL_MAX_PREFIX 64 +typedef union dns_rrl_key dns_rrl_key_t; +union dns_rrl_key { + struct { + isc_uint32_t ip[DNS_RRL_MAX_PREFIX/32]; + isc_uint32_t qname_hash; + dns_rdatatype_t qtype; + isc_uint8_t qclass; + dns_rrl_rtype_t rtype :4; /* 3 bits + sign bit */ + isc_boolean_t ipv6 :1; + } s; + isc_uint16_t w[1]; +}; + +/* + * A rate-limit entry. + * This should be small to limit the total size of the table of entries. + */ +typedef struct dns_rrl_entry dns_rrl_entry_t; +typedef ISC_LIST(dns_rrl_entry_t) dns_rrl_bin_t; +struct dns_rrl_entry { + ISC_LINK(dns_rrl_entry_t) lru; + ISC_LINK(dns_rrl_entry_t) hlink; + dns_rrl_key_t key; +# define DNS_RRL_RESPONSE_BITS 24 + signed int responses :DNS_RRL_RESPONSE_BITS; +# define DNS_RRL_QNAMES_BITS 8 + unsigned int log_qname :DNS_RRL_QNAMES_BITS; + +# define DNS_RRL_TS_GEN_BITS 2 + unsigned int ts_gen :DNS_RRL_TS_GEN_BITS; + isc_boolean_t ts_valid :1; +# define DNS_RRL_HASH_GEN_BITS 1 + unsigned int hash_gen :DNS_RRL_HASH_GEN_BITS; + isc_boolean_t logged :1; +# define DNS_RRL_LOG_BITS 11 + unsigned int log_secs :DNS_RRL_LOG_BITS; + +# define DNS_RRL_TS_BITS 12 + unsigned int ts :DNS_RRL_TS_BITS; + +# define DNS_RRL_MAX_SLIP 10 + unsigned int slip_cnt :4; +}; + +#define DNS_RRL_MAX_TIME_TRAVEL 5 +#define DNS_RRL_FOREVER (1<<DNS_RRL_TS_BITS) +#define DNS_RRL_MAX_TS (DNS_RRL_FOREVER - 1) + +#define DNS_RRL_MAX_RESPONSES ((1<<(DNS_RRL_RESPONSE_BITS-1))-1) +#define DNS_RRL_MAX_WINDOW 3600 +#if DNS_RRL_MAX_WINDOW >= DNS_RRL_MAX_TS +#error "DNS_RRL_MAX_WINDOW is too large" +#endif +#define DNS_RRL_MAX_RATE 1000 +#if DNS_RRL_MAX_RATE >= (DNS_RRL_MAX_RESPONSES / DNS_RRL_MAX_WINDOW) +#error "DNS_RRL_MAX_rate is too large" +#endif + +#if (1<<DNS_RRL_LOG_BITS) >= DNS_RRL_FOREVER +#error DNS_RRL_LOG_BITS is too big +#endif +#define DNS_RRL_MAX_LOG_SECS 1800 +#if DNS_RRL_MAX_LOG_SECS >= (1<<DNS_RRL_LOG_BITS) +#error "DNS_RRL_MAX_LOG_SECS is too large" +#endif +#define DNS_RRL_STOP_LOG_SECS 60 +#if DNS_RRL_STOP_LOG_SECS >= (1<<DNS_RRL_LOG_BITS) +#error "DNS_RRL_STOP_LOG_SECS is too large" +#endif + + +/* + * A hash table of rate-limit entries. + */ +struct dns_rrl_hash { + isc_stdtime_t check_time; + unsigned int gen :DNS_RRL_HASH_GEN_BITS; + int length; + dns_rrl_bin_t bins[1]; +}; + +/* + * A block of rate-limit entries. + */ +typedef struct dns_rrl_block dns_rrl_block_t; +struct dns_rrl_block { + ISC_LINK(dns_rrl_block_t) link; + int size; + dns_rrl_entry_t entries[1]; +}; + +/* + * A rate limited qname buffer. + */ +typedef struct dns_rrl_qname_buf dns_rrl_qname_buf_t; +struct dns_rrl_qname_buf { + ISC_LINK(dns_rrl_qname_buf_t) link; + const dns_rrl_entry_t *e; + unsigned int index; + dns_fixedname_t qname; +}; + +typedef struct dns_rrl_rate dns_rrl_rate_t; +struct dns_rrl_rate { + int r; + int scaled; + const char *str; +}; + +/* + * Per-view query rate limit parameters and a pointer to database. + */ +typedef struct dns_rrl dns_rrl_t; +struct dns_rrl { + isc_mutex_t lock; + isc_mem_t *mctx; + + isc_boolean_t log_only; + dns_rrl_rate_t responses_per_second; + dns_rrl_rate_t referrals_per_second; + dns_rrl_rate_t nodata_per_second; + dns_rrl_rate_t nxdomains_per_second; + dns_rrl_rate_t errors_per_second; + dns_rrl_rate_t all_per_second; + dns_rrl_rate_t slip; + int window; + double qps_scale; + int max_entries; + + dns_acl_t *exempt; + + int num_entries; + + int qps_responses; + isc_stdtime_t qps_time; + double qps; + + unsigned int probes; + unsigned int searches; + + ISC_LIST(dns_rrl_block_t) blocks; + ISC_LIST(dns_rrl_entry_t) lru; + + dns_rrl_hash_t *hash; + dns_rrl_hash_t *old_hash; + unsigned int hash_gen; + + unsigned int ts_gen; +# define DNS_RRL_TS_BASES (1<<DNS_RRL_TS_GEN_BITS) + isc_stdtime_t ts_bases[DNS_RRL_TS_BASES]; + + int ipv4_prefixlen; + isc_uint32_t ipv4_mask; + int ipv6_prefixlen; + isc_uint32_t ipv6_mask[4]; + + isc_stdtime_t log_stops_time; + dns_rrl_entry_t *last_logged; + int num_logged; + int num_qnames; + ISC_LIST(dns_rrl_qname_buf_t) qname_free; +# define DNS_RRL_QNAMES (1<<DNS_RRL_QNAMES_BITS) + dns_rrl_qname_buf_t *qnames[DNS_RRL_QNAMES]; +}; + +typedef enum { + DNS_RRL_RESULT_OK, + DNS_RRL_RESULT_DROP, + DNS_RRL_RESULT_SLIP, +} dns_rrl_result_t; + +dns_rrl_result_t +dns_rrl(dns_view_t *view, + const isc_sockaddr_t *client_addr, isc_boolean_t is_tcp, + dns_rdataclass_t rdclass, dns_rdatatype_t qtype, + dns_name_t *qname, isc_result_t resp_result, isc_stdtime_t now, + isc_boolean_t wouldlog, char *log_buf, unsigned int log_buf_len); + +void +dns_rrl_view_destroy(dns_view_t *view); + +isc_result_t +dns_rrl_init(dns_rrl_t **rrlp, dns_view_t *view, int min_entries); + +ISC_LANG_ENDDECLS + +#endif /* DNS_RRL_H */ diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h index d0c1931d27bed..704e5fe3e9993 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -73,6 +73,7 @@ #include <dns/acl.h> #include <dns/fixedname.h> +#include <dns/rrl.h> #include <dns/rdatastruct.h> #include <dns/rpz.h> #include <dns/types.h> @@ -142,6 +143,7 @@ struct dns_view { dns_rbt_t * answeracl_exclude; dns_rbt_t * denyanswernames; dns_rbt_t * answernames_exclude; + dns_rrl_t * rrl; isc_boolean_t provideixfr; isc_boolean_t requestnsid; dns_ttl_t maxcachettl; diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h index f91801f6fe3f5..9efa1e729767d 100644 --- a/lib/dns/include/dns/zone.h +++ b/lib/dns/include/dns/zone.h @@ -2086,6 +2086,12 @@ dns_zone_rpz_enable(dns_zone_t *zone); * Set the response policy associated with a zone. */ +isc_result_t +dns_zone_rpz_enable_db(dns_zone_t *zone, dns_db_t *db); +/*% + * If a zone is a response policy zone, mark its new database. + */ + isc_boolean_t dns_zone_get_rpz(dns_zone_t *zone); diff --git a/lib/dns/include/dst/dst.h b/lib/dns/include/dst/dst.h index 4724fc64c95e2..1fdce4cc44d76 100644 --- a/lib/dns/include/dst/dst.h +++ b/lib/dns/include/dst/dst.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2013 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -923,6 +923,29 @@ dst_key_restore(dns_name_t *name, unsigned int alg, unsigned int flags, unsigned int protocol, dns_rdataclass_t rdclass, isc_mem_t *mctx, const char *keystr, dst_key_t **keyp); +isc_boolean_t +dst_key_inactive(const dst_key_t *key); +/*%< + * Determines if the private key is missing due the key being deemed inactive. + * + * Requires: + * 'key' to be valid. + */ + +void +dst_key_setinactive(dst_key_t *key, isc_boolean_t inactive); +/*%< + * Set key inactive state. + * + * Requires: + * 'key' to be valid. + */ + +void +dst_key_setexternal(dst_key_t *key, isc_boolean_t value); + +isc_boolean_t +dst_key_isexternal(dst_key_t *key); ISC_LANG_ENDDECLS diff --git a/lib/dns/include/dst/gssapi.h b/lib/dns/include/dst/gssapi.h index 1e81a55b97180..53c594e6b2379 100644 --- a/lib/dns/include/dst/gssapi.h +++ b/lib/dns/include/dst/gssapi.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007, 2009-2011 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009-2011, 2013 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -29,7 +29,7 @@ #include <dns/types.h> #ifdef GSSAPI -#ifdef _WINDOWS +#ifdef WIN32 /* * MSVC does not like macros in #include lines. */ diff --git a/lib/dns/journal.c b/lib/dns/journal.c index 022a3e280f832..2d0b3f5f7494f 100644 --- a/lib/dns/journal.c +++ b/lib/dns/journal.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007-2011, 2013 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007-2011, 2013, 2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -307,7 +307,7 @@ struct dns_journal { unsigned int magic; /*%< JOUR */ isc_mem_t *mctx; /*%< Memory context */ journal_state_t state; - const char *filename; /*%< Journal file name */ + char *filename; /*%< Journal file name */ FILE * fp; /*%< File handle */ isc_offset_t offset; /*%< Current file offset */ journal_header_t header; /*%< In-core journal header */ @@ -357,7 +357,7 @@ journal_pos_encode(journal_rawpos_t *raw, journal_pos_t *cooked) { static void journal_header_decode(journal_rawheader_t *raw, journal_header_t *cooked) { INSIST(sizeof(cooked->format) == sizeof(raw->h.format)); - memcpy(cooked->format, raw->h.format, sizeof(cooked->format)); + memmove(cooked->format, raw->h.format, sizeof(cooked->format)); journal_pos_decode(&raw->h.begin, &cooked->begin); journal_pos_decode(&raw->h.end, &cooked->end); cooked->index_size = decode_uint32(raw->h.index_size); @@ -371,7 +371,7 @@ journal_header_encode(journal_header_t *cooked, journal_rawheader_t *raw) { INSIST(sizeof(cooked->format) == sizeof(raw->h.format)); memset(raw->pad, 0, sizeof(raw->pad)); - memcpy(raw->h.format, cooked->format, sizeof(raw->h.format)); + memmove(raw->h.format, cooked->format, sizeof(raw->h.format)); journal_pos_encode(&raw->h.begin, &cooked->begin); journal_pos_encode(&raw->h.end, &cooked->end); encode_uint32(cooked->index_size, raw->h.index_size); @@ -411,7 +411,7 @@ journal_read(dns_journal_t *j, void *mem, size_t nbytes) { j->filename, isc_result_totext(result)); return (ISC_R_UNEXPECTED); } - j->offset += nbytes; + j->offset += (isc_offset_t)nbytes; return (ISC_R_SUCCESS); } @@ -426,7 +426,7 @@ journal_write(dns_journal_t *j, void *mem, size_t nbytes) { j->filename, isc_result_totext(result)); return (ISC_R_UNEXPECTED); } - j->offset += nbytes; + j->offset += (isc_offset_t)nbytes; return (ISC_R_SUCCESS); } @@ -528,7 +528,7 @@ journal_file_create(isc_mem_t *mctx, const char *filename) { return (ISC_R_NOMEMORY); } memset(mem, 0, size); - memcpy(mem, &rawheader, sizeof(rawheader)); + memmove(mem, &rawheader, sizeof(rawheader)); result = isc_stdio_write(mem, 1, (size_t) size, fp, NULL); if (result != ISC_R_SUCCESS) { @@ -572,10 +572,13 @@ journal_open(isc_mem_t *mctx, const char *filename, isc_boolean_t write, isc_mem_attach(mctx, &j->mctx); j->state = JOURNAL_STATE_INVALID; j->fp = NULL; - j->filename = filename; + j->filename = isc_mem_strdup(mctx, filename); j->index = NULL; j->rawindex = NULL; + if (j->filename == NULL) + FAIL(ISC_R_NOMEMORY); + result = isc_stdio_open(j->filename, write ? "rb+" : "rb", &fp); if (result == ISC_R_FILENOTFOUND) { @@ -678,6 +681,8 @@ journal_open(isc_mem_t *mctx, const char *filename, isc_boolean_t write, sizeof(journal_rawpos_t)); j->index = NULL; } + if (j->filename != NULL) + isc_mem_free(j->mctx, j->filename); if (j->fp != NULL) (void)isc_stdio_close(j->fp); isc_mem_putanddetach(&j->mctx, j, sizeof(*j)); @@ -689,7 +694,7 @@ dns_journal_open(isc_mem_t *mctx, const char *filename, unsigned int mode, dns_journal_t **journalp) { isc_result_t result; - int namelen; + size_t namelen; char backup[1024]; isc_boolean_t write, create; @@ -699,11 +704,11 @@ dns_journal_open(isc_mem_t *mctx, const char *filename, unsigned int mode, result = journal_open(mctx, filename, write, create, journalp); if (result == ISC_R_NOTFOUND) { namelen = strlen(filename); - if (namelen > 4 && strcmp(filename + namelen - 4, ".jnl") == 0) + if (namelen > 4U && strcmp(filename + namelen - 4, ".jnl") == 0) namelen -= 4; result = isc_string_printf(backup, sizeof(backup), "%.*s.jbk", - namelen, filename); + (int)namelen, filename); if (result != ISC_R_SUCCESS) return (result); result = journal_open(mctx, backup, write, write, journalp); @@ -1241,7 +1246,8 @@ dns_journal_destroy(dns_journal_t **journalp) { isc_mem_put(j->mctx, j->it.target.base, j->it.target.length); if (j->it.source.base != NULL) isc_mem_put(j->mctx, j->it.source.base, j->it.source.length); - + if (j->filename != NULL) + isc_mem_free(j->mctx, j->filename); if (j->fp != NULL) (void)isc_stdio_close(j->fp); j->magic = 0; @@ -1257,9 +1263,7 @@ dns_journal_destroy(dns_journal_t **journalp) { /* XXX Share code with incoming IXFR? */ static isc_result_t -roll_forward(dns_journal_t *j, dns_db_t *db, unsigned int options, - isc_uint32_t resign) -{ +roll_forward(dns_journal_t *j, dns_db_t *db, unsigned int options) { isc_buffer_t source; /* Transaction data from disk */ isc_buffer_t target; /* Ditto after _fromwire check */ isc_uint32_t db_serial; /* Database SOA serial */ @@ -1276,7 +1280,6 @@ roll_forward(dns_journal_t *j, dns_db_t *db, unsigned int options, REQUIRE(DNS_DB_VALID(db)); dns_diff_init(j->mctx, &diff); - diff.resign = resign; /* * Set up empty initial buffers for unchecked and checked @@ -1409,6 +1412,8 @@ dns_journal_rollforward2(isc_mem_t *mctx, dns_db_t *db, unsigned int options, REQUIRE(DNS_DB_VALID(db)); REQUIRE(filename != NULL); + UNUSED(resign); + j = NULL; result = dns_journal_open(mctx, filename, DNS_JOURNAL_READ, &j); if (result == ISC_R_NOTFOUND) { @@ -1421,7 +1426,7 @@ dns_journal_rollforward2(isc_mem_t *mctx, dns_db_t *db, unsigned int options, if (JOURNAL_EMPTY(&j->header)) result = DNS_R_UPTODATE; else - result = roll_forward(j, db, options, resign); + result = roll_forward(j, db, options); dns_journal_destroy(&j); @@ -2094,7 +2099,7 @@ dns_journal_compact(isc_mem_t *mctx, char *filename, isc_uint32_t serial, dns_journal_t *new = NULL; journal_rawheader_t rawheader; unsigned int copy_length; - int namelen; + size_t namelen; char *buf = NULL; unsigned int size = 0; isc_result_t result; @@ -2104,16 +2109,16 @@ dns_journal_compact(isc_mem_t *mctx, char *filename, isc_uint32_t serial, isc_boolean_t is_backup = ISC_FALSE; namelen = strlen(filename); - if (namelen > 4 && strcmp(filename + namelen - 4, ".jnl") == 0) + if (namelen > 4U && strcmp(filename + namelen - 4, ".jnl") == 0) namelen -= 4; result = isc_string_printf(newname, sizeof(newname), "%.*s.jnw", - namelen, filename); + (int)namelen, filename); if (result != ISC_R_SUCCESS) return (result); result = isc_string_printf(backup, sizeof(backup), "%.*s.jbk", - namelen, filename); + (int)namelen, filename); if (result != ISC_R_SUCCESS) return (result); diff --git a/lib/dns/keydata.c b/lib/dns/keydata.c index 822bd467dc55b..cb1ed38dd7e3c 100644 --- a/lib/dns/keydata.c +++ b/lib/dns/keydata.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2009, 2014 Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -51,7 +51,7 @@ dns_keydata_todnskey(dns_rdata_keydata_t *keydata, dnskey->data = isc_mem_allocate(mctx, dnskey->datalen); if (dnskey->data == NULL) return (ISC_R_NOMEMORY); - memcpy(dnskey->data, keydata->data, dnskey->datalen); + memmove(dnskey->data, keydata->data, dnskey->datalen); } return (ISC_R_SUCCESS); @@ -82,7 +82,7 @@ dns_keydata_fromdnskey(dns_rdata_keydata_t *keydata, keydata->data = isc_mem_allocate(mctx, keydata->datalen); if (keydata->data == NULL) return (ISC_R_NOMEMORY); - memcpy(keydata->data, dnskey->data, keydata->datalen); + memmove(keydata->data, dnskey->data, keydata->datalen); } return (ISC_R_SUCCESS); diff --git a/lib/dns/log.c b/lib/dns/log.c index c4d644e3899f6..75e0d79ba34bd 100644 --- a/lib/dns/log.c +++ b/lib/dns/log.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007, 2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009, 2011-2013 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -45,6 +45,7 @@ LIBDNS_EXTERNAL_DATA isc_logcategory_t dns_categories[] = { { "delegation-only", 0 }, { "edns-disabled", 0 }, { "rpz", 0 }, + { "rate-limit", 0 }, { NULL, 0 } }; diff --git a/lib/dns/master.c b/lib/dns/master.c index d0c175876f5cb..9e796e6e0ac73 100644 --- a/lib/dns/master.c +++ b/lib/dns/master.c @@ -578,9 +578,9 @@ loadctx_create(dns_masterformat_t format, isc_mem_t *mctx, isc_lex_setcomments(lctx->lex, ISC_LEXCOMMENT_DNSMASTERFILE); } - lctx->ttl_known = ISC_FALSE; + lctx->ttl_known = ISC_TF((options & DNS_MASTER_NOTTL) != 0); lctx->ttl = 0; - lctx->default_ttl_known = ISC_FALSE; + lctx->default_ttl_known = lctx->ttl_known; lctx->default_ttl = 0; lctx->warn_1035 = ISC_TRUE; /* XXX Argument? */ lctx->warn_tcr = ISC_TRUE; /* XXX Argument? */ @@ -686,7 +686,7 @@ genname(char *name, int it, char *buffer, size_t length) { isc_boolean_t nibblemode; r.base = buffer; - r.length = length; + r.length = (unsigned int)length; while (*name != '\0') { if (*name == '$') { @@ -2083,7 +2083,7 @@ read_and_check(isc_boolean_t do_read, isc_buffer_t *buffer, f, NULL); if (result != ISC_R_SUCCESS) return (result); - isc_buffer_add(buffer, len); + isc_buffer_add(buffer, (unsigned int)len); } else if (isc_buffer_remaininglength(buffer) < len) return (ISC_R_RANGE); @@ -2267,7 +2267,7 @@ load_raw(dns_loadctx_t *lctx) { lctx->f, NULL); if (result != ISC_R_SUCCESS) goto cleanup; - isc_buffer_add(&target, readlen); + isc_buffer_add(&target, (unsigned int)readlen); /* Construct RRset headers */ rdatalist.rdclass = isc_buffer_getuint16(&target); diff --git a/lib/dns/masterdump.c b/lib/dns/masterdump.c index 2717658e691ad..01f797cb99ed0 100644 --- a/lib/dns/masterdump.c +++ b/lib/dns/masterdump.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009, 2011-2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -101,6 +101,21 @@ typedef struct dns_totext_ctx { } dns_totext_ctx_t; LIBDNS_EXTERNAL_DATA const dns_master_style_t +dns_master_style_keyzone = { + DNS_STYLEFLAG_OMIT_OWNER | + DNS_STYLEFLAG_OMIT_CLASS | + DNS_STYLEFLAG_REL_OWNER | + DNS_STYLEFLAG_REL_DATA | + DNS_STYLEFLAG_OMIT_TTL | + DNS_STYLEFLAG_TTL | + DNS_STYLEFLAG_COMMENT | + DNS_STYLEFLAG_RRCOMMENT | + DNS_STYLEFLAG_MULTILINE | + DNS_STYLEFLAG_KEYDATA, + 24, 24, 24, 32, 80, 8, UINT_MAX +}; + +LIBDNS_EXTERNAL_DATA const dns_master_style_t dns_master_style_default = { DNS_STYLEFLAG_OMIT_OWNER | DNS_STYLEFLAG_OMIT_CLASS | @@ -232,7 +247,7 @@ indent(unsigned int *current, unsigned int to, int tabwidth, int n = t; if (n > N_TABS) n = N_TABS; - memcpy(p, tabs, n); + memmove(p, tabs, n); p += n; t -= n; } @@ -253,7 +268,7 @@ indent(unsigned int *current, unsigned int to, int tabwidth, int n = t; if (n > N_SPACES) n = N_SPACES; - memcpy(p, spaces, n); + memmove(p, spaces, n); p += n; t -= n; } @@ -343,7 +358,7 @@ str_totext(const char *source, isc_buffer_t *target) { if (l > region.length) return (ISC_R_NOSPACE); - memcpy(region.base, source, l); + memmove(region.base, source, l); isc_buffer_add(target, l); return (ISC_R_SUCCESS); } @@ -460,7 +475,7 @@ rdataset_totext(dns_rdataset_t *rdataset, isc_buffer_availableregion(target, &r); if (r.length < length) return (ISC_R_NOSPACE); - memcpy(r.base, ttlbuf, length); + memmove(r.base, ttlbuf, length); isc_buffer_add(target, length); column += length; @@ -505,9 +520,22 @@ rdataset_totext(dns_rdataset_t *rdataset, type_start = target->used; if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) RETERR(str_totext("\\-", target)); - result = dns_rdatatype_totext(type, target); - if (result != ISC_R_SUCCESS) - return (result); + switch (type) { + case dns_rdatatype_keydata: +#define KEYDATA "KEYDATA" + if ((ctx->style.flags & DNS_STYLEFLAG_KEYDATA) != 0) { + if (isc_buffer_availablelength(target) < + (sizeof(KEYDATA) - 1)) + return (ISC_R_NOSPACE); + isc_buffer_putstr(target, KEYDATA); + break; + } + /* FALLTHROUGH */ + default: + result = dns_rdatatype_totext(type, target); + if (result != ISC_R_SUCCESS) + return (result); + } column += (target->used - type_start); /* diff --git a/lib/dns/message.c b/lib/dns/message.c index 53efc5a1beb5f..901c6b6d991dd 100644 --- a/lib/dns/message.c +++ b/lib/dns/message.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2013 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -1675,8 +1675,8 @@ dns_message_parse(dns_message_t *msg, isc_buffer_t *source, msg->saved.base = isc_mem_get(msg->mctx, msg->saved.length); if (msg->saved.base == NULL) return (ISC_R_NOMEMORY); - memcpy(msg->saved.base, isc_buffer_base(&origsource), - msg->saved.length); + memmove(msg->saved.base, isc_buffer_base(&origsource), + msg->saved.length); msg->free_saved = 1; } @@ -1748,7 +1748,7 @@ dns_message_renderchangebuffer(dns_message_t *msg, isc_buffer_t *buffer) { * Copy the contents from the old to the new buffer. */ isc_buffer_add(buffer, r.length); - memcpy(rn.base, r.base, r.length); + memmove(rn.base, r.base, r.length); msg->buffer = buffer; @@ -3468,7 +3468,7 @@ dns_message_buildopt(dns_message_t *message, dns_rdataset_t **rdatasetp, dns_rdatalist_t *rdatalist = NULL; dns_rdata_t *rdata = NULL; isc_result_t result; - size_t len = 0, i; + unsigned int len = 0, i; REQUIRE(DNS_MESSAGE_VALID(message)); REQUIRE(rdatasetp != NULL && *rdatasetp == NULL); diff --git a/lib/dns/name.c b/lib/dns/name.c index 7fb21e138c3c8..9b24ed3638042 100644 --- a/lib/dns/name.c +++ b/lib/dns/name.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -578,6 +578,11 @@ dns_name_fullcompare(const dns_name_t *name1, const dns_name_t *name2, REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) == (name2->attributes & DNS_NAMEATTR_ABSOLUTE)); + if (name1 == name2) { + *orderp = 0; + return (dns_namereln_equal); + } + SETUP_OFFSETS(name1, offsets1, odata1); SETUP_OFFSETS(name2, offsets2, odata2); @@ -691,6 +696,9 @@ dns_name_equal(const dns_name_t *name1, const dns_name_t *name2) { REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) == (name2->attributes & DNS_NAMEATTR_ABSOLUTE)); + if (name1 == name2) + return (ISC_TRUE); + if (name1->length != name2->length) return (ISC_FALSE); @@ -963,8 +971,8 @@ dns_name_clone(const dns_name_t *source, dns_name_t *target) { DNS_NAMEATTR_DYNOFFSETS); if (target->offsets != NULL && source->labels > 0) { if (source->offsets != NULL) - memcpy(target->offsets, source->offsets, - source->labels); + memmove(target->offsets, source->offsets, + source->labels); else set_offsets(target, target->offsets, NULL); } @@ -993,7 +1001,7 @@ dns_name_fromregion(dns_name_t *name, const isc_region_t *r) { len = (r->length < r2.length) ? r->length : r2.length; if (len > DNS_NAME_MAXWIRE) len = DNS_NAME_MAXWIRE; - memcpy(r2.base, r->base, len); + memmove(r2.base, r->base, len); name->ndata = r2.base; name->length = len; } else { @@ -1977,8 +1985,8 @@ dns_name_towire(const dns_name_t *name, dns_compress_t *cctx, if (gf) { if (target->length - target->used < gp.length) return (ISC_R_NOSPACE); - (void)memcpy((unsigned char *)target->base + target->used, - gp.ndata, (size_t)gp.length); + (void)memmove((unsigned char *)target->base + target->used, + gp.ndata, (size_t)gp.length); isc_buffer_add(target, gp.length); go |= 0xc000; if (target->length - target->used < 2) @@ -1989,8 +1997,8 @@ dns_name_towire(const dns_name_t *name, dns_compress_t *cctx, } else { if (target->length - target->used < name->length) return (ISC_R_NOSPACE); - (void)memcpy((unsigned char *)target->base + target->used, - name->ndata, (size_t)name->length); + (void)memmove((unsigned char *)target->base + target->used, + name->ndata, (size_t)name->length); isc_buffer_add(target, name->length); dns_compress_add(cctx, name, name, offset); } @@ -2070,12 +2078,7 @@ dns_name_concatenate(dns_name_t *prefix, dns_name_t *suffix, dns_name_t *name, if (copy_suffix) { if ((suffix->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) absolute = ISC_TRUE; - if (suffix == name && suffix->buffer == target) - memmove(ndata + prefix_length, suffix->ndata, - suffix->length); - else - memcpy(ndata + prefix_length, suffix->ndata, - suffix->length); + memmove(ndata + prefix_length, suffix->ndata, suffix->length); } /* @@ -2084,7 +2087,7 @@ dns_name_concatenate(dns_name_t *prefix, dns_name_t *suffix, dns_name_t *name, * copy anything. */ if (copy_prefix && (prefix != name || prefix->buffer != target)) - memcpy(ndata, prefix->ndata, prefix_length); + memmove(ndata, prefix->ndata, prefix_length); name->ndata = ndata; name->labels = labels; @@ -2158,7 +2161,7 @@ dns_name_dup(const dns_name_t *source, isc_mem_t *mctx, if (target->ndata == NULL) return (ISC_R_NOMEMORY); - memcpy(target->ndata, source->ndata, source->length); + memmove(target->ndata, source->ndata, source->length); target->length = source->length; target->labels = source->labels; @@ -2167,8 +2170,8 @@ dns_name_dup(const dns_name_t *source, isc_mem_t *mctx, target->attributes |= DNS_NAMEATTR_ABSOLUTE; if (target->offsets != NULL) { if (source->offsets != NULL) - memcpy(target->offsets, source->offsets, - source->labels); + memmove(target->offsets, source->offsets, + source->labels); else set_offsets(target, target->offsets, NULL); } @@ -2200,7 +2203,7 @@ dns_name_dupwithoffsets(dns_name_t *source, isc_mem_t *mctx, if (target->ndata == NULL) return (ISC_R_NOMEMORY); - memcpy(target->ndata, source->ndata, source->length); + memmove(target->ndata, source->ndata, source->length); target->length = source->length; target->labels = source->labels; @@ -2210,7 +2213,7 @@ dns_name_dupwithoffsets(dns_name_t *source, isc_mem_t *mctx, target->attributes |= DNS_NAMEATTR_ABSOLUTE; target->offsets = target->ndata + source->length; if (source->offsets != NULL) - memcpy(target->offsets, source->offsets, source->labels); + memmove(target->offsets, source->offsets, source->labels); else set_offsets(target, target->offsets, NULL); @@ -2390,7 +2393,7 @@ dns_name_tostring(dns_name_t *name, char **target, isc_mem_t *mctx) { isc_buffer_usedregion(&buf, ®); p = isc_mem_allocate(mctx, reg.length + 1); - memcpy(p, (char *) reg.base, (int) reg.length); + memmove(p, (char *) reg.base, (int) reg.length); p[reg.length] = '\0'; *target = p; @@ -2466,7 +2469,7 @@ dns_name_copy(dns_name_t *source, dns_name_t *dest, isc_buffer_t *target) { ndata = (unsigned char *)target->base + target->used; dest->ndata = target->base; - memcpy(ndata, source->ndata, source->length); + memmove(ndata, source->ndata, source->length); dest->ndata = ndata; dest->labels = source->labels; @@ -2478,7 +2481,7 @@ dns_name_copy(dns_name_t *source, dns_name_t *dest, isc_buffer_t *target) { if (dest->labels > 0 && dest->offsets != NULL) { if (source->offsets != NULL) - memcpy(dest->offsets, source->offsets, source->labels); + memmove(dest->offsets, source->offsets, source->labels); else set_offsets(dest, dest->offsets, NULL); } diff --git a/lib/dns/nsec.c b/lib/dns/nsec.c index e446806b4e6a5..5d1197d093b09 100644 --- a/lib/dns/nsec.c +++ b/lib/dns/nsec.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007-2009, 2011-2013 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007-2009, 2011-2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -96,7 +96,7 @@ dns_nsec_compressbitmap(unsigned char *map, const unsigned char *raw, map += octet + 1; raw += 32; } - return (map - start); + return (unsigned int)(map - start); } isc_result_t @@ -115,7 +115,7 @@ dns_nsec_buildrdata(dns_db_t *db, dns_dbversion_t *version, memset(buffer, 0, DNS_NSEC_BUFFERSIZE); dns_name_toregion(target, &r); - memcpy(buffer, r.base, r.length); + memmove(buffer, r.base, r.length); r.base = buffer; /* * Use the end of the space for a raw bitmap leaving enough @@ -164,7 +164,7 @@ dns_nsec_buildrdata(dns_db_t *db, dns_dbversion_t *version, nsec_bits += dns_nsec_compressbitmap(nsec_bits, bm, max_type); - r.length = nsec_bits - r.base; + r.length = (unsigned int)(nsec_bits - r.base); INSIST(r.length <= DNS_NSEC_BUFFERSIZE); dns_rdata_fromregion(rdata, dns_db_class(db), diff --git a/lib/dns/nsec3.c b/lib/dns/nsec3.c index 935f515d23ed8..3724118cb3fe9 100644 --- a/lib/dns/nsec3.c +++ b/lib/dns/nsec3.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2008-2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2006, 2008-2014 Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -97,15 +97,15 @@ dns_nsec3_buildrdata(dns_db_t *db, dns_dbversion_t *version, *p++ = iterations >> 8; *p++ = iterations; - *p++ = salt_length; - memcpy(p, salt, salt_length); + *p++ = (unsigned char)salt_length; + memmove(p, salt, salt_length); p += salt_length; - *p++ = hash_length; - memcpy(p, nexthash, hash_length); + *p++ = (unsigned char)hash_length; + memmove(p, nexthash, hash_length); p += hash_length; - r.length = p - buffer; + r.length = (unsigned int)(p - buffer); r.base = buffer; /* @@ -177,7 +177,7 @@ dns_nsec3_buildrdata(dns_db_t *db, dns_dbversion_t *version, collapse_bitmap: nsec_bits += dns_nsec_compressbitmap(nsec_bits, bm, max_type); - r.length = nsec_bits - r.base; + r.length = (unsigned int)(nsec_bits - r.base); INSIST(r.length <= DNS_NSEC3_BUFFERSIZE); dns_rdata_fromregion(rdata, dns_db_class(db), dns_rdatatype_nsec3, &r); @@ -244,7 +244,8 @@ dns_nsec3_hashname(dns_fixedname_t *result, dns_name_downcase(name, downcased, NULL); /* hash the node name */ - len = isc_iterated_hash(rethash, hashalg, iterations, salt, saltlength, + len = isc_iterated_hash(rethash, hashalg, iterations, + salt, (int)saltlength, downcased->ndata, downcased->length); if (len == 0U) return (DNS_R_BADALG); @@ -254,7 +255,7 @@ dns_nsec3_hashname(dns_fixedname_t *result, /* convert the hash to base32hex */ region.base = rethash; - region.length = len; + region.length = (unsigned int)len; isc_buffer_init(&namebuffer, nametext, sizeof nametext); isc_base32hex_totext(®ion, 1, "", &namebuffer); @@ -300,7 +301,6 @@ do_one_tuple(dns_difftuple_t **tuple, dns_db_t *db, dns_dbversion_t *ver, * Create a singleton diff. */ dns_diff_init(diff->mctx, &temp_diff); - temp_diff.resign = diff->resign; ISC_LIST_APPEND(temp_diff.tuples, *tuple, link); /* @@ -591,7 +591,7 @@ dns_nsec3_addnsec3(dns_db_t *db, dns_dbversion_t *version, flags = nsec3.flags; next_length = nsec3.next_length; INSIST(next_length <= sizeof(nexthash)); - memcpy(nexthash, nsec3.next, next_length); + memmove(nexthash, nsec3.next, next_length); dns_rdataset_disassociate(&rdataset); /* * If the NSEC3 is not for a unsecure delegation then @@ -679,7 +679,7 @@ dns_nsec3_addnsec3(dns_db_t *db, dns_dbversion_t *version, * Fixup the previous NSEC3. */ nsec3.next = nexthash; - nsec3.next_length = next_length; + nsec3.next_length = (unsigned char)next_length; isc_buffer_init(&buffer, nsec3buf, sizeof(nsec3buf)); CHECK(dns_rdata_fromstruct(&rdata, rdataset.rdclass, dns_rdatatype_nsec3, &nsec3, @@ -688,7 +688,7 @@ dns_nsec3_addnsec3(dns_db_t *db, dns_dbversion_t *version, rdataset.ttl, &rdata, &tuple)); CHECK(do_one_tuple(&tuple, db, version, diff)); INSIST(old_length <= sizeof(nexthash)); - memcpy(nexthash, old_next, old_length); + memmove(nexthash, old_next, old_length); if (!CREATE(nsec3param->flags)) flags = nsec3.flags; dns_rdata_reset(&rdata); @@ -798,7 +798,7 @@ dns_nsec3_addnsec3(dns_db_t *db, dns_dbversion_t *version, * Fixup the previous NSEC3. */ nsec3.next = nexthash; - nsec3.next_length = next_length; + nsec3.next_length = (unsigned char)next_length; isc_buffer_init(&buffer, nsec3buf, sizeof(nsec3buf)); CHECK(dns_rdata_fromstruct(&rdata, rdataset.rdclass, @@ -809,7 +809,7 @@ dns_nsec3_addnsec3(dns_db_t *db, dns_dbversion_t *version, &tuple)); CHECK(do_one_tuple(&tuple, db, version, diff)); INSIST(old_length <= sizeof(nexthash)); - memcpy(nexthash, old_next, old_length); + memmove(nexthash, old_next, old_length); if (!CREATE(nsec3param->flags)) flags = nsec3.flags; dns_rdata_reset(&rdata); @@ -939,7 +939,7 @@ dns_nsec3param_fromprivate(dns_rdata_t *src, dns_rdata_t *target, isc_buffer_init(&buf1, src->data + 1, src->length - 1); isc_buffer_add(&buf1, src->length - 1); isc_buffer_setactive(&buf1, src->length - 1); - isc_buffer_init(&buf2, buf, buflen); + isc_buffer_init(&buf2, buf, (unsigned int)buflen); dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_NONE); result = dns_rdata_fromwire(target, src->rdclass, dns_rdatatype_nsec3param, @@ -958,7 +958,7 @@ dns_nsec3param_toprivate(dns_rdata_t *src, dns_rdata_t *target, REQUIRE(DNS_RDATA_INITIALIZED(target)); - memcpy(buf + 1, src->data, src->length); + memmove(buf + 1, src->data, src->length); buf[0] = 0; target->data = buf; target->length = src->length + 1; @@ -1097,7 +1097,7 @@ dns_nsec3param_deletechains(dns_db_t *db, dns_dbversion_t *ver, dns_rdata_reset(&rdata); dns_rdataset_current(&rdataset, &rdata); INSIST(rdata.length <= sizeof(buf)); - memcpy(buf, rdata.data, rdata.length); + memmove(buf, rdata.data, rdata.length); /* * Private NSEC3 record length >= 6. @@ -1361,7 +1361,7 @@ dns_nsec3_delnsec3(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, if (result == ISC_R_SUCCESS) { next_length = nsec3.next_length; INSIST(next_length <= sizeof(nexthash)); - memcpy(nexthash, nsec3.next, next_length); + memmove(nexthash, nsec3.next, next_length); } dns_rdataset_disassociate(&rdataset); if (result == ISC_R_NOMORE) @@ -1405,7 +1405,7 @@ dns_nsec3_delnsec3(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, * Fixup the previous NSEC3. */ nsec3.next = nexthash; - nsec3.next_length = next_length; + nsec3.next_length = (unsigned char)next_length; if (CREATE(nsec3param->flags)) nsec3.flags = nsec3param->flags & DNS_NSEC3FLAG_OPTOUT; isc_buffer_init(&buffer, nsec3buf, sizeof(nsec3buf)); @@ -1464,7 +1464,7 @@ dns_nsec3_delnsec3(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, if (result == ISC_R_SUCCESS) { next_length = nsec3.next_length; INSIST(next_length <= sizeof(nexthash)); - memcpy(nexthash, nsec3.next, next_length); + memmove(nexthash, nsec3.next, next_length); } dns_rdataset_disassociate(&rdataset); if (result == ISC_R_NOMORE) @@ -1505,7 +1505,7 @@ dns_nsec3_delnsec3(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, * Fixup the previous NSEC3. */ nsec3.next = nexthash; - nsec3.next_length = next_length; + nsec3.next_length = (unsigned char)next_length; isc_buffer_init(&buffer, nsec3buf, sizeof(nsec3buf)); CHECK(dns_rdata_fromstruct(&rdata, rdataset.rdclass, diff --git a/lib/dns/openssldh_link.c b/lib/dns/openssldh_link.c index 36b8a412a3eed..cb9fb77d42198 100644 --- a/lib/dns/openssldh_link.c +++ b/lib/dns/openssldh_link.c @@ -1,5 +1,5 @@ /* - * Portions Copyright (C) 2004-2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 2004-2009, 2011-2013 Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -608,11 +608,11 @@ BN_fromhex(BIGNUM *b, const char *str) { s = strchr(hexdigits, tolower((unsigned char)str[i])); RUNTIME_CHECK(s != NULL); - high = s - hexdigits; + high = (unsigned int)(s - hexdigits); s = strchr(hexdigits, tolower((unsigned char)str[i + 1])); RUNTIME_CHECK(s != NULL); - low = s - hexdigits; + low = (unsigned int)(s - hexdigits); data[i/2] = (unsigned char)((high << 4) + low); } diff --git a/lib/dns/openssldsa_link.c b/lib/dns/openssldsa_link.c index 8bea1c09e05e8..61e64db0d4a5a 100644 --- a/lib/dns/openssldsa_link.c +++ b/lib/dns/openssldsa_link.c @@ -1,5 +1,5 @@ /* - * Portions Copyright (C) 2004-2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 2004-2009, 2011-2013 Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -523,6 +523,11 @@ openssldsa_tofile(const dst_key_t *key, const char *directory) { if (key->keydata.dsa == NULL) return (DST_R_NULLKEY); + if (key->external) { + priv.nelements = 0; + return (dst__privstruct_writefile(key, &priv, directory)); + } + dsa = key->keydata.dsa; priv.elements[cnt].tag = TAG_DSA_PRIME; @@ -569,6 +574,7 @@ openssldsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { #define DST_RET(a) {ret = a; goto err;} UNUSED(pub); + /* read private key file */ ret = dst__privstruct_parse(key, DST_ALG_DSA, lexer, mctx, &priv); if (ret != ISC_R_SUCCESS) @@ -607,6 +613,19 @@ openssldsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { } dst__privstruct_free(&priv, mctx); + if (key->external) { + if (pub == NULL) + DST_RET(DST_R_INVALIDPRIVATEKEY); + dsa->q = pub->keydata.dsa->q; + pub->keydata.dsa->q = NULL; + dsa->p = pub->keydata.dsa->p; + pub->keydata.dsa->p = NULL; + dsa->g = pub->keydata.dsa->g; + pub->keydata.dsa->g = NULL; + dsa->pub_key = pub->keydata.dsa->pub_key; + pub->keydata.dsa->pub_key = NULL; + } + key->key_size = BN_num_bits(dsa->p); return (ISC_R_SUCCESS); diff --git a/lib/dns/opensslecdsa_link.c b/lib/dns/opensslecdsa_link.c index c3f5061b75467..40081c2df856e 100644 --- a/lib/dns/opensslecdsa_link.c +++ b/lib/dns/opensslecdsa_link.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2012-2014 Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -371,7 +371,7 @@ opensslecdsa_todns(const dst_key_t *key, isc_buffer_t *data) { cp = buf; if (!i2o_ECPublicKey(eckey, &cp)) DST_RET (dst__openssl_toresult(ISC_R_FAILURE)); - memcpy(r.base, buf + 1, len); + memmove(r.base, buf + 1, len); isc_buffer_add(data, len); ret = ISC_R_SUCCESS; @@ -414,7 +414,7 @@ opensslecdsa_fromdns(dst_key_t *key, isc_buffer_t *data) { return (dst__openssl_toresult(DST_R_OPENSSLFAILURE)); buf[0] = POINT_CONVERSION_UNCOMPRESSED; - memcpy(buf + 1, r.base, len); + memmove(buf + 1, r.base, len); cp = buf; if (o2i_ECPublicKey(&eckey, (const unsigned char **) &cp, @@ -453,6 +453,11 @@ opensslecdsa_tofile(const dst_key_t *key, const char *directory) { if (key->keydata.pkey == NULL) return (DST_R_NULLKEY); + if (key->external) { + priv.nelements = 0; + return (dst__privstruct_writefile(key, &priv, directory)); + } + pkey = key->keydata.pkey; eckey = EVP_PKEY_get1_EC_KEY(pkey); if (eckey == NULL) @@ -514,8 +519,9 @@ static isc_result_t opensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { dst_private_t priv; isc_result_t ret; - EVP_PKEY *pkey; - EC_KEY *eckey = NULL; + EVP_PKEY *pkey, *pubpkey; + EC_KEY *eckey = NULL, *pubeckey = NULL; + const EC_POINT *pubkey; BIGNUM *privkey; int group_nid; isc_mem_t *mctx = key->mctx; @@ -537,16 +543,35 @@ opensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { if (ret != ISC_R_SUCCESS) goto err; - privkey = BN_bin2bn(priv.elements[0].data, - priv.elements[0].length, NULL); - if (privkey == NULL) - DST_RET(ISC_R_NOMEMORY); - if (!EC_KEY_set_private_key(eckey, privkey)) - DST_RET(ISC_R_NOMEMORY); - if (ecdsa_check(eckey, pub) != ISC_R_SUCCESS) - DST_RET(DST_R_INVALIDPRIVATEKEY); - dst__privstruct_free(&priv, mctx); - memset(&priv, 0, sizeof(priv)); + if (key->external) { + /* + * Copy the public key to this new key. + */ + if (pub == NULL) + DST_RET(DST_R_INVALIDPRIVATEKEY); + pubpkey = pub->keydata.pkey; + pubeckey = EVP_PKEY_get1_EC_KEY(pubpkey); + if (pubeckey == NULL) + DST_RET(DST_R_INVALIDPRIVATEKEY); + pubkey = EC_KEY_get0_public_key(pubeckey); + if (pubkey == NULL) + DST_RET(DST_R_INVALIDPRIVATEKEY); + if (EC_KEY_set_public_key(eckey, pubkey) != 1) + DST_RET(DST_R_INVALIDPRIVATEKEY); + if (EC_KEY_check_key(eckey) != 1) + DST_RET(DST_R_INVALIDPRIVATEKEY); + } else { + privkey = BN_bin2bn(priv.elements[0].data, + priv.elements[0].length, NULL); + if (privkey == NULL) + DST_RET(ISC_R_NOMEMORY); + if (!EC_KEY_set_private_key(eckey, privkey)) + DST_RET(ISC_R_NOMEMORY); + if (ecdsa_check(eckey, pub) != ISC_R_SUCCESS) + DST_RET(DST_R_INVALIDPRIVATEKEY); + dst__privstruct_free(&priv, mctx); + memset(&priv, 0, sizeof(priv)); + } pkey = EVP_PKEY_new(); if (pkey == NULL) @@ -561,6 +586,8 @@ opensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { err: if (eckey != NULL) EC_KEY_free(eckey); + if (pubeckey != NULL) + EC_KEY_free(pubeckey); dst__privstruct_free(&priv, mctx); memset(&priv, 0, sizeof(priv)); return (ret); diff --git a/lib/dns/opensslgost_link.c b/lib/dns/opensslgost_link.c index 1ce4405eb21d1..b0578661f97f2 100644 --- a/lib/dns/opensslgost_link.c +++ b/lib/dns/opensslgost_link.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2010-2014 Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -253,7 +253,7 @@ opensslgost_todns(const dst_key_t *key, isc_buffer_t *data) { len = i2d_PUBKEY(pkey, &p); INSIST(len == sizeof(der)); INSIST(memcmp(gost_prefix, der, 37) == 0); - memcpy(r.base, der + 37, 64); + memmove(r.base, der + 37, 64); isc_buffer_add(data, 64); return (ISC_R_SUCCESS); @@ -272,8 +272,8 @@ opensslgost_fromdns(dst_key_t *key, isc_buffer_t *data) { if (r.length != 64) return (DST_R_INVALIDPUBLICKEY); - memcpy(der, gost_prefix, 37); - memcpy(der + 37, r.base, 64); + memmove(der, gost_prefix, 37); + memmove(der + 37, r.base, 64); isc_buffer_forward(data, 64); p = der; @@ -296,6 +296,11 @@ opensslgost_tofile(const dst_key_t *key, const char *directory) { if (key->keydata.pkey == NULL) return (DST_R_NULLKEY); + if (key->external) { + priv.nelements = 0; + return (dst__privstruct_writefile(key, &priv, directory)); + } + pkey = key->keydata.pkey; len = i2d_PrivateKey(pkey, NULL); @@ -337,13 +342,21 @@ opensslgost_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { if (ret != ISC_R_SUCCESS) return (ret); - INSIST(priv.elements[0].tag == TAG_GOST_PRIVASN1); - p = priv.elements[0].data; - if (d2i_PrivateKey(NID_id_GostR3410_2001, &pkey, &p, - (long) priv.elements[0].length) == NULL) - DST_RET(dst__openssl_toresult2("d2i_PrivateKey", - DST_R_INVALIDPRIVATEKEY)); - key->keydata.pkey = pkey; + if (key->external) { + INSIST(priv.nelements == 0); + if (pub == NULL) + DST_RET(DST_R_INVALIDPRIVATEKEY); + key->keydata.pkey = pub->keydata.pkey; + pub->keydata.pkey = NULL; + } else { + INSIST(priv.elements[0].tag == TAG_GOST_PRIVASN1); + p = priv.elements[0].data; + if (d2i_PrivateKey(NID_id_GostR3410_2001, &pkey, &p, + (long) priv.elements[0].length) == NULL) + DST_RET(dst__openssl_toresult2("d2i_PrivateKey", + DST_R_INVALIDPRIVATEKEY)); + key->keydata.pkey = pkey; + } key->key_size = EVP_PKEY_bits(pkey); dst__privstruct_free(&priv, mctx); memset(&priv, 0, sizeof(priv)); diff --git a/lib/dns/opensslrsa_link.c b/lib/dns/opensslrsa_link.c index fa7412cbddbd7..8421c640708a7 100644 --- a/lib/dns/opensslrsa_link.c +++ b/lib/dns/opensslrsa_link.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009, 2011-2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -481,7 +481,7 @@ opensslrsa_sign(dst_context_t *dctx, isc_buffer_t *sig) { INSIST(prefixlen + digestlen <= sizeof(digest)); memmove(digest + prefixlen, digest, digestlen); - memcpy(digest, prefix, prefixlen); + memmove(digest, prefix, prefixlen); status = RSA_private_encrypt(digestlen + prefixlen, digest, r.base, rsa, RSA_PKCS1_PADDING); @@ -1048,8 +1048,14 @@ opensslrsa_tofile(const dst_key_t *key, const char *directory) { return (DST_R_NULLKEY); rsa = key->keydata.rsa; #endif - memset(bufs, 0, sizeof(bufs)); + + if (key->external) { + priv.nelements = 0; + result = dst__privstruct_writefile(key, &priv, directory); + goto fail; + } + for (i = 0; i < 8; i++) { bufs[i] = isc_mem_get(key->mctx, BN_num_bytes(rsa->n)); if (bufs[i] == NULL) { @@ -1205,6 +1211,9 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { if (ret != ISC_R_SUCCESS) goto err; + if (key->external && priv.nelements != 0) + DST_RET(DST_R_INVALIDPRIVATEKEY); + for (i = 0; i < priv.nelements; i++) { switch (priv.elements[i].tag) { case TAG_RSA_ENGINE: @@ -1217,6 +1226,7 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { break; } } + /* * Is this key is stored in a HSM? * See if we can fetch it. @@ -1328,8 +1338,10 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { if (rsa_check(rsa, pubrsa) != ISC_R_SUCCESS) DST_RET(DST_R_INVALIDPRIVATEKEY); - if (BN_num_bits(rsa->e) > RSA_MAX_PUBEXP_BITS) - DST_RET(ISC_R_RANGE); + if (!key->external) { + if (BN_num_bits(rsa->e) > RSA_MAX_PUBEXP_BITS) + DST_RET(ISC_R_RANGE); + } key->key_size = BN_num_bits(rsa->n); if (pubrsa != NULL) RSA_free(pubrsa); diff --git a/lib/dns/portlist.c b/lib/dns/portlist.c index 5bc89f4829840..754eef6687922 100644 --- a/lib/dns/portlist.c +++ b/lib/dns/portlist.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -80,7 +80,7 @@ dns_portlist_create(isc_mem_t *mctx, dns_portlist_t **portlistp) { portlist = isc_mem_get(mctx, sizeof(*portlist)); if (portlist == NULL) return (ISC_R_NOMEMORY); - result = isc_mutex_init(&portlist->lock); + result = isc_mutex_init(&portlist->lock); if (result != ISC_R_SUCCESS) { isc_mem_put(mctx, portlist, sizeof(*portlist)); return (result); @@ -111,7 +111,7 @@ find_port(dns_element_t *list, unsigned int len, in_port_t port) { for (;;) { if (list[xtry].port == port) return (&list[xtry]); - if (port > list[xtry].port) { + if (port > list[xtry].port) { if (xtry == max) break; min = xtry; @@ -164,8 +164,8 @@ dns_portlist_add(dns_portlist_t *portlist, int af, in_port_t port) { goto unlock; } if (portlist->list != NULL) { - memcpy(el, portlist->list, - portlist->allocated * sizeof(*el)); + memmove(el, portlist->list, + portlist->allocated * sizeof(*el)); isc_mem_put(portlist->mctx, portlist->list, portlist->allocated * sizeof(*el)); } @@ -215,7 +215,7 @@ isc_boolean_t dns_portlist_match(dns_portlist_t *portlist, int af, in_port_t port) { dns_element_t *el; isc_boolean_t result = ISC_FALSE; - + REQUIRE(DNS_VALID_PORTLIST(portlist)); REQUIRE(af == AF_INET || af == AF_INET6); LOCK(&portlist->lock); @@ -227,7 +227,7 @@ dns_portlist_match(dns_portlist_t *portlist, int af, in_port_t port) { if (af == AF_INET6 && (el->flags & DNS_PL_INET6) != 0) result = ISC_TRUE; } - } + } UNLOCK(&portlist->lock); return (result); } diff --git a/lib/dns/rbt.c b/lib/dns/rbt.c index 7381b4a325b35..d97fcce28eb9b 100644 --- a/lib/dns/rbt.c +++ b/lib/dns/rbt.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007-2009, 2011-2013 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007-2009, 2011-2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -1479,8 +1479,8 @@ create_node(isc_mem_t *mctx, dns_name_t *name, dns_rbtnode_t **nodep) { OLDOFFSETLEN(node) = OFFSETLEN(node) = labels; ATTRS(node) = name->attributes; - memcpy(NAME(node), region.base, region.length); - memcpy(OFFSETS(node), name->offsets, labels); + memmove(NAME(node), region.base, region.length); + memmove(OFFSETS(node), name->offsets, labels); #if DNS_RBT_USEMAGIC node->magic = DNS_RBTNODE_MAGIC; @@ -1841,7 +1841,7 @@ dns_rbt_deletefromlevel(dns_rbtnode_t *delete, dns_rbtnode_t **rootp) { * information, which will be needed when linking up * delete to the successor's old location. */ - memcpy(tmp, successor, sizeof(dns_rbtnode_t)); + memmove(tmp, successor, sizeof(dns_rbtnode_t)); if (IS_ROOT(delete)) { *rootp = successor; diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index bff52b87ef9d2..013bf34a0a09c 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2013 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -1121,8 +1121,8 @@ newversion(dns_db_t *db, dns_dbversion_t **versionp) { version->hash = rbtdb->current_version->hash; version->salt_length = rbtdb->current_version->salt_length; - memcpy(version->salt, rbtdb->current_version->salt, - version->salt_length); + memmove(version->salt, rbtdb->current_version->salt, + version->salt_length); } else { version->flags = 0; version->iterations = 0; @@ -1706,8 +1706,11 @@ decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, nodelock = &rbtdb->node_locks[bucket]; +#define KEEP_NODE(n, r) \ + ((n)->data != NULL || (n)->down != NULL || (n) == (r)->origin_node) + /* Handle easy and typical case first. */ - if (!node->dirty && (node->data != NULL || node->down != NULL)) { + if (!node->dirty && KEEP_NODE(node, rbtdb)) { dns_rbtnode_refdecrement(node, &nrefs); INSIST((int)nrefs >= 0); if (nrefs == 0) { @@ -1776,12 +1779,11 @@ decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, isc_refcount_decrement(&nodelock->references, &refs); INSIST((int)refs >= 0); - /* - * XXXDCL should this only be done for cache zones? - */ - if (node->data != NULL || node->down != NULL) + if (KEEP_NODE(node, rbtdb)) goto restore_locks; +#undef KEEP_NODE + if (write_locked) { /* * We can now delete the node. @@ -2127,8 +2129,8 @@ setnsec3parameters(dns_db_t *db, rbtdb_version_t *version) { if (nsec3param.flags != 0) continue; - memcpy(version->salt, nsec3param.salt, - nsec3param.salt_length); + memmove(version->salt, nsec3param.salt, + nsec3param.salt_length); version->hash = nsec3param.hash; version->salt_length = nsec3param.salt_length; version->iterations = nsec3param.iterations; @@ -4168,7 +4170,7 @@ cache_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) { header_prev = NULL; for (header = node->data; header != NULL; header = header_next) { header_next = header->next; - if (header->rdh_ttl <= search->now) { + if (header->rdh_ttl < search->now) { /* * This rdataset is stale. If no one else is * using the node, we can clean it up right @@ -4176,7 +4178,7 @@ cache_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) { * the node as dirty, so it will get cleaned * up later. */ - if ((header->rdh_ttl <= search->now - RBTDB_VIRTUAL) && + if ((header->rdh_ttl < search->now - RBTDB_VIRTUAL) && (locktype == isc_rwlocktype_write || NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) { /* @@ -4292,7 +4294,7 @@ find_deepest_zonecut(rbtdb_search_t *search, dns_rbtnode_t *node, header != NULL; header = header_next) { header_next = header->next; - if (header->rdh_ttl <= search->now) { + if (header->rdh_ttl < search->now) { /* * This rdataset is stale. If no one else is * using the node, we can clean it up right @@ -4300,7 +4302,7 @@ find_deepest_zonecut(rbtdb_search_t *search, dns_rbtnode_t *node, * the node as dirty, so it will get cleaned * up later. */ - if ((header->rdh_ttl <= search->now - + if ((header->rdh_ttl < search->now - RBTDB_VIRTUAL) && (locktype == isc_rwlocktype_write || NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) { @@ -4469,7 +4471,7 @@ find_coveringnsec(rbtdb_search_t *search, dns_dbnode_t **nodep, header != NULL; header = header_next) { header_next = header->next; - if (header->rdh_ttl <= now) { + if (header->rdh_ttl < now) { /* * This rdataset is stale. If no one else is * using the node, we can clean it up right @@ -4477,7 +4479,7 @@ find_coveringnsec(rbtdb_search_t *search, dns_dbnode_t **nodep, * node as dirty, so it will get cleaned up * later. */ - if ((header->rdh_ttl <= now - RBTDB_VIRTUAL) && + if ((header->rdh_ttl < now - RBTDB_VIRTUAL) && (locktype == isc_rwlocktype_write || NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) { /* @@ -4626,12 +4628,12 @@ rpz_findips(dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type, switch (rdata.type) { case dns_rdatatype_a: INSIST(rdata.length == 4); - memcpy(&ina.s_addr, rdata.data, 4); + memmove(&ina.s_addr, rdata.data, 4); isc_netaddr_fromin(&netaddr, &ina); break; case dns_rdatatype_aaaa: INSIST(rdata.length == 16); - memcpy(in6a.s6_addr, rdata.data, 16); + memmove(in6a.s6_addr, rdata.data, 16); isc_netaddr_fromin6(&netaddr, &in6a); break; default: @@ -4876,14 +4878,14 @@ cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, header_prev = NULL; for (header = node->data; header != NULL; header = header_next) { header_next = header->next; - if (header->rdh_ttl <= now) { + if (header->rdh_ttl < now) { /* * This rdataset is stale. If no one else is using the * node, we can clean it up right now, otherwise we * mark it as stale, and the node as dirty, so it will * get cleaned up later. */ - if ((header->rdh_ttl <= now - RBTDB_VIRTUAL) && + if ((header->rdh_ttl < now - RBTDB_VIRTUAL) && (locktype == isc_rwlocktype_write || NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) { /* @@ -5183,14 +5185,14 @@ cache_findzonecut(dns_db_t *db, dns_name_t *name, unsigned int options, header_prev = NULL; for (header = node->data; header != NULL; header = header_next) { header_next = header->next; - if (header->rdh_ttl <= now) { + if (header->rdh_ttl < now) { /* * This rdataset is stale. If no one else is using the * node, we can clean it up right now, otherwise we * mark it as stale, and the node as dirty, so it will * get cleaned up later. */ - if ((header->rdh_ttl <= now - RBTDB_VIRTUAL) && + if ((header->rdh_ttl < now - RBTDB_VIRTUAL) && (locktype == isc_rwlocktype_write || NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) { /* @@ -5672,8 +5674,8 @@ cache_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, for (header = rbtnode->data; header != NULL; header = header_next) { header_next = header->next; - if (header->rdh_ttl <= now) { - if ((header->rdh_ttl <= now - RBTDB_VIRTUAL) && + if (header->rdh_ttl < now) { + if ((header->rdh_ttl < now - RBTDB_VIRTUAL) && (locktype == isc_rwlocktype_write || NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) { /* @@ -5981,7 +5983,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, } } if (topheader != NULL && EXISTS(topheader) && - topheader->rdh_ttl > now) { + topheader->rdh_ttl >= now) { /* * Found one. */ @@ -6047,7 +6049,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, * has no effect, provided that the cache data isn't stale. */ if (rbtversion == NULL && trust < header->trust && - (header->rdh_ttl > now || header_nx)) { + (header->rdh_ttl >= now || header_nx)) { free_rdataset(rbtdb, rbtdb->common.mctx, newheader); if (addedrdataset != NULL) bind_rdataset(rbtdb, rbtnode, header, now, @@ -6117,7 +6119,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, * Don't lower trust of existing record if the * update is forced. */ - if (IS_CACHE(rbtdb) && header->rdh_ttl > now && + if (IS_CACHE(rbtdb) && header->rdh_ttl >= now && header->type == dns_rdatatype_ns && !header_nx && !newheader_nx && header->trust >= newheader->trust && @@ -6153,7 +6155,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, * to be no more than the current NS RRset's TTL. This * ensures the delegations that are withdrawn are honoured. */ - if (IS_CACHE(rbtdb) && header->rdh_ttl > now && + if (IS_CACHE(rbtdb) && header->rdh_ttl >= now && header->type == dns_rdatatype_ns && !header_nx && !newheader_nx && header->trust <= newheader->trust) { @@ -6161,7 +6163,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, newheader->rdh_ttl = header->rdh_ttl; } } - if (IS_CACHE(rbtdb) && header->rdh_ttl > now && + if (IS_CACHE(rbtdb) && header->rdh_ttl >= now && (header->type == dns_rdatatype_a || header->type == dns_rdatatype_aaaa || header->type == dns_rdatatype_ds || @@ -6564,7 +6566,7 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, cleanup_dead_nodes(rbtdb, rbtnode->locknum); header = isc_heap_element(rbtdb->heaps[rbtnode->locknum], 1); - if (header && header->rdh_ttl <= now - RBTDB_VIRTUAL) + if (header && header->rdh_ttl < now - RBTDB_VIRTUAL) expire_header(rbtdb, header, tree_locked); /* @@ -6868,28 +6870,21 @@ static isc_result_t loadnode(dns_rbtdb_t *rbtdb, dns_name_t *name, dns_rbtnode_t **nodep, isc_boolean_t hasnsec) { - isc_result_t noderesult, nsecresult; - dns_rbtnode_t *nsecnode; - - noderesult = dns_rbt_addnode(rbtdb->tree, name, nodep); - -#ifdef BIND9 - if (noderesult == ISC_R_SUCCESS && rbtdb->rpz_cidr != NULL) - dns_rpz_cidr_addip(rbtdb->rpz_cidr, name); -#endif + isc_result_t noderesult, nsecresult, tmpresult; + dns_rbtnode_t *nsecnode = NULL, *node = NULL; + noderesult = dns_rbt_addnode(rbtdb->tree, name, &node); if (!hasnsec) - return (noderesult); + goto done; if (noderesult == ISC_R_EXISTS) { /* * Add a node to the auxiliary NSEC tree for an old node * just now getting an NSEC record. */ - if ((*nodep)->nsec == DNS_RBT_NSEC_HAS_NSEC) - return (noderesult); - } else if (noderesult != ISC_R_SUCCESS) { - return (noderesult); - } + if (node->nsec == DNS_RBT_NSEC_HAS_NSEC) + goto done; + } else if (noderesult != ISC_R_SUCCESS) + goto done; /* * Build the auxiliary tree for NSECs as we go. @@ -6899,12 +6894,11 @@ loadnode(dns_rbtdb_t *rbtdb, dns_name_t *name, dns_rbtnode_t **nodep, * Add nodes to the auxiliary tree after corresponding nodes have * been added to the main tree. */ - nsecnode = NULL; nsecresult = dns_rbt_addnode(rbtdb->nsec, name, &nsecnode); if (nsecresult == ISC_R_SUCCESS) { nsecnode->nsec = DNS_RBT_NSEC_NSEC; - (*nodep)->nsec = DNS_RBT_NSEC_HAS_NSEC; - return (noderesult); + node->nsec = DNS_RBT_NSEC_HAS_NSEC; + goto done; } if (nsecresult == ISC_R_EXISTS) { @@ -6915,21 +6909,41 @@ loadnode(dns_rbtdb_t *rbtdb, dns_name_t *name, dns_rbtnode_t **nodep, ISC_LOG_WARNING, "addnode: NSEC node already exists"); #endif - (*nodep)->nsec = DNS_RBT_NSEC_HAS_NSEC; - return (noderesult); + node->nsec = DNS_RBT_NSEC_HAS_NSEC; + goto done; } - nsecresult = dns_rbt_deletenode(rbtdb->tree, *nodep, ISC_FALSE); - if (nsecresult != ISC_R_SUCCESS) - isc_log_write(dns_lctx, - DNS_LOGCATEGORY_DATABASE, - DNS_LOGMODULE_CACHE, - ISC_LOG_WARNING, - "loading_addrdataset: " - "dns_rbt_deletenode: %s after " - "dns_rbt_addnode(NSEC): %s", - isc_result_totext(nsecresult), - isc_result_totext(noderesult)); + if (noderesult == ISC_R_SUCCESS) { + /* + * Remove the node we just added above. + */ + tmpresult = dns_rbt_deletenode(rbtdb->tree, node, ISC_FALSE); + if (tmpresult != ISC_R_SUCCESS) + isc_log_write(dns_lctx, + DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_CACHE, + ISC_LOG_WARNING, + "loading_addrdataset: " + "dns_rbt_deletenode: %s after " + "dns_rbt_addnode(NSEC): %s", + isc_result_totext(tmpresult), + isc_result_totext(noderesult)); + + } + + /* + * Set the error condition to be returned. + */ + noderesult = nsecresult; + + done: +#ifdef BIND9 + if (noderesult == ISC_R_SUCCESS && rbtdb->rpz_cidr != NULL) + dns_rpz_cidr_addip(rbtdb->rpz_cidr, name); +#endif + if (noderesult == ISC_R_SUCCESS || noderesult == ISC_R_EXISTS) + *nodep = node; + return (noderesult); } @@ -7266,7 +7280,8 @@ getnsec3parameters(dns_db_t *db, dns_dbversion_t *version, dns_hash_t *hash, *hash = rbtversion->hash; if (salt != NULL && salt_length != NULL) { REQUIRE(*salt_length >= rbtversion->salt_length); - memcpy(salt, rbtversion->salt, rbtversion->salt_length); + memmove(salt, rbtversion->salt, + rbtversion->salt_length); } if (salt_length != NULL) *salt_length = rbtversion->salt_length; @@ -9289,7 +9304,7 @@ overmem_purge(dns_rbtdb_t *rbtdb, unsigned int locknum_start, isc_rwlocktype_write); header = isc_heap_element(rbtdb->heaps[locknum], 1); - if (header && header->rdh_ttl <= now - RBTDB_VIRTUAL) { + if (header && header->rdh_ttl < now - RBTDB_VIRTUAL) { expire_header(rbtdb, header, tree_locked); purgecount--; } diff --git a/lib/dns/rcode.c b/lib/dns/rcode.c index 0b7fe8c28051d..69007f881efdf 100644 --- a/lib/dns/rcode.c +++ b/lib/dns/rcode.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -194,7 +194,7 @@ str_totext(const char *source, isc_buffer_t *target) { if (l > region.length) return (ISC_R_NOSPACE); - memcpy(region.base, source, l); + memmove(region.base, source, l); isc_buffer_add(target, l); return (ISC_R_SUCCESS); } @@ -381,9 +381,9 @@ dns_keyflags_fromtext(dns_keyflags_t *flagsp, isc_textregion_t *source) unsigned int len; char *delim = memchr(text, '|', end - text); if (delim != NULL) - len = delim - text; + len = (unsigned int)(delim - text); else - len = end - text; + len = (unsigned int)(end - text); for (p = keyflags; p->name != NULL; p++) { if (strncasecmp(p->name, text, len) == 0) break; diff --git a/lib/dns/rdata.c b/lib/dns/rdata.c index a83dab462ce52..5bdd1255b5f75 100644 --- a/lib/dns/rdata.c +++ b/lib/dns/rdata.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2013 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -281,7 +281,7 @@ locator_pton(const char *src, unsigned char *dst) { } if (tp != endp) return (0); - memcpy(dst, tmp, NS_LOCATORSZ); + memmove(dst, tmp, NS_LOCATORSZ); return (1); } @@ -322,7 +322,7 @@ mem_maybedup(isc_mem_t *mctx, void *source, size_t length) { return (source); new = isc_mem_allocate(mctx, length); if (new != NULL) - memcpy(new, source, length); + memmove(new, source, length); return (new); } @@ -502,7 +502,7 @@ dns_rdata_fromwire(dns_rdata_t *rdata, dns_rdataclass_t rdclass, isc_buffer_t st; isc_boolean_t use_default = ISC_FALSE; isc_uint32_t activelength; - size_t length; + unsigned int length; REQUIRE(dctx != NULL); if (rdata != NULL) { @@ -589,7 +589,7 @@ dns_rdata_towire(dns_rdata_t *rdata, dns_compress_t *cctx, isc_buffer_availableregion(target, &tr); if (tr.length < rdata->length) return (ISC_R_NOSPACE); - memcpy(tr.base, rdata->data, rdata->length); + memmove(tr.base, rdata->data, rdata->length); isc_buffer_add(target, rdata->length); return (ISC_R_SUCCESS); } @@ -683,7 +683,7 @@ dns_rdata_fromtext(dns_rdata_t *rdata, dns_rdataclass_t rdclass, unsigned long line; void (*callback)(dns_rdatacallbacks_t *, const char *, ...); isc_result_t tresult; - size_t length; + unsigned int length; isc_boolean_t unknown; REQUIRE(origin == NULL || dns_name_isabsolute(origin) == ISC_TRUE); @@ -916,7 +916,7 @@ dns_rdata_fromstruct(dns_rdata_t *rdata, dns_rdataclass_t rdclass, isc_buffer_t st; isc_region_t region; isc_boolean_t use_default = ISC_FALSE; - size_t length; + unsigned int length; REQUIRE(source != NULL); if (rdata != NULL) { @@ -1179,7 +1179,7 @@ txt_totext(isc_region_t *source, isc_buffer_t *target) { return (ISC_R_NOSPACE); *tp++ = '"'; tl--; - isc_buffer_add(target, tp - (char *)region.base); + isc_buffer_add(target, (unsigned int)(tp - (char *)region.base)); isc_region_consume(source, *source->base + 1); return (ISC_R_SUCCESS); } @@ -1245,7 +1245,7 @@ txt_fromtext(isc_textregion_t *source, isc_buffer_t *target) { } if (escape) return (DNS_R_SYNTAX); - *tregion.base = t - tregion.base - 1; + *tregion.base = (unsigned char)(t - tregion.base - 1); isc_buffer_add(target, *tregion.base + 1); return (ISC_R_SUCCESS); } @@ -1268,7 +1268,7 @@ txt_fromwire(isc_buffer_t *source, isc_buffer_t *target) { return (ISC_R_NOSPACE); if (tregion.base != sregion.base) - memcpy(tregion.base, sregion.base, n); + memmove(tregion.base, sregion.base, n); isc_buffer_forward(source, n); isc_buffer_add(target, n); return (ISC_R_SUCCESS); @@ -1326,7 +1326,7 @@ multitxt_totext(isc_region_t *source, isc_buffer_t *target) { return (ISC_R_NOSPACE); *tp++ = '"'; tl--; - isc_buffer_add(target, tp - (char *)region.base); + isc_buffer_add(target, (unsigned int)(tp - (char *)region.base)); return (ISC_R_SUCCESS); } @@ -1390,7 +1390,7 @@ multitxt_fromtext(isc_textregion_t *source, isc_buffer_t *target) { } if (escape) return (DNS_R_SYNTAX); - *t0 = t - t0 - 1; + *t0 = (unsigned char)(t - t0 - 1); isc_buffer_add(target, *t0 + 1); } while (n != 0); return (ISC_R_SUCCESS); @@ -1418,7 +1418,7 @@ multitxt_fromwire(isc_buffer_t *source, isc_buffer_t *target) { return (ISC_R_NOSPACE); if (tregion.base != sregion.base) - memcpy(tregion.base, sregion.base, n); + memmove(tregion.base, sregion.base, n); isc_buffer_forward(source, n); isc_buffer_add(target, n); isc_buffer_activeregion(source, &sregion); @@ -1469,7 +1469,7 @@ str_totext(const char *source, isc_buffer_t *target) { if (l > region.length) return (ISC_R_NOSPACE); - memcpy(region.base, source, l); + memmove(region.base, source, l); isc_buffer_add(target, l); return (ISC_R_SUCCESS); } @@ -1595,7 +1595,7 @@ mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) { if (length > tr.length) return (ISC_R_NOSPACE); if (tr.base != base) - memcpy(tr.base, base, length); + memmove(tr.base, base, length); isc_buffer_add(target, length); return (ISC_R_SUCCESS); } @@ -1613,7 +1613,7 @@ hexvalue(char value) { c = tolower(c); if ((s = strchr(hexdigits, c)) == NULL) return (-1); - return (s - hexdigits); + return (int)(s - hexdigits); } static int @@ -1628,7 +1628,7 @@ decvalue(char value) { return (-1); if ((s = strchr(decdigits, value)) == NULL) return (-1); - return (s - decdigits); + return (int)(s - decdigits); } static const char atob_digits[86] = @@ -1688,15 +1688,15 @@ byte_atob(int c, isc_buffer_t *target, struct state *state) { } } else if ((s = strchr(atob_digits, c)) != NULL) { if (bcount == 0) { - word = s - atob_digits; + word = (isc_int32_t)(s - atob_digits); ++bcount; } else if (bcount < 4) { word = times85(word); - word += s - atob_digits; + word += (isc_int32_t)(s - atob_digits); ++bcount; } else { word = times85(word); - word += s - atob_digits; + word += (isc_int32_t)(s - atob_digits); RETERR(putbyte((word >> 24) & 0xff, target, state)); RETERR(putbyte((word >> 16) & 0xff, target, state)); RETERR(putbyte((word >> 8) & 0xff, target, state)); diff --git a/lib/dns/rdata/ch_3/a_1.c b/lib/dns/rdata/ch_3/a_1.c index e3f98106514d1..d25fcb50ac40d 100644 --- a/lib/dns/rdata/ch_3/a_1.c +++ b/lib/dns/rdata/ch_3/a_1.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2005, 2007, 2009, 2014 Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -117,7 +117,7 @@ fromwire_ch_a(ARGS_FROMWIRE) { if (tregion.length < 2) return (ISC_R_NOSPACE); - memcpy(tregion.base, sregion.base, 2); + memmove(tregion.base, sregion.base, 2); isc_buffer_forward(source, 2); isc_buffer_add(target, 2); @@ -149,7 +149,7 @@ towire_ch_a(ARGS_TOWIRE) { if (tregion.length < 2) return (ISC_R_NOSPACE); - memcpy(tregion.base, sregion.base, 2); + memmove(tregion.base, sregion.base, 2); isc_buffer_add(target, 2); return (ISC_R_SUCCESS); } diff --git a/lib/dns/rdata/generic/afsdb_18.c b/lib/dns/rdata/generic/afsdb_18.c index 279f86c677d77..af95fa12e91b6 100644 --- a/lib/dns/rdata/generic/afsdb_18.c +++ b/lib/dns/rdata/generic/afsdb_18.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009, 2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -113,7 +113,7 @@ fromwire_afsdb(ARGS_FROMWIRE) { return (ISC_R_NOSPACE); if (sr.length < 2) return (ISC_R_UNEXPECTEDEND); - memcpy(tr.base, sr.base, 2); + memmove(tr.base, sr.base, 2); isc_buffer_forward(source, 2); isc_buffer_add(target, 2); return (dns_name_fromwire(&name, source, dctx, options, target)); @@ -134,7 +134,7 @@ towire_afsdb(ARGS_TOWIRE) { dns_rdata_toregion(rdata, &sr); if (tr.length < 2) return (ISC_R_NOSPACE); - memcpy(tr.base, sr.base, 2); + memmove(tr.base, sr.base, 2); isc_region_consume(&sr, 2); isc_buffer_add(target, 2); diff --git a/lib/dns/rdata/generic/dnskey_48.c b/lib/dns/rdata/generic/dnskey_48.c index 688e7ac5e18f3..aa705cab36848 100644 --- a/lib/dns/rdata/generic/dnskey_48.c +++ b/lib/dns/rdata/generic/dnskey_48.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007, 2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009, 2011-2013 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -32,6 +32,7 @@ static inline isc_result_t fromtext_dnskey(ARGS_FROMTEXT) { + isc_result_t result; isc_token_t token; dns_secalg_t alg; dns_secproto_t proto; @@ -67,7 +68,15 @@ fromtext_dnskey(ARGS_FROMTEXT) { if ((flags & 0xc000) == 0xc000) return (ISC_R_SUCCESS); - return (isc_base64_tobuffer(lexer, target, -1)); + result = isc_base64_tobuffer(lexer, target, -1); + if (result != ISC_R_SUCCESS) + return (result); + + /* Ensure there's at least enough data to compute a key ID for MD5 */ + if (alg == DST_ALG_RSAMD5 && isc_buffer_usedlength(target) < 7) + return (ISC_R_UNEXPECTEDEND); + + return (ISC_R_SUCCESS); } static inline isc_result_t @@ -185,6 +194,15 @@ fromwire_dnskey(ARGS_FROMWIRE) { dns_name_init(&name, NULL); RETERR(dns_name_fromwire(&name, source, dctx, options, target)); } + + /* + * RSAMD5 computes key ID differently from other + * algorithms: we need to ensure there's enough data + * present for the computation + */ + if (algorithm == DST_ALG_RSAMD5 && sr.length < 3) + return (ISC_R_UNEXPECTEDEND); + isc_buffer_activeregion(source, &sr); isc_buffer_forward(source, sr.length); return (mem_tobuffer(target, sr.base, sr.length)); diff --git a/lib/dns/rdata/generic/eui48_108.c b/lib/dns/rdata/generic/eui48_108.c index 3e52fec0ed4a2..b25a7b7e03e43 100644 --- a/lib/dns/rdata/generic/eui48_108.c +++ b/lib/dns/rdata/generic/eui48_108.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2013, 2014 Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -142,7 +142,7 @@ tostruct_eui48(ARGS_TOSTRUCT) { eui48->common.rdtype = rdata->type; ISC_LINK_INIT(&eui48->common, link); - memcpy(eui48->eui48, rdata->data, rdata->length); + memmove(eui48->eui48, rdata->data, rdata->length); return (ISC_R_SUCCESS); } diff --git a/lib/dns/rdata/generic/eui64_109.c b/lib/dns/rdata/generic/eui64_109.c index 245994fdf5c0b..33d2f637c8257 100644 --- a/lib/dns/rdata/generic/eui64_109.c +++ b/lib/dns/rdata/generic/eui64_109.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2013, 2014 Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -147,7 +147,7 @@ tostruct_eui64(ARGS_TOSTRUCT) { eui64->common.rdtype = rdata->type; ISC_LINK_INIT(&eui64->common, link); - memcpy(eui64->eui64, rdata->data, rdata->length); + memmove(eui64->eui64, rdata->data, rdata->length); return (ISC_R_SUCCESS); } diff --git a/lib/dns/rdata/generic/hip_55.c b/lib/dns/rdata/generic/hip_55.c index 5a5140f8ddd6f..5198497dcb078 100644 --- a/lib/dns/rdata/generic/hip_55.c +++ b/lib/dns/rdata/generic/hip_55.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009, 2011 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2009, 2011, 2013 Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -76,7 +76,7 @@ fromtext_hip(ARGS_FROMTEXT) { len = (unsigned char *)isc_buffer_used(target) - start; if (len > 0xffU) RETTOK(ISC_R_RANGE); - RETERR(uint8_tobuffer(len, &hit_len)); + RETERR(uint8_tobuffer((isc_uint32_t)len, &hit_len)); /* * Public key (base64). @@ -92,7 +92,7 @@ fromtext_hip(ARGS_FROMTEXT) { len = (unsigned char *)isc_buffer_used(target) - start; if (len > 0xffffU) RETTOK(ISC_R_RANGE); - RETERR(uint16_tobuffer(len, &key_len)); + RETERR(uint16_tobuffer((isc_uint32_t)len, &key_len)); /* * Rendezvous Servers. @@ -122,7 +122,7 @@ static inline isc_result_t totext_hip(ARGS_TOTEXT) { isc_region_t region; dns_name_t name; - size_t length, key_len, hit_len; + unsigned int length, key_len, hit_len; unsigned char algorithm; char buf[sizeof("225 ")]; diff --git a/lib/dns/rdata/generic/ipseckey_45.c b/lib/dns/rdata/generic/ipseckey_45.c index 1d2508c42e253..230d0d1e1e829 100644 --- a/lib/dns/rdata/generic/ipseckey_45.c +++ b/lib/dns/rdata/generic/ipseckey_45.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005, 2007, 2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2005, 2007, 2009, 2011, 2012, 2014 Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -87,7 +87,7 @@ fromtext_ipseckey(ARGS_FROMTEXT) { isc_buffer_availableregion(target, ®ion); if (region.length < 4) return (ISC_R_NOSPACE); - memcpy(region.base, &addr, 4); + memmove(region.base, &addr, 4); isc_buffer_add(target, 4); break; @@ -97,7 +97,7 @@ fromtext_ipseckey(ARGS_FROMTEXT) { isc_buffer_availableregion(target, ®ion); if (region.length < 16) return (ISC_R_NOSPACE); - memcpy(region.base, addr6, 16); + memmove(region.base, addr6, 16); isc_buffer_add(target, 16); break; @@ -364,7 +364,7 @@ tostruct_ipseckey(ARGS_TOSTRUCT) { break; case 2: - memcpy(ipseckey->in6_addr.s6_addr, region.base, 16); + memmove(ipseckey->in6_addr.s6_addr, region.base, 16); isc_region_consume(®ion, 16); break; diff --git a/lib/dns/rdata/generic/isdn_20.c b/lib/dns/rdata/generic/isdn_20.c index 5aac73f3713f9..0bf2146013e8a 100644 --- a/lib/dns/rdata/generic/isdn_20.c +++ b/lib/dns/rdata/generic/isdn_20.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009, 2013 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -127,6 +127,8 @@ fromstruct_isdn(ARGS_FROMSTRUCT) { RETERR(uint8_tobuffer(isdn->isdn_len, target)); RETERR(mem_tobuffer(target, isdn->isdn, isdn->isdn_len)); + if (isdn->subaddress == NULL) + return (ISC_R_SUCCESS); RETERR(uint8_tobuffer(isdn->subaddress_len, target)); return (mem_tobuffer(target, isdn->subaddress, isdn->subaddress_len)); } @@ -153,11 +155,17 @@ tostruct_isdn(ARGS_TOSTRUCT) { return (ISC_R_NOMEMORY); isc_region_consume(&r, isdn->isdn_len); - isdn->subaddress_len = uint8_fromregion(&r); - isc_region_consume(&r, 1); - isdn->subaddress = mem_maybedup(mctx, r.base, isdn->subaddress_len); - if (isdn->subaddress == NULL) - goto cleanup; + if (r.length == 0) { + isdn->subaddress_len = 0; + isdn->subaddress = NULL; + } else { + isdn->subaddress_len = uint8_fromregion(&r); + isc_region_consume(&r, 1); + isdn->subaddress = mem_maybedup(mctx, r.base, + isdn->subaddress_len); + if (isdn->subaddress == NULL) + goto cleanup; + } isdn->mctx = mctx; return (ISC_R_SUCCESS); diff --git a/lib/dns/rdata/generic/key_25.c b/lib/dns/rdata/generic/key_25.c index 1d0ba83a9b314..f55401e1b8acd 100644 --- a/lib/dns/rdata/generic/key_25.c +++ b/lib/dns/rdata/generic/key_25.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007, 2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009, 2011-2013 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -32,6 +32,7 @@ static inline isc_result_t fromtext_key(ARGS_FROMTEXT) { + isc_result_t result; isc_token_t token; dns_secalg_t alg; dns_secproto_t proto; @@ -67,7 +68,15 @@ fromtext_key(ARGS_FROMTEXT) { if ((flags & 0xc000) == 0xc000) return (ISC_R_SUCCESS); - return (isc_base64_tobuffer(lexer, target, -1)); + result = isc_base64_tobuffer(lexer, target, -1); + if (result != ISC_R_SUCCESS) + return (result); + + /* Ensure there's at least enough data to compute a key ID for MD5 */ + if (alg == DST_ALG_RSAMD5 && isc_buffer_usedlength(target) < 7) + return (ISC_R_UNEXPECTEDEND); + + return (ISC_R_SUCCESS); } static inline isc_result_t @@ -176,6 +185,15 @@ fromwire_key(ARGS_FROMWIRE) { dns_name_init(&name, NULL); RETERR(dns_name_fromwire(&name, source, dctx, options, target)); } + + /* + * RSAMD5 computes key ID differently from other + * algorithms: we need to ensure there's enough data + * present for the computation + */ + if (algorithm == DST_ALG_RSAMD5 && sr.length < 3) + return (ISC_R_UNEXPECTEDEND); + isc_buffer_activeregion(source, &sr); isc_buffer_forward(source, sr.length); return (mem_tobuffer(target, sr.base, sr.length)); diff --git a/lib/dns/rdata/generic/keydata_65533.c b/lib/dns/rdata/generic/keydata_65533.c index a2d83f456e493..fae2bce8dbeb7 100644 --- a/lib/dns/rdata/generic/keydata_65533.c +++ b/lib/dns/rdata/generic/keydata_65533.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2009, 2011-2013 Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -21,10 +21,11 @@ #include <dst/dst.h> -#define RRTYPE_KEYDATA_ATTRIBUTES (DNS_RDATATYPEATTR_DNSSEC) +#define RRTYPE_KEYDATA_ATTRIBUTES (0) static inline isc_result_t fromtext_keydata(ARGS_FROMTEXT) { + isc_result_t result; isc_token_t token; dns_secalg_t alg; dns_secproto_t proto; @@ -79,7 +80,15 @@ fromtext_keydata(ARGS_FROMTEXT) { if ((flags & 0xc000) == 0xc000) return (ISC_R_SUCCESS); - return (isc_base64_tobuffer(lexer, target, -1)); + result = isc_base64_tobuffer(lexer, target, -1); + if (result != ISC_R_SUCCESS) + return (result); + + /* Ensure there's at least enough data to compute a key ID for MD5 */ + if (alg == DST_ALG_RSAMD5 && isc_buffer_usedlength(target) < 19) + return (ISC_R_UNEXPECTEDEND); + + return (ISC_R_SUCCESS); } static inline isc_result_t @@ -93,7 +102,9 @@ totext_keydata(ARGS_TOTEXT) { const char *keyinfo; REQUIRE(rdata->type == 65533); - REQUIRE(rdata->length != 0); + + if ((tctx->flags & DNS_STYLEFLAG_KEYDATA) == 0 || rdata->length < 16) + return (unknown_totext(rdata, tctx, target)); dns_rdata_toregion(rdata, &sr); @@ -194,9 +205,6 @@ fromwire_keydata(ARGS_FROMWIRE) { UNUSED(options); isc_buffer_activeregion(source, &sr); - if (sr.length < 16) - return (ISC_R_UNEXPECTEDEND); - isc_buffer_forward(source, sr.length); return (mem_tobuffer(target, sr.base, sr.length)); } @@ -206,7 +214,6 @@ towire_keydata(ARGS_TOWIRE) { isc_region_t sr; REQUIRE(rdata->type == 65533); - REQUIRE(rdata->length != 0); UNUSED(cctx); @@ -222,8 +229,6 @@ compare_keydata(ARGS_COMPARE) { REQUIRE(rdata1->type == rdata2->type); REQUIRE(rdata1->rdclass == rdata2->rdclass); REQUIRE(rdata1->type == 65533); - REQUIRE(rdata1->length != 0); - REQUIRE(rdata2->length != 0); dns_rdata_toregion(rdata1, &r1); dns_rdata_toregion(rdata2, &r2); @@ -271,7 +276,6 @@ tostruct_keydata(ARGS_TOSTRUCT) { REQUIRE(rdata->type == 65533); REQUIRE(target != NULL); - REQUIRE(rdata->length != 0); keydata->common.rdclass = rdata->rdclass; keydata->common.rdtype = rdata->type; diff --git a/lib/dns/rdata/generic/l32_105.c b/lib/dns/rdata/generic/l32_105.c index 763ddb953fed9..d191624ebc25e 100644 --- a/lib/dns/rdata/generic/l32_105.c +++ b/lib/dns/rdata/generic/l32_105.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2013, 2014 Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -51,7 +51,7 @@ fromtext_l32(ARGS_FROMTEXT) { isc_buffer_availableregion(target, ®ion); if (region.length < 4) return (ISC_R_NOSPACE); - memcpy(region.base, &addr, 4); + memmove(region.base, &addr, 4); isc_buffer_add(target, 4); return (ISC_R_SUCCESS); } diff --git a/lib/dns/rdata/generic/l64_106.c b/lib/dns/rdata/generic/l64_106.c index ff20663355ca7..d811d29ae515a 100644 --- a/lib/dns/rdata/generic/l64_106.c +++ b/lib/dns/rdata/generic/l64_106.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2013, 2014 Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -155,7 +155,7 @@ tostruct_l64(ARGS_TOSTRUCT) { dns_rdata_toregion(rdata, ®ion); l64->pref = uint16_fromregion(®ion); - memcpy(l64->l64, region.base, region.length); + memmove(l64->l64, region.base, region.length); return (ISC_R_SUCCESS); } diff --git a/lib/dns/rdata/generic/nid_104.c b/lib/dns/rdata/generic/nid_104.c index c96b0bf9c9809..39f16ed6f02bf 100644 --- a/lib/dns/rdata/generic/nid_104.c +++ b/lib/dns/rdata/generic/nid_104.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2013, 2014 Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -155,7 +155,7 @@ tostruct_nid(ARGS_TOSTRUCT) { dns_rdata_toregion(rdata, ®ion); nid->pref = uint16_fromregion(®ion); - memcpy(nid->nid, region.base, region.length); + memmove(nid->nid, region.base, region.length); return (ISC_R_SUCCESS); } diff --git a/lib/dns/rdata/generic/opt_41.c b/lib/dns/rdata/generic/opt_41.c index 4b51804317ccd..bd2adb5fe9711 100644 --- a/lib/dns/rdata/generic/opt_41.c +++ b/lib/dns/rdata/generic/opt_41.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007, 2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009, 2011-2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -97,6 +97,7 @@ static inline isc_result_t fromwire_opt(ARGS_FROMWIRE) { isc_region_t sregion; isc_region_t tregion; + isc_uint16_t opt; isc_uint16_t length; unsigned int total; @@ -112,17 +113,48 @@ fromwire_opt(ARGS_FROMWIRE) { while (sregion.length != 0) { if (sregion.length < 4) return (ISC_R_UNEXPECTEDEND); - /* - * Eat the 16bit option code. There is nothing to - * be done with it currently. - */ + opt = uint16_fromregion(&sregion); isc_region_consume(&sregion, 2); length = uint16_fromregion(&sregion); isc_region_consume(&sregion, 2); total += 4; if (sregion.length < length) return (ISC_R_UNEXPECTEDEND); - isc_region_consume(&sregion, length); + switch (opt) { + case DNS_OPT_CLIENT_SUBNET: { + isc_uint16_t family; + isc_uint8_t addrlen; + isc_uint8_t scope; + isc_uint8_t addrbytes; + + if (length < 4) + return (DNS_R_FORMERR); + family = uint16_fromregion(&sregion); + isc_region_consume(&sregion, 2); + addrlen = uint8_fromregion(&sregion); + isc_region_consume(&sregion, 1); + scope = uint8_fromregion(&sregion); + isc_region_consume(&sregion, 1); + switch (family) { + case 1: + if (addrlen > 32U || scope > 32U) + return (DNS_R_FORMERR); + break; + case 2: + if (addrlen > 128U || scope > 128U) + return (DNS_R_FORMERR); + break; + } + addrbytes = (addrlen + 7) / 8; + if (addrbytes + 4 != length) + return (DNS_R_FORMERR); + isc_region_consume(&sregion, addrbytes); + break; + } + default: + isc_region_consume(&sregion, length); + break; + } total += length; } @@ -130,7 +162,7 @@ fromwire_opt(ARGS_FROMWIRE) { isc_buffer_availableregion(target, &tregion); if (tregion.length < total) return (ISC_R_NOSPACE); - memcpy(tregion.base, sregion.base, total); + memmove(tregion.base, sregion.base, total); isc_buffer_forward(source, total); isc_buffer_add(target, total); diff --git a/lib/dns/rdata/generic/rrsig_46.c b/lib/dns/rdata/generic/rrsig_46.c index 58a327c02ed79..5dd5a31a7ca88 100644 --- a/lib/dns/rdata/generic/rrsig_46.c +++ b/lib/dns/rdata/generic/rrsig_46.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007, 2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009, 2011, 2012, 2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -90,7 +90,20 @@ fromtext_rrsig(ARGS_FROMTEXT) { */ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, ISC_FALSE)); - RETTOK(dns_time32_fromtext(DNS_AS_STR(token), &time_expire)); + if (strlen(DNS_AS_STR(token)) <= 10U && + *DNS_AS_STR(token) != '-' && *DNS_AS_STR(token) != '+') { + char *end; + unsigned long u; + isc_uint64_t u64; + + u64 = u = strtoul(DNS_AS_STR(token), &end, 10); + if (u == ULONG_MAX || *end != 0) + RETTOK(DNS_R_SYNTAX); + if (u64 > 0xffffffffUL) + RETTOK(ISC_R_RANGE); + time_expire = u; + } else + RETTOK(dns_time32_fromtext(DNS_AS_STR(token), &time_expire)); RETERR(uint32_tobuffer(time_expire, target)); /* @@ -98,7 +111,20 @@ fromtext_rrsig(ARGS_FROMTEXT) { */ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, ISC_FALSE)); - RETTOK(dns_time32_fromtext(DNS_AS_STR(token), &time_signed)); + if (strlen(DNS_AS_STR(token)) <= 10U && + *DNS_AS_STR(token) != '-' && *DNS_AS_STR(token) != '+') { + char *end; + unsigned long u; + isc_uint64_t u64; + + u64 = u = strtoul(DNS_AS_STR(token), &end, 10); + if (u == ULONG_MAX || *end != 0) + RETTOK(DNS_R_SYNTAX); + if (u64 > 0xffffffffUL) + RETTOK(ISC_R_RANGE); + time_signed = u; + } else + RETTOK(dns_time32_fromtext(DNS_AS_STR(token), &time_signed)); RETERR(uint32_tobuffer(time_signed, target)); /* diff --git a/lib/dns/rdata/generic/rt_21.c b/lib/dns/rdata/generic/rt_21.c index 8f71a2afc8504..86fe2480b7998 100644 --- a/lib/dns/rdata/generic/rt_21.c +++ b/lib/dns/rdata/generic/rt_21.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009, 2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -109,7 +109,7 @@ fromwire_rt(ARGS_FROMWIRE) { return (ISC_R_NOSPACE); if (sregion.length < 2) return (ISC_R_UNEXPECTEDEND); - memcpy(tregion.base, sregion.base, 2); + memmove(tregion.base, sregion.base, 2); isc_buffer_forward(source, 2); isc_buffer_add(target, 2); return (dns_name_fromwire(&name, source, dctx, options, target)); @@ -130,7 +130,7 @@ towire_rt(ARGS_TOWIRE) { dns_rdata_toregion(rdata, ®ion); if (tr.length < 2) return (ISC_R_NOSPACE); - memcpy(tr.base, region.base, 2); + memmove(tr.base, region.base, 2); isc_region_consume(®ion, 2); isc_buffer_add(target, 2); diff --git a/lib/dns/rdata/generic/soa_6.c b/lib/dns/rdata/generic/soa_6.c index ac0a38f7c19e3..fe67d76f1ee3b 100644 --- a/lib/dns/rdata/generic/soa_6.c +++ b/lib/dns/rdata/generic/soa_6.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2007, 2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007, 2009, 2011, 2012, 2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -186,7 +186,7 @@ fromwire_soa(ARGS_FROMWIRE) { if (tregion.length < 20) return (ISC_R_NOSPACE); - memcpy(tregion.base, sregion.base, 20); + memmove(tregion.base, sregion.base, 20); isc_buffer_forward(source, 20); isc_buffer_add(target, 20); @@ -224,7 +224,7 @@ towire_soa(ARGS_TOWIRE) { if (tregion.length < 20) return (ISC_R_NOSPACE); - memcpy(tregion.base, sregion.base, 20); + memmove(tregion.base, sregion.base, 20); isc_buffer_add(target, 20); return (ISC_R_SUCCESS); } diff --git a/lib/dns/rdata/generic/spf_99.c b/lib/dns/rdata/generic/spf_99.c index 492e315d45428..c7cdfc9fbbad5 100644 --- a/lib/dns/rdata/generic/spf_99.c +++ b/lib/dns/rdata/generic/spf_99.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009, 2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -103,7 +103,7 @@ towire_spf(ARGS_TOWIRE) { if (region.length < rdata->length) return (ISC_R_NOSPACE); - memcpy(region.base, rdata->data, rdata->length); + memmove(region.base, rdata->data, rdata->length); isc_buffer_add(target, rdata->length); return (ISC_R_SUCCESS); } diff --git a/lib/dns/rdata/generic/txt_16.c b/lib/dns/rdata/generic/txt_16.c index e1bce6a0deb91..76109251a766d 100644 --- a/lib/dns/rdata/generic/txt_16.c +++ b/lib/dns/rdata/generic/txt_16.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2007-2009, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007-2009, 2012, 2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -110,7 +110,7 @@ towire_txt(ARGS_TOWIRE) { if (region.length < rdata->length) return (ISC_R_NOSPACE); - memcpy(region.base, rdata->data, rdata->length); + memmove(region.base, rdata->data, rdata->length); isc_buffer_add(target, rdata->length); return (ISC_R_SUCCESS); } diff --git a/lib/dns/rdata/hs_4/a_1.c b/lib/dns/rdata/hs_4/a_1.c index 50ae25d52b83e..5f8a87504c0ef 100644 --- a/lib/dns/rdata/hs_4/a_1.c +++ b/lib/dns/rdata/hs_4/a_1.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007, 2009, 2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -48,7 +48,7 @@ fromtext_hs_a(ARGS_FROMTEXT) { isc_buffer_availableregion(target, ®ion); if (region.length < 4) return (ISC_R_NOSPACE); - memcpy(region.base, &addr, 4); + memmove(region.base, &addr, 4); isc_buffer_add(target, 4); return (ISC_R_SUCCESS); } @@ -87,7 +87,7 @@ fromwire_hs_a(ARGS_FROMWIRE) { if (tregion.length < 4) return (ISC_R_NOSPACE); - memcpy(tregion.base, sregion.base, 4); + memmove(tregion.base, sregion.base, 4); isc_buffer_forward(source, 4); isc_buffer_add(target, 4); return (ISC_R_SUCCESS); @@ -106,7 +106,7 @@ towire_hs_a(ARGS_TOWIRE) { isc_buffer_availableregion(target, ®ion); if (region.length < rdata->length) return (ISC_R_NOSPACE); - memcpy(region.base, rdata->data, rdata->length); + memmove(region.base, rdata->data, rdata->length); isc_buffer_add(target, 4); return (ISC_R_SUCCESS); } diff --git a/lib/dns/rdata/in_1/a6_38.c b/lib/dns/rdata/in_1/a6_38.c index 8619f8a213632..b6ef68878e2f0 100644 --- a/lib/dns/rdata/in_1/a6_38.c +++ b/lib/dns/rdata/in_1/a6_38.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007, 2009, 2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -122,7 +122,7 @@ totext_in_a6(ARGS_TOTEXT) { if (prefixlen != 128) { octets = prefixlen/8; memset(addr, 0, sizeof(addr)); - memcpy(&addr[octets], sr.base, 16 - octets); + memmove(&addr[octets], sr.base, 16 - octets); mask = 0xff >> (prefixlen % 8); addr[octets] &= mask; ar.base = addr; @@ -347,7 +347,7 @@ tostruct_in_a6(ARGS_TOSTRUCT) { if (a6->prefixlen != 128) { octets = 16 - a6->prefixlen / 8; INSIST(r.length >= octets); - memcpy(a6->in6_addr.s6_addr + 16 - octets, r.base, octets); + memmove(a6->in6_addr.s6_addr + 16 - octets, r.base, octets); isc_region_consume(&r, octets); } diff --git a/lib/dns/rdata/in_1/a_1.c b/lib/dns/rdata/in_1/a_1.c index 902932e02548a..fcdcaae0545b7 100644 --- a/lib/dns/rdata/in_1/a_1.c +++ b/lib/dns/rdata/in_1/a_1.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007, 2009, 2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -50,7 +50,7 @@ fromtext_in_a(ARGS_FROMTEXT) { isc_buffer_availableregion(target, ®ion); if (region.length < 4) return (ISC_R_NOSPACE); - memcpy(region.base, &addr, 4); + memmove(region.base, &addr, 4); isc_buffer_add(target, 4); return (ISC_R_SUCCESS); } @@ -89,7 +89,7 @@ fromwire_in_a(ARGS_FROMWIRE) { if (tregion.length < 4) return (ISC_R_NOSPACE); - memcpy(tregion.base, sregion.base, 4); + memmove(tregion.base, sregion.base, 4); isc_buffer_forward(source, 4); isc_buffer_add(target, 4); return (ISC_R_SUCCESS); @@ -108,7 +108,7 @@ towire_in_a(ARGS_TOWIRE) { isc_buffer_availableregion(target, ®ion); if (region.length < rdata->length) return (ISC_R_NOSPACE); - memcpy(region.base, rdata->data, rdata->length); + memmove(region.base, rdata->data, rdata->length); isc_buffer_add(target, 4); return (ISC_R_SUCCESS); } diff --git a/lib/dns/rdata/in_1/aaaa_28.c b/lib/dns/rdata/in_1/aaaa_28.c index 5aa59b2ccc2c6..3f88c4db0f2f5 100644 --- a/lib/dns/rdata/in_1/aaaa_28.c +++ b/lib/dns/rdata/in_1/aaaa_28.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009, 2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -51,7 +51,7 @@ fromtext_in_aaaa(ARGS_FROMTEXT) { isc_buffer_availableregion(target, ®ion); if (region.length < 16) return (ISC_R_NOSPACE); - memcpy(region.base, addr, 16); + memmove(region.base, addr, 16); isc_buffer_add(target, 16); return (ISC_R_SUCCESS); } @@ -90,7 +90,7 @@ fromwire_in_aaaa(ARGS_FROMWIRE) { if (tregion.length < 16) return (ISC_R_NOSPACE); - memcpy(tregion.base, sregion.base, 16); + memmove(tregion.base, sregion.base, 16); isc_buffer_forward(source, 16); isc_buffer_add(target, 16); return (ISC_R_SUCCESS); @@ -109,7 +109,7 @@ towire_in_aaaa(ARGS_TOWIRE) { isc_buffer_availableregion(target, ®ion); if (region.length < rdata->length) return (ISC_R_NOSPACE); - memcpy(region.base, rdata->data, rdata->length); + memmove(region.base, rdata->data, rdata->length); isc_buffer_add(target, 16); return (ISC_R_SUCCESS); } @@ -165,7 +165,7 @@ tostruct_in_aaaa(ARGS_TOSTRUCT) { dns_rdata_toregion(rdata, &r); INSIST(r.length == 16); - memcpy(aaaa->in6_addr.s6_addr, r.base, 16); + memmove(aaaa->in6_addr.s6_addr, r.base, 16); return (ISC_R_SUCCESS); } diff --git a/lib/dns/rdata/in_1/apl_42.c b/lib/dns/rdata/in_1/apl_42.c index eb927b9219e3d..94133bae62965 100644 --- a/lib/dns/rdata/in_1/apl_42.c +++ b/lib/dns/rdata/in_1/apl_42.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007-2009, 2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -148,7 +148,7 @@ totext_in_apl(ARGS_TOTEXT) { INSIST(len <= 4); INSIST(prefix <= 32); memset(buf, 0, sizeof(buf)); - memcpy(buf, sr.base, len); + memmove(buf, sr.base, len); RETERR(inet_totext(AF_INET, &ir, target)); break; @@ -156,7 +156,7 @@ totext_in_apl(ARGS_TOTEXT) { INSIST(len <= 16); INSIST(prefix <= 128); memset(buf, 0, sizeof(buf)); - memcpy(buf, sr.base, len); + memmove(buf, sr.base, len); RETERR(inet_totext(AF_INET6, &ir, target)); break; diff --git a/lib/dns/rdata/in_1/wks_11.c b/lib/dns/rdata/in_1/wks_11.c index 1da2611da9b59..4587c813afab1 100644 --- a/lib/dns/rdata/in_1/wks_11.c +++ b/lib/dns/rdata/in_1/wks_11.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2007, 2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007, 2009, 2011-2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -98,7 +98,7 @@ fromtext_in_wks(ARGS_FROMTEXT) { RETTOK(DNS_R_BADDOTTEDQUAD); if (region.length < 4) return (ISC_R_NOSPACE); - memcpy(region.base, &addr, 4); + memmove(region.base, &addr, 4); isc_buffer_add(target, 4); /* @@ -222,7 +222,7 @@ fromwire_in_wks(ARGS_FROMWIRE) { if (tr.length < sr.length) return (ISC_R_NOSPACE); - memcpy(tr.base, sr.base, sr.length); + memmove(tr.base, sr.base, sr.length); isc_buffer_add(target, sr.length); isc_buffer_forward(source, sr.length); @@ -278,7 +278,7 @@ fromstruct_in_wks(ARGS_FROMSTRUCT) { a = ntohl(wks->in_addr.s_addr); RETERR(uint32_tobuffer(a, target)); - RETERR(uint16_tobuffer(wks->protocol, target)); + RETERR(uint8_tobuffer(wks->protocol, target)); return (mem_tobuffer(target, wks->map, wks->map_len)); } @@ -300,8 +300,8 @@ tostruct_in_wks(ARGS_TOSTRUCT) { n = uint32_fromregion(®ion); wks->in_addr.s_addr = htonl(n); isc_region_consume(®ion, 4); - wks->protocol = uint16_fromregion(®ion); - isc_region_consume(®ion, 2); + wks->protocol = uint8_fromregion(®ion); + isc_region_consume(®ion, 1); wks->map_len = region.length; wks->map = mem_maybedup(mctx, region.base, region.length); if (wks->map == NULL) diff --git a/lib/dns/rdataslab.c b/lib/dns/rdataslab.c index cb9ae5425ef9c..1c02b60201b28 100644 --- a/lib/dns/rdataslab.c +++ b/lib/dns/rdataslab.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -318,7 +318,7 @@ dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx, *rawbuf++ |= (x[i].rdata.flags & DNS_RDATA_OFFLINE) ? DNS_RDATASLAB_OFFLINE : 0; } - memcpy(rawbuf, x[i].rdata.data, x[i].rdata.length); + memmove(rawbuf, x[i].rdata.data, x[i].rdata.length); rawbuf += x[i].rdata.length; } @@ -711,7 +711,7 @@ dns_rdataslab_merge(unsigned char *oslab, unsigned char *nslab, tstart = isc_mem_get(mctx, tlength); if (tstart == NULL) return (ISC_R_NOMEMORY); - memcpy(tstart, nslab, reservelen); + memmove(tstart, nslab, reservelen); tcurrent = tstart + reservelen; #if DNS_RDATASET_FIXED offsetbase = tcurrent; @@ -790,7 +790,7 @@ dns_rdataslab_merge(unsigned char *oslab, unsigned char *nslab, #if DNS_RDATASET_FIXED tcurrent += 2; /* fill in later */ #endif - memcpy(tcurrent, data, length); + memmove(tcurrent, data, length); tcurrent += length; oadded++; if (oadded < ocount) { @@ -817,7 +817,7 @@ dns_rdataslab_merge(unsigned char *oslab, unsigned char *nslab, #if DNS_RDATASET_FIXED tcurrent += 2; /* fill in later */ #endif - memcpy(tcurrent, data, length); + memmove(tcurrent, data, length); tcurrent += length; nadded++; if (nadded < ncount) { @@ -913,7 +913,7 @@ dns_rdataslab_subtract(unsigned char *mslab, unsigned char *sslab, * This rdata isn't in the sslab, and thus isn't * being subtracted. */ - tlength += mcurrent - mrdatabegin; + tlength += (unsigned int)(mcurrent - mrdatabegin); tcount++; } else rcount++; @@ -949,7 +949,7 @@ dns_rdataslab_subtract(unsigned char *mslab, unsigned char *sslab, tstart = isc_mem_get(mctx, tlength); if (tstart == NULL) return (ISC_R_NOMEMORY); - memcpy(tstart, mslab, reservelen); + memmove(tstart, mslab, reservelen); tcurrent = tstart + reservelen; #if DNS_RDATASET_FIXED offsetbase = tcurrent; @@ -1000,11 +1000,12 @@ dns_rdataslab_subtract(unsigned char *mslab, unsigned char *sslab, * This rdata isn't in the sslab, and thus should be * copied to the tslab. */ - unsigned int length = mcurrent - mrdatabegin; + unsigned int length; + length = (unsigned int)(mcurrent - mrdatabegin); #if DNS_RDATASET_FIXED offsettable[order] = tcurrent - offsetbase; #endif - memcpy(tcurrent, mrdatabegin, length); + memmove(tcurrent, mrdatabegin, length); tcurrent += length; } dns_rdata_reset(&mrdata); diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 27d15b9329cd5..2e60cd84cca24 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2013 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -105,6 +105,7 @@ #define RTRACE(m) #define RRTRACE(r, m) #define FCTXTRACE(m) +#define FCTXTRACE2(m1, m2) #define FTRACE(m) #define QTRACE(m) #endif @@ -1132,6 +1133,10 @@ log_edns(fetchctx_t *fctx) { if (fctx->reason == NULL) return; + /* + * We do not know if fctx->domain is the actual domain the record + * lives in or a parent domain so we have a '?' after it. + */ dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_EDNS_DISABLED, DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO, @@ -3610,12 +3615,14 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type, */ if (dns_rdatatype_atparent(fctx->type)) findoptions |= DNS_DBFIND_NOEXACT; - result = dns_view_findzonecut(res->view, name, domain, - 0, findoptions, ISC_TRUE, + result = dns_view_findzonecut(res->view, fwdname, + domain, 0, findoptions, + ISC_TRUE, &fctx->nameservers, NULL); if (result != ISC_R_SUCCESS) goto cleanup_name; + result = dns_name_dup(domain, mctx, &fctx->domain); if (result != ISC_R_SUCCESS) { dns_rdataset_disassociate(&fctx->nameservers); @@ -5439,11 +5446,11 @@ is_answeraddress_allowed(dns_view_t *view, dns_name_t *name, dns_rdataset_current(rdataset, &rdata); if (rdataset->type == dns_rdatatype_a) { INSIST(rdata.length == sizeof(ina.s_addr)); - memcpy(&ina.s_addr, rdata.data, sizeof(ina.s_addr)); + memmove(&ina.s_addr, rdata.data, sizeof(ina.s_addr)); isc_netaddr_fromin(&netaddr, &ina); } else { INSIST(rdata.length == sizeof(in6a.s6_addr)); - memcpy(in6a.s6_addr, rdata.data, sizeof(in6a.s6_addr)); + memmove(in6a.s6_addr, rdata.data, sizeof(in6a.s6_addr)); isc_netaddr_fromin6(&netaddr, &in6a); } @@ -6655,7 +6662,7 @@ log_nsid(isc_buffer_t *opt, size_t nsid_len, resquery_t *query, unsigned char *p, *buf, *nsid; /* Allocate buffer for storing hex version of the NSID */ - buflen = nsid_len * 2 + 1; + buflen = (isc_uint16_t)nsid_len * 2 + 1; buf = isc_mem_get(mctx, buflen); if (buf == NULL) return; @@ -7307,9 +7314,12 @@ resquery_response(isc_task_t *task, isc_event_t *event) { * NXDOMAIN, NXRDATASET, or referral. */ result = noanswer_response(fctx, NULL, 0); - if (result == DNS_R_CHASEDSSERVERS) { - } else if (result == DNS_R_DELEGATION) { - force_referral: + switch (result) { + case ISC_R_SUCCESS: + case DNS_R_CHASEDSSERVERS: + break; + case DNS_R_DELEGATION: + force_referral: /* * We don't have the answer, but we know a better * place to look. @@ -7334,7 +7344,8 @@ resquery_response(isc_task_t *task, isc_event_t *event) { fctx->adberr = 0; result = ISC_R_SUCCESS; - } else if (result != ISC_R_SUCCESS) { + break; + default: /* * Something has gone wrong. */ @@ -8844,7 +8855,7 @@ dns_resolver_disable_algorithm(dns_resolver_t *resolver, dns_name_t *name, } memset(new, 0, len); if (algorithms != NULL) - memcpy(new, algorithms, *algorithms); + memmove(new, algorithms, *algorithms); new[len-1] |= mask; *new = len; node->data = new; diff --git a/lib/dns/rootns.c b/lib/dns/rootns.c index 3502022c2ae17..34971788dd89e 100644 --- a/lib/dns/rootns.c +++ b/lib/dns/rootns.c @@ -201,7 +201,7 @@ dns_rootns_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, { isc_result_t result, eresult; isc_buffer_t source; - size_t len; + unsigned int len; dns_rdatacallbacks_t callbacks; dns_db_t *db = NULL; diff --git a/lib/dns/rpz.c b/lib/dns/rpz.c index 2d689e7ba1282..f617fe7b7c6a3 100644 --- a/lib/dns/rpz.c +++ b/lib/dns/rpz.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2013 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2011-2014 Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -1115,7 +1115,7 @@ dns_rpz_cidr_find(dns_rpz_cidr_t *cidr, const isc_netaddr_t *netaddr, * one could cast netaddr->type.in6 to dns_rpz_cidr_key_t *, * but there are objections. */ - memcpy(src_ip6.w, &netaddr->type.in6, sizeof(src_ip6.w)); + memmove(src_ip6.w, &netaddr->type.in6, sizeof(src_ip6.w)); for (i = 0; i < 4; i++) { tgt_ip.w[i] = ntohl(src_ip6.w[i]); } diff --git a/lib/dns/rrl.c b/lib/dns/rrl.c new file mode 100644 index 0000000000000..02554e9a9dfbd --- /dev/null +++ b/lib/dns/rrl.c @@ -0,0 +1,1324 @@ +/* + * Copyright (C) 2013, 2014 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 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. + */ + +/*! \file */ + +/* + * Rate limit DNS responses. + */ + +/* #define ISC_LIST_CHECKINIT */ + +#include <config.h> +#include <isc/mem.h> +#include <isc/net.h> +#include <isc/netaddr.h> +#include <isc/print.h> + +#include <dns/result.h> +#include <dns/rcode.h> +#include <dns/rdatatype.h> +#include <dns/rdataclass.h> +#include <dns/log.h> +#include <dns/rrl.h> +#include <dns/view.h> + +static void +log_end(dns_rrl_t *rrl, dns_rrl_entry_t *e, isc_boolean_t early, + char *log_buf, unsigned int log_buf_len); + +/* + * Get a modulus for a hash function that is tolerably likely to be + * relatively prime to most inputs. Of course, we get a prime for for initial + * values not larger than the square of the last prime. We often get a prime + * after that. + * This works well in practice for hash tables up to at least 100 + * times the square of the last prime and better than a multiplicative hash. + */ +static int +hash_divisor(unsigned int initial) { + static isc_uint16_t primes[] = { + 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, + 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, +#if 0 + 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, + 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, + 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, + 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, + 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, + 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, + 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, + 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, + 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, + 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, + 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, + 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997,1009, +#endif + }; + int divisions, tries; + unsigned int result; + isc_uint16_t *pp, p; + + result = initial; + + if (primes[sizeof(primes)/sizeof(primes[0])-1] >= result) { + pp = primes; + while (*pp < result) + ++pp; + return (*pp); + } + + if ((result & 1) == 0) + ++result; + + divisions = 0; + tries = 1; + pp = primes; + do { + p = *pp++; + ++divisions; + if ((result % p) == 0) { + ++tries; + result += 2; + pp = primes; + } + } while (pp < &primes[sizeof(primes) / sizeof(primes[0])]); + + if (isc_log_wouldlog(dns_lctx, DNS_RRL_LOG_DEBUG3)) + isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL, + DNS_LOGMODULE_REQUEST, DNS_RRL_LOG_DEBUG3, + "%d hash_divisor() divisions in %d tries" + " to get %d from %d", + divisions, tries, result, initial); + + return (result); +} + +/* + * Convert a timestamp to a number of seconds in the past. + */ +static inline int +delta_rrl_time(isc_stdtime_t ts, isc_stdtime_t now) { + int delta; + + delta = now - ts; + if (delta >= 0) + return (delta); + + /* + * The timestamp is in the future. That future might result from + * re-ordered requests, because we use timestamps on requests + * instead of consulting a clock. Timestamps in the distant future are + * assumed to result from clock changes. When the clock changes to + * the past, make existing timestamps appear to be in the past. + */ + if (delta < -DNS_RRL_MAX_TIME_TRAVEL) + return (DNS_RRL_FOREVER); + return (0); +} + +static inline int +get_age(const dns_rrl_t *rrl, const dns_rrl_entry_t *e, isc_stdtime_t now) { + if (!e->ts_valid) + return (DNS_RRL_FOREVER); + return (delta_rrl_time(e->ts + rrl->ts_bases[e->ts_gen], now)); +} + +static inline void +set_age(dns_rrl_t *rrl, dns_rrl_entry_t *e, isc_stdtime_t now) { + dns_rrl_entry_t *e_old; + unsigned int ts_gen; + int i, ts; + + ts_gen = rrl->ts_gen; + ts = now - rrl->ts_bases[ts_gen]; + if (ts < 0) { + if (ts < -DNS_RRL_MAX_TIME_TRAVEL) + ts = DNS_RRL_FOREVER; + else + ts = 0; + } + + /* + * Make a new timestamp base if the current base is too old. + * All entries older than DNS_RRL_MAX_WINDOW seconds are ancient, + * useless history. Their timestamps can be treated as if they are + * all the same. + * We only do arithmetic on more recent timestamps, so bases for + * older timestamps can be recycled provided the old timestamps are + * marked as ancient history. + * This loop is almost always very short because most entries are + * recycled after one second and any entries that need to be marked + * are older than (DNS_RRL_TS_BASES)*DNS_RRL_MAX_TS seconds. + */ + if (ts >= DNS_RRL_MAX_TS) { + ts_gen = (ts_gen + 1) % DNS_RRL_TS_BASES; + for (e_old = ISC_LIST_TAIL(rrl->lru), i = 0; + e_old != NULL && (e_old->ts_gen == ts_gen || + !ISC_LINK_LINKED(e_old, hlink)); + e_old = ISC_LIST_PREV(e_old, lru), ++i) + { + e_old->ts_valid = ISC_FALSE; + } + if (i != 0) + isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL, + DNS_LOGMODULE_REQUEST, DNS_RRL_LOG_DEBUG1, + "rrl new time base scanned %d entries" + " at %d for %d %d %d %d", + i, now, rrl->ts_bases[ts_gen], + rrl->ts_bases[(ts_gen + 1) % + DNS_RRL_TS_BASES], + rrl->ts_bases[(ts_gen + 2) % + DNS_RRL_TS_BASES], + rrl->ts_bases[(ts_gen + 3) % + DNS_RRL_TS_BASES]); + rrl->ts_gen = ts_gen; + rrl->ts_bases[ts_gen] = now; + ts = 0; + } + + e->ts_gen = ts_gen; + e->ts = ts; + e->ts_valid = ISC_TRUE; +} + +static isc_result_t +expand_entries(dns_rrl_t *rrl, int new) { + unsigned int bsize; + dns_rrl_block_t *b; + dns_rrl_entry_t *e; + double rate; + int i; + + if (rrl->num_entries + new >= rrl->max_entries && + rrl->max_entries != 0) + { + new = rrl->max_entries - rrl->num_entries; + if (new <= 0) + return (ISC_R_SUCCESS); + } + + /* + * Log expansions so that the user can tune max-table-size + * and min-table-size. + */ + if (isc_log_wouldlog(dns_lctx, DNS_RRL_LOG_DROP) && + rrl->hash != NULL) { + rate = rrl->probes; + if (rrl->searches != 0) + rate /= rrl->searches; + isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL, + DNS_LOGMODULE_REQUEST, DNS_RRL_LOG_DROP, + "increase from %d to %d RRL entries with" + " %d bins; average search length %.1f", + rrl->num_entries, rrl->num_entries+new, + rrl->hash->length, rate); + } + + bsize = sizeof(dns_rrl_block_t) + (new-1)*sizeof(dns_rrl_entry_t); + b = isc_mem_get(rrl->mctx, bsize); + if (b == NULL) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL, + DNS_LOGMODULE_REQUEST, DNS_RRL_LOG_FAIL, + "isc_mem_get(%d) failed for RRL entries", + bsize); + return (ISC_R_NOMEMORY); + } + memset(b, 0, bsize); + b->size = bsize; + + e = b->entries; + for (i = 0; i < new; ++i, ++e) { + ISC_LINK_INIT(e, hlink); + ISC_LIST_INITANDAPPEND(rrl->lru, e, lru); + } + rrl->num_entries += new; + ISC_LIST_INITANDAPPEND(rrl->blocks, b, link); + + return (ISC_R_SUCCESS); +} + +static inline dns_rrl_bin_t * +get_bin(dns_rrl_hash_t *hash, unsigned int hval) { + return (&hash->bins[hval % hash->length]); +} + +static void +free_old_hash(dns_rrl_t *rrl) { + dns_rrl_hash_t *old_hash; + dns_rrl_bin_t *old_bin; + dns_rrl_entry_t *e, *e_next; + + old_hash = rrl->old_hash; + for (old_bin = &old_hash->bins[0]; + old_bin < &old_hash->bins[old_hash->length]; + ++old_bin) + { + for (e = ISC_LIST_HEAD(*old_bin); e != NULL; e = e_next) { + e_next = ISC_LIST_NEXT(e, hlink); + ISC_LINK_INIT(e, hlink); + } + } + + isc_mem_put(rrl->mctx, old_hash, + sizeof(*old_hash) + + (old_hash->length - 1) * sizeof(old_hash->bins[0])); + rrl->old_hash = NULL; +} + +static isc_result_t +expand_rrl_hash(dns_rrl_t *rrl, isc_stdtime_t now) { + dns_rrl_hash_t *hash; + int old_bins, new_bins, hsize; + double rate; + + if (rrl->old_hash != NULL) + free_old_hash(rrl); + + /* + * Most searches fail and so go to the end of the chain. + * Use a small hash table load factor. + */ + old_bins = (rrl->hash == NULL) ? 0 : rrl->hash->length; + new_bins = old_bins/8 + old_bins; + if (new_bins < rrl->num_entries) + new_bins = rrl->num_entries; + new_bins = hash_divisor(new_bins); + + hsize = sizeof(dns_rrl_hash_t) + (new_bins-1)*sizeof(hash->bins[0]); + hash = isc_mem_get(rrl->mctx, hsize); + if (hash == NULL) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL, + DNS_LOGMODULE_REQUEST, DNS_RRL_LOG_FAIL, + "isc_mem_get(%d) failed for" + " RRL hash table", + hsize); + return (ISC_R_NOMEMORY); + } + memset(hash, 0, hsize); + hash->length = new_bins; + rrl->hash_gen ^= 1; + hash->gen = rrl->hash_gen; + + if (isc_log_wouldlog(dns_lctx, DNS_RRL_LOG_DROP) && old_bins != 0) { + rate = rrl->probes; + if (rrl->searches != 0) + rate /= rrl->searches; + isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL, + DNS_LOGMODULE_REQUEST, DNS_RRL_LOG_DROP, + "increase from %d to %d RRL bins for" + " %d entries; average search length %.1f", + old_bins, new_bins, rrl->num_entries, rate); + } + + rrl->old_hash = rrl->hash; + if (rrl->old_hash != NULL) + rrl->old_hash->check_time = now; + rrl->hash = hash; + + return (ISC_R_SUCCESS); +} + +static void +ref_entry(dns_rrl_t *rrl, dns_rrl_entry_t *e, int probes, isc_stdtime_t now) { + /* + * Make the entry most recently used. + */ + if (ISC_LIST_HEAD(rrl->lru) != e) { + if (e == rrl->last_logged) + rrl->last_logged = ISC_LIST_PREV(e, lru); + ISC_LIST_UNLINK(rrl->lru, e, lru); + ISC_LIST_PREPEND(rrl->lru, e, lru); + } + + /* + * Expand the hash table if it is time and necessary. + * This will leave the newly referenced entry in a chain in the + * old hash table. It will migrate to the new hash table the next + * time it is used or be cut loose when the old hash table is destroyed. + */ + rrl->probes += probes; + ++rrl->searches; + if (rrl->searches > 100 && + delta_rrl_time(rrl->hash->check_time, now) > 1) { + if (rrl->probes/rrl->searches > 2) + expand_rrl_hash(rrl, now); + rrl->hash->check_time = now; + rrl->probes = 0; + rrl->searches = 0; + } +} + +static inline isc_boolean_t +key_cmp(const dns_rrl_key_t *a, const dns_rrl_key_t *b) { + if (memcmp(a, b, sizeof(dns_rrl_key_t)) == 0) + return (ISC_TRUE); + return (ISC_FALSE); +} + +static inline isc_uint32_t +hash_key(const dns_rrl_key_t *key) { + isc_uint32_t hval; + int i; + + hval = key->w[0]; + for (i = sizeof(*key) / sizeof(key->w[0]) - 1; i >= 0; --i) { + hval = key->w[i] + (hval<<1); + } + return (hval); +} + +/* + * Construct the hash table key. + * Use a hash of the DNS query name to save space in the database. + * Collisions result in legitimate rate limiting responses for one + * query name also limiting responses for other names to the + * same client. This is rare and benign enough given the large + * space costs compared to keeping the entire name in the database + * entry or the time costs of dynamic allocation. + */ +static void +make_key(const dns_rrl_t *rrl, dns_rrl_key_t *key, + const isc_sockaddr_t *client_addr, + dns_rdatatype_t qtype, dns_name_t *qname, dns_rdataclass_t qclass, + dns_rrl_rtype_t rtype) +{ + dns_name_t base; + dns_offsets_t base_offsets; + int labels, i; + + memset(key, 0, sizeof(*key)); + + key->s.rtype = rtype; + if (rtype == DNS_RRL_RTYPE_QUERY) { + key->s.qtype = qtype; + key->s.qclass = qclass & 0xff; + } else if (rtype == DNS_RRL_RTYPE_REFERRAL || + rtype == DNS_RRL_RTYPE_NODATA) { + /* + * Because there is no qtype in the empty answer sections of + * referral and NODATA responses, count them as the same. + */ + key->s.qclass = qclass & 0xff; + } + + if (qname != NULL && qname->labels != 0) { + /* + * Ignore the first label of wildcards. + */ + if ((qname->attributes & DNS_NAMEATTR_WILDCARD) != 0 && + (labels = dns_name_countlabels(qname)) > 1) + { + dns_name_init(&base, base_offsets); + dns_name_getlabelsequence(qname, 1, labels-1, &base); + key->s.qname_hash = dns_name_hashbylabel(&base, + ISC_FALSE); + } else { + key->s.qname_hash = dns_name_hashbylabel(qname, + ISC_FALSE); + } + } + + switch (client_addr->type.sa.sa_family) { + case AF_INET: + key->s.ip[0] = (client_addr->type.sin.sin_addr.s_addr & + rrl->ipv4_mask); + break; + case AF_INET6: + key->s.ipv6 = ISC_TRUE; + memmove(key->s.ip, &client_addr->type.sin6.sin6_addr, + sizeof(key->s.ip)); + for (i = 0; i < DNS_RRL_MAX_PREFIX/32; ++i) + key->s.ip[i] &= rrl->ipv6_mask[i]; + break; + } +} + +static inline dns_rrl_rate_t * +get_rate(dns_rrl_t *rrl, dns_rrl_rtype_t rtype) { + switch (rtype) { + case DNS_RRL_RTYPE_QUERY: + return (&rrl->responses_per_second); + case DNS_RRL_RTYPE_REFERRAL: + return (&rrl->referrals_per_second); + case DNS_RRL_RTYPE_NODATA: + return (&rrl->nodata_per_second); + case DNS_RRL_RTYPE_NXDOMAIN: + return (&rrl->nxdomains_per_second); + case DNS_RRL_RTYPE_ERROR: + return (&rrl->errors_per_second); + case DNS_RRL_RTYPE_ALL: + return (&rrl->all_per_second); + default: + INSIST(0); + } + return (NULL); +} + +static int +response_balance(dns_rrl_t *rrl, const dns_rrl_entry_t *e, int age) { + dns_rrl_rate_t *ratep; + int balance, rate; + + if (e->key.s.rtype == DNS_RRL_RTYPE_TCP) { + rate = 1; + } else { + ratep = get_rate(rrl, e->key.s.rtype); + rate = ratep->scaled; + } + + balance = e->responses + age * rate; + if (balance > rate) + balance = rate; + return (balance); +} + +/* + * Search for an entry for a response and optionally create it. + */ +static dns_rrl_entry_t * +get_entry(dns_rrl_t *rrl, const isc_sockaddr_t *client_addr, + dns_rdataclass_t qclass, dns_rdatatype_t qtype, dns_name_t *qname, + dns_rrl_rtype_t rtype, isc_stdtime_t now, isc_boolean_t create, + char *log_buf, unsigned int log_buf_len) +{ + dns_rrl_key_t key; + isc_uint32_t hval; + dns_rrl_entry_t *e; + dns_rrl_hash_t *hash; + dns_rrl_bin_t *new_bin, *old_bin; + int probes, age; + + make_key(rrl, &key, client_addr, qtype, qname, qclass, rtype); + hval = hash_key(&key); + + /* + * Look for the entry in the current hash table. + */ + new_bin = get_bin(rrl->hash, hval); + probes = 1; + e = ISC_LIST_HEAD(*new_bin); + while (e != NULL) { + if (key_cmp(&e->key, &key)) { + ref_entry(rrl, e, probes, now); + return (e); + } + ++probes; + e = ISC_LIST_NEXT(e, hlink); + } + + /* + * Look in the old hash table. + */ + if (rrl->old_hash != NULL) { + old_bin = get_bin(rrl->old_hash, hval); + e = ISC_LIST_HEAD(*old_bin); + while (e != NULL) { + if (key_cmp(&e->key, &key)) { + ISC_LIST_UNLINK(*old_bin, e, hlink); + ISC_LIST_PREPEND(*new_bin, e, hlink); + e->hash_gen = rrl->hash_gen; + ref_entry(rrl, e, probes, now); + return (e); + } + e = ISC_LIST_NEXT(e, hlink); + } + + /* + * Discard prevous hash table when all of its entries are old. + */ + age = delta_rrl_time(rrl->old_hash->check_time, now); + if (age > rrl->window) + free_old_hash(rrl); + } + + if (!create) + return (NULL); + + /* + * The entry does not exist, so create it by finding a free entry. + * Keep currently penalized and logged entries. + * Try to make more entries if none are idle. + * Steal the oldest entry if we cannot create more. + */ + for (e = ISC_LIST_TAIL(rrl->lru); + e != NULL; + e = ISC_LIST_PREV(e, lru)) + { + if (!ISC_LINK_LINKED(e, hlink)) + break; + age = get_age(rrl, e, now); + if (age <= 1) { + e = NULL; + break; + } + if (!e->logged && response_balance(rrl, e, age) > 0) + break; + } + if (e == NULL) { + expand_entries(rrl, ISC_MIN((rrl->num_entries+1)/2, 1000)); + e = ISC_LIST_TAIL(rrl->lru); + } + if (e->logged) + log_end(rrl, e, ISC_TRUE, log_buf, log_buf_len); + if (ISC_LINK_LINKED(e, hlink)) { + if (e->hash_gen == rrl->hash_gen) + hash = rrl->hash; + else + hash = rrl->old_hash; + old_bin = get_bin(hash, hash_key(&e->key)); + ISC_LIST_UNLINK(*old_bin, e, hlink); + } + ISC_LIST_PREPEND(*new_bin, e, hlink); + e->hash_gen = rrl->hash_gen; + e->key = key; + e->ts_valid = ISC_FALSE; + ref_entry(rrl, e, probes, now); + return (e); +} + +static void +debit_log(const dns_rrl_entry_t *e, int age, const char *action) { + char buf[sizeof("age=12345678")]; + const char *age_str; + + if (age == DNS_RRL_FOREVER) { + age_str = ""; + } else { + snprintf(buf, sizeof(buf), "age=%d", age); + age_str = buf; + } + isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL, + DNS_LOGMODULE_REQUEST, DNS_RRL_LOG_DEBUG3, + "rrl %08x %6s responses=%-3d %s", + hash_key(&e->key), age_str, e->responses, action); +} + +static inline dns_rrl_result_t +debit_rrl_entry(dns_rrl_t *rrl, dns_rrl_entry_t *e, double qps, double scale, + const isc_sockaddr_t *client_addr, isc_stdtime_t now, + char *log_buf, unsigned int log_buf_len) +{ + int rate, new_rate, slip, new_slip, age, log_secs, min; + dns_rrl_rate_t *ratep; + dns_rrl_entry_t const *credit_e; + + /* + * Pick the rate counter. + * Optionally adjust the rate by the estimated query/second rate. + */ + ratep = get_rate(rrl, e->key.s.rtype); + rate = ratep->r; + if (rate == 0) + return (DNS_RRL_RESULT_OK); + + if (scale < 1.0) { + /* + * The limit for clients that have used TCP is not scaled. + */ + credit_e = get_entry(rrl, client_addr, + 0, dns_rdatatype_none, NULL, + DNS_RRL_RTYPE_TCP, now, ISC_FALSE, + log_buf, log_buf_len); + if (credit_e != NULL) { + age = get_age(rrl, e, now); + if (age < rrl->window) + scale = 1.0; + } + } + if (scale < 1.0) { + new_rate = (int) (rate * scale); + if (new_rate < 1) + new_rate = 1; + if (ratep->scaled != new_rate) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL, + DNS_LOGMODULE_REQUEST, + DNS_RRL_LOG_DEBUG1, + "%d qps scaled %s by %.2f" + " from %d to %d", + (int)qps, ratep->str, scale, + rate, new_rate); + rate = new_rate; + ratep->scaled = rate; + } + } + + min = -rrl->window * rate; + + /* + * Treat time jumps into the recent past as no time. + * Treat entries older than the window as if they were just created + * Credit other entries. + */ + age = get_age(rrl, e, now); + if (age > 0) { + /* + * Credit tokens earned during elapsed time. + */ + if (age > rrl->window) { + e->responses = rate; + e->slip_cnt = 0; + } else { + e->responses += rate*age; + if (e->responses > rate) { + e->responses = rate; + e->slip_cnt = 0; + } + } + /* + * Find the seconds since last log message without overflowing + * small counter. This counter is reset when an entry is + * created. It is not necessarily reset when some requests + * are answered provided other requests continue to be dropped + * or slipped. This can happen when the request rate is just + * at the limit. + */ + if (e->logged) { + log_secs = e->log_secs; + log_secs += age; + if (log_secs > DNS_RRL_MAX_LOG_SECS || log_secs < 0) + log_secs = DNS_RRL_MAX_LOG_SECS; + e->log_secs = log_secs; + } + } + set_age(rrl, e, now); + + /* + * Debit the entry for this response. + */ + if (--e->responses >= 0) { + if (isc_log_wouldlog(dns_lctx, DNS_RRL_LOG_DEBUG3)) + debit_log(e, age, ""); + return (DNS_RRL_RESULT_OK); + } + + if (e->responses < min) + e->responses = min; + + /* + * Drop this response unless it should slip or leak. + */ + slip = rrl->slip.r; + if (slip > 2 && scale < 1.0) { + new_slip = (int) (slip * scale); + if (new_slip < 2) + new_slip = 2; + if (rrl->slip.scaled != new_slip) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL, + DNS_LOGMODULE_REQUEST, + DNS_RRL_LOG_DEBUG1, + "%d qps scaled slip" + " by %.2f from %d to %d", + (int)qps, scale, + slip, new_slip); + slip = new_slip; + rrl->slip.scaled = slip; + } + } + if (slip != 0 && e->key.s.rtype != DNS_RRL_RTYPE_ALL) { + if (e->slip_cnt++ == 0) { + if ((int) e->slip_cnt >= slip) + e->slip_cnt = 0; + if (isc_log_wouldlog(dns_lctx, DNS_RRL_LOG_DEBUG3)) + debit_log(e, age, "slip"); + return (DNS_RRL_RESULT_SLIP); + } else if ((int) e->slip_cnt >= slip) { + e->slip_cnt = 0; + } + } + + if (isc_log_wouldlog(dns_lctx, DNS_RRL_LOG_DEBUG3)) + debit_log(e, age, "drop"); + return (DNS_RRL_RESULT_DROP); +} + +static inline dns_rrl_qname_buf_t * +get_qname(dns_rrl_t *rrl, const dns_rrl_entry_t *e) { + dns_rrl_qname_buf_t *qbuf; + + qbuf = rrl->qnames[e->log_qname]; + if (qbuf == NULL || qbuf->e != e) + return (NULL); + return (qbuf); +} + +static inline void +free_qname(dns_rrl_t *rrl, dns_rrl_entry_t *e) { + dns_rrl_qname_buf_t *qbuf; + + qbuf = get_qname(rrl, e); + if (qbuf != NULL) { + qbuf->e = NULL; + ISC_LIST_APPEND(rrl->qname_free, qbuf, link); + } +} + +static void +add_log_str(isc_buffer_t *lb, const char *str, unsigned int str_len) { + isc_region_t region; + + isc_buffer_availableregion(lb, ®ion); + if (str_len >= region.length) { + if (region.length <= 0) + return; + str_len = region.length; + } + memmove(region.base, str, str_len); + isc_buffer_add(lb, str_len); +} + +#define ADD_LOG_CSTR(eb, s) add_log_str(eb, s, sizeof(s)-1) + +/* + * Build strings for the logs + */ +static void +make_log_buf(dns_rrl_t *rrl, dns_rrl_entry_t *e, + const char *str1, const char *str2, isc_boolean_t plural, + dns_name_t *qname, isc_boolean_t save_qname, + dns_rrl_result_t rrl_result, isc_result_t resp_result, + char *log_buf, unsigned int log_buf_len) +{ + isc_buffer_t lb; + dns_rrl_qname_buf_t *qbuf; + isc_netaddr_t cidr; + char strbuf[ISC_MAX(sizeof("/123"), sizeof(" (12345678)"))]; + const char *rstr; + isc_result_t msg_result; + + if (log_buf_len <= 1) { + if (log_buf_len == 1) + log_buf[0] = '\0'; + return; + } + isc_buffer_init(&lb, log_buf, log_buf_len-1); + + if (str1 != NULL) + add_log_str(&lb, str1, strlen(str1)); + if (str2 != NULL) + add_log_str(&lb, str2, strlen(str2)); + + switch (rrl_result) { + case DNS_RRL_RESULT_OK: + break; + case DNS_RRL_RESULT_DROP: + ADD_LOG_CSTR(&lb, "drop "); + break; + case DNS_RRL_RESULT_SLIP: + ADD_LOG_CSTR(&lb, "slip "); + break; + default: + INSIST(0); + break; + } + + switch (e->key.s.rtype) { + case DNS_RRL_RTYPE_QUERY: + break; + case DNS_RRL_RTYPE_REFERRAL: + ADD_LOG_CSTR(&lb, "referral "); + break; + case DNS_RRL_RTYPE_NODATA: + ADD_LOG_CSTR(&lb, "NODATA "); + break; + case DNS_RRL_RTYPE_NXDOMAIN: + ADD_LOG_CSTR(&lb, "NXDOMAIN "); + break; + case DNS_RRL_RTYPE_ERROR: + if (resp_result == ISC_R_SUCCESS) { + ADD_LOG_CSTR(&lb, "error "); + } else { + rstr = isc_result_totext(resp_result); + add_log_str(&lb, rstr, strlen(rstr)); + ADD_LOG_CSTR(&lb, " error "); + } + break; + case DNS_RRL_RTYPE_ALL: + ADD_LOG_CSTR(&lb, "all "); + break; + default: + INSIST(0); + } + + if (plural) + ADD_LOG_CSTR(&lb, "responses to "); + else + ADD_LOG_CSTR(&lb, "response to "); + + memset(&cidr, 0, sizeof(cidr)); + if (e->key.s.ipv6) { + snprintf(strbuf, sizeof(strbuf), "/%d", rrl->ipv6_prefixlen); + cidr.family = AF_INET6; + memset(&cidr.type.in6, 0, sizeof(cidr.type.in6)); + memmove(&cidr.type.in6, e->key.s.ip, sizeof(e->key.s.ip)); + } else { + snprintf(strbuf, sizeof(strbuf), "/%d", rrl->ipv4_prefixlen); + cidr.family = AF_INET; + cidr.type.in.s_addr = e->key.s.ip[0]; + } + msg_result = isc_netaddr_totext(&cidr, &lb); + if (msg_result != ISC_R_SUCCESS) + ADD_LOG_CSTR(&lb, "?"); + add_log_str(&lb, strbuf, strlen(strbuf)); + + if (e->key.s.rtype == DNS_RRL_RTYPE_QUERY || + e->key.s.rtype == DNS_RRL_RTYPE_REFERRAL || + e->key.s.rtype == DNS_RRL_RTYPE_NODATA || + e->key.s.rtype == DNS_RRL_RTYPE_NXDOMAIN) { + qbuf = get_qname(rrl, e); + if (save_qname && qbuf == NULL && + qname != NULL && dns_name_isabsolute(qname)) { + /* + * Capture the qname for the "stop limiting" message. + */ + qbuf = ISC_LIST_TAIL(rrl->qname_free); + if (qbuf != NULL) { + ISC_LIST_UNLINK(rrl->qname_free, qbuf, link); + } else if (rrl->num_qnames < DNS_RRL_QNAMES) { + qbuf = isc_mem_get(rrl->mctx, sizeof(*qbuf)); + if (qbuf != NULL) { + memset(qbuf, 0, sizeof(*qbuf)); + ISC_LINK_INIT(qbuf, link); + qbuf->index = rrl->num_qnames; + rrl->qnames[rrl->num_qnames++] = qbuf; + } else { + isc_log_write(dns_lctx, + DNS_LOGCATEGORY_RRL, + DNS_LOGMODULE_REQUEST, + DNS_RRL_LOG_FAIL, + "isc_mem_get(%d)" + " failed for RRL qname", + (int)sizeof(*qbuf)); + } + } + if (qbuf != NULL) { + e->log_qname = qbuf->index; + qbuf->e = e; + dns_fixedname_init(&qbuf->qname); + dns_name_copy(qname, + dns_fixedname_name(&qbuf->qname), + NULL); + } + } + if (qbuf != NULL) + qname = dns_fixedname_name(&qbuf->qname); + if (qname != NULL) { + ADD_LOG_CSTR(&lb, " for "); + (void)dns_name_totext(qname, ISC_TRUE, &lb); + } else { + ADD_LOG_CSTR(&lb, " for (?)"); + } + if (e->key.s.rtype != DNS_RRL_RTYPE_NXDOMAIN) { + ADD_LOG_CSTR(&lb, " "); + (void)dns_rdataclass_totext(e->key.s.qclass, &lb); + if (e->key.s.rtype == DNS_RRL_RTYPE_QUERY) { + ADD_LOG_CSTR(&lb, " "); + (void)dns_rdatatype_totext(e->key.s.qtype, &lb); + } + } + snprintf(strbuf, sizeof(strbuf), " (%08x)", + e->key.s.qname_hash); + add_log_str(&lb, strbuf, strlen(strbuf)); + } + + /* + * We saved room for '\0'. + */ + log_buf[isc_buffer_usedlength(&lb)] = '\0'; +} + +static void +log_end(dns_rrl_t *rrl, dns_rrl_entry_t *e, isc_boolean_t early, + char *log_buf, unsigned int log_buf_len) +{ + if (e->logged) { + make_log_buf(rrl, e, + early ? "*" : NULL, + rrl->log_only ? "would stop limiting " + : "stop limiting ", + ISC_TRUE, NULL, ISC_FALSE, + DNS_RRL_RESULT_OK, ISC_R_SUCCESS, + log_buf, log_buf_len); + isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL, + DNS_LOGMODULE_REQUEST, DNS_RRL_LOG_DROP, + "%s", log_buf); + free_qname(rrl, e); + e->logged = ISC_FALSE; + --rrl->num_logged; + } +} + +/* + * Log messages for streams that have stopped being rate limited. + */ +static void +log_stops(dns_rrl_t *rrl, isc_stdtime_t now, int limit, + char *log_buf, unsigned int log_buf_len) +{ + dns_rrl_entry_t *e; + int age; + + for (e = rrl->last_logged; e != NULL; e = ISC_LIST_PREV(e, lru)) { + if (!e->logged) + continue; + if (now != 0) { + age = get_age(rrl, e, now); + if (age < DNS_RRL_STOP_LOG_SECS || + response_balance(rrl, e, age) < 0) + break; + } + + log_end(rrl, e, now == 0, log_buf, log_buf_len); + if (rrl->num_logged <= 0) + break; + + /* + * Too many messages could stall real work. + */ + if (--limit < 0) { + rrl->last_logged = ISC_LIST_PREV(e, lru); + return; + } + } + if (e == NULL) { + INSIST(rrl->num_logged == 0); + rrl->log_stops_time = now; + } + rrl->last_logged = e; +} + +/* + * Main rate limit interface. + */ +dns_rrl_result_t +dns_rrl(dns_view_t *view, + const isc_sockaddr_t *client_addr, isc_boolean_t is_tcp, + dns_rdataclass_t qclass, dns_rdatatype_t qtype, + dns_name_t *qname, isc_result_t resp_result, isc_stdtime_t now, + isc_boolean_t wouldlog, char *log_buf, unsigned int log_buf_len) +{ + dns_rrl_t *rrl; + dns_rrl_rtype_t rtype; + dns_rrl_entry_t *e; + isc_netaddr_t netclient; + int secs; + double qps, scale; + int exempt_match; + isc_result_t result; + dns_rrl_result_t rrl_result; + + INSIST(log_buf != NULL && log_buf_len > 0); + + rrl = view->rrl; + if (rrl->exempt != NULL) { + isc_netaddr_fromsockaddr(&netclient, client_addr); + result = dns_acl_match(&netclient, NULL, rrl->exempt, + &view->aclenv, &exempt_match, NULL); + if (result == ISC_R_SUCCESS && exempt_match > 0) + return (DNS_RRL_RESULT_OK); + } + + LOCK(&rrl->lock); + + /* + * Estimate total query per second rate when scaling by qps. + */ + if (rrl->qps_scale == 0) { + qps = 0.0; + scale = 1.0; + } else { + ++rrl->qps_responses; + secs = delta_rrl_time(rrl->qps_time, now); + if (secs <= 0) { + qps = rrl->qps; + } else { + qps = (1.0*rrl->qps_responses) / secs; + if (secs >= rrl->window) { + if (isc_log_wouldlog(dns_lctx, + DNS_RRL_LOG_DEBUG3)) + isc_log_write(dns_lctx, + DNS_LOGCATEGORY_RRL, + DNS_LOGMODULE_REQUEST, + DNS_RRL_LOG_DEBUG3, + "%d responses/%d seconds" + " = %d qps", + rrl->qps_responses, secs, + (int)qps); + rrl->qps = qps; + rrl->qps_responses = 0; + rrl->qps_time = now; + } else if (qps < rrl->qps) { + qps = rrl->qps; + } + } + scale = rrl->qps_scale / qps; + } + + /* + * Do maintenance once per second. + */ + if (rrl->num_logged > 0 && rrl->log_stops_time != now) + log_stops(rrl, now, 8, log_buf, log_buf_len); + + /* + * Notice TCP responses when scaling limits by qps. + * Do not try to rate limit TCP responses. + */ + if (is_tcp) { + if (scale < 1.0) { + e = get_entry(rrl, client_addr, + 0, dns_rdatatype_none, NULL, + DNS_RRL_RTYPE_TCP, now, ISC_TRUE, + log_buf, log_buf_len); + if (e != NULL) { + e->responses = -(rrl->window+1); + set_age(rrl, e, now); + } + } + UNLOCK(&rrl->lock); + return (ISC_R_SUCCESS); + } + + /* + * Find the right kind of entry, creating it if necessary. + * If that is impossible, then nothing more can be done + */ + switch (resp_result) { + case ISC_R_SUCCESS: + rtype = DNS_RRL_RTYPE_QUERY; + break; + case DNS_R_DELEGATION: + rtype = DNS_RRL_RTYPE_REFERRAL; + break; + case DNS_R_NXRRSET: + rtype = DNS_RRL_RTYPE_NODATA; + break; + case DNS_R_NXDOMAIN: + rtype = DNS_RRL_RTYPE_NXDOMAIN; + break; + default: + rtype = DNS_RRL_RTYPE_ERROR; + break; + } + e = get_entry(rrl, client_addr, qclass, qtype, qname, rtype, + now, ISC_TRUE, log_buf, log_buf_len); + if (e == NULL) { + UNLOCK(&rrl->lock); + return (DNS_RRL_RESULT_OK); + } + + if (isc_log_wouldlog(dns_lctx, DNS_RRL_LOG_DEBUG1)) { + /* + * Do not worry about speed or releasing the lock. + * This message appears before messages from debit_rrl_entry(). + */ + make_log_buf(rrl, e, "consider limiting ", NULL, ISC_FALSE, + qname, ISC_FALSE, DNS_RRL_RESULT_OK, resp_result, + log_buf, log_buf_len); + isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL, + DNS_LOGMODULE_REQUEST, DNS_RRL_LOG_DEBUG1, + "%s", log_buf); + } + + rrl_result = debit_rrl_entry(rrl, e, qps, scale, client_addr, now, + log_buf, log_buf_len); + + if (rrl->all_per_second.r != 0) { + /* + * We must debit the all-per-second token bucket if we have + * an all-per-second limit for the IP address. + * The all-per-second limit determines the log message + * when both limits are hit. + * The response limiting must continue if the + * all-per-second limiting lapses. + */ + dns_rrl_entry_t *e_all; + dns_rrl_result_t rrl_all_result; + + e_all = get_entry(rrl, client_addr, + 0, dns_rdatatype_none, NULL, + DNS_RRL_RTYPE_ALL, now, ISC_TRUE, + log_buf, log_buf_len); + if (e_all == NULL) { + UNLOCK(&rrl->lock); + return (DNS_RRL_RESULT_OK); + } + rrl_all_result = debit_rrl_entry(rrl, e_all, qps, scale, + client_addr, now, + log_buf, log_buf_len); + if (rrl_all_result != DNS_RRL_RESULT_OK) { + int level; + + e = e_all; + rrl_result = rrl_all_result; + if (rrl_result == DNS_RRL_RESULT_OK) + level = DNS_RRL_LOG_DEBUG2; + else + level = DNS_RRL_LOG_DEBUG1; + if (isc_log_wouldlog(dns_lctx, level)) { + make_log_buf(rrl, e, + "prefer all-per-second limiting ", + NULL, ISC_TRUE, qname, ISC_FALSE, + DNS_RRL_RESULT_OK, resp_result, + log_buf, log_buf_len); + isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL, + DNS_LOGMODULE_REQUEST, level, + "%s", log_buf); + } + } + } + + if (rrl_result == DNS_RRL_RESULT_OK) { + UNLOCK(&rrl->lock); + return (DNS_RRL_RESULT_OK); + } + + /* + * Log occassionally in the rate-limit category. + */ + if ((!e->logged || e->log_secs >= DNS_RRL_MAX_LOG_SECS) && + isc_log_wouldlog(dns_lctx, DNS_RRL_LOG_DROP)) { + make_log_buf(rrl, e, rrl->log_only ? "would " : NULL, + e->logged ? "continue limiting " : "limit ", + ISC_TRUE, qname, ISC_TRUE, + DNS_RRL_RESULT_OK, resp_result, + log_buf, log_buf_len); + if (!e->logged) { + e->logged = ISC_TRUE; + if (++rrl->num_logged <= 1) + rrl->last_logged = e; + } + e->log_secs = 0; + + /* + * Avoid holding the lock. + */ + if (!wouldlog) { + UNLOCK(&rrl->lock); + e = NULL; + } + isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL, + DNS_LOGMODULE_REQUEST, DNS_RRL_LOG_DROP, + "%s", log_buf); + } + + /* + * Make a log message for the caller. + */ + if (wouldlog) + make_log_buf(rrl, e, + rrl->log_only ? "would rate limit " : "rate limit ", + NULL, ISC_FALSE, qname, ISC_FALSE, + rrl_result, resp_result, log_buf, log_buf_len); + + if (e != NULL) { + /* + * Do not save the qname unless we might need it for + * the ending log message. + */ + if (!e->logged) + free_qname(rrl, e); + UNLOCK(&rrl->lock); + } + + return (rrl_result); +} + +void +dns_rrl_view_destroy(dns_view_t *view) { + dns_rrl_t *rrl; + dns_rrl_block_t *b; + dns_rrl_hash_t *h; + char log_buf[DNS_RRL_LOG_BUF_LEN]; + int i; + + rrl = view->rrl; + if (rrl == NULL) + return; + view->rrl = NULL; + + /* + * Assume the caller takes care of locking the view and anything else. + */ + + if (rrl->num_logged > 0) + log_stops(rrl, 0, ISC_INT32_MAX, log_buf, sizeof(log_buf)); + + for (i = 0; i < DNS_RRL_QNAMES; ++i) { + if (rrl->qnames[i] == NULL) + break; + isc_mem_put(rrl->mctx, rrl->qnames[i], sizeof(*rrl->qnames[i])); + } + + if (rrl->exempt != NULL) + dns_acl_detach(&rrl->exempt); + + DESTROYLOCK(&rrl->lock); + + while (!ISC_LIST_EMPTY(rrl->blocks)) { + b = ISC_LIST_HEAD(rrl->blocks); + ISC_LIST_UNLINK(rrl->blocks, b, link); + isc_mem_put(rrl->mctx, b, b->size); + } + + h = rrl->hash; + if (h != NULL) + isc_mem_put(rrl->mctx, h, + sizeof(*h) + (h->length - 1) * sizeof(h->bins[0])); + + h = rrl->old_hash; + if (h != NULL) + isc_mem_put(rrl->mctx, h, + sizeof(*h) + (h->length - 1) * sizeof(h->bins[0])); + + isc_mem_putanddetach(&rrl->mctx, rrl, sizeof(*rrl)); +} + +isc_result_t +dns_rrl_init(dns_rrl_t **rrlp, dns_view_t *view, int min_entries) { + dns_rrl_t *rrl; + isc_result_t result; + + *rrlp = NULL; + + rrl = isc_mem_get(view->mctx, sizeof(*rrl)); + if (rrl == NULL) + return (ISC_R_NOMEMORY); + memset(rrl, 0, sizeof(*rrl)); + isc_mem_attach(view->mctx, &rrl->mctx); + result = isc_mutex_init(&rrl->lock); + if (result != ISC_R_SUCCESS) { + isc_mem_putanddetach(&rrl->mctx, rrl, sizeof(*rrl)); + return (result); + } + isc_stdtime_get(&rrl->ts_bases[0]); + + view->rrl = rrl; + + result = expand_entries(rrl, min_entries); + if (result != ISC_R_SUCCESS) { + dns_rrl_view_destroy(view); + return (result); + } + result = expand_rrl_hash(rrl, 0); + if (result != ISC_R_SUCCESS) { + dns_rrl_view_destroy(view); + return (result); + } + + *rrlp = rrl; + return (ISC_R_SUCCESS); +} diff --git a/lib/dns/spnego.c b/lib/dns/spnego.c index 0c1c8583650df..2da79f8b55ce7 100644 --- a/lib/dns/spnego.c +++ b/lib/dns/spnego.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2013 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2006-2014 Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -463,7 +463,7 @@ code_NegTokenArg(OM_uint32 * minor_status, free(buf); return (GSS_S_FAILURE); } - memcpy(*outbuf, buf + buf_size - buf_len, buf_len); + memmove(*outbuf, buf + buf_size - buf_len, buf_len); *outbuf_size = buf_len; free(buf); @@ -856,7 +856,7 @@ der_get_octet_string(const unsigned char *p, size_t len, data->data = malloc(len); if (data->data == NULL) return (ENOMEM); - memcpy(data->data, p, len); + memmove(data->data, p, len); } else data->data = NULL; if (size) @@ -1107,7 +1107,7 @@ length_len(size_t len) if (len < 128U) return (1); else - return (len_unsigned(len) + 1); + return (len_unsigned((unsigned int)len) + 1); } @@ -1191,18 +1191,18 @@ der_put_length(unsigned char *p, size_t len, size_t val, size_t *size) if (len < 1U) return (ASN1_OVERFLOW); if (val < 128U) { - *p = val; + *p = (unsigned char)val; *size = 1; return (0); } else { size_t l; int e; - e = der_put_unsigned(p, len - 1, val, &l); + e = der_put_unsigned(p, len - 1, (unsigned int)val, &l); if (e) return (e); p -= l; - *p = 0x80 | l; + *p = 0x80 | (unsigned char)l; *size = l + 1; return (0); } @@ -1217,7 +1217,7 @@ der_put_octet_string(unsigned char *p, size_t len, p -= data->length; len -= data->length; POST(len); - memcpy(p + 1, data->data, data->length); + memmove(p + 1, data->data, data->length); *size = data->length; return (0); } @@ -1227,10 +1227,10 @@ der_put_oid(unsigned char *p, size_t len, const oid *data, size_t *size) { unsigned char *base = p; - int n; + size_t n; - for (n = data->length - 1; n >= 2; --n) { - unsigned u = data->components[n]; + for (n = data->length; n >= 3u; --n) { + unsigned u = data->components[n - 1]; if (len < 1U) return (ASN1_OVERFLOW); @@ -1397,7 +1397,7 @@ gssapi_mech_make_header(u_char *p, p += len_len; *p++ = 0x06; *p++ = mech->length; - memcpy(p, mech->elements, mech->length); + memmove(p, mech->elements, mech->length); p += mech->length; return (p); } @@ -1430,7 +1430,7 @@ gssapi_spnego_encapsulate(OM_uint32 * minor_status, gss_release_buffer(minor_status, output_token); return (GSS_S_FAILURE); } - memcpy(p, buf, buf_size); + memmove(p, buf, buf_size); return (GSS_S_COMPLETE); } diff --git a/lib/dns/spnego_asn1.c b/lib/dns/spnego_asn1.c index b506054566935..a90f1be63c2cb 100644 --- a/lib/dns/spnego_asn1.c +++ b/lib/dns/spnego_asn1.c @@ -229,7 +229,7 @@ encode_MechTypeList(unsigned char *p, size_t len, const MechTypeList * data, siz int i, e; for (i = (data)->len - 1; i >= 0; --i) { - int oldret = ret; + size_t oldret = ret; ret = 0; e = encode_MechType(p, len, &(data)->val[i], &l); BACK; @@ -257,7 +257,7 @@ decode_MechTypeList(const unsigned char *p, size_t len, MechTypeList * data, siz len = reallen; { size_t origlen = len; - int oldret = ret; + size_t oldret = ret; ret = 0; (data)->len = 0; (data)->val = NULL; @@ -418,7 +418,7 @@ encode_NegTokenInit(unsigned char *p, size_t len, const NegTokenInit * data, siz int e; if ((data)->mechListMIC) { - int oldret = ret; + size_t oldret = ret; ret = 0; e = encode_octet_string(p, len, (data)->mechListMIC, &l); BACK; @@ -427,7 +427,7 @@ encode_NegTokenInit(unsigned char *p, size_t len, const NegTokenInit * data, siz ret += oldret; } if ((data)->mechToken) { - int oldret = ret; + size_t oldret = ret; ret = 0; e = encode_octet_string(p, len, (data)->mechToken, &l); BACK; @@ -436,7 +436,7 @@ encode_NegTokenInit(unsigned char *p, size_t len, const NegTokenInit * data, siz ret += oldret; } if ((data)->reqFlags) { - int oldret = ret; + size_t oldret = ret; ret = 0; e = encode_ContextFlags(p, len, (data)->reqFlags, &l); BACK; @@ -444,7 +444,7 @@ encode_NegTokenInit(unsigned char *p, size_t len, const NegTokenInit * data, siz BACK; ret += oldret; } { - int oldret = ret; + size_t oldret = ret; ret = 0; e = encode_MechTypeList(p, len, &(data)->mechTypes, &l); BACK; @@ -641,7 +641,7 @@ encode_NegTokenResp(unsigned char *p, size_t len, const NegTokenResp * data, siz int e; if ((data)->mechListMIC) { - int oldret = ret; + size_t oldret = ret; ret = 0; e = encode_octet_string(p, len, (data)->mechListMIC, &l); BACK; @@ -650,7 +650,7 @@ encode_NegTokenResp(unsigned char *p, size_t len, const NegTokenResp * data, siz ret += oldret; } if ((data)->responseToken) { - int oldret = ret; + size_t oldret = ret; ret = 0; e = encode_octet_string(p, len, (data)->responseToken, &l); BACK; @@ -659,7 +659,7 @@ encode_NegTokenResp(unsigned char *p, size_t len, const NegTokenResp * data, siz ret += oldret; } if ((data)->supportedMech) { - int oldret = ret; + size_t oldret = ret; ret = 0; e = encode_MechType(p, len, (data)->supportedMech, &l); BACK; @@ -668,7 +668,7 @@ encode_NegTokenResp(unsigned char *p, size_t len, const NegTokenResp * data, siz ret += oldret; } if ((data)->negState) { - int oldret = ret; + size_t oldret = ret; ret = 0; e = encode_enumerated(p, len, (data)->negState, &l); BACK; diff --git a/lib/dns/ssu.c b/lib/dns/ssu.c index 49a777a6447e2..7adb769cf35e5 100644 --- a/lib/dns/ssu.c +++ b/lib/dns/ssu.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008, 2010, 2011, 2013 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2008, 2010, 2011, 2013, 2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -217,7 +217,7 @@ dns_ssutable_addrule(dns_ssutable_t *table, isc_boolean_t grant, result = ISC_R_NOMEMORY; goto failure; } - memcpy(rule->types, types, ntypes * sizeof(dns_rdatatype_t)); + memmove(rule->types, types, ntypes * sizeof(dns_rdatatype_t)); } else rule->types = NULL; diff --git a/lib/dns/ssu_external.c b/lib/dns/ssu_external.c index 43d231d63eb09..759482768d8f5 100644 --- a/lib/dns/ssu_external.c +++ b/lib/dns/ssu_external.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2011-2013 Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -131,7 +131,7 @@ dns_ssu_external_match(dns_name_t *identity, isc_buffer_t *tkey_token = NULL; int fd; const char *sock_path; - size_t req_len; + unsigned int req_len; isc_region_t token_region; unsigned char *data; isc_buffer_t buf; diff --git a/lib/dns/time.c b/lib/dns/time.c index 0f245a246a9d8..d331ca3bfe102 100644 --- a/lib/dns/time.c +++ b/lib/dns/time.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007, 2009-2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009-2012, 2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -98,7 +98,7 @@ dns_time64_totext(isc_int64_t t, isc_buffer_t *target) { if (l > region.length) return (ISC_R_NOSPACE); - memcpy(region.base, buf, l); + memmove(region.base, buf, l); isc_buffer_add(target, l); return (ISC_R_SUCCESS); } diff --git a/lib/dns/tkey.c b/lib/dns/tkey.c index 161c18808ef46..11b4f49eb04bc 100644 --- a/lib/dns/tkey.c +++ b/lib/dns/tkey.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2013 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -152,7 +152,7 @@ add_rdata_to_list(dns_message_t *msg, dns_name_t *name, dns_rdata_t *rdata, dns_rdata_toregion(rdata, &r); RETERR(isc_buffer_allocate(msg->mctx, &tmprdatabuf, r.length)); isc_buffer_availableregion(tmprdatabuf, &newr); - memcpy(newr.base, r.base, r.length); + memmove(newr.base, r.base, r.length); dns_rdata_fromregion(newrdata, rdata->rdclass, rdata->type, &newr); dns_message_takebuffer(msg, &tmprdatabuf); @@ -252,12 +252,12 @@ compute_secret(isc_buffer_t *shared, isc_region_t *queryrandomness, if (r.length < sizeof(digests) || r.length < r2.length) return (ISC_R_NOSPACE); if (r2.length > sizeof(digests)) { - memcpy(r.base, r2.base, r2.length); + memmove(r.base, r2.base, r2.length); for (i = 0; i < sizeof(digests); i++) r.base[i] ^= digests[i]; isc_buffer_add(secret, r2.length); } else { - memcpy(r.base, digests, sizeof(digests)); + memmove(r.base, digests, sizeof(digests)); for (i = 0; i < r2.length; i++) r.base[i] ^= r2.base[i]; isc_buffer_add(secret, sizeof(digests)); @@ -534,7 +534,7 @@ process_gsstkey(dns_name_t *name, dns_rdata_tkey_t *tkeyin, goto failure; } tkeyout->keylen = isc_buffer_usedlength(outtoken); - memcpy(tkeyout->key, isc_buffer_base(outtoken), + memmove(tkeyout->key, isc_buffer_base(outtoken), isc_buffer_usedlength(outtoken)); isc_buffer_free(&outtoken); } else { @@ -544,7 +544,7 @@ process_gsstkey(dns_name_t *name, dns_rdata_tkey_t *tkeyin, goto failure; } tkeyout->keylen = tkeyin->keylen; - memcpy(tkeyout->key, tkeyin->key, tkeyin->keylen); + memmove(tkeyout->key, tkeyin->key, tkeyin->keylen); } tkeyout->error = dns_rcode_noerror; diff --git a/lib/dns/tsig.c b/lib/dns/tsig.c index c7768f4c788a4..00ab570d9e34d 100644 --- a/lib/dns/tsig.c +++ b/lib/dns/tsig.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2013 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -1370,21 +1370,21 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg, * Extract the header. */ isc_buffer_usedregion(source, &r); - memcpy(header, r.base, DNS_MESSAGE_HEADERLEN); + memmove(header, r.base, DNS_MESSAGE_HEADERLEN); isc_region_consume(&r, DNS_MESSAGE_HEADERLEN); /* * Decrement the additional field counter. */ - memcpy(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2); + memmove(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2); addcount = htons((isc_uint16_t)(ntohs(addcount) - 1)); - memcpy(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2); + memmove(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2); /* * Put in the original id. */ id = htons(tsig.originalid); - memcpy(&header[0], &id, 2); + memmove(&header[0], &id, 2); /* * Digest the modified header. @@ -1609,16 +1609,16 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) { * Extract the header. */ isc_buffer_usedregion(source, &r); - memcpy(header, r.base, DNS_MESSAGE_HEADERLEN); + memmove(header, r.base, DNS_MESSAGE_HEADERLEN); isc_region_consume(&r, DNS_MESSAGE_HEADERLEN); /* * Decrement the additional field counter if necessary. */ if (has_tsig) { - memcpy(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2); + memmove(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2); addcount = htons((isc_uint16_t)(ntohs(addcount) - 1)); - memcpy(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2); + memmove(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2); } /* @@ -1627,7 +1627,7 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) { /* XXX Can TCP transfers be forwarded? How would that work? */ if (has_tsig) { id = htons(tsig.originalid); - memcpy(&header[0], &id, 2); + memmove(&header[0], &id, 2); } /* diff --git a/lib/dns/ttl.c b/lib/dns/ttl.c index d3cf024138db1..c794859064a06 100644 --- a/lib/dns/ttl.c +++ b/lib/dns/ttl.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2011-2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -53,7 +53,7 @@ ttlfmt(unsigned int t, const char *s, isc_boolean_t verbose, isc_boolean_t space, isc_buffer_t *target) { char tmp[60]; - size_t len; + unsigned int len; isc_region_t region; if (verbose) @@ -68,7 +68,7 @@ ttlfmt(unsigned int t, const char *s, isc_boolean_t verbose, isc_buffer_availableregion(target, ®ion); if (len > region.length) return (ISC_R_NOSPACE); - memcpy(region.base, tmp, len); + memmove(region.base, tmp, len); isc_buffer_add(target, len); return (ISC_R_SUCCESS); diff --git a/lib/dns/update.c b/lib/dns/update.c index 14ffcc2234d89..e727c347ce93a 100644 --- a/lib/dns/update.c +++ b/lib/dns/update.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2011-2013 Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -232,7 +232,6 @@ do_one_tuple(dns_difftuple_t **tuple, dns_db_t *db, dns_dbversion_t *ver, * Create a singleton diff. */ dns_diff_init(diff->mctx, &temp_diff); - temp_diff.resign = diff->resign; ISC_LIST_APPEND(temp_diff.tuples, *tuple, link); /* @@ -1211,7 +1210,9 @@ del_keysigs(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, for (i = 0; i < nkeys; i++) { if (rrsig.keyid == dst_key_id(keys[i])) { found = ISC_TRUE; - if (!dst_key_isprivate(keys[i])) { + if (!dst_key_isprivate(keys[i]) && + !dst_key_inactive(keys[i])) + { /* * The re-signing code in zone.c * will mark this as offline. @@ -1354,7 +1355,6 @@ dns_update_signatures(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db, dns_diff_init(diff->mctx, &affected); dns_diff_init(diff->mctx, &sig_diff); - sig_diff.resign = dns_zone_getsigresigninginterval(zone); dns_diff_init(diff->mctx, &nsec_diff); dns_diff_init(diff->mctx, &nsec_mindiff); diff --git a/lib/dns/validator.c b/lib/dns/validator.c index 8cf7f665ec88b..d7982caa777a4 100644 --- a/lib/dns/validator.c +++ b/lib/dns/validator.c @@ -3753,8 +3753,7 @@ dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type, val->keytable = NULL; result = dns_view_getsecroots(val->view, &val->keytable); if (result != ISC_R_SUCCESS) - return (result); - + goto cleanup_mutex; val->keynode = NULL; val->key = NULL; val->siginfo = NULL; @@ -3787,6 +3786,9 @@ dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type, return (ISC_R_SUCCESS); + cleanup_mutex: + DESTROYLOCK(&val->lock); + cleanup_event: isc_task_detach(&tclone); isc_event_free(ISC_EVENT_PTR(&event)); diff --git a/lib/dns/view.c b/lib/dns/view.c index 9c1a201a8bd94..142b09edbd748 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -49,6 +49,7 @@ #include <dns/masterdump.h> #include <dns/order.h> #include <dns/peer.h> +#include <dns/rrl.h> #include <dns/rbt.h> #include <dns/rdataset.h> #include <dns/request.h> @@ -184,6 +185,7 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, view->answeracl_exclude = NULL; view->denyanswernames = NULL; view->answernames_exclude = NULL; + view->rrl = NULL; view->provideixfr = ISC_TRUE; view->maxcachettl = 7 * 24 * 3600; view->maxncachettl = 3 * 3600; @@ -335,10 +337,16 @@ destroy(dns_view_t *view) { dns_acache_detach(&view->acache); } dns_rpz_view_destroy(view); -#else +#ifdef USE_RRL + dns_rrl_view_destroy(view); +#else /* USE_RRL */ + INSIST(view->rrl == NULL); +#endif /* USE_RRL */ +#else /* BIND9 */ INSIST(view->acache == NULL); INSIST(ISC_LIST_EMPTY(view->rpz_zones)); -#endif + INSIST(view->rrl == NULL); +#endif /* BIND9 */ if (view->requestmgr != NULL) dns_requestmgr_detach(&view->requestmgr); if (view->task != NULL) @@ -560,6 +568,8 @@ dialup(dns_zone_t *zone, void *dummy) { void dns_view_dialup(dns_view_t *view) { REQUIRE(DNS_VIEW_VALID(view)); + REQUIRE(view->zonetable != NULL); + (void)dns_zt_apply(view->zonetable, ISC_FALSE, dialup, NULL); } #endif @@ -868,6 +878,7 @@ dns_view_addzone(dns_view_t *view, dns_zone_t *zone) { REQUIRE(DNS_VIEW_VALID(view)); REQUIRE(!view->frozen); + REQUIRE(view->zonetable != NULL); result = dns_zt_mount(view->zonetable, zone); @@ -882,6 +893,7 @@ dns_view_findzone(dns_view_t *view, dns_name_t *name, dns_zone_t **zonep) { REQUIRE(DNS_VIEW_VALID(view)); + LOCK(&view->lock); if (view->zonetable != NULL) { result = dns_zt_find(view->zonetable, name, 0, NULL, zonep); if (result == DNS_R_PARTIALMATCH) { @@ -890,6 +902,7 @@ dns_view_findzone(dns_view_t *view, dns_name_t *name, dns_zone_t **zonep) { } } else result = ISC_R_NOTFOUND; + UNLOCK(&view->lock); return (result); } @@ -952,7 +965,12 @@ dns_view_find2(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type, is_staticstub_zone = ISC_FALSE; #ifdef BIND9 zone = NULL; - result = dns_zt_find(view->zonetable, name, 0, NULL, &zone); + LOCK(&view->lock); + if (view->zonetable != NULL) + result = dns_zt_find(view->zonetable, name, 0, NULL, &zone); + else + result = ISC_R_NOTFOUND; + UNLOCK(&view->lock); if (zone != NULL && dns_zone_gettype(zone) == dns_zone_staticstub && !use_static_stub) { result = ISC_R_NOTFOUND; @@ -1223,9 +1241,14 @@ dns_view_findzonecut2(dns_view_t *view, dns_name_t *name, dns_name_t *fname, */ #ifdef BIND9 zone = NULL; - result = dns_zt_find(view->zonetable, name, 0, NULL, &zone); + LOCK(&view->lock); + if (view->zonetable != NULL) + result = dns_zt_find(view->zonetable, name, 0, NULL, &zone); + else + result = ISC_R_NOTFOUND; if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) result = dns_zone_getdb(zone, &db); + UNLOCK(&view->lock); #else result = ISC_R_NOTFOUND; #endif @@ -1404,6 +1427,8 @@ dns_viewlist_findzone(dns_viewlist_t *list, dns_name_t *name, dns_zone_t **zp = NULL;; REQUIRE(list != NULL); + REQUIRE(zonep != NULL && *zonep == NULL); + for (view = ISC_LIST_HEAD(*list); view != NULL; view = ISC_LIST_NEXT(view, link)) { @@ -1415,7 +1440,13 @@ dns_viewlist_findzone(dns_viewlist_t *list, dns_name_t *name, * treat it as not found. */ zp = (zone1 == NULL) ? &zone1 : &zone2; - result = dns_zt_find(view->zonetable, name, 0, NULL, zp); + LOCK(&view->lock); + if (view->zonetable != NULL) + result = dns_zt_find(view->zonetable, name, 0, + NULL, zp); + else + result = ISC_R_NOTFOUND; + UNLOCK(&view->lock); INSIST(result == ISC_R_SUCCESS || result == ISC_R_NOTFOUND || result == DNS_R_PARTIALMATCH); @@ -1706,13 +1737,17 @@ dns_view_getrootdelonly(dns_view_t *view) { #ifdef BIND9 isc_result_t dns_view_freezezones(dns_view_t *view, isc_boolean_t value) { + REQUIRE(DNS_VIEW_VALID(view)); + REQUIRE(view->zonetable != NULL); + return (dns_zt_freezezones(view->zonetable, value)); } #endif void dns_view_setresstats(dns_view_t *view, isc_stats_t *stats) { + REQUIRE(DNS_VIEW_VALID(view)); REQUIRE(!view->frozen); REQUIRE(view->resstats == NULL); diff --git a/lib/dns/xfrin.c b/lib/dns/xfrin.c index 813f616e6fa08..30f2f3b347f45 100644 --- a/lib/dns/xfrin.c +++ b/lib/dns/xfrin.c @@ -221,7 +221,6 @@ static isc_result_t xfrin_start(dns_xfrin_ctx_t *xfr); static void xfrin_connect_done(isc_task_t *task, isc_event_t *event); static isc_result_t xfrin_send_request(dns_xfrin_ctx_t *xfr); static void xfrin_send_done(isc_task_t *task, isc_event_t *event); -static void xfrin_sendlen_done(isc_task_t *task, isc_event_t *event); static void xfrin_recv_done(isc_task_t *task, isc_event_t *event); static void xfrin_timeout(isc_task_t *task, isc_event_t *event); @@ -270,13 +269,18 @@ axfr_init(dns_xfrin_ctx_t *xfr) { static isc_result_t axfr_makedb(dns_xfrin_ctx_t *xfr, dns_db_t **dbp) { - return (dns_db_create(xfr->mctx, /* XXX */ - "rbt", /* XXX guess */ - &xfr->name, - dns_dbtype_zone, - xfr->rdclass, - 0, NULL, /* XXX guess */ - dbp)); + isc_result_t result; + + result = dns_db_create(xfr->mctx, /* XXX */ + "rbt", /* XXX guess */ + &xfr->name, + dns_dbtype_zone, + xfr->rdclass, + 0, NULL, /* XXX guess */ + dbp); + if (result == ISC_R_SUCCESS) + result = dns_zone_rpz_enable_db(xfr->zone, *dbp); + return (result); } static isc_result_t @@ -861,8 +865,11 @@ xfrin_create(isc_mem_t *mctx, xfr->sourceaddr = *sourceaddr; isc_sockaddr_setport(&xfr->sourceaddr, 0); - isc_buffer_init(&xfr->qbuffer, xfr->qbuffer_data, - sizeof(xfr->qbuffer_data)); + /* + * Reserve 2 bytes for TCP length at the begining of the buffer. + */ + isc_buffer_init(&xfr->qbuffer, &xfr->qbuffer_data[2], + sizeof(xfr->qbuffer_data) - 2); xfr->magic = XFRIN_MAGIC; *xfrp = xfr; @@ -938,6 +945,8 @@ xfrin_connect_done(isc_task_t *task, isc_event_t *event) { isc_result_t result = cev->result; char sourcetext[ISC_SOCKADDR_FORMATSIZE]; isc_sockaddr_t sockaddr; + dns_zonemgr_t * zmgr; + isc_time_t now; REQUIRE(VALID_XFRIN(xfr)); @@ -952,16 +961,16 @@ xfrin_connect_done(isc_task_t *task, isc_event_t *event) { return; } - if (result != ISC_R_SUCCESS) { - dns_zonemgr_t * zmgr = dns_zone_getmgr(xfr->zone); - isc_time_t now; - - if (zmgr != NULL) { + zmgr = dns_zone_getmgr(xfr->zone); + if (zmgr != NULL) { + if (result != ISC_R_SUCCESS) { TIME_NOW(&now); dns_zonemgr_unreachableadd(zmgr, &xfr->masteraddr, &xfr->sourceaddr, &now); - } - goto failure; + goto failure; + } else + dns_zonemgr_unreachabledel(zmgr, &xfr->masteraddr, + &xfr->sourceaddr); } result = isc_socket_getsockname(xfr->socket, &sockaddr); @@ -1042,10 +1051,8 @@ static isc_result_t xfrin_send_request(dns_xfrin_ctx_t *xfr) { isc_result_t result; isc_region_t region; - isc_region_t lregion; dns_rdataset_t *qrdataset = NULL; dns_message_t *msg = NULL; - unsigned char length[2]; dns_difftuple_t *soatuple = NULL; dns_name_t *qname = NULL; dns_dbversion_t *ver = NULL; @@ -1114,12 +1121,16 @@ xfrin_send_request(dns_xfrin_ctx_t *xfr) { isc_buffer_usedregion(&xfr->qbuffer, ®ion); INSIST(region.length <= 65535); - length[0] = region.length >> 8; - length[1] = region.length & 0xFF; - lregion.base = length; - lregion.length = 2; - CHECK(isc_socket_send(xfr->socket, &lregion, xfr->task, - xfrin_sendlen_done, xfr)); + /* + * Record message length and adjust region to include TCP + * length field. + */ + xfr->qbuffer_data[0] = (region.length >> 8) & 0xff; + xfr->qbuffer_data[1] = region.length & 0xff; + region.base -= 2; + region.length += 2; + CHECK(isc_socket_send(xfr->socket, ®ion, xfr->task, + xfrin_send_done, xfr)); xfr->sends++; failure: @@ -1136,42 +1147,6 @@ xfrin_send_request(dns_xfrin_ctx_t *xfr) { return (result); } -/* XXX there should be library support for sending DNS TCP messages */ - -static void -xfrin_sendlen_done(isc_task_t *task, isc_event_t *event) { - isc_socketevent_t *sev = (isc_socketevent_t *) event; - dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *) event->ev_arg; - isc_result_t evresult = sev->result; - isc_result_t result; - isc_region_t region; - - REQUIRE(VALID_XFRIN(xfr)); - - UNUSED(task); - - INSIST(event->ev_type == ISC_SOCKEVENT_SENDDONE); - isc_event_free(&event); - - xfr->sends--; - if (xfr->shuttingdown) { - maybe_free(xfr); - return; - } - - xfrin_log(xfr, ISC_LOG_DEBUG(3), "sent request length prefix"); - CHECK(evresult); - - isc_buffer_usedregion(&xfr->qbuffer, ®ion); - CHECK(isc_socket_send(xfr->socket, ®ion, xfr->task, - xfrin_send_done, xfr)); - xfr->sends++; - failure: - if (result != ISC_R_SUCCESS) - xfrin_fail(xfr, result, "failed sending request length prefix"); -} - - static void xfrin_send_done(isc_task_t *task, isc_event_t *event) { isc_socketevent_t *sev = (isc_socketevent_t *) event; diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 10ba807c52f17..01ff97b11dcbc 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2013 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -37,6 +37,7 @@ #include <isc/strerror.h> #include <isc/string.h> #include <isc/taskpool.h> +#include <isc/thread.h> #include <isc/timer.h> #include <isc/util.h> @@ -162,10 +163,20 @@ typedef struct dns_asyncload dns_asyncload_t; #define UNLOCK_ZONE(z) \ do { (z)->locked = ISC_FALSE; UNLOCK(&(z)->lock); } while (0) #define LOCKED_ZONE(z) ((z)->locked) +#define TRYLOCK_ZONE(result, z) \ + do { \ + result = isc_mutex_trylock(&(z)->lock); \ + if (result == ISC_R_SUCCESS) { \ + INSIST((z)->locked == ISC_FALSE); \ + (z)->locked = ISC_TRUE; \ + } \ + } while (0) #else #define LOCK_ZONE(z) LOCK(&(z)->lock) #define UNLOCK_ZONE(z) UNLOCK(&(z)->lock) #define LOCKED_ZONE(z) ISC_TRUE +#define TRYLOCK_ZONE(result, z) \ + do { result = isc_mutex_trylock(&(z)->lock); } while (0) #endif #ifdef ISC_RWLOCK_USEATOMIC @@ -455,6 +466,7 @@ struct dns_unreachable { isc_sockaddr_t local; isc_uint32_t expire; isc_uint32_t last; + isc_uint32_t count; }; struct dns_zonemgr { @@ -468,7 +480,8 @@ struct dns_zonemgr { isc_taskpool_t * loadtasks; isc_task_t * task; isc_pool_t * mctxpool; - isc_ratelimiter_t * rl; + isc_ratelimiter_t * notifyrl; + isc_ratelimiter_t * refreshrl; isc_rwlock_t rwlock; isc_mutex_t iolock; isc_rwlock_t urlock; @@ -673,7 +686,6 @@ static void zone_name_tostr(dns_zone_t *zone, char *buf, size_t length); static void zone_rdclass_tostr(dns_zone_t *zone, char *buf, size_t length); static void zone_viewname_tostr(dns_zone_t *zone, char *buf, size_t length); static isc_result_t zone_send_secureserial(dns_zone_t *zone, - isc_boolean_t secure_locked, isc_uint32_t serial); #if 0 @@ -729,10 +741,7 @@ static isc_result_t delete_nsec(dns_db_t *db, dns_dbversion_t *ver, dns_dbnode_t *node, dns_name_t *name, dns_diff_t *diff); static void zone_rekey(dns_zone_t *zone); -static isc_boolean_t delsig_ok(dns_rdata_rrsig_t *rrsig_ptr, - dst_key_t **keys, unsigned int nkeys); -static isc_result_t zone_send_securedb(dns_zone_t *zone, isc_boolean_t locked, - dns_db_t *db); +static isc_result_t zone_send_securedb(dns_zone_t *zone, dns_db_t *db); #define ENTER zone_debuglog(zone, me, 1, "enter") @@ -767,6 +776,20 @@ static const char *dbargv_default[] = { "rbt" }; } \ } while (0) +typedef struct nsec3param nsec3param_t; +struct nsec3param { + unsigned char data[DNS_NSEC3PARAM_BUFFERSIZE + 1]; + unsigned int length; + isc_boolean_t nsec; + isc_boolean_t replace; + ISC_LINK(nsec3param_t) link; +}; +typedef ISC_LIST(nsec3param_t) nsec3paramlist_t; +struct np3event { + isc_event_t event; + nsec3param_t params; +}; + /*% * Increment resolver-related statistics counters. Zone must be locked. */ @@ -967,6 +990,7 @@ zone_free(dns_zone_t *zone) { REQUIRE(zone->irefs == 0); REQUIRE(!LOCKED_ZONE(zone)); REQUIRE(zone->timer == NULL); + REQUIRE(zone->zmgr == NULL); /* * Managed objects. Order is important. @@ -981,8 +1005,6 @@ zone_free(dns_zone_t *zone) { isc_task_detach(&zone->task); if (zone->loadtask != NULL) isc_task_detach(&zone->loadtask); - if (zone->zmgr != NULL) - dns_zonemgr_releasezone(zone->zmgr, zone); /* Unmanaged objects */ for (signing = ISC_LIST_HEAD(zone->signing); @@ -1534,6 +1556,18 @@ dns_zone_get_rpz(dns_zone_t *zone) { return (zone->is_rpz); } +/* + * If a zone is a response policy zone, mark its new database. + */ +isc_result_t +dns_zone_rpz_enable_db(dns_zone_t *zone, dns_db_t *db) { +#ifdef BIND9 + if (zone->is_rpz) + return (dns_db_rpz_enabled(db, NULL)); +#endif + return (ISC_R_SUCCESS); +} + static isc_result_t zone_load(dns_zone_t *zone, unsigned int flags) { isc_result_t result; @@ -1880,8 +1914,7 @@ zone_gotreadhandle(isc_task_t *task, isc_event_t *event) { result = dns_master_loadfileinc3(load->zone->masterfile, dns_db_origin(load->db), dns_db_origin(load->db), - load->zone->rdclass, options, - load->zone->sigresigninginterval, + load->zone->rdclass, options, 0, &load->callbacks, task, zone_loaddone, load, &load->zone->lctx, load->zone->mctx, @@ -1933,15 +1966,20 @@ zone_gotwritehandle(isc_task_t *task, isc_event_t *event) { LOCK_ZONE(zone); ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); if (zone->db != NULL) { + const dns_master_style_t *output_style; + dns_db_currentversion(zone->db, &version); dns_master_initrawheader(&rawdata); if (inline_secure(zone)) get_raw_serial(zone->raw, &rawdata); + if (zone->type == dns_zone_key) + output_style = &dns_master_style_keyzone; + else + output_style = &dns_master_style_default; result = dns_master_dumpinc3(zone->mctx, zone->db, version, - &dns_master_style_default, - zone->masterfile, zone->task, - dump_done, zone, &zone->dctx, - zone->masterformat, &rawdata); + output_style, zone->masterfile, + zone->task, dump_done, zone, &zone->dctx, zone->masterformat, + &rawdata); dns_db_closeversion(zone->db, &version, ISC_FALSE); } else result = ISC_R_CANCELED; @@ -1987,14 +2025,9 @@ zone_startload(dns_db_t *db, dns_zone_t *zone, isc_time_t loadtime) { isc_result_t tresult; unsigned int options; -#ifdef BIND9 - if (zone->is_rpz) { - result = dns_db_rpz_enabled(db, NULL); - if (result != ISC_R_SUCCESS) - return (result); - } -#endif - + result = dns_zone_rpz_enable_db(zone, db); + if (result != ISC_R_SUCCESS) + return (result); options = get_master_options(zone); if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_MANYERRORS)) options |= DNS_MASTER_MANYERRORS; @@ -2047,8 +2080,7 @@ zone_startload(dns_db_t *db, dns_zone_t *zone, isc_time_t loadtime) { } result = dns_master_loadfile3(zone->masterfile, &zone->origin, &zone->origin, - zone->rdclass, options, - zone->sigresigninginterval, + zone->rdclass, options, 0, &callbacks, zone->mctx, zone->masterformat); tresult = dns_db_endload(db, &callbacks.add_private); @@ -2485,7 +2517,7 @@ isspf(const dns_rdata_t *rdata) { INSIST(tl <= rdl); if (len > sizeof(buf) - i - 1) len = sizeof(buf) - i - 1; - memcpy(buf + i, data, len); + memmove(buf + i, data, len); i += len; data += tl; rdl -= tl; @@ -2737,14 +2769,22 @@ resume_signingwithkey(dns_zone_t *zone) { dns_rdata_t rdata = DNS_RDATA_INIT; dns_rdataset_t rdataset; isc_result_t result; + dns_db_t *db = NULL; + + ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); + if (zone->db != NULL) + dns_db_attach(zone->db, &db); + ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); + if (db == NULL) + goto cleanup; - result = dns_db_findnode(zone->db, &zone->origin, ISC_FALSE, &node); + result = dns_db_findnode(db, &zone->origin, ISC_FALSE, &node); if (result != ISC_R_SUCCESS) goto cleanup; - dns_db_currentversion(zone->db, &version); + dns_db_currentversion(db, &version); dns_rdataset_init(&rdataset); - result = dns_db_findrdataset(zone->db, node, version, + result = dns_db_findrdataset(db, node, version, zone->privatetype, dns_rdatatype_none, 0, &rdataset, NULL); @@ -2777,10 +2817,13 @@ resume_signingwithkey(dns_zone_t *zone) { dns_rdataset_disassociate(&rdataset); cleanup: - if (node != NULL) - dns_db_detachnode(zone->db, &node); - if (version != NULL) - dns_db_closeversion(zone->db, &version, ISC_FALSE); + if (db != NULL) { + if (node != NULL) + dns_db_detachnode(db, &node); + if (version != NULL) + dns_db_closeversion(db, &version, ISC_FALSE); + dns_db_detach(&db); + } } static isc_result_t @@ -2793,18 +2836,33 @@ zone_addnsec3chain(dns_zone_t *zone, dns_rdata_nsec3param_t *nsec3param) { unsigned int options = 0; char saltbuf[255*2+1]; char flags[sizeof("INITIAL|REMOVE|CREATE|NONSEC|OPTOUT")]; + dns_db_t *db = NULL; int i; - dns_db_currentversion(zone->db, &version); - result = dns_nsec_nseconly(zone->db, version, &nseconly); + ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); + if (zone->db != NULL) + dns_db_attach(zone->db, &db); + ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); + + if (db == NULL) { + result = ISC_R_SUCCESS; + goto cleanup; + } + + dns_db_currentversion(db, &version); + result = dns_nsec_nseconly(db, version, &nseconly); nsec3ok = (result == ISC_R_SUCCESS && !nseconly); - dns_db_closeversion(zone->db, &version, ISC_FALSE); - if (!nsec3ok && (nsec3param->flags & DNS_NSEC3FLAG_REMOVE) == 0) - return (ISC_R_SUCCESS); + dns_db_closeversion(db, &version, ISC_FALSE); + if (!nsec3ok && (nsec3param->flags & DNS_NSEC3FLAG_REMOVE) == 0) { + result = ISC_R_SUCCESS; + goto cleanup; + } nsec3chain = isc_mem_get(zone->mctx, sizeof *nsec3chain); - if (nsec3chain == NULL) - return (ISC_R_NOMEMORY); + if (nsec3chain == NULL) { + result = ISC_R_NOMEMORY; + goto cleanup; + } nsec3chain->magic = 0; nsec3chain->done = ISC_FALSE; @@ -2816,7 +2874,7 @@ zone_addnsec3chain(dns_zone_t *zone, dns_rdata_nsec3param_t *nsec3param) { nsec3chain->nsec3param.iterations = nsec3param->iterations; nsec3chain->nsec3param.flags = nsec3param->flags; nsec3chain->nsec3param.salt_length = nsec3param->salt_length; - memcpy(nsec3chain->salt, nsec3param->salt, nsec3param->salt_length); + memmove(nsec3chain->salt, nsec3param->salt, nsec3param->salt_length); nsec3chain->nsec3param.salt = nsec3chain->salt; nsec3chain->seen_nsec = ISC_FALSE; nsec3chain->delete_nsec = ISC_FALSE; @@ -2866,7 +2924,7 @@ zone_addnsec3chain(dns_zone_t *zone, dns_rdata_nsec3param_t *nsec3param) { for (current = ISC_LIST_HEAD(zone->nsec3chain); current != NULL; current = ISC_LIST_NEXT(current, link)) { - if (current->db == zone->db && + if (current->db == db && current->nsec3param.hash == nsec3param->hash && current->nsec3param.iterations == nsec3param->iterations && current->nsec3param.salt_length == nsec3param->salt_length @@ -2875,28 +2933,25 @@ zone_addnsec3chain(dns_zone_t *zone, dns_rdata_nsec3param_t *nsec3param) { current->done = ISC_TRUE; } - if (zone->db != NULL) { - dns_db_attach(zone->db, &nsec3chain->db); - if ((nsec3chain->nsec3param.flags & DNS_NSEC3FLAG_CREATE) != 0) - options = DNS_DB_NONSEC3; - result = dns_db_createiterator(nsec3chain->db, options, - &nsec3chain->dbiterator); - if (result == ISC_R_SUCCESS) - dns_dbiterator_first(nsec3chain->dbiterator); - if (result == ISC_R_SUCCESS) { - dns_dbiterator_pause(nsec3chain->dbiterator); - ISC_LIST_INITANDAPPEND(zone->nsec3chain, - nsec3chain, link); - nsec3chain = NULL; - if (isc_time_isepoch(&zone->nsec3chaintime)) { - TIME_NOW(&now); - zone->nsec3chaintime = now; - if (zone->task != NULL) - zone_settimer(zone, &now); - } + dns_db_attach(db, &nsec3chain->db); + if ((nsec3chain->nsec3param.flags & DNS_NSEC3FLAG_CREATE) != 0) + options = DNS_DB_NONSEC3; + result = dns_db_createiterator(nsec3chain->db, options, + &nsec3chain->dbiterator); + if (result == ISC_R_SUCCESS) + dns_dbiterator_first(nsec3chain->dbiterator); + if (result == ISC_R_SUCCESS) { + dns_dbiterator_pause(nsec3chain->dbiterator); + ISC_LIST_INITANDAPPEND(zone->nsec3chain, + nsec3chain, link); + nsec3chain = NULL; + if (isc_time_isepoch(&zone->nsec3chaintime)) { + TIME_NOW(&now); + zone->nsec3chaintime = now; + if (zone->task != NULL) + zone_settimer(zone, &now); } - } else - result = ISC_R_NOTFOUND; + } if (nsec3chain != NULL) { if (nsec3chain->db != NULL) @@ -2905,6 +2960,10 @@ zone_addnsec3chain(dns_zone_t *zone, dns_rdata_nsec3param_t *nsec3param) { dns_dbiterator_destroy(&nsec3chain->dbiterator); isc_mem_put(zone->mctx, nsec3chain, sizeof *nsec3chain); } + + cleanup: + if (db != NULL) + dns_db_detach(&db); return (result); } @@ -2916,21 +2975,29 @@ resume_addnsec3chain(dns_zone_t *zone) { isc_result_t result; dns_rdata_nsec3param_t nsec3param; isc_boolean_t nseconly = ISC_FALSE, nsec3ok = ISC_FALSE; + dns_db_t *db = NULL; if (zone->privatetype == 0) return; - result = dns_db_findnode(zone->db, &zone->origin, ISC_FALSE, &node); + ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); + if (zone->db != NULL) + dns_db_attach(zone->db, &db); + ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); + if (db == NULL) + goto cleanup; + + result = dns_db_findnode(db, &zone->origin, ISC_FALSE, &node); if (result != ISC_R_SUCCESS) goto cleanup; - dns_db_currentversion(zone->db, &version); + dns_db_currentversion(db, &version); - result = dns_nsec_nseconly(zone->db, version, &nseconly); + result = dns_nsec_nseconly(db, version, &nseconly); nsec3ok = (result == ISC_R_SUCCESS && !nseconly); dns_rdataset_init(&rdataset); - result = dns_db_findrdataset(zone->db, node, version, + result = dns_db_findrdataset(db, node, version, zone->privatetype, dns_rdatatype_none, 0, &rdataset, NULL); if (result != ISC_R_SUCCESS) { @@ -2965,10 +3032,13 @@ resume_addnsec3chain(dns_zone_t *zone) { } dns_rdataset_disassociate(&rdataset); cleanup: - if (node != NULL) - dns_db_detachnode(zone->db, &node); - if (version != NULL) - dns_db_closeversion(zone->db, &version, ISC_FALSE); + if (db != NULL) { + if (node != NULL) + dns_db_detachnode(db, &node); + if (version != NULL) + dns_db_closeversion(db, &version, ISC_FALSE); + dns_db_detach(&db); + } } static void @@ -2978,20 +3048,35 @@ set_resigntime(dns_zone_t *zone) { unsigned int resign; isc_result_t result; isc_uint32_t nanosecs; + dns_db_t *db = NULL; dns_rdataset_init(&rdataset); dns_fixedname_init(&fixed); - result = dns_db_getsigningtime(zone->db, &rdataset, + + ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); + if (zone->db != NULL) + dns_db_attach(zone->db, &db); + ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); + if (db == NULL) { + isc_time_settoepoch(&zone->resigntime); + return; + } + + result = dns_db_getsigningtime(db, &rdataset, dns_fixedname_name(&fixed)); if (result != ISC_R_SUCCESS) { isc_time_settoepoch(&zone->resigntime); - return; + goto cleanup; } - resign = rdataset.resign; + + resign = rdataset.resign - zone->sigresigninginterval; dns_rdataset_disassociate(&rdataset); isc_random_get(&nanosecs); nanosecs %= 1000000000; isc_time_set(&zone->resigntime, resign, nanosecs); + cleanup: + dns_db_detach(&db); + return; } static isc_result_t @@ -3334,6 +3419,8 @@ load_secroots(dns_zone_t *zone, dns_name_t *name, dns_rdataset_t *rdataset) { /* Convert rdata to keydata. */ result = dns_rdata_tostruct(&rdata, &keydata, NULL); + if (result == ISC_R_UNEXPECTEDEND) + continue; RUNTIME_CHECK(result == ISC_R_SUCCESS); /* Set the key refresh timer. */ @@ -3387,7 +3474,6 @@ do_one_tuple(dns_difftuple_t **tuple, dns_db_t *db, dns_dbversion_t *ver, * Create a singleton diff. */ dns_diff_init(diff->mctx, &temp_diff); - temp_diff.resign = diff->resign; ISC_LIST_APPEND(temp_diff.tuples, *tuple, link); /* @@ -3739,9 +3825,9 @@ maybe_send_secure(dns_zone_t *zone) { NULL, &soacount, &serial, NULL, NULL, NULL, NULL, NULL); if (result == ISC_R_SUCCESS && soacount > 0U) - zone_send_secureserial(zone->raw, ISC_TRUE, serial); + zone_send_secureserial(zone->raw, serial); } else - zone_send_securedb(zone->raw, ISC_TRUE, zone->raw->db); + zone_send_securedb(zone->raw, zone->raw->db); } else DNS_ZONE_SETFLAG(zone->raw, DNS_ZONEFLG_SENDSECURE); @@ -3763,6 +3849,7 @@ zone_unchanged(dns_db_t *db1, dns_db_t *db2, isc_mem_t *mctx) { /* * The zone is presumed to be locked. + * If this is a inline_raw zone the secure version is also locked. */ static isc_result_t zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, @@ -3778,6 +3865,10 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, isc_boolean_t nomaster = ISC_FALSE; unsigned int options; + INSIST(LOCKED_ZONE(zone)); + if (inline_raw(zone)) + INSIST(LOCKED_ZONE(zone->secure)); + TIME_NOW(&now); /* @@ -3855,8 +3946,7 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, else options = 0; result = dns_journal_rollforward2(zone->mctx, db, options, - zone->sigresigninginterval, - zone->journal); + 0, zone->journal); if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND && result != DNS_R_UPTODATE && result != DNS_R_NOJOURNAL && result != ISC_R_RANGE) { @@ -4128,9 +4218,9 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, inline_raw(zone)) { if (zone->secure->db == NULL) - zone_send_securedb(zone, ISC_FALSE, db); + zone_send_securedb(zone, db); else - zone_send_secureserial(zone, ISC_FALSE, serial); + zone_send_secureserial(zone, serial); } } @@ -4183,7 +4273,8 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, dns_zone_log(zone, ISC_LOG_DEBUG(3), "next resign: %s/%s in %d seconds", namebuf, typebuf, - next.resign - timenow); + next.resign - timenow - + zone->sigresigninginterval); dns_rdataset_disassociate(&next); } else dns_zone_log(zone, ISC_LOG_WARNING, @@ -4231,12 +4322,9 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, static isc_boolean_t exit_check(dns_zone_t *zone) { - REQUIRE(LOCKED_ZONE(zone)); - if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_SHUTDOWN) && - zone->irefs == 0) - { + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_SHUTDOWN) && zone->irefs == 0) { /* * DNS_ZONEFLG_SHUTDOWN can only be set if erefs == 0. */ @@ -4891,7 +4979,7 @@ set_addrkeylist(unsigned int count, newaddrs = isc_mem_get(mctx, count * sizeof(*newaddrs)); if (newaddrs == NULL) return (ISC_R_NOMEMORY); - memcpy(newaddrs, addrs, count * sizeof(*newaddrs)); + memmove(newaddrs, addrs, count * sizeof(*newaddrs)); newnames = NULL; if (names != NULL) { @@ -5153,6 +5241,7 @@ find_zone_keys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, const char *directory = dns_zone_getkeydirectory(zone); CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node)); + memset(keys, 0, sizeof(*keys) * maxkeys); result = dns_dnssec_findzonekeys2(db, ver, node, dns_db_origin(db), directory, mctx, maxkeys, keys, nkeys); @@ -5219,19 +5308,39 @@ set_key_expiry_warning(dns_zone_t *zone, isc_stdtime_t when, isc_stdtime_t now) * have no new key. */ static isc_boolean_t -delsig_ok(dns_rdata_rrsig_t *rrsig_ptr, dst_key_t **keys, unsigned int nkeys) { +delsig_ok(dns_rdata_rrsig_t *rrsig_ptr, dst_key_t **keys, unsigned int nkeys, + isc_boolean_t *warn) +{ unsigned int i = 0; + isc_boolean_t have_ksk = ISC_FALSE, have_zsk = ISC_FALSE; + isc_boolean_t have_pksk = ISC_FALSE, have_pzsk = ISC_FALSE; - /* - * It's okay to delete a signature if there is an active ZSK - * with the same algorithm - */ for (i = 0; i < nkeys; i++) { - if (rrsig_ptr->algorithm == dst_key_alg(keys[i]) && - (dst_key_isprivate(keys[i])) && !KSK(keys[i])) - return (ISC_TRUE); + if (rrsig_ptr->algorithm != dst_key_alg(keys[i])) + continue; + if (dst_key_isprivate(keys[i])) { + if (KSK(keys[i])) + have_ksk = have_pksk = ISC_TRUE; + else + have_zsk = have_pzsk = ISC_TRUE; + } else { + if (KSK(keys[i])) + have_ksk = ISC_TRUE; + else + have_zsk = ISC_TRUE; + } } + if (have_zsk && have_ksk && !have_pzsk) + *warn = ISC_TRUE; + + /* + * It's okay to delete a signature if there is an active key + * with the same algorithm to replace it. + */ + if (have_pksk || have_pzsk) + return (ISC_TRUE); + /* * Failing that, it is *not* okay to delete a signature * if the associated public key is still in the DNSKEY RRset @@ -5299,7 +5408,8 @@ del_sigs(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, RUNTIME_CHECK(result == ISC_R_SUCCESS); if (type != dns_rdatatype_dnskey) { - if (delsig_ok(&rrsig, keys, nkeys)) { + isc_boolean_t warn = ISC_FALSE, deleted = ISC_FALSE; + if (delsig_ok(&rrsig, keys, nkeys, &warn)) { result = update_one_rr(db, ver, zonediff->diff, DNS_DIFFOP_DELRESIGN, name, rdataset.ttl, &rdata); @@ -5307,7 +5417,9 @@ del_sigs(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, changed = ISC_TRUE; if (result != ISC_R_SUCCESS) break; - } else { + deleted = ISC_TRUE; + } + if (warn) { /* * At this point, we've got an RRSIG, * which is signed by an inactive key. @@ -5317,7 +5429,7 @@ del_sigs(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, * offline will prevent us spinning waiting * for the private part. */ - if (incremental) { + if (incremental && !deleted) { result = offline(db, ver, zonediff, name, rdataset.ttl, &rdata); @@ -5365,7 +5477,9 @@ del_sigs(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, * We want the earliest offline expire time * iff there is a new offline signature. */ - if (!dst_key_isprivate(keys[i])) { + if (!dst_key_inactive(keys[i]) && + !dst_key_isprivate(keys[i])) + { isc_int64_t timeexpire = dns_time64_from32(rrsig.timeexpire); if (warn != 0 && warn > timeexpire) @@ -5383,6 +5497,7 @@ del_sigs(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, result = offline(db, ver, zonediff, name, rdataset.ttl, &rdata); + changed = ISC_TRUE; break; } result = update_one_rr(db, ver, zonediff->diff, @@ -5551,7 +5666,6 @@ zone_resigninc(dns_zone_t *zone) { dns_rdataset_init(&rdataset); dns_fixedname_init(&fixed); dns_diff_init(zone->mctx, &_sig_diff); - _sig_diff.resign = zone->sigresigninginterval; zonediff_init(&zonediff, &_sig_diff); /* @@ -5611,7 +5725,7 @@ zone_resigninc(dns_zone_t *zone) { i = 0; while (result == ISC_R_SUCCESS) { - resign = rdataset.resign; + resign = rdataset.resign - zone->sigresigninginterval; covers = rdataset.covers; dns_rdataset_disassociate(&rdataset); @@ -6480,7 +6594,6 @@ zone_nsec3chain(dns_zone_t *zone) { dns_diff_init(zone->mctx, &nsec3_diff); dns_diff_init(zone->mctx, &nsec_diff); dns_diff_init(zone->mctx, &_sig_diff); - _sig_diff.resign = zone->sigresigninginterval; zonediff_init(&zonediff, &_sig_diff); ISC_LIST_INIT(cleanup); @@ -7326,7 +7439,6 @@ zone_sign(dns_zone_t *zone) { dns_fixedname_init(&nextfixed); nextname = dns_fixedname_name(&nextfixed); dns_diff_init(zone->mctx, &_sig_diff); - _sig_diff.resign = zone->sigresigninginterval; dns_diff_init(zone->mctx, &post_diff); zonediff_init(&zonediff, &_sig_diff); ISC_LIST_INIT(cleanup); @@ -7340,8 +7452,13 @@ zone_sign(dns_zone_t *zone) { } ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); - dns_db_attach(zone->db, &db); + if (zone->db != NULL) + dns_db_attach(zone->db, &db); ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); + if (db == NULL) { + result = ISC_R_FAILURE; + goto failure; + } result = dns_db_newversion(db, &version); if (result != ISC_R_SUCCESS) { @@ -7760,7 +7877,7 @@ zone_sign(dns_zone_t *zone) { isc_time_settoepoch(&zone->signingtime); } -static void +static isc_result_t normalize_key(dns_rdata_t *rr, dns_rdata_t *target, unsigned char *data, int size) { dns_rdata_dnskey_t dnskey; @@ -7781,6 +7898,8 @@ normalize_key(dns_rdata_t *rr, dns_rdata_t *target, break; case dns_rdatatype_keydata: result = dns_rdata_tostruct(rr, &keydata, NULL); + if (result == ISC_R_UNEXPECTEDEND) + return (result); RUNTIME_CHECK(result == ISC_R_SUCCESS); dns_keydata_todnskey(&keydata, &dnskey, NULL); dns_rdata_fromstruct(target, rr->rdclass, dns_rdatatype_dnskey, @@ -7789,6 +7908,7 @@ normalize_key(dns_rdata_t *rr, dns_rdata_t *target, default: INSIST(0); } + return (ISC_R_SUCCESS); } /* @@ -7812,14 +7932,18 @@ matchkey(dns_rdataset_t *rdset, dns_rdata_t *rr) { dns_rdata_init(&rdata1); dns_rdata_init(&rdata2); - normalize_key(rr, &rdata1, data1, sizeof(data1)); + result = normalize_key(rr, &rdata1, data1, sizeof(data1)); + if (result != ISC_R_SUCCESS) + return (ISC_FALSE); for (result = dns_rdataset_first(rdset); result == ISC_R_SUCCESS; result = dns_rdataset_next(rdset)) { dns_rdata_reset(&rdata); dns_rdataset_current(rdset, &rdata); - normalize_key(&rdata, &rdata2, data2, sizeof(data2)); + result = normalize_key(&rdata, &rdata2, data2, sizeof(data2)); + if (result != ISC_R_SUCCESS) + continue; if (dns_rdata_compare(&rdata1, &rdata2) == 0) return (ISC_TRUE); } @@ -7926,7 +8050,11 @@ minimal_update(dns_keyfetch_t *kfetch, dns_dbversion_t *ver, dns_diff_t *diff) name, 0, &rdata)); /* Update refresh timer */ - CHECK(dns_rdata_tostruct(&rdata, &keydata, NULL)); + result = dns_rdata_tostruct(&rdata, &keydata, NULL); + if (result == ISC_R_UNEXPECTEDEND) + continue; + if (result != ISC_R_SUCCESS) + goto failure; keydata.refresh = refresh_time(kfetch, ISC_TRUE); set_refreshkeytimer(zone, &keydata, now); @@ -8077,7 +8205,6 @@ keyfetch_done(isc_task_t *task, isc_event_t *event) { INSIST(result == ISC_R_SUCCESS); dns_diff_init(mctx, &diff); - diff.resign = zone->sigresigninginterval; CHECK(dns_db_newversion(kfetch->db, &ver)); @@ -8823,11 +8950,29 @@ void dns_zone_markdirty(dns_zone_t *zone) { isc_uint32_t serial; isc_result_t result = ISC_R_SUCCESS; + dns_zone_t *secure = NULL; + /* + * Obtaining a lock on the zone->secure (see zone_send_secureserial) + * could result in a deadlock due to a LOR so we will spin if we + * can't obtain the both locks. + */ + again: LOCK_ZONE(zone); if (zone->type == dns_zone_master) { if (inline_raw(zone)) { unsigned int soacount; + secure = zone->secure; + INSIST(secure != zone); + TRYLOCK_ZONE(result, secure); + if (result != ISC_R_SUCCESS) { + UNLOCK_ZONE(zone); + secure = NULL; +#ifdef ISC_PLATFORM_USETHREADS + isc_thread_yield(); +#endif + goto again; + } ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); if (zone->db != NULL) { @@ -8839,13 +8984,15 @@ dns_zone_markdirty(dns_zone_t *zone) { result = DNS_R_NOTLOADED; ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); if (result == ISC_R_SUCCESS && soacount > 0U) - zone_send_secureserial(zone, ISC_FALSE, serial); + zone_send_secureserial(zone, serial); } /* XXXMPA make separate call back */ if (result == ISC_R_SUCCESS) set_resigntime(zone); } + if (secure != NULL) + UNLOCK_ZONE(secure); zone_needdump(zone, DNS_DUMP_DELAY); UNLOCK_ZONE(zone); } @@ -9156,15 +9303,20 @@ zone_dump(dns_zone_t *zone, isc_boolean_t compact) { result = DNS_R_CONTINUE; UNLOCK_ZONE(zone); } else { + const dns_master_style_t *output_style; + dns_masterrawheader_t rawdata; dns_db_currentversion(db, &version); dns_master_initrawheader(&rawdata); if (inline_secure(zone)) get_raw_serial(zone->raw, &rawdata); + if (zone->type == dns_zone_key) + output_style = &dns_master_style_keyzone; + else + output_style = &dns_master_style_default; result = dns_master_dump3(zone->mctx, db, version, - &dns_master_style_default, - masterfile, masterformat, - &rawdata); + output_style, masterfile, + masterformat, &rawdata); dns_db_closeversion(db, &version, ISC_FALSE); } fail: @@ -9311,7 +9463,6 @@ forward_cancel(dns_zone_t *zone) { static void zone_unload(dns_zone_t *zone) { - /* * 'zone' locked by caller. */ @@ -9565,7 +9716,7 @@ notify_send_queue(dns_notify_t *notify) { return (ISC_R_NOMEMORY); e->ev_arg = notify; e->ev_sender = NULL; - result = isc_ratelimiter_enqueue(notify->zone->zmgr->rl, + result = isc_ratelimiter_enqueue(notify->zone->zmgr->notifyrl, notify->zone->task, &e); if (result != ISC_R_SUCCESS) isc_event_free(&e); @@ -10331,6 +10482,12 @@ refresh_callback(isc_task_t *task, isc_event_t *event) { LOCK_ZONE(zone); + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) { + isc_event_free(&event); + dns_request_destroy(&zone->request); + goto detach; + } + /* * if timeout log and next master; */ @@ -10718,7 +10875,7 @@ queue_soa_query(dns_zone_t *zone) { e->ev_arg = zone; e->ev_sender = NULL; - result = isc_ratelimiter_enqueue(zone->zmgr->rl, zone->task, &e); + result = isc_ratelimiter_enqueue(zone->zmgr->refreshrl, zone->task, &e); if (result != ISC_R_SUCCESS) { zone_idetach(&dummy); isc_event_free(&e); @@ -11279,6 +11436,12 @@ zone_shutdown(isc_task_t *task, isc_event_t *event) { linked = ISC_TRUE; zone->statelist = NULL; } + if (zone->statelist == &zone->zmgr->xfrin_in_progress) { + ISC_LIST_UNLINK(zone->zmgr->xfrin_in_progress, zone, + statelink); + zone->statelist = NULL; + zmgr_resume_xfrs(zone->zmgr, ISC_FALSE); + } RWUNLOCK(&zone->zmgr->rwlock, isc_rwlocktype_write); } @@ -11288,6 +11451,10 @@ zone_shutdown(isc_task_t *task, isc_event_t *event) { if (zone->xfr != NULL) dns_xfrin_shutdown(zone->xfr); + /* Safe to release the zone now */ + if (zone->zmgr != NULL) + dns_zonemgr_releasezone(zone->zmgr, zone); + LOCK_ZONE(zone); if (linked) { INSIST(zone->irefs > 0); @@ -11439,10 +11606,10 @@ zone_settimer(dns_zone_t *zone, isc_time_t *now) { isc_time_compare(&zone->refreshtime, &next) < 0) next = zone->refreshtime; } - if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED)) { - INSIST(!isc_time_isepoch(&zone->expiretime)); + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED) && + !isc_time_isepoch(&zone->expiretime)) { if (isc_time_isepoch(&next) || - isc_time_compare(&zone->expiretime, &next) < 0) + isc_time_compare(&zone->expiretime, &next) < 0) next = zone->expiretime; } if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDDUMP) && @@ -12102,7 +12269,7 @@ zone_namerd_tostr(dns_zone_t *zone, char *buf, size_t length) { /* * Leave space for terminating '\0'. */ - isc_buffer_init(&buffer, buf, length - 1); + isc_buffer_init(&buffer, buf, (unsigned int)length - 1); if (zone->type != dns_zone_redirect && zone->type != dns_zone_key) { if (dns_name_dynamic(&zone->origin)) result = dns_name_totext(&zone->origin, ISC_TRUE, &buffer); @@ -12140,7 +12307,7 @@ zone_name_tostr(dns_zone_t *zone, char *buf, size_t length) { /* * Leave space for terminating '\0'. */ - isc_buffer_init(&buffer, buf, length - 1); + isc_buffer_init(&buffer, buf, (unsigned int)length - 1); if (dns_name_dynamic(&zone->origin)) result = dns_name_totext(&zone->origin, ISC_TRUE, &buffer); if (result != ISC_R_SUCCESS && @@ -12160,7 +12327,7 @@ zone_rdclass_tostr(dns_zone_t *zone, char *buf, size_t length) { /* * Leave space for terminating '\0'. */ - isc_buffer_init(&buffer, buf, length - 1); + isc_buffer_init(&buffer, buf, (unsigned int)length - 1); (void)dns_rdataclass_totext(zone->rdclass, &buffer); buf[isc_buffer_usedlength(&buffer)] = '\0'; @@ -12177,7 +12344,7 @@ zone_viewname_tostr(dns_zone_t *zone, char *buf, size_t length) { /* * Leave space for terminating '\0'. */ - isc_buffer_init(&buffer, buf, length - 1); + isc_buffer_init(&buffer, buf, (unsigned int)length - 1); if (zone->view == NULL) { isc_buffer_putstr(&buffer, "_none"); @@ -12644,6 +12811,7 @@ sync_secure_db(dns_zone_t *seczone, dns_db_t *secdb, static void receive_secure_serial(isc_task_t *task, isc_event_t *event) { + static char me[] = "receive_secure_serial"; isc_result_t result; dns_journal_t *rjournal = NULL; isc_uint32_t start, end; @@ -12659,16 +12827,23 @@ receive_secure_serial(isc_task_t *task, isc_event_t *event) { end = ((struct secure_event *)event)->serial; isc_event_free(&event); + ENTER; + LOCK_ZONE(zone); dns_diff_init(zone->mctx, &diff); UNUSED(task); + ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); + if (zone->db != NULL) + dns_db_attach(zone->db, &db); + ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); + /* * zone->db may be NULL if the load from disk failed. */ - if (zone->db == NULL || !inline_secure(zone)) { + if (db == NULL || !inline_secure(zone)) { result = ISC_R_FAILURE; goto failure; } @@ -12713,7 +12888,6 @@ receive_secure_serial(isc_task_t *task, isc_event_t *event) { } } - dns_db_attach(zone->db, &db); dns_db_currentversion(db, &oldver); CHECK(dns_db_newversion(db, &newver)); @@ -12795,9 +12969,7 @@ receive_secure_serial(isc_task_t *task, isc_event_t *event) { } static isc_result_t -zone_send_secureserial(dns_zone_t *zone, isc_boolean_t locked, - isc_uint32_t serial) -{ +zone_send_secureserial(dns_zone_t *zone, isc_uint32_t serial) { isc_event_t *e; dns_zone_t *dummy = NULL; @@ -12808,10 +12980,8 @@ zone_send_secureserial(dns_zone_t *zone, isc_boolean_t locked, if (e == NULL) return (ISC_R_NOMEMORY); ((struct secure_event *)e)->serial = serial; - if (locked) - zone_iattach(zone->secure, &dummy); - else - dns_zone_iattach(zone->secure, &dummy); + INSIST(LOCKED_ZONE(zone->secure)); + zone_iattach(zone->secure, &dummy); isc_task_send(zone->secure->task, &e); DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_SENDSECURE); @@ -12869,6 +13039,203 @@ checkandaddsoa(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, 0, NULL)); } +/* + * This function should populate an nsec3paramlist_t with the + * nsecparam_t data from a zone. + */ +static isc_result_t +save_nsec3param(dns_zone_t *zone, nsec3paramlist_t *nsec3list) { + isc_result_t result; + dns_dbnode_t *node = NULL; + dns_rdataset_t rdataset, prdataset; + dns_rdata_t rdata_in, prdata_in, prdata_out; + dns_dbversion_t *version = NULL; + nsec3param_t *nsec3param = NULL; + nsec3param_t *nsec3p = NULL; + nsec3param_t *next; + dns_db_t *db = NULL; + unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE]; + + REQUIRE(DNS_ZONE_VALID(zone)); + REQUIRE(nsec3list != NULL); + REQUIRE(ISC_LIST_EMPTY(*nsec3list)); + + dns_db_attach(zone->db, &db); + CHECK(dns_db_getoriginnode(db, &node)); + + dns_rdataset_init(&rdataset); + dns_db_currentversion(db, &version); + result = dns_db_findrdataset(db, node, version, + dns_rdatatype_nsec3param, + dns_rdatatype_none, 0, &rdataset, NULL); + + if (result != ISC_R_SUCCESS) + goto getprivate; + + /* + * walk nsec3param rdataset making a list of parameters (note that + * multiple simultaneous nsec3 chains are annoyingly legal -- this + * is why we use an nsec3list, even tho we will usually only have + * one) + */ + for (result = dns_rdataset_first(&rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&rdataset)) + { + dns_rdata_init(&rdata_in); + dns_rdataset_current(&rdataset, &rdata_in); + isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_ZONE, ISC_LOG_DEBUG(3), + "looping through nsec3param data"); + nsec3param = isc_mem_get(zone->mctx, sizeof(nsec3param_t)); + if (nsec3param == NULL) + CHECK(ISC_R_NOMEMORY); + ISC_LINK_INIT(nsec3param, link); + + /* + * now transfer the data from the rdata to + * the nsec3param + */ + dns_rdata_init(&prdata_out); + dns_nsec3param_toprivate(&rdata_in, &prdata_out, + zone->privatetype, nsec3param->data, + sizeof(nsec3param->data)); + nsec3param->length = prdata_out.length; + ISC_LIST_APPEND(*nsec3list, nsec3param, link); + } + + getprivate: + dns_rdataset_init(&prdataset); + result = dns_db_findrdataset(db, node, version, zone->privatetype, + dns_rdatatype_none, 0, &prdataset, NULL); + if (result != ISC_R_SUCCESS) + goto done; + + /* + * walk private type records, converting them to nsec3 parameters + * using dns_nsec3param_fromprivate(), do the right thing based on + * CREATE and REMOVE flags + */ + for (result = dns_rdataset_first(&prdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&prdataset)) + { + dns_rdata_init(&prdata_in); + dns_rdataset_current(&prdataset, &prdata_in); + isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_ZONE, ISC_LOG_DEBUG(3), + "looping through nsec3param private data"); + + if (!dns_nsec3param_fromprivate(&prdata_in, &prdata_out, + buf, sizeof(buf))) + continue; + + if ((prdata_out.data[1] & DNS_NSEC3FLAG_REMOVE) !=0) { + prdata_out.data[1] = 0; + + for (nsec3p = ISC_LIST_HEAD(*nsec3list); + nsec3p != NULL; + nsec3p = next) + { + next = ISC_LIST_NEXT(nsec3p, link); + if (memcmp(prdata_out.data, nsec3p->data, + sizeof(nsec3p->data)) == 0) { + ISC_LIST_UNLINK(*nsec3list, + nsec3p, link); + isc_mem_put(zone->mctx, nsec3p, + sizeof(nsec3param_t)); + } + } + continue; + } + + nsec3param = isc_mem_get(zone->mctx, sizeof(nsec3param_t)); + if (nsec3param == NULL) + CHECK(ISC_R_NOMEMORY); + ISC_LINK_INIT(nsec3param, link); + + dns_rdata_init(&prdata_out); + dns_nsec3param_toprivate(&prdata_in, &prdata_out, + zone->privatetype, nsec3param->data, + sizeof(nsec3param->data)); + nsec3param->length = prdata_out.length; + ISC_LIST_APPEND(*nsec3list, nsec3param, link); + } + + done: + if (result == ISC_R_NOMORE || result == ISC_R_NOTFOUND) + result = ISC_R_SUCCESS; + + failure: + if (node != NULL) + dns_db_detachnode(db, &node); + if (version != NULL) + dns_db_closeversion(db, &version, ISC_FALSE); + if (db != NULL) + dns_db_detach(&db); + if (dns_rdataset_isassociated(&rdataset)) + dns_rdataset_disassociate(&rdataset); + if (dns_rdataset_isassociated(&prdataset)) + dns_rdataset_disassociate(&prdataset); + return (result); +} + +/* + * Walk the list of the nsec3 chains desired for the zone, converting + * parameters to private type records using dns_nsec3param_toprivate(), + * and insert them into the new zone db. + */ +static isc_result_t +restore_nsec3param(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version, + nsec3paramlist_t *nsec3list) +{ + isc_result_t result; + dns_diff_t diff; + dns_rdata_t rdata; + nsec3param_t *nsec3p = NULL; + nsec3param_t *next; + + REQUIRE(DNS_ZONE_VALID(zone)); + REQUIRE(!ISC_LIST_EMPTY(*nsec3list)); + + dns_diff_init(zone->mctx, &diff); + + /* + * Loop through the list of private-type records, set the INITIAL + * and CREATE flags, and the add the record to the apex of the tree + * in db. + */ + for (nsec3p = ISC_LIST_HEAD(*nsec3list); + nsec3p != NULL; + nsec3p = next) + { + next = ISC_LIST_NEXT(nsec3p, link); + dns_rdata_init(&rdata); + nsec3p->data[2] = DNS_NSEC3FLAG_CREATE | DNS_NSEC3FLAG_INITIAL; + rdata.length = nsec3p->length; + rdata.data = nsec3p->data; + rdata.type = zone->privatetype; + rdata.rdclass = zone->rdclass; + CHECK(update_one_rr(db, version, &diff, DNS_DIFFOP_ADD, + &zone->origin, 0, &rdata)); + } + + result = ISC_R_SUCCESS; + +failure: + for (nsec3p = ISC_LIST_HEAD(*nsec3list); + nsec3p != NULL; + nsec3p = next) + { + next = ISC_LIST_NEXT(nsec3p, link); + ISC_LIST_UNLINK(*nsec3list, nsec3p, link); + isc_mem_put(zone->mctx, nsec3p, sizeof(nsec3param_t)); + } + + dns_diff_clear(&diff); + return (result); +} + static void receive_secure_db(isc_task_t *task, isc_event_t *event) { isc_result_t result; @@ -12884,25 +13251,44 @@ receive_secure_db(isc_task_t *task, isc_event_t *event) { isc_time_t loadtime; unsigned int oldserial = 0; isc_boolean_t have_oldserial = ISC_FALSE; + nsec3paramlist_t nsec3list; UNUSED(task); + ISC_LIST_INIT(nsec3list); + zone = event->ev_arg; rawdb = ((struct secure_event *)event)->db; isc_event_free(&event); - REQUIRE(inline_secure(zone)); - dns_fixedname_init(&fname); name = dns_fixedname_name(&fname); dns_rdataset_init(&rdataset); + LOCK_ZONE(zone); + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING) || !inline_secure(zone)) { + result = ISC_R_SHUTTINGDOWN; + goto failure; + } + TIME_NOW(&loadtime); + ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); if (zone->db != NULL) { result = dns_db_getsoaserial(zone->db, NULL, &oldserial); if (result == ISC_R_SUCCESS) have_oldserial = ISC_TRUE; + + /* + * assemble nsec3parameters from the old zone, and set a flag + * if any are found + */ + result = save_nsec3param(zone, &nsec3list); + if (result != ISC_R_SUCCESS) { + ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); + goto failure; + } } + ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); result = dns_db_create(zone->mctx, zone->db_argv[0], &zone->origin, dns_dbtype_zone, zone->rdclass, @@ -12963,21 +13349,27 @@ receive_secure_db(isc_task_t *task, isc_event_t *event) { dns_db_detachnode(db, &node); } + /* + * Call restore_nsec3param() to create private-type records from + * the old nsec3 parameters and insert them into db + */ + if (!ISC_LIST_EMPTY(nsec3list)) + restore_nsec3param(zone, db, version, &nsec3list); + dns_db_closeversion(db, &version, ISC_TRUE); + /* * Lock hierarchy: zmgr, zone, raw. */ - LOCK_ZONE(zone); - if (inline_secure(zone)) - LOCK_ZONE(zone->raw); + INSIST(zone != zone->raw); + LOCK_ZONE(zone->raw); DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDNOTIFY); result = zone_postload(zone, db, loadtime, ISC_R_SUCCESS); zone_needdump(zone, 0); /* XXXMPA */ - if (inline_secure(zone)) - UNLOCK_ZONE(zone->raw); - UNLOCK_ZONE(zone); + UNLOCK_ZONE(zone->raw); failure: + UNLOCK_ZONE(zone); if (result != ISC_R_SUCCESS) dns_zone_log(zone, ISC_LOG_ERROR, "receive_secure_db: %s", dns_result_totext(result)); @@ -12998,7 +13390,7 @@ receive_secure_db(isc_task_t *task, isc_event_t *event) { } static isc_result_t -zone_send_securedb(dns_zone_t *zone, isc_boolean_t locked, dns_db_t *db) { +zone_send_securedb(dns_zone_t *zone, dns_db_t *db) { isc_event_t *e; dns_db_t *dummy = NULL; dns_zone_t *secure = NULL; @@ -13011,11 +13403,8 @@ zone_send_securedb(dns_zone_t *zone, isc_boolean_t locked, dns_db_t *db) { return (ISC_R_NOMEMORY); dns_db_attach(db, &dummy); ((struct secure_event *)e)->db = dummy; - if (locked) - zone_iattach(zone->secure, &secure); - else - dns_zone_iattach(zone->secure, &secure); - + INSIST(LOCKED_ZONE(zone->secure)); + zone_iattach(zone->secure, &secure); isc_task_send(zone->secure->task, &e); DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_SENDSECURE); return (ISC_R_SUCCESS); @@ -13024,12 +13413,29 @@ zone_send_securedb(dns_zone_t *zone, isc_boolean_t locked, dns_db_t *db) { isc_result_t dns_zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) { isc_result_t result; + dns_zone_t *secure = NULL; REQUIRE(DNS_ZONE_VALID(zone)); + again: LOCK_ZONE(zone); + if (inline_raw(zone)) { + secure = zone->secure; + INSIST(secure != zone); + TRYLOCK_ZONE(result, secure); + if (result != ISC_R_SUCCESS) { + UNLOCK_ZONE(zone); + secure = NULL; +#if ISC_PLATFORM_USETHREADS + isc_thread_yield(); +#endif + goto again; + } + } ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_write); result = zone_replacedb(zone, db, dump); ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write); + if (secure != NULL) + UNLOCK_ZONE(secure); UNLOCK_ZONE(zone); return (result); } @@ -13046,6 +13452,8 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) { */ REQUIRE(DNS_ZONE_VALID(zone)); REQUIRE(LOCKED_ZONE(zone)); + if (inline_raw(zone)) + REQUIRE(LOCKED_ZONE(zone->secure)); result = zone_get_from_db(zone, db, &nscount, &soacount, NULL, NULL, NULL, NULL, NULL, NULL); @@ -13145,7 +13553,7 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) { } } if (zone->type == dns_zone_master && inline_raw(zone)) - zone_send_secureserial(zone, ISC_FALSE, serial); + zone_send_secureserial(zone, serial); } else { if (dump && zone->masterfile != NULL) { /* @@ -13198,7 +13606,7 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) { } if (inline_raw(zone)) - zone_send_securedb(zone, ISC_FALSE, db); + zone_send_securedb(zone, db); } dns_db_closeversion(db, &ver, ISC_FALSE); @@ -13253,13 +13661,34 @@ zone_xfrdone(dns_zone_t *zone, isc_result_t result) { isc_uint32_t serial, refresh, retry, expire, minimum; isc_result_t xfrresult = result; isc_boolean_t free_needed; + dns_zone_t *secure = NULL; REQUIRE(DNS_ZONE_VALID(zone)); dns_zone_log(zone, ISC_LOG_DEBUG(1), "zone transfer finished: %s", dns_result_totext(result)); + /* + * Obtaining a lock on the zone->secure (see zone_send_secureserial) + * could result in a deadlock due to a LOR so we will spin if we + * can't obtain the both locks. + */ + again: LOCK_ZONE(zone); + if (inline_raw(zone)) { + secure = zone->secure; + INSIST(secure != zone); + TRYLOCK_ZONE(result, secure); + if (result != ISC_R_SUCCESS) { + UNLOCK_ZONE(zone); + secure = NULL; +#if ISC_PLATFORM_USETHREADS + isc_thread_yield(); +#endif + goto again; + } + } + INSIST((zone->flags & DNS_ZONEFLG_REFRESH) != 0); DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESH); DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_SOABEFOREAXFR); @@ -13349,7 +13778,7 @@ zone_xfrdone(dns_zone_t *zone, isc_result_t result) { "transferred serial %u%s", serial, buf); if (inline_raw(zone)) - zone_send_secureserial(zone, ISC_FALSE, serial); + zone_send_secureserial(zone, serial); } /* @@ -13461,17 +13890,22 @@ zone_xfrdone(dns_zone_t *zone, isc_result_t result) { DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDCOMPACT); } + if (secure != NULL) + UNLOCK_ZONE(secure); /* * This transfer finishing freed up a transfer quota slot. * Let any other zones waiting for quota have it. */ - UNLOCK_ZONE(zone); - RWLOCK(&zone->zmgr->rwlock, isc_rwlocktype_write); - ISC_LIST_UNLINK(zone->zmgr->xfrin_in_progress, zone, statelink); - zone->statelist = NULL; - zmgr_resume_xfrs(zone->zmgr, ISC_FALSE); - RWUNLOCK(&zone->zmgr->rwlock, isc_rwlocktype_write); - LOCK_ZONE(zone); + if (zone->zmgr != NULL && + zone->statelist == &zone->zmgr->xfrin_in_progress) { + UNLOCK_ZONE(zone); + RWLOCK(&zone->zmgr->rwlock, isc_rwlocktype_write); + ISC_LIST_UNLINK(zone->zmgr->xfrin_in_progress, zone, statelink); + zone->statelist = NULL; + zmgr_resume_xfrs(zone->zmgr, ISC_FALSE); + RWUNLOCK(&zone->zmgr->rwlock, isc_rwlocktype_write); + LOCK_ZONE(zone); + } /* * Retry with a different server if necessary. @@ -13493,6 +13927,7 @@ zone_loaddone(void *arg, isc_result_t result) { dns_load_t *load = arg; dns_zone_t *zone; isc_result_t tresult; + dns_zone_t *secure = NULL; REQUIRE(DNS_LOAD_VALID(load)); zone = load->zone; @@ -13507,9 +13942,22 @@ zone_loaddone(void *arg, isc_result_t result) { /* * Lock hierarchy: zmgr, zone, raw. */ + again: LOCK_ZONE(zone); if (inline_secure(zone)) LOCK_ZONE(zone->raw); + else if (inline_raw(zone)) { + secure = zone->secure; + TRYLOCK_ZONE(result, secure); + if (result != ISC_R_SUCCESS) { + UNLOCK_ZONE(zone); + secure = NULL; +#if ISC_PLATFORM_USETHREADS + isc_thread_yield(); +#endif + goto again; + } + } (void)zone_postload(zone, load->db, load->loadtime, result); zonemgr_putio(&zone->readio); DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_LOADING); @@ -13523,6 +13971,8 @@ zone_loaddone(void *arg, isc_result_t result) { DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_THAW); if (inline_secure(zone)) UNLOCK_ZONE(zone->raw); + else if (secure != NULL) + UNLOCK_ZONE(secure); UNLOCK_ZONE(zone); load->magic = 0; @@ -13573,9 +14023,18 @@ dns_zone_getsigvalidityinterval(dns_zone_t *zone) { void dns_zone_setsigresigninginterval(dns_zone_t *zone, isc_uint32_t interval) { + isc_time_t now; + REQUIRE(DNS_ZONE_VALID(zone)); + LOCK_ZONE(zone); zone->sigresigninginterval = interval; + set_resigntime(zone); + if (zone->task != NULL) { + TIME_NOW(&now); + zone_settimer(zone, &now); + } + UNLOCK_ZONE(zone); } isc_uint32_t @@ -13632,6 +14091,7 @@ got_transfer_quota(isc_task_t *task, isc_event_t *event) { isc_sockaddr_t masteraddr; isc_time_t now; const char *soa_before = ""; + isc_boolean_t loaded; UNUSED(task); @@ -13665,7 +14125,11 @@ got_transfer_quota(isc_task_t *task, isc_event_t *event) { /* * Decide whether we should request IXFR or AXFR. */ - if (zone->db == NULL) { + ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); + loaded = ISC_TF(zone->db != NULL); + ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); + + if (!loaded) { dns_zone_log(zone, ISC_LOG_DEBUG(1), "no database exists yet, requesting AXFR of " "initial version from %s", master); @@ -13885,8 +14349,18 @@ forward_callback(isc_task_t *task, isc_event_t *event) { case dns_rcode_yxrrset: case dns_rcode_nxrrset: case dns_rcode_refused: - case dns_rcode_nxdomain: + case dns_rcode_nxdomain: { + char rcode[128]; + isc_buffer_t rb; + + isc_buffer_init(&rb, rcode, sizeof(rcode)); + (void)dns_rcode_totext(msg->rcode, &rb); + dns_zone_log(zone, ISC_LOG_INFO, + "forwarded dynamic update: " + "master %s returned: %.*s", + master, (int)rb.used, rcode); break; + } /* These should not occur if the masters/zone are valid. */ case dns_rcode_notzone: @@ -14036,7 +14510,8 @@ dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, zmgr->loadtasks = NULL; zmgr->mctxpool = NULL; zmgr->task = NULL; - zmgr->rl = NULL; + zmgr->notifyrl = NULL; + zmgr->refreshrl = NULL; ISC_LIST_INIT(zmgr->zones); ISC_LIST_INIT(zmgr->waiting_for_xfrin); ISC_LIST_INIT(zmgr->xfrin_in_progress); @@ -14060,15 +14535,24 @@ dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, isc_task_setname(zmgr->task, "zmgr", zmgr); result = isc_ratelimiter_create(mctx, timermgr, zmgr->task, - &zmgr->rl); + &zmgr->notifyrl); if (result != ISC_R_SUCCESS) goto free_task; + result = isc_ratelimiter_create(mctx, timermgr, zmgr->task, + &zmgr->refreshrl); + if (result != ISC_R_SUCCESS) + goto free_notifyrl; + /* default to 20 refresh queries / notifies per second. */ isc_interval_set(&interval, 0, 1000000000/2); - result = isc_ratelimiter_setinterval(zmgr->rl, &interval); + result = isc_ratelimiter_setinterval(zmgr->notifyrl, &interval); RUNTIME_CHECK(result == ISC_R_SUCCESS); - isc_ratelimiter_setpertic(zmgr->rl, 10); + isc_ratelimiter_setpertic(zmgr->notifyrl, 10); + + result = isc_ratelimiter_setinterval(zmgr->refreshrl, &interval); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + isc_ratelimiter_setpertic(zmgr->refreshrl, 10); zmgr->iolimit = 1; zmgr->ioactive = 0; @@ -14077,7 +14561,7 @@ dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, result = isc_mutex_init(&zmgr->iolock); if (result != ISC_R_SUCCESS) - goto free_rl; + goto free_refreshrl; zmgr->magic = ZONEMGR_MAGIC; @@ -14088,8 +14572,10 @@ dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, free_iolock: DESTROYLOCK(&zmgr->iolock); #endif - free_rl: - isc_ratelimiter_detach(&zmgr->rl); + free_refreshrl: + isc_ratelimiter_detach(&zmgr->refreshrl); + free_notifyrl: + isc_ratelimiter_detach(&zmgr->notifyrl); free_task: isc_task_detach(&zmgr->task); free_urlock: @@ -14287,7 +14773,8 @@ dns_zonemgr_shutdown(dns_zonemgr_t *zmgr) { REQUIRE(DNS_ZONEMGR_VALID(zmgr)); - isc_ratelimiter_shutdown(zmgr->rl); + isc_ratelimiter_shutdown(zmgr->notifyrl); + isc_ratelimiter_shutdown(zmgr->refreshrl); if (zmgr->task != NULL) isc_task_destroy(&zmgr->task); @@ -14419,7 +14906,8 @@ zonemgr_free(dns_zonemgr_t *zmgr) { zmgr->magic = 0; DESTROYLOCK(&zmgr->iolock); - isc_ratelimiter_detach(&zmgr->rl); + isc_ratelimiter_detach(&zmgr->notifyrl); + isc_ratelimiter_detach(&zmgr->refreshrl); isc_rwlock_destroy(&zmgr->urlock); isc_rwlock_destroy(&zmgr->rwlock); @@ -14809,9 +15297,14 @@ dns_zonemgr_setserialqueryrate(dns_zonemgr_t *zmgr, unsigned int value) { } isc_interval_set(&interval, s, ns); - result = isc_ratelimiter_setinterval(zmgr->rl, &interval); + + result = isc_ratelimiter_setinterval(zmgr->notifyrl, &interval); RUNTIME_CHECK(result == ISC_R_SUCCESS); - isc_ratelimiter_setpertic(zmgr->rl, pertic); + isc_ratelimiter_setpertic(zmgr->notifyrl, pertic); + + result = isc_ratelimiter_setinterval(zmgr->refreshrl, &interval); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + isc_ratelimiter_setpertic(zmgr->refreshrl, pertic); zmgr->serialqueryrate = value; } @@ -14831,6 +15324,7 @@ dns_zonemgr_unreachable(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote, isc_rwlocktype_t locktype; isc_result_t result; isc_uint32_t seconds = isc_time_seconds(now); + isc_uint32_t count = 0; REQUIRE(DNS_ZONEMGR_VALID(zmgr)); @@ -14844,12 +15338,13 @@ dns_zonemgr_unreachable(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote, if (result == ISC_R_SUCCESS) { locktype = isc_rwlocktype_write; zmgr->unreachable[i].last = seconds; + count = zmgr->unreachable[i].count; } break; } } RWUNLOCK(&zmgr->urlock, locktype); - return (ISC_TF(i < UNREACH_CHACHE_SIZE)); + return (ISC_TF(i < UNREACH_CHACHE_SIZE && count > 1U)); } void @@ -14923,6 +15418,10 @@ dns_zonemgr_unreachableadd(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote, */ zmgr->unreachable[i].expire = seconds + UNREACH_HOLD_TIME; zmgr->unreachable[i].last = seconds; + if (zmgr->unreachable[i].expire < seconds) + zmgr->unreachable[i].count = 1; + else + zmgr->unreachable[i].count++; } else if (slot != UNREACH_CHACHE_SIZE) { /* * Found a empty slot. Add a new entry to the cache. @@ -14931,6 +15430,7 @@ dns_zonemgr_unreachableadd(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote, zmgr->unreachable[slot].last = seconds; zmgr->unreachable[slot].remote = *remote; zmgr->unreachable[slot].local = *local; + zmgr->unreachable[slot].count = 1; } else { /* * Replace the least recently used entry in the cache. @@ -14939,6 +15439,7 @@ dns_zonemgr_unreachableadd(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote, zmgr->unreachable[oldest].last = seconds; zmgr->unreachable[oldest].remote = *remote; zmgr->unreachable[oldest].local = *local; + zmgr->unreachable[oldest].count = 1; } RWUNLOCK(&zmgr->urlock, isc_rwlocktype_write); } @@ -15358,6 +15859,7 @@ zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm, isc_uint16_t keyid, dns_signing_t *current; isc_result_t result = ISC_R_SUCCESS; isc_time_t now; + dns_db_t *db = NULL; signing = isc_mem_get(zone->mctx, sizeof *signing); if (signing == NULL) @@ -15373,10 +15875,22 @@ zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm, isc_uint16_t keyid, TIME_NOW(&now); + ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); + if (zone->db != NULL) + dns_db_attach(zone->db, &db); + ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); + + if (db == NULL) { + result = ISC_R_NOTFOUND; + goto cleanup; + } + + dns_db_attach(db, &signing->db); + for (current = ISC_LIST_HEAD(zone->signing); current != NULL; current = ISC_LIST_NEXT(current, link)) { - if (current->db == zone->db && + if (current->db == signing->db && current->algorithm == signing->algorithm && current->keyid == signing->keyid) { if (current->delete != signing->delete) @@ -15386,25 +15900,21 @@ zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm, isc_uint16_t keyid, } } - if (zone->db != NULL) { - dns_db_attach(zone->db, &signing->db); - result = dns_db_createiterator(signing->db, 0, - &signing->dbiterator); + result = dns_db_createiterator(signing->db, 0, + &signing->dbiterator); - if (result == ISC_R_SUCCESS) - result = dns_dbiterator_first(signing->dbiterator); - if (result == ISC_R_SUCCESS) { - dns_dbiterator_pause(signing->dbiterator); - ISC_LIST_INITANDAPPEND(zone->signing, signing, link); - signing = NULL; - if (isc_time_isepoch(&zone->signingtime)) { - zone->signingtime = now; - if (zone->task != NULL) - zone_settimer(zone, &now); - } + if (result == ISC_R_SUCCESS) + result = dns_dbiterator_first(signing->dbiterator); + if (result == ISC_R_SUCCESS) { + dns_dbiterator_pause(signing->dbiterator); + ISC_LIST_INITANDAPPEND(zone->signing, signing, link); + signing = NULL; + if (isc_time_isepoch(&zone->signingtime)) { + zone->signingtime = now; + if (zone->task != NULL) + zone_settimer(zone, &now); } - } else - result = ISC_R_NOTFOUND; + } cleanup: if (signing != NULL) { @@ -15414,6 +15924,8 @@ zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm, isc_uint16_t keyid, dns_dbiterator_destroy(&signing->dbiterator); isc_mem_put(zone->mctx, signing, sizeof *signing); } + if (db != NULL) + dns_db_detach(&db); return (result); } @@ -15822,7 +16334,6 @@ zone_rekey(dns_zone_t *zone) { mctx = zone->mctx; dns_diff_init(mctx, &diff); dns_diff_init(mctx, &_sig_diff); - _sig_diff.resign = zone->sigresigninginterval; zonediff_init(&zonediff, &_sig_diff); CHECK(dns_zone_getdb(zone, &db)); @@ -16182,18 +16693,34 @@ dns_zone_dlzpostload(dns_zone_t *zone, dns_db_t *db) { isc_time_t loadtime; isc_result_t result; + dns_zone_t *secure = NULL; TIME_NOW(&loadtime); /* * Lock hierarchy: zmgr, zone, raw. */ + again: LOCK_ZONE(zone); if (inline_secure(zone)) LOCK_ZONE(zone->raw); + else if (inline_raw(zone)) { + secure = zone->secure; + TRYLOCK_ZONE(result, secure); + if (result != ISC_R_SUCCESS) { + UNLOCK_ZONE(zone); + secure = NULL; +#if ISC_PLATFORM_USETHREADS + isc_thread_yield(); +#endif + goto again; + } + } result = zone_postload(zone, db, loadtime, ISC_R_SUCCESS); if (inline_secure(zone)) UNLOCK_ZONE(zone->raw); + else if (secure != NULL) + UNLOCK_ZONE(secure); UNLOCK_ZONE(zone); return result; } @@ -16504,14 +17031,6 @@ dns_zone_keydone(dns_zone_t *zone, const char *keystr) { return (result); } -struct nsec3param { - isc_event_t event; - unsigned char data[DNS_NSEC3PARAM_BUFFERSIZE + 1]; - unsigned int length; - isc_boolean_t nsec; - isc_boolean_t replace; -}; - static void setnsec3param(isc_task_t *task, isc_event_t *event) { const char *me = "setnsec3param"; @@ -16523,7 +17042,8 @@ setnsec3param(isc_task_t *task, isc_event_t *event) { dns_dbnode_t *node = NULL; dns_rdataset_t prdataset, nrdataset; dns_diff_t diff; - struct nsec3param *np = (struct nsec3param *)event; + struct np3event *npe = (struct np3event *)event; + nsec3param_t *np; dns_update_log_t log = { update_log_cb, NULL }; dns_rdata_t rdata; isc_boolean_t nseconly; @@ -16536,6 +17056,8 @@ setnsec3param(isc_task_t *task, isc_event_t *event) { ENTER; + np = &npe->params; + dns_rdataset_init(&prdataset); dns_rdataset_init(&nrdataset); dns_diff_init(zone->mctx, &diff); @@ -16687,7 +17209,8 @@ dns_zone_setnsec3param(dns_zone_t *zone, isc_uint8_t hash, isc_uint8_t flags, dns_rdata_t nrdata = DNS_RDATA_INIT; dns_rdata_t prdata = DNS_RDATA_INIT; unsigned char nbuf[DNS_NSEC3PARAM_BUFFERSIZE]; - struct nsec3param *np; + struct np3event *npe; + nsec3param_t *np; dns_zone_t *dummy = NULL; isc_buffer_t b; isc_event_t *e; @@ -16698,13 +17221,15 @@ dns_zone_setnsec3param(dns_zone_t *zone, isc_uint8_t hash, isc_uint8_t flags, LOCK_ZONE(zone); e = isc_event_allocate(zone->mctx, zone, DNS_EVENT_SETNSEC3PARAM, - setnsec3param, zone, sizeof(struct nsec3param)); + setnsec3param, zone, sizeof(struct np3event)); if (e == NULL) { result = ISC_R_NOMEMORY; goto failure; } - np = (struct nsec3param *) e; + npe = (struct np3event *) e; + np = &npe->params; + np->replace = replace; if (hash == 0) { np->length = 0; |