Compare commits

...

4 Commits

Author SHA1 Message Date
Evan Hunt
f56d22ca37 exercise named-makejournal with multiple transactions
the journal system test now checks that named-makejournal is
able to create journal files with multiple transactions.
2025-02-14 21:05:51 -08:00
Evan Hunt
a83d1e762e load the journal file if it already exists
apply the existing journal file, if any, to the old version of the
database before diffing it against the new version. then, append
the diff to the end of the journal. this allows easy creation of
a journal file with multiple deltas, by running named-makejournal
successively.
2025-02-14 21:05:51 -08:00
Evan Hunt
52d7b09218 improvements to named-makejournal
- write the journal to a default location (file1.jnl) if it was not
  specified on the commandline.
- exit with a clear error message if file2's SOA serial number is
  not changed from file1.
2025-02-14 21:05:51 -08:00
Evan Hunt
976e23d773 move makejournal to bin/tools
move the "makejournal" tool from bin/tests/system to bin/tools
and rename it to "named-makejournal". add a man page. update
tests to use the new file location.
2025-02-14 21:05:51 -08:00
17 changed files with 407 additions and 128 deletions

View File

@@ -25,7 +25,6 @@ if HAVE_PYTEST
noinst_PROGRAMS = \
feature-test \
makejournal \
pipelined/pipequeries \
rndc/gencheck
@@ -39,14 +38,6 @@ feature_test_LDADD = \
$(LIBDNS_LIBS) \
$(OPENSSL_LIBS)
makejournal_CPPFLAGS = \
$(AM_CPPFLAGS) \
$(LIBDNS_CFLAGS)
makejournal_LDADD = \
$(LDADD) \
$(LIBDNS_LIBS)
pipelined_pipequeries_CPPFLAGS = \
$(AM_CPPFLAGS) \
$(LIBDNS_CFLAGS)

View File

