2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-09-02 23:55:27 +00:00

3252. [bug] When master zones using inline-signing were

updated while the server was offline, the source
			zone could fall out of sync with the signed
			copy. They can now resynchronize. [RT #26676]
This commit is contained in:
Evan Hunt
2011-12-22 07:32:41 +00:00
parent dd0d54ff01
commit f30785f506
23 changed files with 558 additions and 201 deletions

View File

@@ -1,3 +1,8 @@
3252. [bug] When master zones using inline-signing were
updated while the server was offline, the source
zone could fall out of sync with the signed
copy. They can now resynchronize. [RT #26676]
3251. [bug] Enforce a upper bound (65535 bytes) on the amount of
memory dns_sdlz_putrr() can allocate per record to
prevent run away memory consumption on ISC_R_NOSPACE.

View File

@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: check-tool.c,v 1.43 2011/12/09 23:47:02 tbox Exp $ */
/* $Id: check-tool.c,v 1.44 2011/12/22 07:32:39 each Exp $ */
/*! \file */
@@ -661,7 +661,6 @@ dump_zone(const char *zonename, dns_zone_t *zone, const char *filename,
result = dns_zone_dumptostream3(zone, output, fileformat, style,
rawversion);
if (output != stdout)
(void)isc_stdio_close(output);

View File

@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: named-checkzone.c,v 1.63 2011/12/09 23:47:02 tbox Exp $ */
/* $Id: named-checkzone.c,v 1.64 2011/12/22 07:32:39 each Exp $ */
/*! \file */
@@ -39,6 +39,7 @@
#include <dns/db.h>
#include <dns/fixedname.h>
#include <dns/log.h>
#include <dns/master.h>
#include <dns/masterdump.h>
#include <dns/name.h>
#include <dns/rdataclass.h>
@@ -112,8 +113,11 @@ main(int argc, char **argv) {
const char *outputformatstr = NULL;
dns_masterformat_t inputformat = dns_masterformat_text;
dns_masterformat_t outputformat = dns_masterformat_text;
isc_uint32_t rawversion = 1;
dns_masterrawheader_t header;
isc_uint32_t rawversion = 1, serialnum = 0;
isc_boolean_t snset = ISC_FALSE;
FILE *errout = stdout;
char *endp;
outputstyle = &dns_master_style_full;
@@ -157,7 +161,7 @@ main(int argc, char **argv) {
isc_commandline_errprint = ISC_FALSE;
while ((c = isc_commandline_parse(argc, argv,
"c:df:hi:jk:m:n:qr:s:t:o:vw:DF:M:S:W:"))
"c:df:hi:jk:L:m:n:qr:s:t:o:vw:DF:M:S:W:"))
!= EOF) {
switch (c) {
case 'c':
@@ -235,6 +239,17 @@ main(int argc, char **argv) {
}
break;
case 'L':
snset = ISC_TRUE;
endp = NULL;
serialnum = strtol(isc_commandline_argument, &endp, 0);
if (*endp != '\0') {
fprintf(stderr, "source serial number "
"must be numeric");
exit(1);
}
break;
case 'n':
if (ARGCMP("ignore")) {
zone_options &= ~(DNS_ZONEOPT_CHECKNS|
@@ -477,6 +492,13 @@ main(int argc, char **argv) {
result = load_zone(mctx, origin, filename, inputformat, classname,
&zone);
if (snset) {
dns_master_initrawheader(&header);
header.flags = DNS_MASTERRAW_SOURCESERIALSET;
header.sourceserial = serialnum;
dns_zone_setrawdata(zone, &header);
}
if (result == ISC_R_SUCCESS && dumpzone) {
if (!quiet && progmode == progmode_compile) {
fprintf(errout, "dump zone to %s...", output_filename);

View File

@@ -18,7 +18,7 @@
- PERFORMANCE OF THIS SOFTWARE.
-->
<!-- $Id: named-checkzone.docbook,v 1.43 2011/12/09 23:47:02 tbox Exp $ -->
<!-- $Id: named-checkzone.docbook,v 1.44 2011/12/22 07:32:39 each Exp $ -->
<refentry id="man.named-checkzone">
<refentryinfo>
<date>June 13, 2000</date>
@@ -71,6 +71,7 @@
<arg><option>-m <replaceable class="parameter">mode</replaceable></option></arg>
<arg><option>-M <replaceable class="parameter">mode</replaceable></option></arg>
<arg><option>-n <replaceable class="parameter">mode</replaceable></option></arg>
<arg><option>-L <replaceable class="parameter">serial</replaceable></option></arg>
<arg><option>-o <replaceable class="parameter">filename</replaceable></option></arg>
<arg><option>-r <replaceable class="parameter">mode</replaceable></option></arg>
<arg><option>-s <replaceable class="parameter">style</replaceable></option></arg>
@@ -96,6 +97,7 @@
<arg><option>-k <replaceable class="parameter">mode</replaceable></option></arg>
<arg><option>-m <replaceable class="parameter">mode</replaceable></option></arg>
<arg><option>-n <replaceable class="parameter">mode</replaceable></option></arg>
<arg><option>-L <replaceable class="parameter">serial</replaceable></option></arg>
<arg><option>-r <replaceable class="parameter">mode</replaceable></option></arg>
<arg><option>-s <replaceable class="parameter">style</replaceable></option></arg>
<arg><option>-t <replaceable class="parameter">directory</replaceable></option></arg>
@@ -280,6 +282,17 @@
</listitem>
</varlistentry>
<varlistentry>
<term>-L <replaceable class="parameter">serial</replaceable></term>
<listitem>
<para>
When compiling a zone to 'raw' format, set the "source serial"
value in the header to the specified serial number. (This is
expected to be used primarily for testing purposes.)
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-m <replaceable class="parameter">mode</replaceable></term>
<listitem>

View File

@@ -29,7 +29,7 @@
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: dnssec-signzone.c,v 1.284 2011/12/08 23:45:02 marka Exp $ */
/* $Id: dnssec-signzone.c,v 1.285 2011/12/22 07:32:39 each Exp $ */
/*! \file */
@@ -139,7 +139,8 @@ static char *tempfile = NULL;
static const dns_master_style_t *masterstyle;
static dns_masterformat_t inputformat = dns_masterformat_text;
static dns_masterformat_t outputformat = dns_masterformat_text;
static unsigned int rawversion = 1;
static isc_uint32_t rawversion = 1, serialnum = 0;
static isc_boolean_t snset = ISC_FALSE;
static unsigned int nsigned = 0, nretained = 0, ndropped = 0;
static unsigned int nverified = 0, nverifyfailed = 0;
static const char *directory = NULL, *dsdir = NULL;
@@ -3470,7 +3471,7 @@ main(int argc, char *argv[]) {
isc_boolean_t set_iter = ISC_FALSE;
#define CMDLINE_FLAGS \
"3:AaCc:Dd:E:e:f:FghH:i:I:j:K:k:l:m:n:N:o:O:PpRr:s:ST:tuUv:X:xz"
"3:AaCc:Dd:E:e:f:FghH:i:I:j:K:k:L:l:m:n:N:o:O:PpRr:s:ST:tuUv:X:xz"
/*
* Process memory debugging argument first.
@@ -3620,6 +3621,17 @@ main(int argc, char *argv[]) {
dskeyfile[ndskeys++] = isc_commandline_argument;
break;
case 'L':
snset = ISC_TRUE;
endp = NULL;
serialnum = strtol(isc_commandline_argument, &endp, 0);
if (*endp != '\0') {
fprintf(stderr, "source serial number "
"must be numeric");
exit(1);
}
break;
case 'l':
len = strlen(isc_commandline_argument);
isc_buffer_init(&b, isc_commandline_argument, len);
@@ -4077,6 +4089,10 @@ main(int argc, char *argv[]) {
dns_master_initrawheader(&header);
if (rawversion == 0U)
header.flags = DNS_MASTERRAW_COMPAT;
else if (snset) {
header.flags = DNS_MASTERRAW_SOURCESERIALSET;
header.sourceserial = serialnum;
}
result = dns_master_dumptostream3(mctx, gdb, gversion,
masterstyle, outputformat,
&header, fp);

View File

@@ -18,7 +18,7 @@
- PERFORMANCE OF THIS SOFTWARE.
-->
<!-- $Id: dnssec-signzone.docbook,v 1.51 2011/12/08 16:07:20 each Exp $ -->
<!-- $Id: dnssec-signzone.docbook,v 1.52 2011/12/22 07:32:40 each Exp $ -->
<refentry id="man.dnssec-signzone">
<refentryinfo>
<date>June 05, 2009</date>
@@ -69,6 +69,7 @@
<arg><option>-h</option></arg>
<arg><option>-K <replaceable class="parameter">directory</replaceable></option></arg>
<arg><option>-k <replaceable class="parameter">key</replaceable></option></arg>
<arg><option>-L <replaceable class="parameter">serial</replaceable></option></arg>
<arg><option>-l <replaceable class="parameter">domain</replaceable></option></arg>
<arg><option>-i <replaceable class="parameter">interval</replaceable></option></arg>
<arg><option>-I <replaceable class="parameter">input-format</replaceable></option></arg>
@@ -371,6 +372,17 @@
</listitem>
</varlistentry>
<varlistentry>
<term>-L <replaceable class="parameter">serial</replaceable></term>
<listitem>
<para>
When writing a signed zone to 'raw' format, set the "source serial"
value in the header to the specified serial number. (This is
expected to be used primarily for testing purposes.)
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-n <replaceable class="parameter">ncpus</replaceable></term>
<listitem>

View File

@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: update.c,v 1.198 2011/10/28 06:20:04 each Exp $ */
/* $Id: update.c,v 1.199 2011/12/22 07:32:40 each Exp $ */
#include <config.h>
@@ -3095,7 +3095,7 @@ update_action(isc_task_t *task, isc_event_t *event) {
journal = NULL;
result = dns_journal_open(mctx, journalfile,
ISC_TRUE, &journal);
DNS_JOURNAL_CREATE, &journal);
if (result != ISC_R_SUCCESS)
FAILS(result, "journal open failed");

View File

@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: xfrout.c,v 1.143 2011/12/01 00:53:58 marka Exp $ */
/* $Id: xfrout.c,v 1.144 2011/12/22 07:32:40 each Exp $ */
#include <config.h>
@@ -252,7 +252,7 @@ ixfr_rrstream_create(isc_mem_t *mctx,
s->journal = NULL;
CHECK(dns_journal_open(mctx, journal_filename,
ISC_FALSE, &s->journal));
DNS_JOURNAL_READ, &s->journal));
CHECK(dns_journal_iter_init(s->journal, begin_serial, end_serial));
*sp = (rrstream_t *) s;

View File

@@ -12,13 +12,14 @@
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
# $Id: clean.sh,v 1.7 2011/12/02 02:44:01 marka Exp $
# $Id: clean.sh,v 1.8 2011/12/22 07:32:40 each Exp $
rm -f */named.memstats
rm -f */named.run
rm -f */trusted.conf
rm -f ns1/K*
rm -f ns1/dsset-*
rm -f ns3/dsset-*
rm -f ns1/root.db
rm -f ns1/root.db.signed
rm -f ns2/bits.db
@@ -40,6 +41,10 @@ rm -f ns3/dynamic.db
rm -f ns3/dynamic.db.jnl
rm -f ns3/dynamic.db.signed
rm -f ns3/dynamic.db.signed.jnl
rm -f ns3/updated.db
rm -f ns3/updated.db.jnl
rm -f ns3/updated.db.signed
rm -f ns3/updated.db.signed.jnl
rm -f ns4/K*
rm -f ns4/noixfr.db
rm -f ns4/noixfr.db.jnl

View File

@@ -12,7 +12,7 @@
; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
; PERFORMANCE OF THIS SOFTWARE.
; $Id: root.db.in,v 1.4 2011/10/26 20:56:45 marka Exp $
; $Id: root.db.in,v 1.5 2011/12/22 07:32:40 each Exp $
$TTL 300
. IN SOA gson.nominum.com. a.root.servers.nil. (
@@ -38,3 +38,6 @@ ns3.master. A 10.53.0.3
dynamic. NS ns3.dynamic.
ns3.dynamic. A 10.53.0.3
updated. NS ns3.updated.
ns3.updated. A 10.53.0.3

View File

@@ -14,7 +14,7 @@
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
# $Id: sign.sh,v 1.2 2011/10/25 01:54:20 marka Exp $
# $Id: sign.sh,v 1.3 2011/12/22 07:32:40 each Exp $
SYSTEMTESTTOP=../..
. $SYSTEMTESTTOP/conf.sh
@@ -26,7 +26,7 @@ rm -f K.+*+*.key
rm -f K.+*+*.private
keyname=`$KEYGEN -q -r $RANDFILE -a RSASHA1 -b 768 -n zone $zone`
keyname=`$KEYGEN -q -r $RANDFILE -a RSASHA1 -b 1024 -n zone -f KSK $zone`
$SIGNER -S -x -T 1200 -o ${zone} root.db
$SIGNER -S -x -T 1200 -o ${zone} root.db > /dev/null 2>&1
cat ${keyname}.key | grep -v '^; ' | $PERL -n -e '
local ($dn, $class, $type, $flags, $proto, $alg, @rest) = split;

View File

@@ -14,7 +14,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: named.conf,v 1.4 2011/10/26 20:56:45 marka Exp $ */
/* $Id: named.conf,v 1.5 2011/12/22 07:32:40 each Exp $ */
// NS3
@@ -70,3 +70,11 @@ zone "dynamic" {
allow-update { any; };
file "dynamic.db";
};
zone "updated" {
type master;
inline-signing yes;
auto-dnssec maintain;
allow-update { none; };
file "updated.db";
};

View File

@@ -14,7 +14,7 @@
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
# $Id: sign.sh,v 1.4 2011/10/26 20:56:45 marka Exp $
# $Id: sign.sh,v 1.5 2011/12/22 07:32:40 each Exp $
SYSTEMTESTTOP=../..
. $SYSTEMTESTTOP/conf.sh
@@ -48,3 +48,12 @@ rm -f K${zone}.+*+*.private
keyname=`$KEYGEN -q -r $RANDFILE -a RSASHA1 -b 768 -n zone $zone`
keyname=`$KEYGEN -q -r $RANDFILE -a RSASHA1 -b 1024 -n zone -f KSK $zone`
$DSFROMKEY -T 1200 $keyname >> ../ns1/root.db
zone=updated
rm -f K${zone}.+*+*.key
rm -f K${zone}.+*+*.private
keyname=`$KEYGEN -q -r $RANDFILE -a RSASHA1 -b 768 -n zone $zone`
keyname=`$KEYGEN -q -r $RANDFILE -a RSASHA1 -b 1024 -n zone -f KSK $zone`
$DSFROMKEY -T 1200 $keyname >> ../ns1/root.db
$SIGNER -S -O raw -L 2000042407 -o ${zone} ${zone}.db > /dev/null 2>&1
cp master2.db.in updated.db

View File

@@ -12,7 +12,7 @@
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
# $Id: setup.sh,v 1.7 2011/12/09 22:09:25 marka Exp $
# $Id: setup.sh,v 1.8 2011/12/22 07:32:40 each Exp $
sh clean.sh
@@ -45,6 +45,7 @@ rm -f ns3/dynamic.db.signed.jnl
cp ns3/master.db.in ns3/master.db
cp ns3/master.db.in ns3/dynamic.db
cp ns3/master.db.in ns3/updated.db
touch ns4/trusted.conf
cp ns4/noixfr.db.in ns4/noixfr.db

View File

@@ -14,7 +14,7 @@
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
# $Id: tests.sh,v 1.10 2011/12/19 23:46:13 marka Exp $
# $Id: tests.sh,v 1.11 2011/12/22 07:32:40 each Exp $
SYSTEMTESTTOP=..
. $SYSTEMTESTTOP/conf.sh
@@ -353,6 +353,27 @@ do
done
if [ $ret != 0 ]; then echo "I:failed"; fi
n=`expr $n + 1`
echo "I:checking master zone that was updated while offline is correct ($n)"
ret=0
serial=`$DIG $DIGOPTS +short @10.53.0.3 -p 5300 updated SOA | awk '{print $3}'`
# serial should have changed
[ "$serial" = "2000042407" ] && ret=1
# e.updated should exist and should be signed
$DIG $DIGOPTS @10.53.0.3 -p 5300 e.updated A > dig.out.ns3.test$n
grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1
grep "ANSWER: 2," dig.out.ns3.test$n > /dev/null || ret=1
# updated.db.signed.jnl should exist, should have the source serial
# of master2.db, and should show a minimal diff: no more than 8 added
# records (SOA/RRSIG, 2 x NSEC/RRSIG, A/RRSIG), and 4 removed records
# (SOA/RRSIG, NSEC/RRSIG).
serial=`$JOURNALPRINT ns3/updated.db.signed.jnl | head -1 | awk '{print $4}'`
[ "$serial" = "2000042408" ] || ret=1
diffsize=`$JOURNALPRINT ns3/updated.db.signed.jnl | wc -l`
[ "$diffsize" -le 13 ] || ret=1
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:checking adding of record to unsigned master using UPDATE ($n)"
ret=0

View File

@@ -14,11 +14,12 @@
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
# $Id: clean.sh,v 1.9 2011/12/08 16:07:20 each Exp $
# $Id: clean.sh,v 1.10 2011/12/22 07:32:40 each Exp $
rm -f named-compilezone
rm -f ns1/example.db.raw*
rm -f ns1/example.db.compat
rm -f ns1/example.db.serial.raw
rm -f ns2/example.db
rm -f dig.out.*
rm -f */named.memstats

View File

@@ -12,7 +12,7 @@
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
# $Id: compile.sh,v 1.8 2011/12/09 23:47:03 tbox Exp $
# $Id: compile.sh,v 1.9 2011/12/22 07:32:40 each Exp $
../named-compilezone -D -F raw -o example.db.raw example \
example.db > /dev/null 2>&1
@@ -20,3 +20,5 @@
example.db > /dev/null 2>&1
../named-compilezone -D -F raw=0 -o example.db.compat example-compat \
example.db > /dev/null 2>&1
../named-compilezone -D -F raw -L 3333 -o example.db.serial.raw example \
example.db > /dev/null 2>&1

View File

@@ -14,7 +14,7 @@
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
# $Id: tests.sh,v 1.8 2011/12/08 16:07:20 each Exp $
# $Id: tests.sh,v 1.9 2011/12/22 07:32:40 each Exp $
SYSTEMTESTTOP=..
. $SYSTEMTESTTOP/conf.sh
@@ -28,11 +28,24 @@ israw () {
rawversion () {
perl -e '$input = <STDIN>;
if (length($input) < 2) { print "not raw\n"; exit 0; };
if (length($input) < 8) { print "not raw\n"; exit 0; };
($style, $version) = unpack("NN", $input);
print ($style == 2 ? "$version\n" : "not raw\n");' < $1
}
sourceserial () {
perl -e '$input = <STDIN>;
if (length($input) < 20) { print "UNSET\n"; exit; };
($format, $version, $dumptime, $flags, $sourceserial) =
unpack("NNNNN", $input);
if ($format != 2 || $version < 1) { print "UNSET\n"; exit; };
if ($flags & 02) {
print $sourceserial . "\n";
} else {
print "UNSET\n";
}' < $1
}
DIGOPTS="+tcp +noauth +noadd +nosea +nostat +noquest +nocomm +nocmd"
status=0
@@ -62,6 +75,13 @@ israw ns1/example.db.compat || ret=1
[ $ret -eq 0 ] || echo "I:failed"
status=`expr $status + $ret`
echo "I:checking source serial numbers"
ret=0
[ "`sourceserial ns1/example.db.raw`" = "UNSET" ] || ret=1
[ "`sourceserial ns1/example.db.serial.raw`" = "3333" ] || ret=1
[ $ret -eq 0 ] || echo "I:failed"
status=`expr $status + $ret`
echo "I:waiting for transfers to complete"
sleep 1

View File

@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: journal.h,v 1.42 2011/12/05 23:46:35 tbox Exp $ */
/* $Id: journal.h,v 1.43 2011/12/22 07:32:41 each Exp $ */
#ifndef DNS_JOURNAL_H
#define DNS_JOURNAL_H 1
@@ -106,7 +106,7 @@ dns_journal_open(isc_mem_t *mctx, const char *filename, unsigned int mode,
*
* DNS_JOURNAL_CREATE open the journal for reading and writing and create
* the journal if it does not exist.
* DNS_JOURNAL_WRITE open the journal for readinge and writing.
* DNS_JOURNAL_WRITE open the journal for reading and writing.
* DNS_JOURNAL_READ open the journal for reading only.
*/
@@ -293,12 +293,15 @@ dns_journal_compact(isc_mem_t *mctx, char *filename, isc_uint32_t serial,
* exists and is non-empty 'serial' must exist in the journal.
*/
isc_uint32_t
dns_journal_get_sourceserial(dns_journal_t *j);
isc_boolean_t
dns_journal_get_sourceserial(dns_journal_t *j, isc_uint32_t *sourceserial);
void
dns_journal_set_sourceserial(dns_journal_t *j, isc_uint32_t sourceserial);
/*%<
* Get and set source serial.
*
* Returns:
* ISC_TRUE if sourceserial has previously been set.
*/
ISC_LANG_ENDDECLS

View File

@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: zone.h,v 1.198 2011/12/08 16:07:21 each Exp $ */
/* $Id: zone.h,v 1.199 2011/12/22 07:32:41 each Exp $ */
#ifndef DNS_ZONE_H
#define DNS_ZONE_H 1
@@ -32,6 +32,7 @@
#include <isc/lang.h>
#include <isc/rwlock.h>
#include <dns/master.h>
#include <dns/masterdump.h>
#include <dns/rdatastruct.h>
#include <dns/types.h>
@@ -2029,6 +2030,13 @@ dns_zone_setnsec3param(dns_zone_t *zone, isc_uint8_t hash, isc_uint8_t flags,
* Requires:
* \li 'zone' to be valid.
*/
void
dns_zone_setrawdata(dns_zone_t *zone, dns_masterrawheader_t *header);
/*%
* Set the data to be included in the header when the zone is dumped in
* binary format.
*/
ISC_LANG_ENDDECLS
#endif /* DNS_ZONE_H */

View File

@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: journal.c,v 1.119 2011/12/05 23:46:35 tbox Exp $ */
/* $Id: journal.c,v 1.120 2011/12/22 07:32:41 each Exp $ */
#include <config.h>
@@ -111,6 +111,8 @@ static isc_boolean_t bind8_compat = ISC_TRUE; /* XXX config */
if (result != ISC_R_SUCCESS) goto failure; \
} while (0)
#define JOURNAL_SERIALSET 0x01U
static isc_result_t index_to_disk(dns_journal_t *);
static inline isc_uint32_t
@@ -215,6 +217,7 @@ typedef union {
unsigned char index_size[4];
/*% Source serial number. */
unsigned char sourceserial[4];
unsigned char flags;
} h;
/* Pad the header to a fixed size. */
unsigned char pad[JOURNAL_HEADER_SIZE];
@@ -255,6 +258,7 @@ typedef struct {
journal_pos_t end;
isc_uint32_t index_size;
isc_uint32_t sourceserial;
isc_boolean_t serialset;
} journal_header_t;
/*%
@@ -287,7 +291,7 @@ typedef struct {
*/
static journal_header_t
initial_journal_header = { ";BIND LOG V9\n", { 0, 0 }, { 0, 0 }, 0, 0 };
initial_journal_header = { ";BIND LOG V9\n", { 0, 0 }, { 0, 0 }, 0, 0, 0 };
#define JOURNAL_EMPTY(h) ((h)->begin.offset == (h)->end.offset)
@@ -358,10 +362,13 @@ journal_header_decode(journal_rawheader_t *raw, journal_header_t *cooked) {
journal_pos_decode(&raw->h.end, &cooked->end);
cooked->index_size = decode_uint32(raw->h.index_size);
cooked->sourceserial = decode_uint32(raw->h.sourceserial);
cooked->serialset = ISC_TF(raw->h.flags & JOURNAL_SERIALSET);
}
static void
journal_header_encode(journal_header_t *cooked, journal_rawheader_t *raw) {
unsigned char flags = 0;
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));
@@ -369,6 +376,9 @@ journal_header_encode(journal_header_t *cooked, journal_rawheader_t *raw) {
journal_pos_encode(&raw->h.end, &cooked->end);
encode_uint32(cooked->index_size, raw->h.index_size);
encode_uint32(cooked->sourceserial, raw->h.sourceserial);
if (cooked->serialset)
flags |= JOURNAL_SERIALSET;
raw->h.flags = flags;
}
/*
@@ -546,7 +556,8 @@ journal_file_create(isc_mem_t *mctx, const char *filename) {
static isc_result_t
journal_open(isc_mem_t *mctx, const char *filename, isc_boolean_t write,
isc_boolean_t create, dns_journal_t **journalp) {
isc_boolean_t create, dns_journal_t **journalp)
{
FILE *fp = NULL;
isc_result_t result;
journal_rawheader_t rawheader;
@@ -674,7 +685,8 @@ journal_open(isc_mem_t *mctx, const char *filename, isc_boolean_t write,
isc_result_t
dns_journal_open(isc_mem_t *mctx, const char *filename, unsigned int mode,
dns_journal_t **journalp) {
dns_journal_t **journalp)
{
isc_result_t result;
int namelen;
char backup[1024];
@@ -1164,10 +1176,8 @@ dns_journal_commit(dns_journal_t *j) {
/*
* Update the journal header.
*/
if (JOURNAL_EMPTY(&j->header)) {
if (JOURNAL_EMPTY(&j->header))
j->header.begin = j->x.pos[0];
j->header.sourceserial = j->header.begin.serial;
}
j->header.end = j->x.pos[1];
journal_header_encode(&j->header, &rawheader);
CHECK(journal_seek(j, 0));
@@ -1399,7 +1409,7 @@ dns_journal_rollforward2(isc_mem_t *mctx, dns_db_t *db, unsigned int options,
REQUIRE(filename != NULL);
j = NULL;
result = dns_journal_open(mctx, filename, ISC_FALSE, &j);
result = dns_journal_open(mctx, filename, DNS_JOURNAL_READ, &j);
if (result == ISC_R_NOTFOUND) {
isc_log_write(JOURNAL_DEBUG_LOGARGS(3),
"no journal file, but that's OK");
@@ -1432,7 +1442,7 @@ dns_journal_print(isc_mem_t *mctx, const char *filename, FILE *file) {
REQUIRE(filename != NULL);
j = NULL;
result = dns_journal_open(mctx, filename, ISC_FALSE, &j);
result = dns_journal_open(mctx, filename, DNS_JOURNAL_READ, &j);
if (result == ISC_R_NOTFOUND) {
isc_log_write(JOURNAL_DEBUG_LOGARGS(3), "no journal file");
return (DNS_R_NOJOURNAL);
@@ -1445,7 +1455,8 @@ dns_journal_print(isc_mem_t *mctx, const char *filename, FILE *file) {
return (result);
}
fprintf(file, "Source serial = %u\n", j->header.sourceserial);
if (j->header.serialset)
fprintf(file, "Source serial = %u\n", j->header.sourceserial);
dns_diff_init(j->mctx, &diff);
/*
@@ -1546,13 +1557,19 @@ dns_journal_set_sourceserial(dns_journal_t *j, isc_uint32_t sourceserial) {
j->state == JOURNAL_STATE_TRANSACTION);
j->header.sourceserial = sourceserial;
j->header.serialset = ISC_TRUE;
if (j->state == JOURNAL_STATE_WRITE)
j->state = JOURNAL_STATE_INLINE;
}
isc_uint32_t
dns_journal_get_sourceserial(dns_journal_t *j) {
return (j->header.sourceserial);
isc_boolean_t
dns_journal_get_sourceserial(dns_journal_t *j, isc_uint32_t *sourceserial) {
REQUIRE(sourceserial != NULL);
if (!j->header.serialset)
return (ISC_FALSE);
*sourceserial = j->header.sourceserial;
return (ISC_TRUE);
}
/**************************************************************************/
@@ -2043,8 +2060,8 @@ dns_db_diffx(dns_diff_t *diff, dns_db_t *dba, dns_dbversion_t *dbvera,
dns_journal_t *journal = NULL;
if (filename != NULL) {
result = dns_journal_open(diff->mctx, filename, ISC_TRUE,
&journal);
result = dns_journal_open(diff->mctx, filename,
DNS_JOURNAL_CREATE, &journal);
if (result != ISC_R_SUCCESS)
return (result);
}
@@ -2213,6 +2230,7 @@ dns_journal_compact(isc_mem_t *mctx, char *filename, isc_uint32_t serial,
new->header.end.serial = j->header.end.serial;
new->header.end.offset = indexend + copy_length;
new->header.sourceserial = j->header.sourceserial;
new->header.serialset = j->header.serialset;
/*
* Update the journal header.

View File

@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: xfrin.c,v 1.171 2011/08/30 05:16:14 marka Exp $ */
/* $Id: xfrin.c,v 1.172 2011/12/22 07:32:41 each Exp $ */
/*! \file */
@@ -360,7 +360,7 @@ ixfr_init(dns_xfrin_ctx_t *xfr) {
journalfile = dns_zone_getjournal(xfr->zone);
if (journalfile != NULL)
CHECK(dns_journal_open(xfr->mctx, journalfile,
ISC_TRUE, &xfr->ixfr.journal));
DNS_JOURNAL_CREATE, &xfr->ixfr.journal));
result = ISC_R_SUCCESS;
failure:

View File

@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: zone.c,v 1.657 2011/12/20 00:26:52 marka Exp $ */
/* $Id: zone.c,v 1.658 2011/12/22 07:32:41 each Exp $ */
/*! \file */
@@ -364,8 +364,8 @@ struct dns_zone {
dns_zone_t *raw;
dns_zone_t *secure;
isc_boolean_t rawserialset;
isc_uint32_t rawserial;
isc_boolean_t sourceserialset;
isc_uint32_t sourceserial;
};
#define DNS_ZONE_FLAG(z,f) (ISC_TF(((z)->flags & (f)) != 0))
@@ -655,6 +655,7 @@ 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 locked,
isc_uint32_t serial);
#if 0
@@ -712,7 +713,8 @@ static isc_result_t delete_nsec(dns_db_t *db, dns_dbversion_t *ver,
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, dns_db_t *db);
static isc_result_t zone_send_securedb(dns_zone_t *zone, isc_boolean_t locked,
dns_db_t *db);
#define ENTER zone_debuglog(zone, me, 1, "enter")
@@ -899,8 +901,8 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) {
ISC_LIST_INIT(zone->forwards);
zone->raw = NULL;
zone->secure = NULL;
zone->rawserial = 0;
zone->rawserialset = ISC_FALSE;
zone->sourceserial = 0;
zone->sourceserialset = ISC_FALSE;
zone->magic = ZONE_MAGIC;
@@ -1038,6 +1040,28 @@ zone_free(dns_zone_t *zone) {
isc_mem_detach(&mctx);
}
/*
* Returns ISC_TRUE iff this the signed side of an inline-signing zone
*/
static inline isc_boolean_t
inline_secure(dns_zone_t *zone) {
REQUIRE(DNS_ZONE_VALID(zone));
if (zone->raw != NULL)
return (ISC_TRUE);
return (ISC_FALSE);
}
/*
* Returns ISC_TRUE iff this the unsigned side of an inline-signing zone
*/
static inline isc_boolean_t
inline_raw(dns_zone_t *zone) {
REQUIRE(DNS_ZONE_VALID(zone));
if (zone->secure != NULL)
return (ISC_TRUE);
return (ISC_FALSE);
}
/*
* Single shot.
*/
@@ -1066,7 +1090,7 @@ dns_zone_setclass(dns_zone_t *zone, dns_rdataclass_t rdclass) {
zone_rdclass_tostr(zone, namebuf, sizeof namebuf);
zone->strrdclass = isc_mem_strdup(zone->mctx, namebuf);
if (zone->raw != NULL)
if (inline_secure(zone))
dns_zone_setclass(zone->raw, rdclass);
UNLOCK_ZONE(zone);
}
@@ -1259,7 +1283,7 @@ dns_zone_setview(dns_zone_t *zone, dns_view_t *view) {
zone_viewname_tostr(zone, namebuf, sizeof namebuf);
zone->strviewname = isc_mem_strdup(zone->mctx, namebuf);
if (zone->raw != NULL)
if (inline_secure(zone))
dns_zone_setview(zone->raw, view);
UNLOCK_ZONE(zone);
@@ -1298,7 +1322,7 @@ dns_zone_setorigin(dns_zone_t *zone, const dns_name_t *origin) {
zone_name_tostr(zone, namebuf, sizeof namebuf);
zone->strname = isc_mem_strdup(zone->mctx, namebuf);
if (result == ISC_R_SUCCESS && zone->raw != NULL)
if (result == ISC_R_SUCCESS && inline_secure(zone))
result = dns_zone_setorigin(zone->raw, origin);
UNLOCK_ZONE(zone);
return (result);
@@ -1470,7 +1494,7 @@ zone_load(dns_zone_t *zone, unsigned int flags) {
LOCK_ZONE(zone);
TIME_NOW(&now);
if (zone->raw != NULL) {
if (inline_secure(zone)) {
result = zone_load(zone->raw, flags);
if (result != ISC_R_SUCCESS)
goto cleanup;
@@ -1723,7 +1747,11 @@ isc_result_t
dns_zone_loadandthaw(dns_zone_t *zone) {
isc_result_t result;
result = zone_load(zone, DNS_ZONELOADFLAG_THAW);
if (inline_raw(zone))
result = zone_load(zone->secure, DNS_ZONELOADFLAG_THAW);
else
result = zone_load(zone, DNS_ZONELOADFLAG_THAW);
switch (result) {
case DNS_R_CONTINUE:
/* Deferred thaw. */
@@ -1846,7 +1874,7 @@ zone_gotwritehandle(isc_task_t *task, isc_event_t *event) {
ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
dns_db_currentversion(zone->db, &version);
dns_master_initrawheader(&rawdata);
if (zone->raw != NULL)
if (inline_secure(zone))
get_raw_serial(zone->raw, &rawdata);
result = dns_master_dumpinc3(zone->mctx, zone->db, version,
&dns_master_style_default,
@@ -1864,24 +1892,28 @@ zone_gotwritehandle(isc_task_t *task, isc_event_t *event) {
dump_done(zone, result);
}
/*
* Save the raw serial number for inline-signing zones.
* (XXX: Other information from the header will be used
* for other purposes in the future, but for now this is
* all we're interested in.)
*/
static void
zone_setrawdata(dns_zone_t *zone, dns_masterrawheader_t *header) {
if ((header->flags & DNS_MASTERRAW_SOURCESERIALSET) == 0)
return;
zone->sourceserial = header->sourceserial;
zone->sourceserialset = ISC_TRUE;
}
void
dns_zone_setrawdata(dns_zone_t *zone, dns_masterrawheader_t *header) {
if (zone == NULL)
return;
/*
* Save the raw serial number for inline-signing zones.
* (XXX: Other information from the header will be used
* for other purposes in the future, but for now this is
* all we're interested in.)
*/
if (zone->raw != NULL ||
((header->flags & DNS_MASTERRAW_SOURCESERIALSET) == 0))
return;
LOCK_ZONE(zone);
zone->rawserial = header->sourceserial;
zone->rawserialset = ISC_TRUE;
zone_setrawdata(zone, header);
UNLOCK_ZONE(zone);
}
@@ -3289,30 +3321,32 @@ zone_journal(dns_zone_t *zone, dns_diff_t *diff, isc_uint32_t *sourceserial,
const char *journalfile;
isc_result_t result = ISC_R_SUCCESS;
dns_journal_t *journal = NULL;
unsigned int mode = DNS_JOURNAL_CREATE|DNS_JOURNAL_WRITE;
ENTER;
journalfile = dns_zone_getjournal(zone);
if (journalfile != NULL) {
result = dns_journal_open(zone->mctx, journalfile,
DNS_JOURNAL_CREATE, &journal);
result = dns_journal_open(zone->mctx, journalfile, mode,
&journal);
if (result != ISC_R_SUCCESS) {
dns_zone_log(zone, ISC_LOG_ERROR,
"%s:dns_journal_open -> %s\n",
caller, dns_result_totext(result));
return (result);
}
if (sourceserial != NULL)
dns_journal_set_sourceserial(journal, *sourceserial);
result = dns_journal_write_transaction(journal, diff);
dns_journal_destroy(&journal);
if (result != ISC_R_SUCCESS) {
dns_zone_log(zone, ISC_LOG_ERROR,
"%s:dns_journal_write_transaction -> %s\n",
caller, dns_result_totext(result));
return (result);
}
dns_journal_destroy(&journal);
}
return (result);
}
@@ -3515,12 +3549,34 @@ sync_keyzone(dns_zone_t *zone, dns_db_t *db) {
}
static void
maybe_send_securedb(dns_zone_t *zone) {
maybe_send_secure(dns_zone_t *zone) {
isc_result_t result;
/*
* We've finished loading, or else failed to load, an inline-signing
* 'secure' zone. We now need information about the status of the
* 'raw' zone. If we failed to load, then we need it to send a
* copy of its database; if we succeeded, we need it to send its
* serial number so that we can sync with it. If it has not yet
* loaded, we set a flag so that it will send the necessary
* information when it has finished loading.
*/
LOCK_ZONE(zone->raw);
if (zone->raw->db != NULL)
zone_send_securedb(zone->raw, zone->raw->db);
else
if (zone->raw->db != NULL) {
if (zone->db != NULL) {
isc_uint32_t serial;
result = zone_get_from_db(zone->raw, zone->raw->db,
NULL, NULL, &serial, NULL,
NULL, NULL, NULL, NULL);
if (result == ISC_R_SUCCESS)
zone_send_secureserial(zone->raw, ISC_TRUE,
serial);
} else
zone_send_securedb(zone->raw, ISC_TRUE, zone->raw->db);
} else
DNS_ZONE_SETFLAG(zone->raw, DNS_ZONEFLG_SENDSECURE);
UNLOCK_ZONE(zone->raw);
}
@@ -3538,6 +3594,9 @@ zone_unchanged(dns_db_t *db1, dns_db_t *db2, isc_mem_t *mctx) {
return (answer);
}
/*
* The zone is presumed to be locked.
*/
static isc_result_t
zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
isc_result_t result)
@@ -3574,10 +3633,11 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
zone->masterfile,
dns_result_totext(result));
} else if (zone->type == dns_zone_master &&
zone->raw != NULL && result == ISC_R_FILENOTFOUND) {
inline_secure(zone) && result == ISC_R_FILENOTFOUND)
{
dns_zone_log(zone, ISC_LOG_DEBUG(1),
"no master file, requesting db");
maybe_send_securedb(zone);
maybe_send_secure(zone);
} else {
int level = ISC_LOG_ERROR;
if (zone->type == dns_zone_key &&
@@ -3677,7 +3737,7 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
dns_journal_t *journal = NULL;
result = dns_journal_open(zone->mctx, zone->journal,
ISC_FALSE, &journal);
DNS_JOURNAL_READ, &journal);
if (result == ISC_R_SUCCESS) {
jserial = dns_journal_last_serial(journal);
dns_journal_destroy(&journal);
@@ -3843,6 +3903,7 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
&zone->expiretime) >= 0)
zone->refreshtime = now;
}
break;
case dns_zone_key:
@@ -3895,10 +3956,23 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
DNS_ZONE_SETFLAG(zone,
DNS_ZONEFLG_LOADED|DNS_ZONEFLG_NEEDNOTIFY);
if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_SENDSECURE) &&
zone->secure != NULL)
zone_send_securedb(zone, db);
inline_raw(zone))
{
if (zone->secure->db == NULL)
zone_send_securedb(zone, ISC_FALSE, db);
else
zone_send_secureserial(zone, ISC_FALSE, serial);
}
}
/*
* Finished loading inline-signing zone; need to get status
* from the raw side now.
*/
if (zone->type == dns_zone_master && inline_secure(zone))
maybe_send_secure(zone);
result = ISC_R_SUCCESS;
if (needdump) {
@@ -8491,7 +8565,7 @@ dns_zone_markdirty(dns_zone_t *zone) {
LOCK_ZONE(zone);
if (zone->type == dns_zone_master) {
if (zone->secure != NULL) {
if (inline_raw(zone)) {
ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
if (zone->db != NULL) {
result = zone_get_from_db(zone, zone->db, NULL,
@@ -8502,7 +8576,7 @@ dns_zone_markdirty(dns_zone_t *zone) {
result = DNS_R_NOTLOADED;
ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
if (result == ISC_R_SUCCESS)
zone_send_secureserial(zone, serial);
zone_send_secureserial(zone, ISC_FALSE, serial);
}
set_resigntime(zone); /* XXXMPA make separate call back */
}
@@ -8694,8 +8768,9 @@ dump_done(void *arg, isc_result_t result) {
* If there is a secure version of this zone
* use its serial if it is less than ours.
*/
if (tresult == ISC_R_SUCCESS &&
zone->secure != NULL && zone->secure->db != NULL) {
if (tresult == ISC_R_SUCCESS && inline_raw(zone) &&
zone->secure->db != NULL)
{
isc_uint32_t sserial;
isc_result_t mresult;
@@ -8816,7 +8891,7 @@ zone_dump(dns_zone_t *zone, isc_boolean_t compact) {
dns_masterrawheader_t rawdata;
dns_db_currentversion(db, &version);
dns_master_initrawheader(&rawdata);
if (zone->raw != NULL)
if (inline_secure(zone))
get_raw_serial(zone->raw, &rawdata);
result = dns_master_dump3(zone->mctx, db, version,
&dns_master_style_default,
@@ -8880,8 +8955,12 @@ dumptostream(dns_zone_t *zone, FILE *fd, const dns_master_style_t *style,
dns_master_initrawheader(&rawdata);
if (rawversion == 0)
rawdata.flags |= DNS_MASTERRAW_COMPAT;
if (zone->raw != NULL && rawversion > 0)
else if (inline_secure(zone))
get_raw_serial(zone->raw, &rawdata);
else if (zone->sourceserialset) {
rawdata.flags = DNS_MASTERRAW_SOURCESERIALSET;
rawdata.sourceserial = zone->sourceserial;
}
result = dns_master_dumptostream3(zone->mctx, db, version, style,
format, &rawdata, fd);
dns_db_closeversion(db, &version, ISC_FALSE);
@@ -10984,11 +11063,11 @@ zone_shutdown(isc_task_t *task, isc_event_t *event) {
*/
DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_SHUTDOWN);
free_needed = exit_check(zone);
if (zone->raw != NULL) {
if (inline_secure(zone)) {
raw = zone->raw;
zone->raw = NULL;
}
if (zone->secure != NULL) {
if (inline_raw(zone)) {
secure = zone->secure;
zone->secure = NULL;
}
@@ -11360,7 +11439,7 @@ dns_zone_notifyreceive(dns_zone_t *zone, isc_sockaddr_t *from,
* Notify messages are processed by the raw zone.
*/
LOCK_ZONE(zone);
if (zone->raw != NULL) {
if (inline_secure(zone)) {
result = dns_zone_notifyreceive(zone->raw, from, msg);
UNLOCK_ZONE(zone);
return (result);
@@ -11771,9 +11850,9 @@ zone_namerd_tostr(dns_zone_t *zone, char *buf, size_t length) {
isc_buffer_putstr(&buffer, "/");
isc_buffer_putstr(&buffer, zone->view->name);
}
if (zone->raw != NULL && 9U < isc_buffer_availablelength(&buffer))
if (inline_secure(zone) && 9U < isc_buffer_availablelength(&buffer))
isc_buffer_putstr(&buffer, " (signed)");
if (zone->secure != NULL && 11U < isc_buffer_availablelength(&buffer))
if (inline_raw(zone) && 11U < isc_buffer_availablelength(&buffer))
isc_buffer_putstr(&buffer, " (unsigned)");
buf[isc_buffer_usedlength(&buffer)] = '\0';
@@ -12092,8 +12171,9 @@ notify_done(isc_task_t *task, isc_event_t *event) {
dns_message_destroy(&message);
}
struct secure_serial {
struct secure_event {
isc_event_t e;
dns_db_t *db;
isc_uint32_t serial;
};
@@ -12103,89 +12183,55 @@ update_log_cb(void *arg, dns_zone_t *zone, int level, const char *message) {
dns_zone_log(zone, level, "%s", message);
}
static void
receive_secure_serial(isc_task_t *task, isc_event_t *event) {
isc_result_t result;
dns_journal_t *rjournal = NULL, *sjournal = NULL;
isc_uint32_t start, end;
dns_zone_t *zone;
int n_soa = 0;
dns_db_t *db = NULL;
dns_dbnode_t *node = NULL;
dns_dbversion_t *newver = NULL, *oldver = NULL;
isc_uint32_t oldserial, newserial;
static isc_result_t
sync_secure_journal(dns_zone_t *zone, dns_journal_t *journal,
isc_uint32_t start, isc_uint32_t end,
dns_difftuple_t **soatuplep, dns_diff_t *diff)
{
isc_result_t result;
dns_difftuple_t *tuple = NULL;
dns_diffop_t op = DNS_DIFFOP_ADD;
dns_diff_t diff;
dns_difftuple_t *tuple = NULL, *soatuple = NULL;
dns_update_log_t log = { update_log_cb, NULL };
isc_time_t timenow;
int n_soa = 0;
zone = event->ev_arg;
end = ((struct secure_serial *)event)->serial;
REQUIRE(soatuplep != NULL);
dns_diff_init(zone->mctx, &diff);
if (start == end)
return (DNS_R_UNCHANGED);
UNUSED(task);
CHECK(dns_journal_open(zone->raw->mctx, zone->raw->journal,
DNS_JOURNAL_WRITE, &rjournal));
result = dns_journal_open(zone->raw->mctx, zone->journal,
DNS_JOURNAL_READ, &sjournal);
if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND)
goto failure;
start = dns_journal_get_sourceserial(rjournal);
if (sjournal != NULL) {
isc_uint32_t serial = dns_journal_get_sourceserial(sjournal);
/*
* We write the secure journal first so if that exists
* use its value provided it is greater that from the
* raw journal.
*/
if (isc_serial_gt(serial, start))
start = serial;
dns_journal_destroy(&sjournal);
}
if (start == end)
goto failure;
CHECK(dns_journal_iter_init(rjournal, start, end));
dns_db_attach(zone->db, &db);
dns_db_currentversion(db, &oldver);
CHECK(dns_db_newversion(db, &newver));
for (result = dns_journal_first_rr(rjournal);
result == ISC_R_SUCCESS;
result = dns_journal_next_rr(rjournal)) {
dns_name_t *name = NULL;
isc_uint32_t ttl;
dns_rdata_t *rdata = NULL;
dns_journal_current_rr(rjournal, &name, &ttl, &rdata);
if (rdata->type == dns_rdatatype_soa) {
n_soa++;
if (n_soa == 2) {
/*
* Save the lastest raw SOA record.
*/
if (soatuple != NULL)
dns_difftuple_free(&soatuple);
CHECK(dns_difftuple_create(diff.mctx,
DNS_DIFFOP_ADD,
name, ttl, rdata,
&soatuple));
}
if (n_soa == 3)
n_soa = 1;
CHECK(dns_journal_iter_init(journal, start, end));
for (result = dns_journal_first_rr(journal);
result == ISC_R_SUCCESS;
result = dns_journal_next_rr(journal))
{
dns_name_t *name = NULL;
isc_uint32_t ttl;
dns_rdata_t *rdata = NULL;
dns_journal_current_rr(journal, &name, &ttl, &rdata);
if (rdata->type == dns_rdatatype_soa) {
n_soa++;
if (n_soa == 2) {
/*
* Save the latest raw SOA record.
*/
if (*soatuplep != NULL)
dns_difftuple_free(soatuplep);
CHECK(dns_difftuple_create(diff->mctx,
DNS_DIFFOP_ADD,
name, ttl, rdata,
soatuplep));
}
if (n_soa == 3)
n_soa = 1;
continue;
}
/* Sanity. */
/* Sanity. */
if (n_soa == 0) {
dns_zone_log(zone->raw, ISC_LOG_ERROR,
"corrupt journal file: '%s'\n",
zone->raw->journal);
goto failure;
return (ISC_R_FAILURE);
}
if (zone->privatetype != 0 &&
@@ -12201,18 +12247,149 @@ receive_secure_serial(isc_task_t *task, isc_event_t *event) {
op = (n_soa == 1) ? DNS_DIFFOP_DEL : DNS_DIFFOP_ADD;
CHECK(dns_difftuple_create(diff.mctx, op, name, ttl, rdata,
CHECK(dns_difftuple_create(diff->mctx, op, name, ttl, rdata,
&tuple));
dns_diff_appendminimal(&diff, &tuple);
dns_diff_appendminimal(diff, &tuple);
}
if (result == ISC_R_NOMORE)
result = ISC_R_SUCCESS;
failure:
return(result);
}
static isc_result_t
sync_secure_db(dns_zone_t *seczone, dns_db_t *secdb,
dns_dbversion_t *secver, dns_diff_t *diff)
{
isc_result_t result;
dns_db_t *rawdb = NULL;
dns_dbversion_t *rawver = NULL;
dns_difftuple_t *tuple = NULL, *next;
REQUIRE(DNS_ZONE_VALID(seczone));
REQUIRE(inline_secure(seczone));
if (!seczone->sourceserialset)
return (DNS_R_UNCHANGED);
dns_db_attach(seczone->raw->db, &rawdb);
dns_db_currentversion(rawdb, &rawver);
result = dns_db_diffx(diff, rawdb, rawver, secdb, secver, NULL);
dns_db_closeversion(rawdb, &rawver, ISC_FALSE);
dns_db_detach(&rawdb);
if (result != ISC_R_SUCCESS)
return (result);
for (tuple = ISC_LIST_HEAD(diff->tuples);
tuple != NULL;
tuple = next)
{
next = ISC_LIST_NEXT(tuple, link);
if (tuple->rdata.type == dns_rdatatype_nsec ||
tuple->rdata.type == dns_rdatatype_rrsig ||
tuple->rdata.type == dns_rdatatype_dnskey ||
tuple->rdata.type == dns_rdatatype_nsec3 ||
tuple->rdata.type == dns_rdatatype_soa ||
tuple->rdata.type == dns_rdatatype_nsec3param)
{
ISC_LIST_UNLINK(diff->tuples, tuple, link);
dns_difftuple_free(&tuple);
}
}
if (ISC_LIST_EMPTY(diff->tuples))
return (DNS_R_UNCHANGED);
return (ISC_R_SUCCESS);
}
static void
receive_secure_serial(isc_task_t *task, isc_event_t *event) {
isc_result_t result;
dns_journal_t *rjournal = NULL;
isc_uint32_t start, end;
dns_zone_t *zone;
dns_db_t *db = NULL;
dns_dbnode_t *node = NULL;
dns_dbversion_t *newver = NULL, *oldver = NULL;
dns_diff_t diff;
dns_difftuple_t *tuple = NULL, *soatuple = NULL;
dns_update_log_t log = { update_log_cb, NULL };
isc_time_t timenow;
zone = event->ev_arg;
end = ((struct secure_event *)event)->serial;
isc_event_free(&event);
REQUIRE(inline_secure(zone));
dns_diff_init(zone->mctx, &diff);
UNUSED(task);
/*
* We first attempt to sync the raw zone to the secure zone
* by using the raw zone's journal, applying all the deltas
* from the latest source-serial of the secure zone up to
* the current serial number of the raw zone.
*
* If that fails, then we'll fall back to a direct comparison
* between raw and secure zones.
*/
result = dns_journal_open(zone->raw->mctx, zone->raw->journal,
DNS_JOURNAL_WRITE, &rjournal);
if (result != ISC_R_SUCCESS)
goto failure;
else {
dns_journal_t *sjournal = NULL;
result = dns_journal_open(zone->raw->mctx, zone->journal,
DNS_JOURNAL_READ, &sjournal);
if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND)
goto failure;
if (!dns_journal_get_sourceserial(rjournal, &start)) {
start = dns_journal_first_serial(rjournal);
dns_journal_set_sourceserial(rjournal, start);
}
if (sjournal != NULL) {
isc_uint32_t serial;
/*
* We read the secure journal first, if that exists
* use its value provided it is greater that from the
* raw journal.
*/
if (dns_journal_get_sourceserial(sjournal, &serial)) {
if (isc_serial_gt(serial, start))
start = serial;
}
dns_journal_destroy(&sjournal);
}
}
dns_db_attach(zone->db, &db);
dns_db_currentversion(db, &oldver);
CHECK(dns_db_newversion(db, &newver));
/*
* Try to apply diffs from the raw zone's journal to the secure
* zone. If that fails, we recover by syncing up the databases
* directly.
*/
result = sync_secure_journal(zone, rjournal, start, end,
&soatuple, &diff);
if (result == DNS_R_UNCHANGED)
goto failure;
else if (result != ISC_R_SUCCESS) {
CHECK(sync_secure_db(zone, db, oldver, &diff));
}
if (result == ISC_R_NOMORE)
result = ISC_R_SUCCESS;
CHECK(result);
CHECK(dns_diff_apply(&diff, db, newver));
if (soatuple != NULL) {
isc_uint32_t desired;
isc_uint32_t oldserial, newserial, desired;
CHECK(dns_db_createsoatuple(db, oldver, diff.mctx,
DNS_DIFFOP_DEL, &tuple));
@@ -12243,8 +12420,8 @@ receive_secure_serial(isc_task_t *task, isc_event_t *event) {
LOCK_ZONE(zone);
DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDNOTIFY);
zone->rawserial = start;
zone->rawserialset = ISC_TRUE;
zone->sourceserial = end;
zone->sourceserialset = ISC_TRUE;
zone_needdump(zone, DNS_DUMP_DELAY);
TIME_NOW(&timenow);
@@ -12256,6 +12433,9 @@ receive_secure_serial(isc_task_t *task, isc_event_t *event) {
dns_db_closeversion(db, &newver, ISC_TRUE);
failure:
if (result != ISC_R_SUCCESS)
dns_zone_log(zone, ISC_LOG_ERROR, "receive_secure_serial: %s",
dns_result_totext(result));
if (tuple != NULL)
dns_difftuple_free(&tuple);
if (soatuple != NULL)
@@ -12271,33 +12451,33 @@ receive_secure_serial(isc_task_t *task, isc_event_t *event) {
}
if (rjournal != NULL)
dns_journal_destroy(&rjournal);
if (sjournal != NULL)
dns_journal_destroy(&sjournal);
dns_diff_clear(&diff);
isc_event_free(&event);
dns_zone_idetach(&zone);
}
static isc_result_t
zone_send_secureserial(dns_zone_t *zone, isc_uint32_t serial) {
zone_send_secureserial(dns_zone_t *zone, isc_boolean_t locked,
isc_uint32_t serial)
{
isc_event_t *e;
dns_zone_t *dummy = NULL;
e = isc_event_allocate(zone->secure->mctx, zone,
DNS_EVENT_ZONESECURESERIAL,
receive_secure_serial, zone->secure,
sizeof(struct secure_serial));
sizeof(struct secure_event));
if (e == NULL)
return (ISC_R_NOMEMORY);
((struct secure_serial *)e)->serial = serial;
((struct secure_event *)e)->serial = serial;
if (locked)
zone_iattach(zone->secure, &dummy);
else
dns_zone_iattach(zone->secure, &dummy);
isc_task_send(zone->secure->task, &e);
DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_SENDSECURE);
return (ISC_R_SUCCESS);
}
struct secure_db {
isc_event_t e;
dns_db_t *db;
};
static void
receive_secure_db(isc_task_t *task, isc_event_t *event) {
isc_result_t result;
@@ -12315,7 +12495,11 @@ receive_secure_db(isc_task_t *task, isc_event_t *event) {
UNUSED(task);
zone = event->ev_arg;
rawdb = ((struct secure_db *)event)->db;
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);
@@ -12400,22 +12584,27 @@ receive_secure_db(isc_task_t *task, isc_event_t *event) {
dns_db_detach(&rawdb);
if (dbiterator != NULL)
dns_dbiterator_destroy(&dbiterator);
isc_event_free(&event);
dns_zone_idetach(&zone);
}
static isc_result_t
zone_send_securedb(dns_zone_t *zone, dns_db_t *db) {
zone_send_securedb(dns_zone_t *zone, isc_boolean_t locked, dns_db_t *db) {
isc_event_t *e;
dns_db_t *dummy = NULL;
dns_zone_t *secure = NULL;
e = isc_event_allocate(zone->secure->mctx, zone,
DNS_EVENT_ZONESECUREDB,
receive_secure_db, zone->secure,
sizeof(struct secure_db));
sizeof(struct secure_event));
if (e == NULL)
return (ISC_R_NOMEMORY);
dns_db_attach(db, &dummy);
((struct secure_db *)e)->db = dummy;
((struct secure_event *)e)->db = dummy;
if (locked)
zone_iattach(zone->secure, &secure);
else
dns_zone_iattach(zone->secure, &secure);
isc_task_send(zone->secure->task, &e);
DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_SENDSECURE);
@@ -12483,7 +12672,8 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) {
*/
if (zone->db != NULL && zone->journal != NULL &&
DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IXFRFROMDIFFS) &&
!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER)) {
!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER))
{
isc_uint32_t serial, oldserial;
dns_zone_log(zone, ISC_LOG_DEBUG(3), "generating diffs");
@@ -12542,8 +12732,8 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) {
break;
}
}
if (zone->type == dns_zone_master && zone->secure != NULL)
zone_send_secureserial(zone, serial);
if (zone->type == dns_zone_master && inline_raw(zone))
zone_send_secureserial(zone, ISC_FALSE, serial);
} else {
if (dump && zone->masterfile != NULL) {
/*
@@ -12594,8 +12784,9 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) {
zone->journal, strbuf);
}
}
if (zone->secure != NULL)
zone_send_securedb(zone, db);
if (inline_raw(zone))
zone_send_securedb(zone, ISC_FALSE, db);
}
dns_db_closeversion(db, &ver, ISC_FALSE);
@@ -12747,8 +12938,8 @@ zone_xfrdone(dns_zone_t *zone, isc_result_t result) {
dns_zone_log(zone, ISC_LOG_INFO,
"transferred serial %u%s",
serial, buf);
if (zone->secure != NULL)
zone_send_secureserial(zone, serial);
if (inline_raw(zone))
zone_send_secureserial(zone, ISC_FALSE, serial);
}
/*