@@ -32,6 +32,7 @@ BASIC_VARS = {
"KEYFRLAB": f"{AC_VARS['TOP_BUILDDIR']}/bin/dnssec/dnssec-keyfromlabel",
"KEYGEN": f"{AC_VARS['TOP_BUILDDIR']}/bin/dnssec/dnssec-keygen",
"KSR": f"{AC_VARS['TOP_BUILDDIR']}/bin/dnssec/dnssec-ksr",
"MAKEJOURNAL": f"{AC_VARS['TOP_BUILDDIR']}/bin/tools/named-makejournal",
"MDIG": f"{AC_VARS['TOP_BUILDDIR']}/bin/tools/mdig",
"NAMED": f"{AC_VARS['TOP_BUILDDIR']}/bin/named/named",
"NSEC3HASH": f"{AC_VARS['TOP_BUILDDIR']}/bin/tools/nsec3hash",
@@ -49,7 +50,6 @@ BASIC_VARS = {
"WIRETEST": f"{AC_VARS['TOP_BUILDDIR']}/bin/tests/wire_test",
"BIGKEY": f"{AC_VARS['TOP_BUILDDIR']}/bin/tests/system/rsabigexponent/bigkey",
"GENCHECK": f"{AC_VARS['TOP_BUILDDIR']}/bin/tests/system/rndc/gencheck",
"MAKEJOURNAL": f"{AC_VARS['TOP_BUILDDIR']}/bin/tests/system/makejournal",
"PIPEQUERIES": f"{AC_VARS['TOP_BUILDDIR']}/bin/tests/system/pipelined/pipequeries",
"TMPDIR": os.getenv("TMPDIR", "/tmp"),
"KRB5_CONFIG": "/dev/null", # we don't want a KRB5_CONFIG setting breaking the tests

View File

@@ -251,5 +251,22 @@ ret=0
grep 'managed-keys-zone: journal rollforward completed successfully: up to date' ns2/named.run >/dev/null 2>&1 || ret=1
[ $ret -eq 0 ] || echo_i "failed"
n=$((n + 1))
echo_i "check named-makejournal with multiple transactions ($n)"
ret=0
# fail if there's no delta to journal
$MAKEJOURNAL example zones/example.db zones/example.db >makejournal.out.test$n 2>&1 && ret=1
grep -q "Error: SOA serial (1) unchanged between files" makejournal.out.test$n || ret=1
# add first delta to journal
$MAKEJOURNAL example zones/example.db zones/example2.db >/dev/null 2>&1 || ret=1
# warn if the new transaction doesn't update the serial
$MAKEJOURNAL example zones/example.db zones/example2.db >makejournal.out.test$n 2>&1 || ret=1
grep -q "Journal zones/example.db.jnl already has serial 2" makejournal.out.test$n || ret=1
# now add a second delta and count the transactions
$MAKEJOURNAL example zones/example.db zones/example3.db >/dev/null 2>&1 || ret=1
$JOURNALPRINT zones/example.db.jnl >journalprint.out.test$n
soas=$(awk '$5 == "SOA" {print}' journalprint.out.test$n | wc -l)
[ "$soas" -eq 4 ] || ret=1
[ $ret -eq 0 ] || echo_i "failed"
echo_i "exit status: $status"
[ $status -eq 0 ] || exit 1

View File

@@ -15,11 +15,13 @@ pytestmark = pytest.mark.extra_artifacts(
[
"dig.out.*",
"journalprint.out.*",
"makejournal.out.*",
"tmp.jnl",
"ns*/*.db",
"ns*/*.jnl",
"ns1/managed-keys.bind",
"ns2/managed-keys.bind",
"zones/example.db.jnl",
]
)

View File

@@ -0,0 +1,23 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; SPDX-License-Identifier: MPL-2.0
;
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, you can obtain one at https://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
$ORIGIN example.
$TTL 300 ; 5 minutes
@ IN SOA ns1.example. hostmaster.example. (
1 ; serial
2000 ; refresh (33 minutes 20 seconds)
2000 ; retry (33 minutes 20 seconds)
1814400 ; expire (3 weeks)
3600 ; minimum (1 hour)
)
NS ns1.example.
ns1 A 10.53.0.1
a A 192.0.1.1
b A 192.0.1.2

View File

@@ -0,0 +1,24 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; SPDX-License-Identifier: MPL-2.0
;
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, you can obtain one at https://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
$ORIGIN example.
$TTL 300 ; 5 minutes
@ IN SOA ns1.example. hostmaster.example. (
2 ; serial
2000 ; refresh (33 minutes 20 seconds)
2000 ; retry (33 minutes 20 seconds)
1814400 ; expire (3 weeks)
3600 ; minimum (1 hour)
)
NS ns1.example.
ns1 A 10.53.0.1
a A 192.0.1.1
b A 192.0.1.2
c A 192.0.1.3

View File

@@ -0,0 +1,23 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; SPDX-License-Identifier: MPL-2.0
;
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, you can obtain one at https://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
$ORIGIN example.
$TTL 300 ; 5 minutes
@ IN SOA ns1.example. hostmaster.example. (
3 ; serial
2000 ; refresh (33 minutes 20 seconds)
2000 ; retry (33 minutes 20 seconds)
1814400 ; expire (3 weeks)
3600 ; minimum (1 hour)
)
NS ns1.example.
ns1 A 10.53.0.1
b A 192.0.1.2
c A 192.0.1.3

View File

@@ -1,116 +0,0 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
/*! \file */
#include <stdbool.h>
#include <stdlib.h>
#include <isc/hash.h>
#include <isc/log.h>
#include <isc/mem.h>
#include <isc/result.h>
#include <isc/util.h>
#include <dns/db.h>
#include <dns/fixedname.h>
#include <dns/journal.h>
#include <dns/name.h>
#include <dns/types.h>
isc_mem_t *mctx = NULL;
static isc_result_t
loadzone(dns_db_t **db, const char *origin, const char *filename) {
isc_result_t result;
dns_fixedname_t fixed;
dns_name_t *name;
name = dns_fixedname_initname(&fixed);
result = dns_name_fromstring(name, origin, dns_rootname, 0, NULL);
if (result != ISC_R_SUCCESS) {
return result;
}
result = dns_db_create(mctx, ZONEDB_DEFAULT, name, dns_dbtype_zone,
dns_rdataclass_in, 0, NULL, db);
if (result != ISC_R_SUCCESS) {
return result;
}
result = dns_db_load(*db, filename, dns_masterformat_text, 0);
if (result == DNS_R_SEENINCLUDE) {
result = ISC_R_SUCCESS;
}
return result;
}
int
main(int argc, char **argv) {
isc_result_t result;
char *origin, *file1, *file2, *journal;
dns_db_t *olddb = NULL, *newdb = NULL;
isc_logconfig_t *logconfig = NULL;
if (argc != 5) {
printf("usage: %s origin file1 file2 journal\n", argv[0]);
return 1;
}
origin = argv[1];
file1 = argv[2];
file2 = argv[3];
journal = argv[4];
isc_mem_debugging |= ISC_MEM_DEBUGRECORD;
isc_mem_create(&mctx);
logconfig = isc_logconfig_get();
isc_log_createandusechannel(
logconfig, "default_stderr", ISC_LOG_TOFILEDESC,
ISC_LOG_DYNAMIC, ISC_LOGDESTINATION_STDERR, 0,
ISC_LOGCATEGORY_DEFAULT, ISC_LOGMODULE_DEFAULT);
result = loadzone(&olddb, origin, file1);
if (result != ISC_R_SUCCESS) {
fprintf(stderr, "Couldn't load %s: ", file1);
goto cleanup;
}
result = loadzone(&newdb, origin, file2);
if (result != ISC_R_SUCCESS) {
fprintf(stderr, "Couldn't load %s: ", file2);
goto cleanup;
}
result = dns_db_diff(mctx, newdb, NULL, olddb, NULL, journal);
cleanup:
if (result != ISC_R_SUCCESS) {
fprintf(stderr, "%s\n", isc_result_totext(result));
}
if (newdb != NULL) {
dns_db_detach(&newdb);
}
if (olddb != NULL) {
dns_db_detach(&olddb);
}
if (mctx != NULL) {
isc_mem_destroy(&mctx);
}
return result != ISC_R_SUCCESS ? 1 : 0;
}

View File

@@ -10,6 +10,7 @@ LDADD += \
bin_PROGRAMS = \
arpaname \
named-makejournal \
mdig \
named-journalprint \
named-rrchecker \

View File

@@ -63,4 +63,4 @@ bug in that release.) Note that these options *must not* be used while
See Also
~~~~~~~~
:iscman:`named(8) <named>`, :iscman:`nsupdate(1) <nsupdate>`, BIND 9 Administrator Reference Manual.
:iscman:`named(8) <named>`, :iscman:`nsupdate(1) <nsupdate>`, :iscman:`named-makejournal(1) <named-makejournal>`, BIND 9 Administrator Reference Manual.

View File

@@ -0,0 +1,225 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
/*! \file */
#include <stdbool.h>
#include <stdlib.h>
#include <isc/commandline.h>
#include <isc/dir.h>
#include <isc/hash.h>
#include <isc/log.h>
#include <isc/mem.h>
#include <isc/result.h>
#include <isc/util.h>
#include <dns/db.h>
#include <dns/fixedname.h>
#include <dns/journal.h>
#include <dns/name.h>
#include <dns/types.h>
isc_mem_t *mctx = NULL;
const char *progname = NULL;
char jbuf[PATH_MAX];
static void
usage(int ret) {
fprintf(stderr, "usage: %s [-hm] origin oldfile newfile [journal]\n",
progname);
exit(ret);
}
static isc_result_t
loadzone(dns_db_t **db, const char *origin, const char *filename) {
isc_result_t result;
dns_fixedname_t fixed;
dns_name_t *name = NULL;
name = dns_fixedname_initname(&fixed);
result = dns_name_fromstring(name, origin, dns_rootname, 0, NULL);
if (result != ISC_R_SUCCESS) {
return result;
}
result = dns_db_create(mctx, ZONEDB_DEFAULT, name, dns_dbtype_zone,
dns_rdataclass_in, 0, NULL, db);
if (result != ISC_R_SUCCESS) {
return result;
}
result = dns_db_load(*db, filename, dns_masterformat_text, 0);
if (result == DNS_R_SEENINCLUDE) {
result = ISC_R_SUCCESS;
}
return result;
}
static isc_result_t
loadjournal(dns_db_t *db, const char *file) {
dns_journal_t *jnl = NULL;
isc_result_t result;
result = dns_journal_open(mctx, file, DNS_JOURNAL_READ, &jnl);
if (result == ISC_R_NOTFOUND) {
return ISC_R_SUCCESS;
} else if (result != ISC_R_SUCCESS) {
fprintf(stderr, "Error: unable to open journal %s: %s\n", file,
isc_result_totext(result));
return result;
}
if (dns_journal_empty(jnl)) {
dns_journal_destroy(&jnl);
return ISC_R_SUCCESS;
}
result = dns_journal_rollforward(jnl, db, 0);
switch (result) {
case ISC_R_SUCCESS:
break;
case DNS_R_UPTODATE:
result = ISC_R_SUCCESS;
break;
case ISC_R_NOTFOUND:
case ISC_R_RANGE:
fprintf(stderr, "Error: journal %s out of sync with zone",
file);
break;
default:
fprintf(stderr, "Error: journal %s: %s\n", file,
isc_result_totext(result));
}
dns_journal_destroy(&jnl);
return result;
}
int
main(int argc, char **argv) {
isc_result_t result;
const char *origin = NULL;
const char *file1 = NULL, *file2 = NULL;
const char *journal = NULL;
dns_db_t *olddb = NULL, *newdb = NULL;
isc_logconfig_t *logconfig = NULL;
uint32_t s1, s2, s3;
int ch;
progname = argv[0];
while ((ch = isc_commandline_parse(argc, argv, "hm")) != -1) {
switch (ch) {
case 'h':
usage(0);
break;
case 'm':
isc_mem_debugging |= ISC_MEM_DEBUGRECORD;
break;
default:
usage(1);
}
}
argc -= isc_commandline_index;
argv += isc_commandline_index;
if (argc < 3 || argc > 4) {
usage(1);
}
origin = argv[0];
file1 = argv[1];
file2 = argv[2];
if (argc == 4) {
journal = argv[3];
} else {
snprintf(jbuf, sizeof(jbuf), "%s.jnl", file1);
journal = (const char *)jbuf;
}
isc_mem_create(&mctx);
logconfig = isc_logconfig_get();
isc_log_createandusechannel(
logconfig, "default_stderr", ISC_LOG_TOFILEDESC,
ISC_LOG_DYNAMIC, ISC_LOGDESTINATION_STDERR, 0,
ISC_LOGCATEGORY_DEFAULT, ISC_LOGMODULE_DEFAULT);
result = loadzone(&olddb, origin, file1);
if (result != ISC_R_SUCCESS) {
fprintf(stderr, "Unable to load %s: %s\n", file1,
isc_result_totext(result));
goto cleanup;
}
result = loadzone(&newdb, origin, file2);
if (result != ISC_R_SUCCESS) {
fprintf(stderr, "Unable to load %s: %s\n", file1,
isc_result_totext(result));
goto cleanup;
}
result = dns_db_getsoaserial(olddb, NULL, &s1);
if (result != ISC_R_SUCCESS) {
fprintf(stderr, "Error: %s: SOA lookup failed\n", file1);
goto cleanup;
}
result = loadjournal(olddb, journal);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
result = dns_db_getsoaserial(olddb, NULL, &s2);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
result = dns_db_getsoaserial(newdb, NULL, &s3);
if (result != ISC_R_SUCCESS) {
fprintf(stderr, "Error: %s: SOA lookup failed\n", file2);
goto cleanup;
}
if (s1 == s3) {
fprintf(stderr,
"Error: SOA serial (%u) unchanged between files\n", s1);
result = ISC_R_FAILURE;
goto cleanup;
} else if (s2 == s3) {
fprintf(stderr, "Journal %s already has serial %u\n", journal,
s3);
goto cleanup;
}
result = dns_db_diff(mctx, newdb, NULL, olddb, NULL, journal);
if (result != ISC_R_SUCCESS) {
fprintf(stderr, "Comparison failed: %s\n",
isc_result_totext(result));
}
cleanup:
if (newdb != NULL) {
dns_db_detach(&newdb);
}
if (olddb != NULL) {
dns_db_detach(&olddb);
}
if (mctx != NULL) {
isc_mem_destroy(&mctx);
}
return result != ISC_R_SUCCESS ? 1 : 0;
}

View File

@@ -0,0 +1,64 @@
.. Copyright (C) Internet Systems Consortium, Inc. ("ISC")
..
.. SPDX-License-Identifier: MPL-2.0
..
.. This Source Code Form is subject to the terms of the Mozilla Public
.. License, v. 2.0. If a copy of the MPL was not distributed with this
.. file, you can obtain one at https://mozilla.org/MPL/2.0/.
..
.. See the COPYRIGHT file distributed with this work for additional
.. information regarding copyright ownership.
.. highlight: console
.. iscman:: named-makejournal
.. program:: named-makejournal
.. _man_named-makejournal:
named-makejournal - create a journal from zone files
----------------------------------------------------
Synopsis
~~~~~~~~
:program:`named-makejournal` [-hm] {origin} {oldfile} {newfile} [journal]
Description
~~~~~~~~~~~
:program:`named-makejournal` scans the contents of two zone files for
the domain specified by ``origin``, compares them, and writes the
differences into a journal file. The resulting journal file could
then be used by :iscman:`named` to load the zone and provide incremental
zone transfers.
Both ``oldfile`` and ``newfile`` must be successfully loadable as zone
databases, and ``newfile`` must have a higher SOA serial number than
``oldfile``.
If the optional argument ``journal`` is not specified, then the journal
file name will be formed by appending the extension ``.jnl`` to the
zone file name specified as ``oldfile``.
If the journal file already exists, then it will be applied to ``oldfile``
immediately after loading. The difference between the resulting zone and
the one in ``newfile`` will then be appended onto the end of the journal.
This allows creation of journal files with multiple transactions, by
running ``named-makejournal`` multiple times, updating ``newfile`` each
time.
Options
~~~~~~~
.. option:: -h
Print a usage summary.
.. option:: -m
Enables memory usage debugging.
See Also
~~~~~~~~
:iscman:`named(8) <named>`, :iscman:`named-journalprint(1) <named-journalprint>`, BIND 9 Administrator Reference Manual.

View File

@@ -36,6 +36,7 @@ Manual Pages
.. include:: ../../bin/check/named-checkzone.rst
.. include:: ../../bin/check/named-compilezone.rst
.. include:: ../../bin/tools/named-journalprint.rst
.. include:: ../../bin/tools/named-makejournal.rst
.. include:: ../../bin/tools/named-nzd2nzf.rst
.. include:: ../../bin/tools/named-rrchecker.rst
.. include:: ../../bin/named/named.conf.rst

View File

@@ -206,7 +206,7 @@ libraries.
* `bind9/bin/confgen`: `rndc-confgen`, `ddns-confgen`, and
`tsig-keygen` (BIND 9.9+)
* `bind9/bin/tools`: assorted useful tools: `named-journalprint`,
`nsec3hash`, etc
`named-makejournal`, `nsec3hash`, etc
* `bind9/lib`: libraries
* `bind9/lib/isc`: implements basic functionality such as threads,
tasks, timers, sockets, memory manager, buffers, and basic data types.

View File

@@ -26,6 +26,7 @@ MANPAGES_RST = \
named-checkzone.rst \
named-compilezone.rst \
named-journalprint.rst \
named-makejournal.rst \
named-nzd2nzf.rst \
named-rrchecker.rst \
named.conf.rst \
@@ -68,6 +69,7 @@ MANPAGES_RST = \
../../bin/tools/dnstap-read.rst \
../../bin/tools/mdig.rst \
../../bin/tools/named-journalprint.rst \
../../bin/tools/named-makejournal.rst \
../../bin/tools/named-nzd2nzf.rst \
../../bin/tools/named-rrchecker.rst \
../../bin/tools/nsec3hash.rst
@@ -100,6 +102,7 @@ man_MANS = \
named-checkzone.1 \
named-compilezone.1 \
named-journalprint.1 \
named-makejournal.1 \
named.8 \
nsec3hash.1 \
rndc-confgen.8 \

View File

@@ -174,6 +174,13 @@ man_pages = [
author,
1,
),
(
"named-makejournal",
"named-makejournal",
"create a journal from zone files",
author,
1,
),
(
"named-nzd2nzf",
"named-nzd2nzf",

View File

@@ -0,0 +1,14 @@
.. Copyright (C) Internet Systems Consortium, Inc. ("ISC")
..
.. SPDX-License-Identifier: MPL-2.0
..
.. This Source Code Form is subject to the terms of the Mozilla Public
.. License, v. 2.0. If a copy of the MPL was not distributed with this
.. file, you can obtain one at https://mozilla.org/MPL/2.0/.
..
.. See the COPYRIGHT file distributed with this work for additional
.. information regarding copyright ownership.
:orphan:
.. include:: ../../bin/tools/named-makejournal.rst