BIND 10 trac1781, updated. a318061e3c20ad5deeebe41884cbe3dcf9a3a413 [1781] Merge branch 'master' into trac1781 with fixing conflicts.
BIND 10 source code commits
bind10-changes at lists.isc.org
Tue Apr 17 00:23:55 UTC 2012
The branch, trac1781 has been updated
via a318061e3c20ad5deeebe41884cbe3dcf9a3a413 (commit)
via 149ac337e9a8e43896e84268a462463429061aed (commit)
via 93f11d2a96ce4dba9308889bdb9be6be4a765b27 (commit)
via a7dbb75a88c71513c2ff2d0c86eb98b1f287e6f4 (commit)
via 952cf4c1d92cf00179347abbc15fa37318c5ec90 (commit)
via 277af902ee91a90c1ef8ebce3895ecc27d8dec2d (commit)
via 56bd002f57d397ec4c1fffb40c499425e36b21de (commit)
via 4653281fb863709e2ab9ca26514fe9e31cd8444d (commit)
via 0f9b1d45d37223a5e1f7167a97c9760b52e744e9 (commit)
via d3fd5c7fa44e0f19a97d2dcb99ee937eaa80d704 (commit)
via ae46e78f9e1d4261bbf86a3dcaf7bd813851edf0 (commit)
via 0464833becda85dca7deae50a7f4adbf9589076f (commit)
via 2c8983c96edd2e98f285d35343a5e4958fb1971c (commit)
via c89bd8e38d3fcad506676876cc110c937cc3fbfe (commit)
via 22041b8ed4dd46d27981c3e645973de62c34a25e (commit)
via 66a9862c8ec60bd4c64f1535590ac16fae2fd088 (commit)
via 2fd8732e2b16ad5dffcbf12345e97a05b146c592 (commit)
via 5a3ba49ea9cdd4cde08d1855a0944f6899eaae8b (commit)
via efc43a67d27a14c468d3cf53df87ed3f808fd730 (commit)
via d833b85d17a2958890faa25927c1d1ed3443279c (commit)
via 3e27e1508a29251494a907a6b00258900a5200b2 (commit)
via 412304add5726cd16f91c010471fd895d65c2a6d (commit)
via a2da847353f3fd79feb1a4b902faebd74b31fa64 (commit)
via 8b8dbb612ba7f55ae49d113297a8e119c51f492d (commit)
via 837533a24607e825f2dc72f7fb45665c4e8aec99 (commit)
via c545fba97414013e52eda55f2d61ba23f9e076e9 (commit)
via 2e25759b8ff76ff81d75201bc4c8ef6eb243d144 (commit)
via 0a9dad718d84b7de43478df6804da1da25e5dab9 (commit)
via ff240f0bc7b13b7932054f435b7159f788eaf912 (commit)
via 7544617e812757e1d1f02ebf9d1c44e1fd01a4df (commit)
via c537d66e97d1a10a544baeba5e5490bd061f1590 (commit)
via cf96b2ad155c63f0ffceaf69b634e5f772d22770 (commit)
via 92c00e5601f7816113eab6be8a165cca0fe6956e (commit)
via 8cdf67b6ff82596aa51e56fd5eccbd75763e9011 (commit)
via 69bcd5348b07321645cbd749dc964d96bf654076 (commit)
via a83554ce6da992e5d060ceb12baa6948c6e4bf33 (commit)
via 9cc9ffd9f10433f85a6b056d7face686b5522a13 (commit)
via c3b46d0b46f88f759c7a4738040e6edaf6845d5b (commit)
via 034bc4e02eb482913c2e2c0892d5cf10e5525aae (commit)
via b303b434d956c7b5842fc0ca5c43f4aa69351a34 (commit)
via b7f87132783143fab9f8f6ecc0977fe220f2e58e (commit)
via 22aa6eec949ced4a40a599019a275c7e732cbb70 (commit)
via b23c36ef2e61cb4133f8c2708aa8cf85e4809d61 (commit)
via a17f42a08fa2d0fbd2de357d90dbbfeaaba32335 (commit)
via 0d2ebae0cc3b6119ae0cc2f7fa509a5792290ecf (commit)
via 325b81328b624d467c674a7bf74e73a271892d4a (commit)
via be50e95723a83adcb63e9622eaada199f3f17463 (commit)
via 31de885ba0409f54d9a1615eff5a4b03ed420393 (commit)
via 29264296474f103f8ece3e299171f835b81d9e9a (commit)
via 65e64487c28d3688d65ed625cdb1531ce5691095 (commit)
via 4108ca766cb9bce434bfbb786436b7c08adb87a4 (commit)
via de9ccf5df44c42526b2cd8e7f078d6073729c35a (commit)
via 7efc7ddb385ef56c5df5a23474a10900bbe36cf9 (commit)
via fcdc7a7b7fbf23338d1c7165e6f3a8ffe4a20459 (commit)
via e0bcbb981c3b22f3380fcee592ae7cc2dadd0c00 (commit)
via 57512ac60b298b3873b9ee74d46f4f56ab746494 (commit)
via 00a36e752802df3cc683023d256687bf222e256a (commit)
via 5dcf1dadd19d9b251fa6dbefefbc98f16fb62c66 (commit)
via 7c75154f52853de902bfd7c880b6e16fe3a79c0f (commit)
via d127560b02816a7ba12869d19ca51a30e695ff35 (commit)
via 793772f302013324ee4964e5b2c3439c0eed2221 (commit)
via be2b8d67e266598e0fba9e658042986c6833d220 (commit)
via 6cd82ad2a63dfc9bcd15dabdf650da242eaf924b (commit)
via 493f952e6937adf7045732a2f7e0c4a4313fc0a5 (commit)
via 9b6993002b4ba9019551e50613c8a2c6c7ff9fec (commit)
via d8b8e46b853f13d3e9ef2857f0fce424f1876ef5 (commit)
via 7116ee3c764180aad581e52b36dc67124b7d72f0 (commit)
via fb2317550507bb357cba2eee89c3a469f1a89803 (commit)
via 291d0cbfdc964c1d60542edbe9f442cc383657cd (commit)
via 52e971851f0c7ee8f45c511d810497e3c038dc71 (commit)
via 07274f662a772c856f0bf80213b246e689582409 (commit)
via c3bc4e02519d15e27b8e32291bda1a59ed08f42b (commit)
via b77375be27718eea1619f4e4fdb4899a29eea18e (commit)
via 05793b5a18793908b17190008382a27e133e5979 (commit)
via 186bacfc7ba324647f6689fd627c8d9d2d724c0c (commit)
via 058af3dc4b9f1e03d46c549f3ea848fb1a5c7960 (commit)
via c47c4c3541a5a9ed7a77f47610d8f14c29295969 (commit)
via 7130e28820b2e9e603f64546deebf12b410b897d (commit)
via a29df11575ac9b1aa036ab212b49f4706ba1e607 (commit)
via 56338ac70f174880ff1ca73bda0afe73dad2e7d4 (commit)
via 2d99288b3400b01e3eb1402717a182f5e828c7b7 (commit)
via 52ee8a28742a20415742651cbdf7982387050641 (commit)
via 33f9ea32c67a6e5e7df816432c98f3c9772b0b0f (commit)
via ed4c07d55c90e871d0c2b8ce571273cf83740e66 (commit)
via 283053c1a3dd96ff3811f25361f900dd7c9d97ef (commit)
via f173bdf07ec3f4d099176dcc6b7f878b218fb93a (commit)
via 7ce82914391a42fde56946b284f386bf0f3fe169 (commit)
via 5c9b7307a56c8b578be2b5b1ad73799b899a2e93 (commit)
via 77b918b70668c7755f3b7fb8335f5fc1f9f119a6 (commit)
via 0c0e8a5f4ddafbd7724545c08bc813c70f360faa (commit)
via 4eeff0e79de122645ffd3bf117a1486147fc9541 (commit)
via a98fc15799b0d8898ab3b5071ba55dd8935d45dc (commit)
via 94077743ff440dfbcfd4a723f3fd676acbfbefe4 (commit)
via b407617f16ae9d672ef0e7812a8eb9e18509b6e6 (commit)
via 76f364b152f174c57982f294f97274a212684121 (commit)
via d12134b3a9f135f9ae4317587eef31f45e6c0454 (commit)
via 55cecba6f3c43d725fc7c1614e5b47bc7729d5ec (commit)
via 7ef140c77fa2ddd4194ffdc344781a55232d68b3 (commit)
via 7a0dc75cee48aceeb218147331ddc81a05376358 (commit)
via 61446fd4004c89a7d568988776a0fc2c1b67046a (commit)
via 9ad569a0f568d9faf5f213f1403dce51cbcf08b8 (commit)
via 9b060a79e29c1691d1e84da5d6a656e99f2ec8a2 (commit)
via 501c5f296f27b565b6e2229e62f8f19754818abf (commit)
via 99adadb0496046011060ec22e6834dfede9f1ce3 (commit)
via e267a6928ace0651795f188f43a6a5a85c479d44 (commit)
via 08d13321640259a5036053852ff0c8731b54239c (commit)
via 7610a7bacea56b07ae06975ee771d010846addd2 (commit)
via 0996aa92a103e7af59bf1ae9c501f5feb2a5894c (commit)
via f1f0bc00441057e7050241415ee0367a09c35032 (commit)
via fb9b8cd9f1200dcd6d7146a45fdbfd2c7675be56 (commit)
via 16a1358aa2960039e192ac66d504150a55b374fe (commit)
via c02b9f4c1f0970cd50c5486f739dd750046ae97b (commit)
via aaf4fb3d70f5868ba9c6fa16c490abd7ed5035d3 (commit)
via 2397c86b17e71f1472a867dfa1fb4e7223cb811c (commit)
via 2fa92e23966279921c57bd1fa67ec79e56b328ed (commit)
via 9858d6dd9af2640765266d6b99056e93dc368277 (commit)
via 654f0cbd1850a78758194cf3dcc7d5a90d37e495 (commit)
via dcdd4e10f22f795754f91805b741988ef8a389c2 (commit)
via 68308bd95eb0a3d52f048790cd16611b5fdc7ee9 (commit)
via d5531c9856c5bb85f63d2e3168fc8b08c9700418 (commit)
via ea528f50fddfb83618aa338bdd4607791fd788ef (commit)
via b4466188150a50872bc3c426242bc7bba4c5f38d (commit)
via 97389bad9bf82cd32329407557aed4ea669401f4 (commit)
via 44d2850a0d3e96ad2b405aadb222a975c0462826 (commit)
via f48ddb14605e0ba0bf226ab074dc881e4a782a9b (commit)
via cf16578b3ecf2da1b38a724107dfaa802b03339c (commit)
via 8a33648413f84e7a7be65db8890d217d91f7c8f6 (commit)
via c31cfdf8449030f874406f4efad754ba7eb786e6 (commit)
via cd6faa250e082808a86d9ccb1f11ea07ab81a618 (commit)
via 5893305969aec78850e2462859b3bf4b7a157057 (commit)
via 419665026524f1a1b46efba377d41bd1f7f806d0 (commit)
via ad0ce258df14fa88a299ef37238d4c2527f273c8 (commit)
via fa4aa9c87c599a985bb19b78ae3f2d1d4ab9bb63 (commit)
via 94793e41d922cb10e35e0ff146b19c38ace415b1 (commit)
via 5f7f84779f66576555728e70ea75383945e0700a (commit)
via b0a028bf381e5467acca8d66f37e778d569e331d (commit)
via dfd2aeefef39f064183c84c23451637247e32399 (commit)
via 1c57fb2350d9b8440ae4cf50a94be7c61cc462b0 (commit)
via 8c55200c178773691ace2785240bfc65f4e351a9 (commit)
via ae40f56b7e12776479161c7d7a2d6616fae09850 (commit)
via dd8d9d4ab35db98d5269dd9c0728a5af6e748f1a (commit)
via 29e01b55a5acd72e651c2b2bd5cc63ffe8b21da8 (commit)
via c96ac865ac20c4e80b3206a00c15fa998cb85bfd (commit)
via 8e4c96040527d952da60338f7cf061f976780543 (commit)
via 0b1b0da6ffc60991c0ccad85695631dec02db4da (commit)
from 4a7381b8b8a03c010372c7a62192bec325a40a8a (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit a318061e3c20ad5deeebe41884cbe3dcf9a3a413
Merge: 4a7381b 149ac33
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Mon Apr 16 17:14:03 2012 -0700
[1781] Merge branch 'master' into trac1781 with fixing conflicts.
As part of conflict resolution, I've extended the unified textToRRset
so it takes an optional 'origin' parameter. It's necessary to convert
SOA RRs.
-----------------------------------------------------------------------
Summary of changes:
COPYING | 6 +
ChangeLog | 22 +
configure.ac | 1 -
doc/guide/bind10-guide.xml | 24 +-
ext/LICENSE_1_0.txt | 23 +
src/bin/auth/auth_config.cc | 38 ++-
src/bin/auth/tests/Makefile.am | 4 +
src/bin/auth/tests/config_unittest.cc | 42 ++-
src/bin/auth/tests/datasrc_util.cc | 77 +++
src/bin/auth/tests/datasrc_util.h | 61 +++
src/bin/bind10/bind10.xml | 16 -
src/bin/bind10/bob.spec | 4 -
src/bin/host/host.cc | 2 +-
src/bin/xfrin/tests/xfrin_test.py | 131 +++++
src/bin/xfrin/xfrin.py.in | 106 ++++-
src/bin/xfrin/xfrin_messages.mes | 5 +-
src/bin/xfrout/xfrout.py.in | 7 +
src/bin/xfrout/xfrout_messages.mes | 4 +
src/bin/zonemgr/zonemgr.py.in | 6 +
src/bin/zonemgr/zonemgr_messages.mes | 4 +
src/lib/cc/cc_messages.mes | 2 +-
src/lib/cc/session.cc | 2 +-
src/lib/cc/tests/Makefile.am | 7 +-
src/lib/datasrc/Makefile.am | 1 +
src/lib/datasrc/database.cc | 496 ++++++++++++++------
src/lib/datasrc/database.h | 155 ++++++-
src/lib/datasrc/datasrc_messages.mes | 39 ++-
src/lib/datasrc/factory.h | 2 +-
src/lib/datasrc/memory_datasrc.cc | 104 ++++-
src/lib/datasrc/memory_datasrc.h | 20 +
src/lib/datasrc/sqlite3_accessor_link.cc | 6 +-
src/lib/datasrc/tests/Makefile.am | 3 +-
src/lib/datasrc/tests/database_unittest.cc | 513 +++++++++++++++-----
src/lib/datasrc/tests/faked_nsec3.cc | 196 ++++++++
src/lib/datasrc/tests/faked_nsec3.h | 86 ++++
src/lib/datasrc/tests/memory_datasrc_unittest.cc | 199 ++++-----
src/lib/datasrc/tests/sqlite3_accessor_unittest.cc | 13 +-
src/lib/datasrc/tests/test_client.cc | 92 ++++
src/lib/datasrc/tests/test_client.h | 71 +++
.../datasrc/tests/zone_finder_context_unittest.cc | 27 +-
src/lib/dns/Makefile.am | 2 +-
src/lib/python/isc/config/cfgmgr.py | 2 +-
src/lib/python/isc/config/config_data.py | 11 +-
.../python/isc/config/tests/config_data_test.py | 20 +
src/lib/python/isc/datasrc/tests/datasrc_test.py | 6 +-
src/lib/testutils/dnsmessage_test.cc | 7 +-
src/lib/testutils/dnsmessage_test.h | 8 +-
src/lib/testutils/testdata/Makefile.am | 1 +
.../testdata/auth_test.sqlite3} | Bin 16384 -> 16384 bytes
.../testdata/auth_test.sqlite3.copied} | Bin 16384 -> 16384 bytes
.../tests => testutils}/testdata/rwtest.sqlite3 | Bin 16384 -> 16384 bytes
tests/lettuce/configurations/.gitignore | 1 +
.../configurations/bindctl_commands.config.orig | 34 ++
.../{example.org.config.orig => default.config} | 7 +-
.../lettuce/configurations/example.org.config.orig | 8 +-
.../configurations/example.org.inmem.config | 9 +-
tests/lettuce/configurations/example2.org.config | 8 +-
.../inmemory_over_sqlite3/secondary.conf | 32 ++
.../configurations/ixfr-out/testset1-config.db | 12 +-
.../multi_instance/multi_auth.config.orig | 2 +-
tests/lettuce/configurations/no_db_file.config | 14 +
.../lettuce/configurations/nsec3/nsec3_auth.config | 2 +-
.../resolver/resolver_basic.config.orig | 2 +-
.../configurations/xfrin/retransfer_master.conf | 10 +-
.../configurations/xfrin/retransfer_slave.conf | 10 +-
tests/lettuce/data/.gitignore | 1 +
.../data/ixfr-out/{zones.slite3 => zones.sqlite3} | Bin 468992 -> 468992 bytes
tests/lettuce/features/bindctl_commands.feature | 33 ++-
tests/lettuce/features/default.feature | 22 +
tests/lettuce/features/example.feature | 60 ++-
.../lettuce/features/inmemory_over_sqlite3.feature | 9 +
tests/lettuce/features/ixfr_out_bind10.feature | 18 +-
tests/lettuce/features/multi_instance.feature | 19 +-
tests/lettuce/features/nsec3_auth.feature | 360 ++++++++++----
tests/lettuce/features/queries.feature | 60 ++-
tests/lettuce/features/resolver_basic.feature | 12 +-
tests/lettuce/features/terrain/bind10_control.py | 29 +-
tests/lettuce/features/terrain/steps.py | 18 +-
tests/lettuce/features/terrain/terrain.py | 38 +-
tests/lettuce/features/xfrin_bind10.feature | 12 +
tests/lettuce/setup_intree_bind10.sh.in | 2 +-
tests/system/bindctl/tests.sh | 22 +-
tests/system/glue/nsx1/b10-config.db.in | 10 +
tests/system/ixfr/b10-config.db.in | 10 +
tests/system/start.pl | 7 +-
85 files changed, 2870 insertions(+), 697 deletions(-)
create mode 100644 ext/LICENSE_1_0.txt
create mode 100644 src/bin/auth/tests/datasrc_util.cc
create mode 100644 src/bin/auth/tests/datasrc_util.h
create mode 100644 src/lib/datasrc/tests/faked_nsec3.cc
create mode 100644 src/lib/datasrc/tests/faked_nsec3.h
create mode 100644 src/lib/datasrc/tests/test_client.cc
create mode 100644 src/lib/datasrc/tests/test_client.h
copy src/lib/{datasrc/tests/testdata/rwtest.sqlite3 => testutils/testdata/auth_test.sqlite3} (100%)
mode change 100644 => 100755
copy src/lib/{datasrc/tests/testdata/rwtest.sqlite3 => testutils/testdata/auth_test.sqlite3.copied} (96%)
mode change 100644 => 100755
rename src/lib/{datasrc/tests => testutils}/testdata/rwtest.sqlite3 (100%)
create mode 100644 tests/lettuce/configurations/bindctl_commands.config.orig
copy tests/lettuce/configurations/{example.org.config.orig => default.config} (64%)
create mode 100644 tests/lettuce/configurations/inmemory_over_sqlite3/secondary.conf
create mode 100644 tests/lettuce/data/.gitignore
rename tests/lettuce/data/ixfr-out/{zones.slite3 => zones.sqlite3} (100%)
create mode 100644 tests/lettuce/features/default.feature
create mode 100644 tests/lettuce/features/inmemory_over_sqlite3.feature
-----------------------------------------------------------------------
diff --git a/COPYING b/COPYING
index 557bdfb..63717af 100644
--- a/COPYING
+++ b/COPYING
@@ -11,3 +11,9 @@ 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.
+
+-----------------------------------------------------------------------------
+
+The ext/asio and ext/coroutine code is externally maintained and
+distributed under the Boost Software License, Version 1.0.
+(See accompanying file ext/LICENSE_1_0.txt.)
diff --git a/ChangeLog b/ChangeLog
index 808b92d..d1a0ad2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+425. [func]* muks
+ Don't autostart b10-auth, b10-xfrin, b10-xfrout and b10-zonemgr in
+ the default configuration.
+ (Trac #1818, git 31de885ba0409f54d9a1615eff5a4b03ed420393)
+
+424. [bug] jelte
+ Fixed a bug in bindctl where in some cases, configuration settings
+ in a named set could disappear, if a child element is modified.
+ (Trac #1491, git 00a36e752802df3cc683023d256687bf222e256a)
+
+423. [bug] jinmei
+ The database based zone iterator now correctly resets mixed TTLs
+ of the same RRset (when that happens) to the lowest one. The
+ previous implementation could miss lower ones if it appears in a
+ later part of the RRset.
+ (part of Trac #1791, git f1f0bc00441057e7050241415ee0367a09c35032)
+
+422. [bug] jinmei
+ The database based zone iterator now separates RRSIGs of the same
+ name and type but for different covered types.
+ (part of Trac #1791, git b4466188150a50872bc3c426242bc7bba4c5f38d)
+
421. [build] jinmei
Made sure BIND 10 can be built with clang++ 3.1. (It failed on
MacOS 10.7 using Xcode 4.3, but it's more likely to be a matter of
diff --git a/configure.ac b/configure.ac
index 324f045..a35da4c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1201,7 +1201,6 @@ AC_OUTPUT([doc/version.ent
tests/system/ixfr/in-3/setup.sh
tests/system/ixfr/in-4/setup.sh
], [
- chmod +x compatcheck/sqlite3-difftbl-check.py
chmod +x src/bin/cmdctl/run_b10-cmdctl.sh
chmod +x src/bin/xfrin/run_b10-xfrin.sh
chmod +x src/bin/xfrout/run_b10-xfrout.sh
diff --git a/doc/guide/bind10-guide.xml b/doc/guide/bind10-guide.xml
index dcf7cd8..1eaad90 100644
--- a/doc/guide/bind10-guide.xml
+++ b/doc/guide/bind10-guide.xml
@@ -771,12 +771,8 @@ as a dependency earlier -->
master process will also start up
<command>b10-cmdctl</command> for administration tools to
communicate with the system,
- <command>b10-auth</command> for authoritative DNS service,
- <command>b10-stats</command> for statistics collection,
- <command>b10-stats-httpd</command> for statistics reporting,
- <command>b10-xfrin</command> for inbound DNS zone transfers,
- <command>b10-xfrout</command> for outbound DNS zone transfers,
- and <command>b10-zonemgr</command> for secondary service.
+ <command>b10-stats</command> for statistics collection, and
+ <command>b10-stats-httpd</command> for statistics reporting.
</para>
<section id="start">
@@ -810,12 +806,7 @@ as a dependency earlier -->
The configuration is in the Boss/components section. Each element
represents one component, which is an abstraction of a process
(currently there's also one component which doesn't represent
- a process). If you didn't want to transfer out at all (your server
- is a slave only), you would just remove the corresponding component
- from the set, like this and the process would be stopped immediately
- (and not started on the next startup):
- <screen>> <userinput>config remove Boss/components b10-xfrout</userinput>
-> <userinput>config commit</userinput></screen>
+ a process).
</para>
<para>
@@ -1861,15 +1852,10 @@ what is XfroutClient xfr_client??
<para>
The main <command>bind10</command> process can be configured
to select to run either the authoritative or resolver or both.
- By default, it starts the authoritative service.
-<!-- TODO: later both -->
-
- You may change this using <command>bindctl</command>, for example:
+ By default, it doesn't start either one. You may change this using
+ <command>bindctl</command>, for example:
<screen>
-> <userinput>config remove Boss/components b10-xfrout</userinput>
-> <userinput>config remove Boss/components b10-xfrin</userinput>
-> <userinput>config remove Boss/components b10-auth</userinput>
> <userinput>config add Boss/components b10-resolver</userinput>
> <userinput>config set Boss/components/b10-resolver/special resolver</userinput>
> <userinput>config set Boss/components/b10-resolver/kind needed</userinput>
diff --git a/ext/LICENSE_1_0.txt b/ext/LICENSE_1_0.txt
new file mode 100644
index 0000000..36b7cd9
--- /dev/null
+++ b/ext/LICENSE_1_0.txt
@@ -0,0 +1,23 @@
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/src/bin/auth/auth_config.cc b/src/bin/auth/auth_config.cc
index 3b391d3..3a04dc8 100644
--- a/src/bin/auth/auth_config.cc
+++ b/src/bin/auth/auth_config.cc
@@ -12,14 +12,6 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#include <set>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include <boost/foreach.hpp>
-#include <boost/shared_ptr.hpp>
-
#include <dns/name.h>
#include <dns/rrclass.h>
@@ -27,6 +19,7 @@
#include <datasrc/memory_datasrc.h>
#include <datasrc/zonetable.h>
+#include <datasrc/factory.h>
#include <auth/auth_srv.h>
#include <auth/auth_config.h>
@@ -34,6 +27,15 @@
#include <server_common/portconfig.h>
+#include <boost/foreach.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/scoped_ptr.hpp>
+
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
using namespace std;
using namespace isc::dns;
using namespace isc::data;
@@ -165,10 +167,21 @@ MemoryDatasourceConfig::build(ConstElementPtr config_value) {
isc_throw(AuthConfigError, "Missing zone file for zone: "
<< origin_txt);
}
+
+ // We support the traditional text type and SQLite3 backend. For the
+ // latter we create a client for the underlying SQLite3 data source,
+ // and build the in-memory zone using an iterator of the underlying
+ // zone.
ConstElementPtr filetype = zone_config->get("filetype");
const string filetype_txt = filetype ? filetype->stringValue() :
"text";
- if (filetype_txt != "text") {
+ boost::scoped_ptr<DataSourceClientContainer> container;
+ if (filetype_txt == "sqlite3") {
+ container.reset(new DataSourceClientContainer(
+ "sqlite3",
+ Element::fromJSON("{\"database_file\": \"" +
+ file_txt + "\"}")));
+ } else if (filetype_txt != "text") {
isc_throw(AuthConfigError, "Invalid filetype for zone "
<< origin_txt << ": " << filetype_txt);
}
@@ -198,7 +211,12 @@ MemoryDatasourceConfig::build(ConstElementPtr config_value) {
* need the load method to be split into some kind of build and
* commit/abort parts.
*/
- zone_finder->load(file_txt);
+ if (filetype_txt == "text") {
+ zone_finder->load(file_txt);
+ } else {
+ zone_finder->load(*container->getInstance().getIterator(
+ Name(origin_txt)));
+ }
}
}
diff --git a/src/bin/auth/tests/Makefile.am b/src/bin/auth/tests/Makefile.am
index 521890e..b33c7af 100644
--- a/src/bin/auth/tests/Makefile.am
+++ b/src/bin/auth/tests/Makefile.am
@@ -12,6 +12,9 @@ AM_CXXFLAGS = $(B10_CXXFLAGS)
if USE_STATIC_LINK
AM_LDFLAGS = -static
+# Some test cases cannot work with static link. To selectively disable such
+# tests we signal it via a definition.
+AM_CPPFLAGS += -DUSE_STATIC_LINK=1
endif
CLEANFILES = *.gcno *.gcda
@@ -29,6 +32,7 @@ run_unittests_SOURCES += ../auth_config.h ../auth_config.cc
run_unittests_SOURCES += ../command.h ../command.cc
run_unittests_SOURCES += ../common.h ../common.cc
run_unittests_SOURCES += ../statistics.h ../statistics.cc
+run_unittests_SOURCES += datasrc_util.h datasrc_util.cc
run_unittests_SOURCES += auth_srv_unittest.cc
run_unittests_SOURCES += config_unittest.cc
run_unittests_SOURCES += config_syntax_unittest.cc
diff --git a/src/bin/auth/tests/config_unittest.cc b/src/bin/auth/tests/config_unittest.cc
index 7b4a225..d471a53 100644
--- a/src/bin/auth/tests/config_unittest.cc
+++ b/src/bin/auth/tests/config_unittest.cc
@@ -21,6 +21,7 @@
#include <cc/data.h>
+#include <datasrc/data_source.h>
#include <datasrc/memory_datasrc.h>
#include <xfr/xfrout_client.h>
@@ -29,14 +30,20 @@
#include <auth/auth_config.h>
#include <auth/common.h>
+#include "datasrc_util.h"
+
#include <testutils/mockups.h>
#include <testutils/portconfig.h>
#include <testutils/socket_request.h>
+#include <sstream>
+
+using namespace std;
using namespace isc::dns;
using namespace isc::data;
using namespace isc::datasrc;
using namespace isc::asiodns;
+using namespace isc::auth::unittest;
using namespace isc::testutils;
namespace {
@@ -201,17 +208,44 @@ TEST_F(MemoryDatasrcConfigTest, addOneZone) {
RRType::A())->code);
}
-TEST_F(MemoryDatasrcConfigTest, addOneWithFiletype) {
- // Until #1792 is completed, only "text" filetype is allowed.
+// This test uses dynamic load of a data source module, and won't work when
+// statically linked.
+TEST_F(MemoryDatasrcConfigTest,
+#ifdef USE_STATIC_LINK
+ DISABLED_addOneWithFiletypeSQLite3
+#else
+ addOneWithFiletypeSQLite3
+#endif
+ )
+{
+ const string test_db = TEST_DATA_BUILDDIR "/auth_test.sqlite3.copied";
+ stringstream ss("example.org. 3600 IN SOA . . 0 0 0 0 0\n");
+ createSQLite3DB(rrclass, Name("example.org"), test_db.c_str(), ss);
+
+ // In-memory with an SQLite3 data source as the backend.
+ parser->build(Element::fromJSON(
+ "[{\"type\": \"memory\","
+ " \"zones\": [{\"origin\": \"example.org\","
+ " \"file\": \""
+ + test_db + "\","
+ " \"filetype\": \"sqlite3\"}]}]"));
+ parser->commit();
+ EXPECT_EQ(1, server.getInMemoryClient(rrclass)->getZoneCount());
+
+ // Failure case: the specified zone doesn't exist in the DB file.
+ delete parser;
+ parser = createAuthConfigParser(server, "datasources");
EXPECT_THROW(parser->build(
Element::fromJSON(
"[{\"type\": \"memory\","
" \"zones\": [{\"origin\": \"example.com\","
" \"file\": \""
- TEST_DATA_DIR "/example.zone\","
+ + test_db + "\","
" \"filetype\": \"sqlite3\"}]}]")),
- AuthConfigError);
+ DataSourceError);
+}
+TEST_F(MemoryDatasrcConfigTest, addOneWithFiletypeText) {
// Explicitly specifying "text" is okay.
parser->build(Element::fromJSON(
"[{\"type\": \"memory\","
diff --git a/src/bin/auth/tests/datasrc_util.cc b/src/bin/auth/tests/datasrc_util.cc
new file mode 100644
index 0000000..d9e99b6
--- /dev/null
+++ b/src/bin/auth/tests/datasrc_util.cc
@@ -0,0 +1,77 @@
+// Copyright (C) 2012 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.
+
+#include <exceptions/exceptions.h>
+
+#include <dns/masterload.h>
+#include <dns/name.h>
+#include <dns/rrclass.h>
+
+#include <cc/data.h>
+
+#include <datasrc/client.h>
+#include <datasrc/zone.h>
+#include <datasrc/factory.h>
+
+#include "datasrc_util.h"
+
+#include <boost/bind.hpp>
+
+#include <istream>
+
+#include <cstdlib>
+
+using namespace std;
+
+using namespace isc::dns;
+using namespace isc::data;
+using namespace isc::datasrc;
+
+namespace isc {
+namespace auth {
+namespace unittest {
+
+namespace {
+void
+addRRset(ZoneUpdaterPtr updater, ConstRRsetPtr rrset) {
+ updater->addRRset(*rrset);
+}
+}
+
+void
+createSQLite3DB(RRClass zclass, const Name& zname,
+ const char* const db_file, istream& rr_stream)
+{
+ // We always begin with an empty template SQLite3 DB file and install
+ // the zone data from the zone file.
+ const char* const install_cmd_prefix = INSTALL_PROG " " TEST_DATA_DIR
+ "/rwtest.sqlite3 ";
+ const string install_cmd = string(install_cmd_prefix) + db_file;
+ if (system(install_cmd.c_str()) != 0) {
+ isc_throw(isc::Unexpected,
+ "Error setting up; command failed: " << install_cmd);
+ }
+
+ DataSourceClientContainer container("sqlite3",
+ Element::fromJSON(
+ "{\"database_file\": \"" +
+ string(db_file) + "\"}"));
+ ZoneUpdaterPtr updater = container.getInstance().getUpdater(zname, true);
+ masterLoad(rr_stream, zname, zclass, boost::bind(addRRset, updater, _1));
+ updater->commit();
+}
+
+} // end of unittest
+} // end of auth
+} // end of isc
diff --git a/src/bin/auth/tests/datasrc_util.h b/src/bin/auth/tests/datasrc_util.h
new file mode 100644
index 0000000..fc4109b
--- /dev/null
+++ b/src/bin/auth/tests/datasrc_util.h
@@ -0,0 +1,61 @@
+// Copyright (C) 2012 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 __AUTH_DATA_SOURCE_UTIL_H
+#define __AUTH_DATA_SOURCE_UTIL_H 1
+
+#include <dns/name.h>
+#include <dns/rrclass.h>
+
+#include <istream>
+
+namespace isc {
+namespace auth {
+namespace unittest {
+
+// Here we define utility modules for the convenience of tests that create
+// a data source client according to the specified conditions.
+
+/// \brief Create an SQLite3 data source client from a stream.
+///
+/// This function creates an SQLite3 DB file for the specified zone
+/// with specified content. The zone will be created in the given
+/// SQLite3 database file. The database file does not have to exist;
+/// this function will automatically create a new file for the test
+/// based on a template that only contains the necessary schema. If
+/// the given file already exists this function overrides the content
+/// (so basically the file must be an ephemeral one only for that test
+/// case).
+///
+/// The input stream must produce strings as the corresponding
+/// \c dns::masterLoad() function expects.
+///
+/// \param zclass The RR class of the zone
+/// \param zname The origin name of the zone
+/// \param db_file The SQLite3 data base file in which the zone data should be
+/// installed.
+/// \param rr_stream An input stream that produces zone data.
+void
+createSQLite3DB(dns::RRClass zclass, const dns::Name& zname,
+ const char* const db_file, std::istream& rr_stream);
+
+} // end of unittest
+} // end of auth
+} // end of isc
+
+#endif // __AUTH_DATA_SOURCE_UTIL_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/bin/bind10/bind10.xml b/src/bin/bind10/bind10.xml
index c86ce83..9a8f2fe 100644
--- a/src/bin/bind10/bind10.xml
+++ b/src/bin/bind10/bind10.xml
@@ -244,10 +244,6 @@ TODO: configuration section
<itemizedlist>
<listitem>
- <para> <varname>/Boss/components/b10-auth</varname> </para>
- </listitem>
-
- <listitem>
<para> <varname>/Boss/components/b10-cmdctl</varname> </para>
</listitem>
@@ -259,18 +255,6 @@ TODO: configuration section
<para> <varname>/Boss/components/b10-stats-httpd</varname> </para>
</listitem>
- <listitem>
- <para> <varname>/Boss/components/b10-xfrin</varname> </para>
- </listitem>
-
- <listitem>
- <para> <varname>/Boss/components/b10-xfrout</varname> </para>
- </listitem>
-
- <listitem>
- <para> <varname>/Boss/components/b10-zonemgr</varname> </para>
- </listitem>
-
</itemizedlist>
<para>
diff --git a/src/bin/bind10/bob.spec b/src/bin/bind10/bob.spec
index 29b1f40..b358f96 100644
--- a/src/bin/bind10/bob.spec
+++ b/src/bin/bind10/bob.spec
@@ -8,10 +8,6 @@
"item_type": "named_set",
"item_optional": false,
"item_default": {
- "b10-auth": { "special": "auth", "kind": "needed" },
- "b10-xfrin": { "address": "Xfrin", "kind": "dispensable" },
- "b10-xfrout": { "address": "Xfrout", "kind": "dispensable" },
- "b10-zonemgr": { "address": "Zonemgr", "kind": "dispensable" },
"b10-stats": { "address": "Stats", "kind": "dispensable" },
"b10-stats-httpd": {
"address": "StatsHttpd",
diff --git a/src/bin/host/host.cc b/src/bin/host/host.cc
index f1bb415..a5c6522 100644
--- a/src/bin/host/host.cc
+++ b/src/bin/host/host.cc
@@ -232,7 +232,7 @@ main(int argc, char* argv[]) {
argv += optind;
if (argc < 1) {
- cout << "Usage: host [-adprv] [-c class] [-t type] hostname [server]\n";
+ cout << "Usage: host [-adrv] [-c class] [-p port] [-t type] hostname [server]\n";
exit(1);
}
diff --git a/src/bin/xfrin/tests/xfrin_test.py b/src/bin/xfrin/tests/xfrin_test.py
index a5c92ab..b88d6a9 100644
--- a/src/bin/xfrin/tests/xfrin_test.py
+++ b/src/bin/xfrin/tests/xfrin_test.py
@@ -139,6 +139,9 @@ class MockCC(MockModuleCCSession):
if identifier == "zones/use_ixfr":
return False
+ def remove_remote_config(self, module_name):
+ pass
+
class MockDataSourceClient():
'''A simple mock data source client.
@@ -2574,6 +2577,134 @@ class TestXfrin(unittest.TestCase):
self.common_ixfr_setup('refresh', False)
self.assertEqual(RRType.AXFR(), self.xfr.xfrin_started_request_type)
+class TextXfrinMemoryZones(unittest.TestCase):
+ def setUp(self):
+ self.xfr = MockXfrin()
+ # Configuration snippet containing 2 memory datasources,
+ # one for IN and one for CH. Both contain a zone 'example.com'
+ # the IN ds also contains a zone example2.com, and a zone example3.com,
+ # which is of file type 'text' (and hence, should be ignored)
+ self.config = { 'datasources': [
+ { 'type': 'memory',
+ 'class': 'IN',
+ 'zones': [
+ { 'origin': 'example.com',
+ 'filetype': 'sqlite3' },
+ { 'origin': 'EXAMPLE2.com.',
+ 'filetype': 'sqlite3' },
+ { 'origin': 'example3.com',
+ 'filetype': 'text' }
+ ]
+ },
+ { 'type': 'memory',
+ 'class': 'ch',
+ 'zones': [
+ { 'origin': 'example.com',
+ 'filetype': 'sqlite3' }
+ ]
+ }
+ ] }
+
+ def test_updates(self):
+ self.assertFalse(self.xfr._is_memory_zone("example.com", "IN"))
+ self.assertFalse(self.xfr._is_memory_zone("example2.com", "IN"))
+ self.assertFalse(self.xfr._is_memory_zone("example3.com", "IN"))
+ self.assertFalse(self.xfr._is_memory_zone("example.com", "CH"))
+
+ # add them all
+ self.xfr._set_memory_zones(self.config, None)
+ self.assertTrue(self.xfr._is_memory_zone("example.com", "IN"))
+ self.assertTrue(self.xfr._is_memory_zone("example2.com", "IN"))
+ self.assertFalse(self.xfr._is_memory_zone("example3.com", "IN"))
+ self.assertTrue(self.xfr._is_memory_zone("example.com", "CH"))
+
+ # Remove the CH data source from the self.config snippet, and update
+ del self.config['datasources'][1]
+ self.xfr._set_memory_zones(self.config, None)
+ self.assertTrue(self.xfr._is_memory_zone("example.com", "IN"))
+ self.assertTrue(self.xfr._is_memory_zone("example2.com", "IN"))
+ self.assertFalse(self.xfr._is_memory_zone("example3.com", "IN"))
+ self.assertFalse(self.xfr._is_memory_zone("example.com", "CH"))
+
+ # Remove example2.com from the datasource, and update
+ del self.config['datasources'][0]['zones'][1]
+ self.xfr._set_memory_zones(self.config, None)
+ self.assertTrue(self.xfr._is_memory_zone("example.com", "IN"))
+ self.assertFalse(self.xfr._is_memory_zone("example2.com", "IN"))
+ self.assertFalse(self.xfr._is_memory_zone("example3.com", "IN"))
+ self.assertFalse(self.xfr._is_memory_zone("example.com", "CH"))
+
+ # If 'datasources' is not in the self.config update list (i.e. its
+ # self.config has not changed), no difference should be found
+ self.xfr._set_memory_zones({}, None)
+ self.assertTrue(self.xfr._is_memory_zone("example.com", "IN"))
+ self.assertFalse(self.xfr._is_memory_zone("example2.com", "IN"))
+ self.assertFalse(self.xfr._is_memory_zone("example3.com", "IN"))
+ self.assertFalse(self.xfr._is_memory_zone("example.com", "CH"))
+
+ # If datasources list becomes empty, everything should be removed
+ self.config['datasources'][0]['zones'] = []
+ self.xfr._set_memory_zones(self.config, None)
+ self.assertFalse(self.xfr._is_memory_zone("example.com", "IN"))
+ self.assertFalse(self.xfr._is_memory_zone("example2.com", "IN"))
+ self.assertFalse(self.xfr._is_memory_zone("example3.com", "IN"))
+ self.assertFalse(self.xfr._is_memory_zone("example.com", "CH"))
+
+ def test_normalization(self):
+ self.xfr._set_memory_zones(self.config, None)
+ # make sure it is case insensitive, root-dot-insensitive,
+ # and supports CLASSXXX notation
+ self.assertTrue(self.xfr._is_memory_zone("EXAMPLE.com", "IN"))
+ self.assertTrue(self.xfr._is_memory_zone("example.com", "in"))
+ self.assertTrue(self.xfr._is_memory_zone("example2.com.", "IN"))
+ self.assertTrue(self.xfr._is_memory_zone("example.com", "CLASS3"))
+
+ def test_bad_name(self):
+ # First set it to some config
+ self.xfr._set_memory_zones(self.config, None)
+
+ # Error checking; bad owner name should result in no changes
+ self.config['datasources'][1]['zones'][0]['origin'] = ".."
+ self.xfr._set_memory_zones(self.config, None)
+ self.assertTrue(self.xfr._is_memory_zone("example.com", "IN"))
+ self.assertTrue(self.xfr._is_memory_zone("example2.com", "IN"))
+ self.assertFalse(self.xfr._is_memory_zone("example3.com", "IN"))
+ self.assertTrue(self.xfr._is_memory_zone("example.com", "CH"))
+
+ def test_bad_class(self):
+ # First set it to some config
+ self.xfr._set_memory_zones(self.config, None)
+
+ # Error checking; bad owner name should result in no changes
+ self.config['datasources'][1]['class'] = "Foo"
+ self.xfr._set_memory_zones(self.config, None)
+ self.assertTrue(self.xfr._is_memory_zone("example.com", "IN"))
+ self.assertTrue(self.xfr._is_memory_zone("example2.com", "IN"))
+ self.assertFalse(self.xfr._is_memory_zone("example3.com", "IN"))
+ self.assertTrue(self.xfr._is_memory_zone("example.com", "CH"))
+
+ def test_no_filetype(self):
+ # omitting the filetype should leave that zone out, but not
+ # the rest
+ del self.config['datasources'][1]['zones'][0]['filetype']
+ self.xfr._set_memory_zones(self.config, None)
+ self.assertTrue(self.xfr._is_memory_zone("example.com", "IN"))
+ self.assertTrue(self.xfr._is_memory_zone("example2.com", "IN"))
+ self.assertFalse(self.xfr._is_memory_zone("example3.com", "IN"))
+ self.assertFalse(self.xfr._is_memory_zone("example.com", "CH"))
+
+ def test_class_filetype(self):
+ # omitting the class should have it default to what is in the
+ # specfile for Auth.
+ AuthConfigData = isc.config.config_data.ConfigData(
+ isc.config.module_spec_from_file(xfrin.AUTH_SPECFILE_LOCATION))
+ del self.config['datasources'][0]['class']
+ self.xfr._set_memory_zones(self.config, AuthConfigData)
+ self.assertTrue(self.xfr._is_memory_zone("example.com", "IN"))
+ self.assertTrue(self.xfr._is_memory_zone("example2.com", "IN"))
+ self.assertFalse(self.xfr._is_memory_zone("example3.com", "IN"))
+ self.assertTrue(self.xfr._is_memory_zone("example.com", "CH"))
+
def raise_interrupt():
raise KeyboardInterrupt()
diff --git a/src/bin/xfrin/xfrin.py.in b/src/bin/xfrin/xfrin.py.in
index 863c5b9..58713be 100755
--- a/src/bin/xfrin/xfrin.py.in
+++ b/src/bin/xfrin/xfrin.py.in
@@ -38,6 +38,11 @@ from isc.log_messages.xfrin_messages import *
isc.log.init("b10-xfrin")
logger = isc.log.Logger("xfrin")
+# Pending system-wide debug level definitions, the ones we
+# use here are hardcoded for now
+DBG_PROCESS = logger.DBGLVL_TRACE_BASIC
+DBG_COMMANDS = logger.DBGLVL_TRACE_DETAIL
+
try:
from pydnspp import *
except ImportError as e:
@@ -1246,6 +1251,11 @@ class Xfrin:
def __init__(self):
self._max_transfers_in = 10
self._zones = {}
+ # This is a set of (zone/class) tuples (both as strings),
+ # representing the in-memory zones maintaned by Xfrin. It
+ # is used to trigger Auth/in-memory so that it reloads
+ # zones when they have been transfered in
+ self._memory_zones = set()
self._cc_setup()
self.recorder = XfrinRecorder()
self._shutdown_event = threading.Event()
@@ -1264,6 +1274,8 @@ class Xfrin:
self._module_cc.start()
config_data = self._module_cc.get_full_config()
self.config_handler(config_data)
+ self._module_cc.add_remote_config(AUTH_SPECFILE_LOCATION,
+ self._auth_config_handler)
def _cc_check_command(self):
'''This is a straightforward wrapper for cc.check_command,
@@ -1310,10 +1322,78 @@ class Xfrin:
return create_answer(0)
+ def _auth_config_handler(self, new_config, config_data):
+ # Config handler for changes in Auth configuration
+ self._set_db_file()
+ self._set_memory_zones(new_config, config_data)
+
+ def _clear_memory_zones(self):
+ """Clears the memory_zones set; called before processing the
+ changed list of memory datasource zones that have file type
+ sqlite3"""
+ self._memory_zones.clear()
+
+ def _is_memory_zone(self, zone_name_str, zone_class_str):
+ """Returns true if the given zone/class combination is configured
+ in the in-memory datasource of the Auth process with file type
+ 'sqlite3'.
+ Note: this method is not thread-safe. We are considering
+ changing the threaded model here, but if we do not, take
+ care in accessing and updating the memory zone set (or add
+ locks)
+ """
+ # Normalize them first, if either conversion fails, return false
+ # (they won't be in the set anyway)
+ try:
+ zone_name_str = Name(zone_name_str).to_text().lower()
+ zone_class_str = RRClass(zone_class_str).to_text()
+ except Exception:
+ return False
+ return (zone_name_str, zone_class_str) in self._memory_zones
+
+ def _set_memory_zones(self, new_config, config_data):
+ """Part of the _auth_config_handler function, keeps an internal set
+ of zones in the datasources config subset that have 'sqlite3' as
+ their file type.
+ Note: this method is not thread-safe. We are considering
+ changing the threaded model here, but if we do not, take
+ care in accessing and updating the memory zone set (or add
+ locks)
+ """
+ # walk through the data and collect the memory zones
+ # If this causes any exception, assume we were passed bad data
+ # and keep the original set
+ new_memory_zones = set()
+ try:
+ if "datasources" in new_config:
+ for datasource in new_config["datasources"]:
+ if "class" in datasource:
+ ds_class = RRClass(datasource["class"])
+ else:
+ # Get the default
+ ds_class = RRClass(config_data.get_default_value(
+ "datasources/class"))
+ if datasource["type"] == "memory":
+ for zone in datasource["zones"]:
+ if "filetype" in zone and \
+ zone["filetype"] == "sqlite3":
+ zone_name = Name(zone["origin"])
+ zone_name_str = zone_name.to_text().lower()
+ new_memory_zones.add((zone_name_str,
+ ds_class.to_text()))
+ # Ok, we can use the data, update our list
+ self._memory_zones = new_memory_zones
+ except Exception:
+ # Something is wrong with the data. If this data even reached us,
+ # we cannot do more than assume the real module has logged and
+ # reported an error. Keep the old set.
+ return
+
def shutdown(self):
''' shutdown the xfrin process. the thread which is doing xfrin should be
terminated.
'''
+ self._module_cc.remove_remote_config(AUTH_SPECFILE_LOCATION)
self._module_cc.send_stopping()
self._shutdown_event.set()
main_thread = threading.currentThread()
@@ -1446,20 +1526,19 @@ class Xfrin:
return (addr.family, socket.SOCK_STREAM, (str(addr), port))
def _get_db_file(self):
- #TODO, the db file path should be got in auth server's configuration
- # if we need access to this configuration more often, we
- # should add it on start, and not remove it here
- # (or, if we have writable ds, we might not need this in
- # the first place)
- self._module_cc.add_remote_config(AUTH_SPECFILE_LOCATION)
- db_file, is_default = self._module_cc.get_remote_config_value("Auth", "database_file")
+ return self._db_file
+
+ def _set_db_file(self):
+ db_file, is_default =\
+ self._module_cc.get_remote_config_value("Auth", "database_file")
if is_default and "B10_FROM_BUILD" in os.environ:
- # this too should be unnecessary, but currently the
- # 'from build' override isn't stored in the config
- # (and we don't have writable datasources yet)
- db_file = os.environ["B10_FROM_BUILD"] + os.sep + "bind10_zones.sqlite3"
- self._module_cc.remove_remote_config(AUTH_SPECFILE_LOCATION)
- return db_file
+ # override the local database setting if it is default and we
+ # are running from the source tree
+ # This should be hidden inside the data source library and/or
+ # done as a configuration, and this special case should be gone).
+ db_file = os.environ["B10_FROM_BUILD"] + os.sep +\
+ "bind10_zones.sqlite3"
+ self._db_file = db_file
def publish_xfrin_news(self, zone_name, zone_class, xfr_result):
'''Send command to xfrout/zone manager module.
@@ -1502,6 +1581,7 @@ class Xfrin:
logger.error(XFRIN_MSGQ_SEND_ERROR_ZONE_MANAGER, ZONE_MANAGER_MODULE_NAME)
def startup(self):
+ logger.debug(DBG_PROCESS, XFRIN_STARTED)
while not self._shutdown_event.is_set():
self._cc_check_command()
diff --git a/src/bin/xfrin/xfrin_messages.mes b/src/bin/xfrin/xfrin_messages.mes
index eae1c69..25a1fc1 100644
--- a/src/bin/xfrin/xfrin_messages.mes
+++ b/src/bin/xfrin/xfrin_messages.mes
@@ -129,8 +129,9 @@ zone is not known to the system. This may indicate that the configuration
for xfrin is incomplete, or there was a typographical error in the
zone name in the configuration.
-% XFRIN_STARTING starting resolver with command line '%1'
-An informational message, this is output when the resolver starts up.
+% XFRIN_STARTED xfrin started
+This informational message is output by xfrin when all initialization
+has been completed and it is entering its main loop.
% XFRIN_STOPPED_BY_KEYBOARD keyboard interrupt, shutting down
There was a keyboard interrupt signal to stop the xfrin daemon. The
diff --git a/src/bin/xfrout/xfrout.py.in b/src/bin/xfrout/xfrout.py.in
index 8f236ec..4dd12ce 100755
--- a/src/bin/xfrout/xfrout.py.in
+++ b/src/bin/xfrout/xfrout.py.in
@@ -40,6 +40,12 @@ from isc.log_messages.xfrout_messages import *
isc.log.init("b10-xfrout")
logger = isc.log.Logger("xfrout")
+
+# Pending system-wide debug level definitions, the ones we
+# use here are hardcoded for now
+DBG_PROCESS = logger.DBGLVL_TRACE_BASIC
+DBG_COMMANDS = logger.DBGLVL_TRACE_DETAIL
+
DBG_XFROUT_TRACE = logger.DBGLVL_TRACE_BASIC
try:
@@ -1002,6 +1008,7 @@ class XfroutServer:
def run(self):
'''Get and process all commands sent from cfgmgr or other modules. '''
+ logger.debug(DBG_PROCESS, XFROUT_STARTED)
while not self._shutdown_event.is_set():
self._cc.check_command(False)
diff --git a/src/bin/xfrout/xfrout_messages.mes b/src/bin/xfrout/xfrout_messages.mes
index fcc2e59..9996a5a 100644
--- a/src/bin/xfrout/xfrout_messages.mes
+++ b/src/bin/xfrout/xfrout_messages.mes
@@ -133,6 +133,10 @@ be a result of rare local error such as memory allocation failure and
shouldn't happen under normal conditions. The error is included in the
log message.
+% XFROUT_STARTED xfrout started
+This informational message is output by xfrout when all initialization
+has been completed and it is entering its main loop.
+
% XFROUT_STOPPED_BY_KEYBOARD keyboard interrupt, shutting down
There was a keyboard interrupt signal to stop the xfrout daemon. The
daemon will now shut down.
diff --git a/src/bin/zonemgr/zonemgr.py.in b/src/bin/zonemgr/zonemgr.py.in
index 7b16f1b..87589a8 100755
--- a/src/bin/zonemgr/zonemgr.py.in
+++ b/src/bin/zonemgr/zonemgr.py.in
@@ -44,6 +44,11 @@ from isc.log_messages.zonemgr_messages import *
isc.log.init("b10-zonemgr")
logger = isc.log.Logger("zonemgr")
+# Pending system-wide debug level definitions, the ones we
+# use here are hardcoded for now
+DBG_PROCESS = logger.DBGLVL_TRACE_BASIC
+DBG_COMMANDS = logger.DBGLVL_TRACE_DETAIL
+
# Constants for debug levels.
DBG_START_SHUT = logger.DBGLVL_START_SHUT
DBG_ZONEMGR_COMMAND = logger.DBGLVL_COMMAND
@@ -657,6 +662,7 @@ class Zonemgr:
return answer
def run(self):
+ logger.debug(DBG_PROCESS, ZONEMGR_STARTED)
self.running = True
try:
while not self._shutdown_event.is_set():
diff --git a/src/bin/zonemgr/zonemgr_messages.mes b/src/bin/zonemgr/zonemgr_messages.mes
index d33e263..c866b79 100644
--- a/src/bin/zonemgr/zonemgr_messages.mes
+++ b/src/bin/zonemgr/zonemgr_messages.mes
@@ -67,6 +67,10 @@ zone manager to record the master server for the zone and start a timer;
when the timer expires, the master will be polled to see if it contains
new data.
+% ZONEMGR_STARTED zonemgr started
+This informational message is output by zonemgr when all initialization
+has been completed and it is entering its main loop.
+
% ZONEMGR_RECEIVE_SHUTDOWN received SHUTDOWN command
This is a debug message indicating that the zone manager has received
a SHUTDOWN command over the command channel from the Boss process.
diff --git a/src/lib/cc/cc_messages.mes b/src/lib/cc/cc_messages.mes
index 8370cdd..94b955a 100644
--- a/src/lib/cc/cc_messages.mes
+++ b/src/lib/cc/cc_messages.mes
@@ -14,7 +14,7 @@
$NAMESPACE isc::cc
-% CC_ASYNC_READ_FAILED asynchronous read failed
+% CC_ASYNC_READ_FAILED asynchronous read failed (error code = %1)
This marks a low level error, we tried to read data from the message queue
daemon asynchronously, but the ASIO library returned an error.
diff --git a/src/lib/cc/session.cc b/src/lib/cc/session.cc
index 1b21d21..40ab86d 100644
--- a/src/lib/cc/session.cc
+++ b/src/lib/cc/session.cc
@@ -249,7 +249,7 @@ SessionImpl::internalRead(const asio::error_code& error,
}
user_handler_();
} else {
- LOG_ERROR(logger, CC_ASYNC_READ_FAILED);
+ LOG_ERROR(logger, CC_ASYNC_READ_FAILED).arg(error.value());
isc_throw(SessionError, "asynchronous read failed");
}
}
diff --git a/src/lib/cc/tests/Makefile.am b/src/lib/cc/tests/Makefile.am
index 4760855..08b7f33 100644
--- a/src/lib/cc/tests/Makefile.am
+++ b/src/lib/cc/tests/Makefile.am
@@ -24,11 +24,14 @@ run_unittests_SOURCES = data_unittests.cc session_unittests.cc run_unittests.cc
run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
-run_unittests_LDADD = $(GTEST_LDADD)
-run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.la
+# We need to put our libs first, in case gtest (or any dependency, really)
+# is installed in the same location as a different version of bind10
+# Otherwise the linker may not use the source tree libs
+run_unittests_LDADD = $(top_builddir)/src/lib/cc/libcc.la
run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+run_unittests_LDADD += $(GTEST_LDADD)
endif
diff --git a/src/lib/datasrc/Makefile.am b/src/lib/datasrc/Makefile.am
index 1e743dd..2cdb8ea 100644
--- a/src/lib/datasrc/Makefile.am
+++ b/src/lib/datasrc/Makefile.am
@@ -31,6 +31,7 @@ libdatasrc_la_SOURCES += client.h iterator.h
libdatasrc_la_SOURCES += database.h database.cc
libdatasrc_la_SOURCES += factory.h factory.cc
nodist_libdatasrc_la_SOURCES = datasrc_messages.h datasrc_messages.cc
+libdatasrc_la_LDFLAGS = -no-undefined -version-info 1:0:1
pkglib_LTLIBRARIES = sqlite3_ds.la memory_ds.la
diff --git a/src/lib/datasrc/database.cc b/src/lib/datasrc/database.cc
index b13f799..7b271f1 100644
--- a/src/lib/datasrc/database.cc
+++ b/src/lib/datasrc/database.cc
@@ -27,15 +27,18 @@
#include <dns/rrset.h>
#include <dns/rdata.h>
#include <dns/rdataclass.h>
+#include <dns/nsec3hash.h>
#include <datasrc/data_source.h>
#include <datasrc/logger.h>
#include <boost/foreach.hpp>
+#include <boost/scoped_ptr.hpp>
using namespace isc::dns;
using namespace std;
using namespace isc::dns::rdata;
+using namespace boost;
namespace isc {
namespace datasrc {
@@ -177,15 +180,17 @@ private:
DatabaseClient::Finder::FoundRRsets
DatabaseClient::Finder::getRRsets(const string& name, const WantedTypes& types,
bool check_ns, const string* construct_name,
- bool any)
+ bool any,
+ DatabaseAccessor::IteratorContextPtr context)
{
RRsigStore sig_store;
bool records_found = false;
std::map<RRType, RRsetPtr> result;
- // Request the context
- DatabaseAccessor::IteratorContextPtr
- context(accessor_->getRecords(name, zone_id_));
+ // Request the context in case we didn't get one
+ if (!context) {
+ context = accessor_->getRecords(name, zone_id_);
+ }
// It must not return NULL, that's a bug of the implementation
if (!context) {
isc_throw(isc::Unexpected, "Iterator context null at " + name);
@@ -286,13 +291,11 @@ DatabaseClient::Finder::getRRsets(const string& name, const WantedTypes& types,
i != result.end(); ++ i) {
sig_store.appendSignatures(i->second);
}
-
if (records_found && any) {
result[RRType::ANY()] = RRsetPtr();
// These will be sitting on the other RRsets.
result.erase(RRType::RRSIG());
}
-
return (FoundRRsets(records_found, result));
}
@@ -318,6 +321,30 @@ namespace {
typedef std::set<RRType> WantedTypes;
const WantedTypes&
+NSEC3_TYPES() {
+ static bool initialized(false);
+ static WantedTypes result;
+
+ if (!initialized) {
+ result.insert(RRType::NSEC3());
+ initialized = true;
+ }
+ return (result);
+}
+
+const WantedTypes&
+NSEC3PARAM_TYPES() {
+ static bool initialized(false);
+ static WantedTypes result;
+
+ if (!initialized) {
+ result.insert(RRType::NSEC3PARAM());
+ initialized = true;
+ }
+ return (result);
+}
+
+const WantedTypes&
NSEC_TYPES() {
static bool initialized(false);
static WantedTypes result;
@@ -355,45 +382,6 @@ FINAL_TYPES() {
}
return (result);
}
-
-}
-
-ConstRRsetPtr
-DatabaseClient::Finder::findNSECCover(const Name& name) {
- try {
- // Which one should contain the NSEC record?
- const Name coverName(findPreviousName(name));
- // Get the record and copy it out
- const FoundRRsets found = getRRsets(coverName.toText(), NSEC_TYPES(),
- coverName != getOrigin());
- const FoundIterator
- nci(found.second.find(RRType::NSEC()));
- if (nci != found.second.end()) {
- return (nci->second);
- } else {
- // The previous doesn't contain NSEC.
- // Badly signed zone or a bug?
-
- // FIXME: Currently, if the zone is not signed, we could get
- // here. In that case we can't really throw, but for now, we can't
- // recognize it. So we don't throw at all, enable it once
- // we have a is_signed flag or something.
-#if 0
- isc_throw(DataSourceError, "No NSEC in " +
- coverName.toText() + ", but it was "
- "returned as previous - "
- "accessor error? Badly signed zone?");
-#endif
- }
- }
- catch (const isc::NotImplemented&) {
- // Well, they want DNSSEC, but there is no available.
- // So we don't provide anything.
- LOG_INFO(logger, DATASRC_DATABASE_COVER_NSEC_UNSUPPORTED).
- arg(accessor_->getDBName()).arg(name);
- }
- // We didn't find it, return nothing
- return (ConstRRsetPtr());
}
ZoneFinderContextPtr
@@ -416,8 +404,8 @@ DatabaseClient::Finder::find(const isc::dns::Name& name,
isc_throw(isc::Unexpected, "Use findAll to answer ANY");
}
return (ZoneFinderContextPtr(new Context(*this, options,
- findInternal(name, type,
- NULL, options))));
+ findInternal(name, type, NULL,
+ options))));
}
DatabaseClient::Finder::DelegationSearchResult
@@ -580,9 +568,9 @@ DatabaseClient::Finder::findDelegationPoint(const isc::dns::Name& name,
// If none of the above applies in any level, the search fails with NXDOMAIN.
ZoneFinder::ResultContext
DatabaseClient::Finder::findWildcardMatch(
- const isc::dns::Name& name, const isc::dns::RRType& type,
- const FindOptions options, const DelegationSearchResult& dresult,
- std::vector<isc::dns::ConstRRsetPtr>* target)
+ const Name& name, const RRType& type, const FindOptions options,
+ const DelegationSearchResult& dresult, vector<ConstRRsetPtr>* target,
+ FindDNSSECContext& dnssec_ctx)
{
// Note that during the search we are going to search not only for the
// requested type, but also for types that indicate a delegation -
@@ -625,8 +613,8 @@ DatabaseClient::Finder::findWildcardMatch(
} else if (!hasSubdomains(name.split(i - 1).toText())) {
// The wildcard match is the best one, find the final result
// at it. Note that wildcard should never be the zone origin.
- return (findOnNameResult(name, type, options, false,
- found, &wildcard, target));
+ return (findOnNameResult(name, type, options, false, found,
+ &wildcard, target, dnssec_ctx));
} else {
// more specified match found, cancel wildcard match
@@ -642,15 +630,11 @@ DatabaseClient::Finder::findWildcardMatch(
LOG_DEBUG(logger, DBG_TRACE_DETAILED,
DATASRC_DATABASE_WILDCARD_EMPTY).
arg(accessor_->getDBName()).arg(wildcard).arg(name);
- if ((options & FIND_DNSSEC) != 0) {
- ConstRRsetPtr nsec = findNSECCover(Name(wildcard));
- if (nsec) {
- return (ResultContext(NXRRSET, nsec,
- RESULT_WILDCARD |
- RESULT_NSEC_SIGNED));
- }
- }
- return (ResultContext(NXRRSET, ConstRRsetPtr(), RESULT_WILDCARD));
+ const FindResultFlags flags = (RESULT_WILDCARD |
+ dnssec_ctx.getResultFlags());
+ return (ResultContext(NXRRSET,
+ dnssec_ctx.getDNSSECRRset(Name(wildcard),
+ true), flags));
}
}
@@ -688,6 +672,121 @@ DatabaseClient::Finder::logAndCreateResult(
return (ResultContext(code, rrset, flags));
}
+DatabaseClient::Finder::FindDNSSECContext::FindDNSSECContext(
+ DatabaseClient::Finder& finder,
+ const FindOptions options) :
+ finder_(finder),
+ need_dnssec_((options & FIND_DNSSEC) != 0),
+ is_nsec3_(false),
+ is_nsec_(false),
+ probed_(false)
+{}
+
+void
+DatabaseClient::Finder::FindDNSSECContext::probe() {
+ if (!probed_) {
+ probed_ = true;
+ if (need_dnssec_) {
+ // If an NSEC3PARAM RR exists at the zone apex, it's quite likely
+ // that the zone is signed with NSEC3. (If not the zone is more
+ // or less broken, but it's caller's responsibility how to handle
+ // such cases).
+ const string origin = finder_.getOrigin().toText();
+ const FoundRRsets nsec3_found =
+ finder_.getRRsets(origin, NSEC3PARAM_TYPES(), false);
+ const FoundIterator nfi=
+ nsec3_found.second.find(RRType::NSEC3PARAM());
+ is_nsec3_ = (nfi != nsec3_found.second.end());
+
+ // Likewise for NSEC, depending on the apex has an NSEC RR.
+ // If we know the zone is NSEC3-signed, however, we don't bother
+ // to check that. This is aligned with the transition guideline
+ // described in Section 10.4 of RFC 5155.
+ if (!is_nsec3_) {
+ const FoundRRsets nsec_found =
+ finder_.getRRsets(origin, NSEC_TYPES(), false);
+ const FoundIterator nfi =
+ nsec_found.second.find(RRType::NSEC());
+ is_nsec_ = (nfi != nsec_found.second.end());
+ }
+ }
+ }
+}
+
+bool
+DatabaseClient::Finder::FindDNSSECContext::isNSEC3() {
+ if (!probed_) {
+ probe();
+ }
+ return (is_nsec3_);
+}
+
+bool
+DatabaseClient::Finder::FindDNSSECContext::isNSEC() {
+ if (!probed_) {
+ probe();
+ }
+ return (is_nsec_);
+}
+
+isc::dns::ConstRRsetPtr
+DatabaseClient::Finder::FindDNSSECContext::getDNSSECRRset(
+ const FoundRRsets& found_set)
+{
+ if (!isNSEC()) {
+ return (ConstRRsetPtr());
+ }
+
+ const FoundIterator nci = found_set.second.find(RRType::NSEC());
+ if (nci != found_set.second.end()) {
+ return (nci->second);
+ } else {
+ return (ConstRRsetPtr());
+ }
+}
+
+isc::dns::ConstRRsetPtr
+DatabaseClient::Finder::FindDNSSECContext::getDNSSECRRset(const Name &name,
+ bool covering)
+{
+ if (!isNSEC()) {
+ return (ConstRRsetPtr());
+ }
+
+ try {
+ const Name& nsec_name =
+ covering ? finder_.findPreviousName(name) : name;
+ const bool need_nscheck = (nsec_name != finder_.getOrigin());
+ const FoundRRsets found = finder_.getRRsets(nsec_name.toText(),
+ NSEC_TYPES(),
+ need_nscheck);
+ const FoundIterator nci = found.second.find(RRType::NSEC());
+ if (nci != found.second.end()) {
+ return (nci->second);
+ }
+ } catch (const isc::NotImplemented&) {
+ // This happens when the underlying database accessor doesn't support
+ // findPreviousName() (it probably doesn't support DNSSEC at all) but
+ // there is somehow an NSEC RR at the zone apex. We log the fact but
+ // otherwise let the caller decide what to do (so, for example, a
+ // higher level query processing won't completely fail but can return
+ // anything it can get).
+ LOG_INFO(logger, DATASRC_DATABASE_COVER_NSEC_UNSUPPORTED).
+ arg(finder_.accessor_->getDBName()).arg(name);
+ }
+ return (ConstRRsetPtr());
+}
+
+ZoneFinder::FindResultFlags
+DatabaseClient::Finder::FindDNSSECContext::getResultFlags() {
+ if (isNSEC3()) {
+ return (RESULT_NSEC3_SIGNED);
+ } else if (isNSEC()) {
+ return (RESULT_NSEC_SIGNED);
+ }
+ return (RESULT_DEFAULT);
+}
+
ZoneFinder::ResultContext
DatabaseClient::Finder::findOnNameResult(const Name& name,
const RRType& type,
@@ -696,28 +795,22 @@ DatabaseClient::Finder::findOnNameResult(const Name& name,
const FoundRRsets& found,
const string* wildname,
std::vector<isc::dns::ConstRRsetPtr>*
- target)
+ target, FindDNSSECContext& dnssec_ctx)
{
const bool wild = (wildname != NULL);
- FindResultFlags flags = wild ? RESULT_WILDCARD : RESULT_DEFAULT;
+ // For wildcard case with DNSSEC required, the caller would need to
+ // know whether it's NSEC or NSEC3 signed. getResultFlags returns
+ // appropriate flag based on the query context and zone status.
+ const FindResultFlags flags =
+ wild ? (RESULT_WILDCARD | dnssec_ctx.getResultFlags()) : RESULT_DEFAULT;
// Get iterators for the different types of records we are interested in -
// CNAME, NS and Wanted types.
const FoundIterator nsi(found.second.find(RRType::NS()));
const FoundIterator cni(found.second.find(RRType::CNAME()));
const FoundIterator wti(found.second.find(type));
- // For wildcard case with DNSSEC required, the caller would need to know
- // whether it's NSEC or NSEC3 signed. So we need to do an additional
- // search here, even though the NSEC RR may not be returned.
- // TODO: this part should be revised when we support NSEC3; ideally we
- // should use more effective and efficient way to identify (whether and)
- // in which way the zone is signed.
- if (wild && (options & FIND_DNSSEC) != 0 &&
- found.second.find(RRType::NSEC()) != found.second.end()) {
- flags = flags | RESULT_NSEC_SIGNED;
- }
-
- if (!is_origin && ((options & FIND_GLUE_OK) == 0) &&
+
+ if (!is_origin && (options & FIND_GLUE_OK) == 0 &&
nsi != found.second.end()) {
// A NS RRset was found at the domain we were searching for. As it is
// not at the origin of the zone, it is a delegation and indicates that
@@ -744,7 +837,6 @@ DatabaseClient::Finder::findOnNameResult(const Name& name,
wild ? DATASRC_DATABASE_WILDCARD_CNAME :
DATASRC_DATABASE_FOUND_CNAME,
flags));
-
} else if (wti != found.second.end()) {
bool any(type == RRType::ANY());
isc::log::MessageID lid(wild ? DATASRC_DATABASE_WILDCARD_MATCH :
@@ -776,32 +868,20 @@ DatabaseClient::Finder::findOnNameResult(const Name& name,
// provide the NSEC records. If it's for wildcard, we need to get the
// NSEC records in the name of the wildcard, not the substituted one,
// so we need to search the tree again.
- ConstRRsetPtr nsec_rrset; // possibly used with DNSSEC, otherwise NULL
- if ((options & FIND_DNSSEC) != 0) {
- if (wild) {
- const FoundRRsets wfound = getRRsets(*wildname, NSEC_TYPES(),
- true);
- const FoundIterator nci = wfound.second.find(RRType::NSEC());
- if (nci != wfound.second.end()) {
- nsec_rrset = nci->second;
- }
- } else {
- const FoundIterator nci = found.second.find(RRType::NSEC());
- if (nci != found.second.end()) {
- nsec_rrset = nci->second;
- }
- }
- }
- if (nsec_rrset) {
+ const ConstRRsetPtr dnssec_rrset =
+ wild ? dnssec_ctx.getDNSSECRRset(Name(*wildname), false) :
+ dnssec_ctx.getDNSSECRRset(found);
+ if (dnssec_rrset) {
// This log message covers both normal and wildcard cases, so we pass
// NULL for 'wildname'.
- return (logAndCreateResult(name, NULL, type, NXRRSET, nsec_rrset,
+ return (logAndCreateResult(name, NULL, type, NXRRSET, dnssec_rrset,
DATASRC_DATABASE_FOUND_NXRRSET_NSEC,
flags | RESULT_NSEC_SIGNED));
}
- return (logAndCreateResult(name, wildname, type, NXRRSET, nsec_rrset,
+ return (logAndCreateResult(name, wildname, type, NXRRSET, dnssec_rrset,
wild ? DATASRC_DATABASE_WILDCARD_NXRRSET :
- DATASRC_DATABASE_FOUND_NXRRSET, flags));
+ DATASRC_DATABASE_FOUND_NXRRSET,
+ flags | dnssec_ctx.getResultFlags()));
}
ZoneFinder::ResultContext
@@ -809,10 +889,8 @@ DatabaseClient::Finder::findNoNameResult(const Name& name, const RRType& type,
FindOptions options,
const DelegationSearchResult& dresult,
std::vector<isc::dns::ConstRRsetPtr>*
- target)
+ target, FindDNSSECContext& dnssec_ctx)
{
- const bool dnssec_data = ((options & FIND_DNSSEC) != 0);
-
// On entry to this method, we know that the database doesn't have any
// entry for this name. Before returning NXDOMAIN, we need to check
// for special cases.
@@ -824,17 +902,16 @@ DatabaseClient::Finder::findNoNameResult(const Name& name, const RRType& type,
LOG_DEBUG(logger, DBG_TRACE_DETAILED,
DATASRC_DATABASE_FOUND_EMPTY_NONTERMINAL).
arg(accessor_->getDBName()).arg(name);
- const ConstRRsetPtr nsec = dnssec_data ? findNSECCover(name) :
- ConstRRsetPtr();
- return (ResultContext(NXRRSET, nsec,
- nsec ? RESULT_NSEC_SIGNED : RESULT_DEFAULT));
+ return (ResultContext(NXRRSET, dnssec_ctx.getDNSSECRRset(name, true),
+ dnssec_ctx.getResultFlags()));
} else if ((options & NO_WILDCARD) == 0) {
// It's not an empty non-terminal and wildcard matching is not
// disabled, so check for wildcards. If there is a wildcard match
// (i.e. all results except NXDOMAIN) return it; otherwise fall
// through to the NXDOMAIN case below.
const ResultContext wcontext =
- findWildcardMatch(name, type, options, dresult, target);
+ findWildcardMatch(name, type, options, dresult, target,
+ dnssec_ctx);
if (wcontext.code != NXDOMAIN) {
return (wcontext);
}
@@ -844,10 +921,8 @@ DatabaseClient::Finder::findNoNameResult(const Name& name, const RRType& type,
// NSEC records if requested).
LOG_DEBUG(logger, DBG_TRACE_DETAILED, DATASRC_DATABASE_NO_MATCH).
arg(accessor_->getDBName()).arg(name).arg(type).arg(getClass());
- const ConstRRsetPtr nsec = dnssec_data ? findNSECCover(name) :
- ConstRRsetPtr();
- return (ResultContext(NXDOMAIN, nsec,
- nsec ? RESULT_NSEC_SIGNED : RESULT_DEFAULT));
+ return (ResultContext(NXDOMAIN, dnssec_ctx.getDNSSECRRset(name, true),
+ dnssec_ctx.getResultFlags()));
}
ZoneFinder::ResultContext
@@ -897,23 +972,134 @@ DatabaseClient::Finder::findInternal(const Name& name, const RRType& type,
const FoundRRsets found = getRRsets(name.toText(), final_types,
!is_origin, NULL,
type == RRType::ANY());
-
+ FindDNSSECContext dnssec_ctx(*this, options);
if (found.first) {
// Something found at the domain name. Look into it further to get
// the final result.
return (findOnNameResult(name, type, options, is_origin, found, NULL,
- target));
+ target, dnssec_ctx));
} else {
// Did not find anything at all at the domain name, so check for
// subdomains or wildcards.
- return (findNoNameResult(name, type, options, dresult, target));
+ return (findNoNameResult(name, type, options, dresult, target,
+ dnssec_ctx));
}
}
+// The behaviour is inspired by the one in the in-memory implementation.
ZoneFinder::FindNSEC3Result
-DatabaseClient::Finder::findNSEC3(const Name&, bool) {
- isc_throw(NotImplemented, "findNSEC3 is not yet implemented for database "
- "data source");
+DatabaseClient::Finder::findNSEC3(const Name& name, bool recursive) {
+ LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_DATABASE_FINDNSEC3).arg(name).
+ arg(recursive ? "recursive" : "non-recursive");
+
+ // First, validate the input
+ const NameComparisonResult cmp_result(name.compare(getOrigin()));
+ if (cmp_result.getRelation() != NameComparisonResult::EQUAL &&
+ cmp_result.getRelation() != NameComparisonResult::SUBDOMAIN) {
+ isc_throw(OutOfZone, "findNSEC3 attempt for out-of-zone name: " <<
+ name << ", zone: " << getOrigin() << "/" << getClass());
+ }
+
+ // Now, we need to get the NSEC3 params from the apex and create the hash
+ // creator for it.
+ const FoundRRsets nsec3param(getRRsets(getOrigin().toText(),
+ NSEC3PARAM_TYPES(), false));
+ const FoundIterator param(nsec3param.second.find(RRType::NSEC3PARAM()));
+ if (!nsec3param.first || param == nsec3param.second.end()) {
+ // No NSEC3 params? :-(
+ isc_throw(DataSourceError, "findNSEC3 attempt for non NSEC3 signed " <<
+ "zone: " << getOrigin() << "/" << getClass());
+ }
+ // This takes the RRset received from the find method, takes the first RR
+ // in it, casts it to NSEC3PARAM (as it should be that one) and then creates
+ // the hash calculator class from it.
+ const scoped_ptr<NSEC3Hash> calculator(NSEC3Hash::create(
+ dynamic_cast<const generic::NSEC3PARAM&>(
+ param->second->getRdataIterator()->getCurrent())));
+
+ // Few shortcut variables
+ const unsigned olabels(getOrigin().getLabelCount());
+ const unsigned qlabels(name.getLabelCount());
+ const string otext(getOrigin().toText());
+
+ // This will be set to the one covering the query name
+ ConstRRsetPtr covering_proof;
+
+ // We keep stripping the leftmost label until we find something.
+ // In case it is recursive, we'll exit the loop at the first iteration.
+ for (unsigned labels(qlabels); labels >= olabels; -- labels) {
+ const string hash(calculator->calculate(labels == qlabels ? name :
+ name.split(qlabels - labels,
+ labels)));
+ // Get the exact match for the name.
+ LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_DATABASE_FINDNSEC3_TRYHASH).
+ arg(name).arg(labels).arg(hash);
+
+ DatabaseAccessor::IteratorContextPtr
+ context(accessor_->getNSEC3Records(hash, zone_id_));
+
+ if (!context) {
+ isc_throw(Unexpected, "Iterator context null for hash " + hash);
+ }
+
+ const FoundRRsets nsec3(getRRsets(hash + "." + otext, NSEC3_TYPES(),
+ false, NULL, false, context));
+
+ if (nsec3.first) {
+ // We found an exact match against the current label.
+ const FoundIterator it(nsec3.second.find(RRType::NSEC3()));
+ if (it == nsec3.second.end()) {
+ isc_throw(DataSourceError, "Hash " + hash +
+ "exists, but no NSEC3 there");
+ }
+
+ LOG_DEBUG(logger, DBG_TRACE_BASIC,
+ DATASRC_DATABASE_FINDNSEC3_MATCH).arg(name).arg(labels).
+ arg(*it->second);
+ // Yes, we win
+ return (FindNSEC3Result(true, labels, it->second, covering_proof));
+ } else {
+ // There's no exact match. We try a previous one. We must find it
+ // (if the zone is properly signed).
+ const string prevHash(accessor_->findPreviousNSEC3Hash(zone_id_,
+ hash));
+ LOG_DEBUG(logger, DBG_TRACE_BASIC,
+ DATASRC_DATABASE_FINDNSEC3_TRYHASH_PREV).arg(name).
+ arg(labels).arg(prevHash);
+ context = accessor_->getNSEC3Records(prevHash, zone_id_);
+ const FoundRRsets prev_nsec3(getRRsets(prevHash + "." + otext,
+ NSEC3_TYPES(), false, NULL,
+ false, context));
+
+ if (!prev_nsec3.first) {
+ isc_throw(DataSourceError, "Hash " + prevHash + " returned "
+ "from findPreviousNSEC3Hash, but it is empty");
+ }
+ const FoundIterator
+ prev_it(prev_nsec3.second.find(RRType::NSEC3()));
+ if (prev_it == prev_nsec3.second.end()) {
+ isc_throw(DataSourceError, "The previous hash " + prevHash +
+ "exists, but does not contain the NSEC3");
+ }
+
+ covering_proof = prev_it->second;
+ // In case it is recursive, we try to get an exact match a level
+ // up. If it is not recursive, the caller is ok with a covering
+ // one, so we just return it.
+ if (!recursive) {
+ LOG_DEBUG(logger, DBG_TRACE_BASIC,
+ DATASRC_DATABASE_FINDNSEC3_COVER).arg(name).
+ arg(labels).arg(*covering_proof);
+ return (FindNSEC3Result(false, labels, covering_proof,
+ ConstRRsetPtr()));
+ }
+ }
+ }
+
+ // The zone must contain at least the apex and that one should match
+ // exactly. If that doesn't happen, we have a problem.
+ isc_throw(DataSourceError, "recursive findNSEC3 mode didn't stop, likely a "
+ "broken NSEC3 zone: " << otext << "/" << getClass());
}
Name
@@ -1005,28 +1191,44 @@ public:
// At the end of zone
accessor_->commit();
ready_ = false;
- LOG_DEBUG(logger, DBG_TRACE_DETAILED,
- DATASRC_DATABASE_ITERATE_END);
+ LOG_DEBUG(logger, DBG_TRACE_DETAILED, DATASRC_DATABASE_ITERATE_END);
return (ConstRRsetPtr());
}
- const string name_str(name_), rtype_str(rtype_), ttl(ttl_);
- const Name name(name_str);
- const RRType rtype(rtype_str);
- RRsetPtr rrset(new RRset(name, class_, rtype, RRTTL(ttl)));
- while (data_ready_ && name_ == name_str && rtype_str == rtype_) {
- if (ttl_ != ttl) {
- if (ttl < ttl_) {
- ttl_ = ttl;
- rrset->setTTL(RRTTL(ttl));
- }
- LOG_WARN(logger, DATASRC_DATABASE_ITERATE_TTL_MISMATCH).
- arg(name_).arg(class_).arg(rtype_).arg(rrset->getTTL());
- }
- rrset->addRdata(rdata::createRdata(rtype, class_, rdata_));
+ const RRType rtype(rtype_txt_);
+ RRsetPtr rrset(new RRset(Name(name_txt_), class_, rtype,
+ RRTTL(ttl_txt_)));
+ // Remember the first RDATA of the RRset for comparison:
+ const ConstRdataPtr rdata_base = rdata_;
+ while (true) {
+ // Extend the RRset with the new RDATA.
+ rrset->addRdata(rdata_);
+
+ // Retrieve the next record from the database. If we reach the
+ // end of the zone, done; if we were requested to separate all RRs,
+ // just remember this record and return the single RR.
getData();
- if (separate_rrs_) {
+ if (separate_rrs_ || !data_ready_) {
+ break;
+ }
+
+ // Check if the next record belongs to the same RRset. If not,
+ // we are done. The next RDATA has been stored in rdata_, which
+ // is used within this loop (if it belongs to the same RRset) or
+ // in the next call.
+ if (Name(name_txt_) != rrset->getName() ||
+ !isSameType(rtype, rdata_base, RRType(rtype_txt_), rdata_)) {
break;
}
+
+ // Adjust TTL if necessary
+ const RRTTL next_ttl(ttl_txt_);
+ if (next_ttl != rrset->getTTL()) {
+ if (next_ttl < rrset->getTTL()) {
+ rrset->setTTL(next_ttl);
+ }
+ LOG_WARN(logger, DATASRC_DATABASE_ITERATE_TTL_MISMATCH).
+ arg(name_txt_).arg(class_).arg(rtype).arg(rrset->getTTL());
+ }
}
LOG_DEBUG(logger, DBG_TRACE_DETAILED, DATASRC_DATABASE_ITERATE_NEXT).
arg(rrset->getName()).arg(rrset->getType());
@@ -1034,14 +1236,34 @@ public:
}
private:
+ // Check two RDATA types are equivalent. Basically it's a trivial
+ // comparison, but if both are of RRSIG, we should also compare the types
+ // covered.
+ static bool isSameType(RRType type1, ConstRdataPtr rdata1,
+ RRType type2, ConstRdataPtr rdata2)
+ {
+ if (type1 != type2) {
+ return (false);
+ }
+ if (type1 == RRType::RRSIG()) {
+ return (dynamic_cast<const generic::RRSIG&>(*rdata1).typeCovered()
+ == dynamic_cast<const generic::RRSIG&>(*rdata2).
+ typeCovered());
+ }
+ return (true);
+ }
+
// Load next row of data
void getData() {
string data[DatabaseAccessor::COLUMN_COUNT];
data_ready_ = context_->getNext(data);
- name_ = data[DatabaseAccessor::NAME_COLUMN];
- rtype_ = data[DatabaseAccessor::TYPE_COLUMN];
- ttl_ = data[DatabaseAccessor::TTL_COLUMN];
- rdata_ = data[DatabaseAccessor::RDATA_COLUMN];
+ if (data_ready_) {
+ name_txt_ = data[DatabaseAccessor::NAME_COLUMN];
+ rtype_txt_ = data[DatabaseAccessor::TYPE_COLUMN];
+ ttl_txt_ = data[DatabaseAccessor::TTL_COLUMN];
+ rdata_ = rdata::createRdata(RRType(rtype_txt_), class_,
+ data[DatabaseAccessor::RDATA_COLUMN]);
+ }
}
// The dedicated accessor
@@ -1055,10 +1277,12 @@ private:
// Status
bool ready_, data_ready_;
// Data of the next row
- string name_, rtype_, rdata_, ttl_;
+ string name_txt_, rtype_txt_, ttl_txt_;
+ // RDATA of the next row
+ ConstRdataPtr rdata_;
// Whether to modify differing TTL values, or treat a different TTL as
// a different RRset
- bool separate_rrs_;
+ const bool separate_rrs_;
};
}
diff --git a/src/lib/datasrc/database.h b/src/lib/datasrc/database.h
index 24953c9..8083322 100644
--- a/src/lib/datasrc/database.h
+++ b/src/lib/datasrc/database.h
@@ -824,6 +824,7 @@ public:
DatabaseClient(isc::dns::RRClass rrclass,
boost::shared_ptr<DatabaseAccessor> accessor);
+
/// \brief Corresponding ZoneFinder implementation
///
/// The zone finder implementation for database data sources. Similarly
@@ -933,6 +934,7 @@ public:
boost::shared_ptr<DatabaseAccessor> accessor_;
const int zone_id_;
const isc::dns::Name origin_;
+
/// \brief Shortcut name for the result of getRRsets
typedef std::pair<bool, std::map<dns::RRType, dns::RRsetPtr> >
FoundRRsets;
@@ -975,6 +977,9 @@ public:
/// ones requested by types. It also puts a NULL pointer under the
/// ANY type into the result, if it finds any RRs at all, to easy the
/// identification of success.
+ /// \param srcContext This can be set to non-NULL value to override the
+ /// iterator context used for obtaining the data. This can be used,
+ /// for example, to get data from the NSEC3 namespace.
/// \return A pair, where the first element indicates if the domain
/// contains any RRs at all (not only the requested, it may happen
/// this is set to true, but the second part is empty). The second
@@ -986,7 +991,122 @@ public:
FoundRRsets getRRsets(const std::string& name,
const WantedTypes& types, bool check_ns,
const std::string* construct_name = NULL,
- bool any = false);
+ bool any = false,
+ DatabaseAccessor::IteratorContextPtr srcContext =
+ DatabaseAccessor::IteratorContextPtr());
+
+ /// \brief DNSSEC related context for ZoneFinder::findInternal.
+ ///
+ /// This class is a helper for the ZoneFinder::findInternal method,
+ /// encapsulating DNSSEC related information and processing logic.
+ /// Specifically, it tells the finder whether the zone under search
+ /// is DNSSEC signed or not, and if it is, whether it's with NSEC or
+ /// with NSEC3. It also provides a RRset DNSSEC proof RRset for some
+ /// specific situations (in practice, this means an NSEC RRs for
+ /// negative proof when they are needed and expected).
+ ///
+ /// The purpose of this class is to keep the main finder implementation
+ /// unaware of DNSSEC related details. It's also intended to help
+ /// avoid unnecessary lookup for DNSSEC proof RRsets; this class
+ /// doesn't look into the DB for these RRsets unless it's known to
+ /// be needed. The same optimization could be implemented in the
+ /// main code, but it will result in duplicate similar code logic
+ /// and make the code more complicated. By encapsulating and unifying
+ /// the logic in a single separate class, we can keep the main
+ /// search logic readable.
+ class FindDNSSECContext {
+ public:
+ /// \brief Constructor for FindDNSSECContext class.
+ ///
+ /// This constructor doesn't involve any expensive operation such
+ /// as database lookups. It only initializes some internal
+ /// states (in a cheap way) and remembers if DNSSEC proof
+ /// is requested.
+ ///
+ /// \param finder The Finder for the findInternal that uses this
+ /// context.
+ /// \param options Find options given to the finder.
+ FindDNSSECContext(Finder& finder, const FindOptions options);
+
+ /// \brief Return DNSSEC related result flags for the context.
+ ///
+ /// This method returns a FindResultFlags value related to
+ /// DNSSEC, based on the context. If DNSSEC proof is requested
+ /// and the zone is signed with NSEC/NSEC3, it returns
+ /// RESULT_NSEC_SIGNED/RESULT_NSEC3_SIGNED, respectively;
+ /// otherwise it returns RESULT_DEFAULT. So the caller can simply
+ /// take a logical OR for the returned value of this method and
+ /// whatever other flags it's going to set, without knowing
+ /// DNSSEC specific information.
+ ///
+ /// If it's not yet identified whether and how the zone is DNSSEC
+ /// signed at the time of the call, it now detects that via
+ /// database lookups (if necessary). (And this is because why
+ /// this method cannot be a const member function).
+ ZoneFinder::FindResultFlags getResultFlags();
+
+ /// \brief Get DNSSEC negative proof for a given name.
+ ///
+ /// If the zone is considered NSEC-signed and the context
+ /// requested DNSSEC proofs, this method tries to find NSEC RRs
+ /// for the give name. If \c covering is true, it means a
+ /// "no name" proof is requested, so it calls findPreviousName on
+ /// the given name and extracts an NSEC record on the result;
+ /// otherwise it tries to get NSEC RRs for the given name. If
+ /// the NSEC is found, this method returns it; otherwise it returns
+ /// NULL.
+ ///
+ /// In all other cases this method simply returns NULL.
+ ///
+ /// \param name The name which the NSEC RRset belong to.
+ /// \param covering true if a covering NSEC is required; false if
+ /// a matching NSEC is required.
+ /// \return Any found DNSSEC proof RRset or NULL
+ isc::dns::ConstRRsetPtr getDNSSECRRset(
+ const isc::dns::Name& name, bool covering);
+
+ /// \brief Get DNSSEC negative proof for a given name.
+ ///
+ /// If the zone is considered NSEC-signed and the context
+ /// requested DNSSEC proofs, this method tries to find NSEC RRset
+ /// from the given set (\c found_set) and returns it if found;
+ /// in other cases this method simply returns NULL.
+ ///
+ /// \param found_set The RRset which may contain an NSEC RRset.
+ /// \return Any found DNSSEC proof RRset or NULL
+ isc::dns::ConstRRsetPtr getDNSSECRRset(const FoundRRsets&
+ found_set);
+
+ private:
+ /// \brief Returns whether the zone is signed with NSEC3.
+ ///
+ /// This method returns true if the zone for the finder that
+ /// uses this context is considered DNSSEC signed with NSEC3;
+ /// otherwise it returns false. If it's not yet detected,
+ /// this method now detects that via database lookups (if
+ /// necessary).
+ bool isNSEC3();
+
+ /// \brief Returns whether the zone is signed with NSEC.
+ ///
+ /// This is similar to isNSEC3(), but works for NSEC.
+ bool isNSEC();
+
+ /// \brief Probe into the database to see if/how the zone is
+ /// signed.
+ ///
+ /// This is a subroutine of isNSEC3() and isNSEC(), and performs
+ /// delayed database probe to detect whether the zone used by
+ /// the finder is DNSSEC signed, and if it is, with NSEC or NSEC3.
+ void probe();
+
+ DatabaseClient::Finder& finder_;
+ const bool need_dnssec_;
+
+ bool is_nsec3_;
+ bool is_nsec_;
+ bool probed_;
+ };
/// \brief Search result of \c findDelegationPoint().
///
@@ -1090,7 +1210,8 @@ public:
/// \param target If the type happens to be ANY, it will insert all
/// the RRsets of the found name (if any is found) here instead
/// of being returned by the result.
- ///
+ /// \param dnssec_ctx The dnssec context, it is a DNSSEC wrapper for
+ /// find function.
/// \return Tuple holding the result of the search - the RRset of the
/// wildcard records matching the name, together with a status
/// indicating the match type (e.g. CNAME at the wildcard
@@ -1098,12 +1219,12 @@ public:
/// success due to an exact match). Also returned if there
/// is no match is an indication as to whether there was an
/// NXDOMAIN or an NXRRSET.
- ResultContext findWildcardMatch(
- const isc::dns::Name& name,
- const isc::dns::RRType& type,
- const FindOptions options,
- const DelegationSearchResult& dresult,
- std::vector<isc::dns::ConstRRsetPtr>* target);
+ ResultContext findWildcardMatch(const isc::dns::Name& name,
+ const isc::dns::RRType& type,
+ const FindOptions options,
+ const DelegationSearchResult& dresult,
+ std::vector<isc::dns::ConstRRsetPtr>*
+ target, FindDNSSECContext& dnssec_ctx);
/// \brief Handle matching results for name
///
@@ -1136,7 +1257,9 @@ public:
/// it's NULL in the case of non wildcard match.
/// \param target When the query is any, this must be set to a vector
/// where the result will be stored.
- ///
+ /// \param dnssec_ctx The dnssec context, it is a DNSSEC wrapper for
+ /// find function.
+
/// \return Tuple holding the result of the search - the RRset of the
/// wildcard records matching the name, together with a status
/// indicating the match type (corresponding to the each of
@@ -1150,7 +1273,7 @@ public:
const FoundRRsets& found,
const std::string* wildname,
std::vector<isc::dns::ConstRRsetPtr>*
- target);
+ target, FindDNSSECContext& dnssec_ctx);
/// \brief Handle no match for name
///
@@ -1175,7 +1298,8 @@ public:
/// \param target If the query is for type ANY, the successfull result,
/// if there happens to be one, will be returned through the
/// parameter, as it doesn't fit into the result.
- ///
+ /// \param dnssec_ctx The dnssec context, it is a DNSSEC wrapper for
+ /// find function.
/// \return Tuple holding the result of the search - the RRset of the
/// wildcard records matching the name, together with a status
/// indicating the match type (e.g. CNAME at the wildcard
@@ -1186,7 +1310,7 @@ public:
FindOptions options,
const DelegationSearchResult& dresult,
std::vector<isc::dns::ConstRRsetPtr>*
- target);
+ target, FindDNSSECContext& dnssec_ctx);
/// Logs condition and creates result
///
@@ -1227,13 +1351,6 @@ public:
/// \return true if the name has subdomains, false if not.
bool hasSubdomains(const std::string& name);
- /// \brief Get the NSEC covering a name.
- ///
- /// This one calls findPreviousName on the given name and extracts an
- /// NSEC record on the result. It handles various error cases. The
- /// method exists to share code present at more than one location.
- dns::ConstRRsetPtr findNSECCover(const dns::Name& name);
-
/// \brief Convenience type shortcut.
///
/// To find stuff in the result of getRRsets.
diff --git a/src/lib/datasrc/datasrc_messages.mes b/src/lib/datasrc/datasrc_messages.mes
index ef46cb5..a9870d6 100644
--- a/src/lib/datasrc/datasrc_messages.mes
+++ b/src/lib/datasrc/datasrc_messages.mes
@@ -75,6 +75,35 @@ The datasource tried to provide an NSEC proof that the named domain does not
exist, but the database backend doesn't support DNSSEC. No proof is included
in the answer as a result.
+% DATASRC_DATABASE_FINDNSEC3 Looking for NSEC3 for %1 in %2 mode
+Debug information. A search in an database data source for NSEC3 that
+matches or covers the given name is being started.
+
+% DATASRC_DATABASE_FINDNSEC3_COVER found a covering NSEC3 for %1: %2
+Debug information. An NSEC3 that covers the given name is found and
+being returned. The found NSEC3 RRset is also displayed.
+
+% DATASRC_DATABASE_FINDNSEC3_MATCH found a matching NSEC3 for %1 at label count %2: %3
+Debug information. An NSEC3 that matches (a possibly superdomain of)
+the given name is found and being returned. When the shown label
+count is smaller than that of the given name, the matching NSEC3 is
+for a superdomain of the given name (see DATASRC_DATABSE_FINDNSEC3_TRYHASH).
+The found NSEC3 RRset is also displayed.
+
+% DATASRC_DATABASE_FINDNSEC3_TRYHASH looking for NSEC3 for %1 at label count %2 (hash %3)
+Debug information. In an attempt of finding an NSEC3 for the give name,
+(a possibly superdomain of) the name is hashed and searched for in the
+NSEC3 name space. When the shown label count is smaller than that of the
+shown name, the search tries the superdomain name that share the shown
+(higher) label count of the shown name (e.g., for
+www.example.com. with shown label count of 3, example.com. is being
+tried, as "." is 1 label long).
+
+% DATASRC_DATABASE_FINDNSEC3_TRYHASH_PREV looking for previous NSEC3 for %1 at label count %2 (hash %3)
+Debug information. An exact match on hash (see
+DATASRC_DATABASE_FINDNSEC3_TRYHASH) was unsuccessful. We get the previous hash
+to that one instead.
+
% DATASRC_DATABASE_FIND_RECORDS looking in datasource %1 for record %2/%3/%4
Debug information. The database data source is looking up records with the given
name and type in the database.
@@ -145,10 +174,12 @@ While iterating through the zone, the program extracted next RRset from it.
The name and RRtype of the RRset is indicated in the message.
% DATASRC_DATABASE_ITERATE_TTL_MISMATCH TTL values differ for RRs of %1/%2/%3, setting to %4
-While iterating through the zone, the time to live for RRs of the given RRset
-were found to be different. This isn't allowed on the wire and is considered
-an error, so we set it to the lowest value we found (but we don't modify the
-database). The data in database should be checked and fixed.
+While iterating through the zone, the time to live for RRs of the
+given RRset were found to be different. Since an RRset cannot have
+multiple TTLs, we set it to the lowest value we found (but we don't
+modify the database). This is what the client would do when such RRs
+were given in a DNS response according to RFC2181. The data in
+database should be checked and fixed.
% DATASRC_DATABASE_JOURNALREADER_END %1/%2 on %3 from %4 to %5
This is a debug message indicating that the program (successfully)
diff --git a/src/lib/datasrc/factory.h b/src/lib/datasrc/factory.h
index 9d0a762..f3ca397 100644
--- a/src/lib/datasrc/factory.h
+++ b/src/lib/datasrc/factory.h
@@ -163,7 +163,7 @@ public:
///
/// \return Reference to the DataSourceClient instance contained in this
/// container.
- DataSourceClient& getInstance() { return *instance_; }
+ DataSourceClient& getInstance() { return (*instance_); }
private:
DataSourceClient* instance_;
diff --git a/src/lib/datasrc/memory_datasrc.cc b/src/lib/datasrc/memory_datasrc.cc
index 4cfadfc..c19d5ae 100644
--- a/src/lib/datasrc/memory_datasrc.cc
+++ b/src/lib/datasrc/memory_datasrc.cc
@@ -29,6 +29,7 @@
#include <datasrc/data_source.h>
#include <datasrc/factory.h>
+#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/bind.hpp>
@@ -53,6 +54,9 @@ using namespace internal;
namespace {
// Some type aliases
+// A functor type used for loading.
+typedef boost::function<void(ConstRRsetPtr)> LoadCallback;
+
// RRset specified for this implementation
typedef boost::shared_ptr<internal::RBNodeRRset> RBNodeRRsetPtr;
typedef boost::shared_ptr<const internal::RBNodeRRset> ConstRBNodeRRsetPtr;
@@ -761,6 +765,17 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
// The actual zone data
scoped_ptr<ZoneData> zone_data_;
+ // Common process for zone load.
+ // rrset_installer is a functor that takes another functor as an argument,
+ // and expected to call the latter for each RRset of the zone. How the
+ // sequence of the RRsets is generated depends on the internal
+ // details of the loader: either from a textual master file or from
+ // another data source.
+ // filename is the file name of the master file or empty if the zone is
+ // loaded from another data source.
+ void load(const string& filename,
+ boost::function<void(LoadCallback)> rrset_installer);
+
// Add the necessary magic for any wildcard contained in 'name'
// (including itself) to be found in the zone.
//
@@ -1551,24 +1566,16 @@ addWildAdditional(RBNodeRRset* rrset, ZoneData* zone_data) {
}
void
-InMemoryZoneFinder::load(const string& filename) {
- LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_LOAD).arg(getOrigin()).
- arg(filename);
- // Load it into temporary zone data. As we build the zone, we record
- // the (RBNode)RRsets that needs to be associated with additional
- // information in 'need_additionals'.
+InMemoryZoneFinder::InMemoryZoneFinderImpl::load(
+ const string& filename,
+ boost::function<void(LoadCallback)> rrset_installer)
+{
vector<RBNodeRRset*> need_additionals;
- scoped_ptr<ZoneData> tmp(new ZoneData(getOrigin()));
+ scoped_ptr<ZoneData> tmp(new ZoneData(origin_));
- masterLoad(filename.c_str(), getOrigin(), getClass(),
- boost::bind(&InMemoryZoneFinderImpl::addFromLoad, impl_,
- _1, tmp.get(), &need_additionals));
+ rrset_installer(boost::bind(&InMemoryZoneFinderImpl::addFromLoad, this,
+ _1, tmp.get(), &need_additionals));
- // For each RRset in need_additionals, identify the corresponding
- // RBnode for additional processing and associate it in the RRset.
- // If some additional names in an RRset RDATA as additional need wildcard
- // expansion, we'll remember them in a separate vector, and handle them
- // with addWildAdditional.
vector<RBNodeRRset*> wild_additionals;
for_each(need_additionals.begin(), need_additionals.end(),
boost::bind(addAdditional, _1, tmp.get(), &wild_additionals));
@@ -1584,16 +1591,77 @@ InMemoryZoneFinder::load(const string& filename) {
if (tmp->origin_data_->getData()->find(RRType::NSEC3PARAM()) ==
tmp->origin_data_->getData()->end()) {
LOG_WARN(logger, DATASRC_MEM_NO_NSEC3PARAM).
- arg(getOrigin()).arg(getClass());
+ arg(origin_).arg(zone_class_);
}
}
// If it went well, put it inside
- impl_->file_name_ = filename;
- tmp.swap(impl_->zone_data_);
+ file_name_ = filename;
+ tmp.swap(zone_data_);
// And let the old data die with tmp
}
+namespace {
+// A wrapper for dns::masterLoad used by load() below. Essentially it
+// converts the two callback types. Note the mostly redundant wrapper of
+// boost::bind. It converts function<void(ConstRRsetPtr)> to
+// function<void(RRsetPtr)> (masterLoad() expects the latter). SunStudio
+// doesn't seem to do this conversion if we just pass 'callback'.
+void
+masterLoadWrapper(const char* const filename, const Name& origin,
+ const RRClass& zone_class, LoadCallback callback)
+{
+ masterLoad(filename, origin, zone_class, boost::bind(callback, _1));
+}
+
+// The installer called from Impl::load() for the iterator version of load().
+void
+generateRRsetFromIterator(ZoneIterator* iterator, LoadCallback callback) {
+ ConstRRsetPtr rrset;
+ vector<ConstRRsetPtr> rrsigs; // placeholder for RRSIGs until "commitable".
+
+ // The current internal implementation assumes an RRSIG is always added
+ // after the RRset they cover. So we store any RRSIGs in 'rrsigs' until
+ // it's safe to add them; based on our assumption if the owner name
+ // changes, all covered RRsets of the previous name should have been
+ // installed and any pending RRSIGs can be added at that point. RRSIGs
+ // of the last name from the iterator must be added separately.
+ while ((rrset = iterator->getNextRRset()) != NULL) {
+ if (!rrsigs.empty() && rrset->getName() != rrsigs[0]->getName()) {
+ BOOST_FOREACH(ConstRRsetPtr sig_rrset, rrsigs) {
+ callback(sig_rrset);
+ }
+ rrsigs.clear();
+ }
+ if (rrset->getType() == RRType::RRSIG()) {
+ rrsigs.push_back(rrset);
+ } else {
+ callback(rrset);
+ }
+ }
+
+ BOOST_FOREACH(ConstRRsetPtr sig_rrset, rrsigs) {
+ callback(sig_rrset);
+ }
+}
+}
+
+void
+InMemoryZoneFinder::load(const string& filename) {
+ LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_LOAD).arg(getOrigin()).
+ arg(filename);
+
+ impl_->load(filename,
+ boost::bind(masterLoadWrapper, filename.c_str(), getOrigin(),
+ getClass(), _1));
+}
+
+void
+InMemoryZoneFinder::load(ZoneIterator& iterator) {
+ impl_->load(string(),
+ boost::bind(generateRRsetFromIterator, &iterator, _1));
+}
+
void
InMemoryZoneFinder::swap(InMemoryZoneFinder& zone_finder) {
LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_SWAP).arg(getOrigin()).
diff --git a/src/lib/datasrc/memory_datasrc.h b/src/lib/datasrc/memory_datasrc.h
index fdb3786..c687d1b 100644
--- a/src/lib/datasrc/memory_datasrc.h
+++ b/src/lib/datasrc/memory_datasrc.h
@@ -188,6 +188,26 @@ public:
/// configuration reloading is written.
void load(const std::string& filename);
+ /// \brief Load zone from another data source.
+ ///
+ /// This is similar to the other version, but zone's RRsets are provided
+ /// by an iterator of another data source. On successful load, the
+ /// internal filename will be cleared.
+ ///
+ /// This implementation assumes the iterator produces combined RRsets,
+ /// that is, there should exactly one RRset for the same owner name and
+ /// RR type. This means the caller is expected to create the iterator
+ /// with \c separate_rrs being \c false. This implementation also assumes
+ /// RRsets of different names are not mixed; so if the iterator produces
+ /// an RRset of a different name than that of the previous RRset, that
+ /// previous name must never appear in the subsequent sequence of RRsets.
+ /// Note that the iterator API does not ensure this. If the underlying
+ /// implementation does not follow it, load() will fail. Note, however,
+ /// that this whole interface is tentative. in-memory zone loading will
+ /// have to be revisited fundamentally, and at that point this restriction
+ /// probably won't matter.
+ void load(ZoneIterator& iterator);
+
/// Exchanges the content of \c this zone finder with that of the given
/// \c zone_finder.
///
diff --git a/src/lib/datasrc/sqlite3_accessor_link.cc b/src/lib/datasrc/sqlite3_accessor_link.cc
index 81ac6b5..c064e0f 100644
--- a/src/lib/datasrc/sqlite3_accessor_link.cc
+++ b/src/lib/datasrc/sqlite3_accessor_link.cc
@@ -82,13 +82,15 @@ createInstance(isc::data::ConstElementPtr config, std::string& error) {
error = "Configuration error: " + errors->str();
return (NULL);
}
- std::string dbfile = config->get(CONFIG_ITEM_DATABASE_FILE)->stringValue();
+ const std::string dbfile =
+ config->get(CONFIG_ITEM_DATABASE_FILE)->stringValue();
try {
boost::shared_ptr<DatabaseAccessor> sqlite3_accessor(
new SQLite3Accessor(dbfile, "IN")); // XXX: avoid hardcode RR class
return (new DatabaseClient(isc::dns::RRClass::IN(), sqlite3_accessor));
} catch (const std::exception& exc) {
- error = std::string("Error creating sqlite3 datasource: ") + exc.what();
+ error = std::string("Error creating sqlite3 datasource: ") +
+ exc.what();
return (NULL);
} catch (...) {
error = std::string("Error creating sqlite3 datasource, "
diff --git a/src/lib/datasrc/tests/Makefile.am b/src/lib/datasrc/tests/Makefile.am
index ac20e34..90fb3e4 100644
--- a/src/lib/datasrc/tests/Makefile.am
+++ b/src/lib/datasrc/tests/Makefile.am
@@ -48,6 +48,7 @@ run_unittests_SOURCES += datasrc_unittest.cc
run_unittests_SOURCES += static_unittest.cc
run_unittests_SOURCES += query_unittest.cc
run_unittests_SOURCES += cache_unittest.cc
+run_unittests_SOURCES += test_client.h test_client.cc
run_unittests_SOURCES += test_datasrc.h test_datasrc.cc
run_unittests_SOURCES += rbtree_unittest.cc
run_unittests_SOURCES += logger_unittest.cc
@@ -58,6 +59,7 @@ run_unittests_SOURCES += sqlite3_accessor_unittest.cc
run_unittests_SOURCES += memory_datasrc_unittest.cc
run_unittests_SOURCES += rbnode_rrset_unittest.cc
run_unittests_SOURCES += zone_finder_context_unittest.cc
+run_unittests_SOURCES += faked_nsec3.h faked_nsec3.cc
# We need the actual module implementation in the tests (they are not part
# of libdatasrc)
@@ -105,7 +107,6 @@ EXTRA_DIST += testdata/mkbrokendb.c
EXTRA_DIST += testdata/root.zone
EXTRA_DIST += testdata/rrset_toWire1
EXTRA_DIST += testdata/rrset_toWire2
-EXTRA_DIST += testdata/rwtest.sqlite3
EXTRA_DIST += testdata/sql1.example.com.signed
EXTRA_DIST += testdata/sql2.example.com.signed
EXTRA_DIST += testdata/test-root.sqlite3
diff --git a/src/lib/datasrc/tests/database_unittest.cc b/src/lib/datasrc/tests/database_unittest.cc
index eead1e7..5b3a5dc 100644
--- a/src/lib/datasrc/tests/database_unittest.cc
+++ b/src/lib/datasrc/tests/database_unittest.cc
@@ -12,12 +12,15 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
+#include "faked_nsec3.h"
+
#include <exceptions/exceptions.h>
#include <dns/masterload.h>
#include <dns/name.h>
#include <dns/rrttl.h>
#include <dns/rrset.h>
+#include <dns/nsec3hash.h>
#include <exceptions/exceptions.h>
#include <datasrc/database.h>
@@ -46,6 +49,7 @@ using boost::dynamic_pointer_cast;
using boost::lexical_cast;
using namespace isc::dns;
using namespace isc::testutils;
+using namespace isc::datasrc::test;
namespace {
@@ -169,7 +173,10 @@ const char* const TEST_RECORDS[][5] = {
"1234 3600 1800 2419200 7200" },
{"example.org.", "NS", "3600", "", "ns.example.com."},
{"example.org.", "A", "3600", "", "192.0.2.1"},
- {"example.org.", "NSEC", "3600", "", "acnamesig1.example.org. NS A NSEC RRSIG"},
+ // Note that the RDATA text is "normalized", i.e., identical to what
+ // Rdata::toText() would produce. some tests rely on that behavior.
+ {"example.org.", "NSEC", "3600", "",
+ "acnamesig1.example.org. A NS RRSIG NSEC"},
{"example.org.", "RRSIG", "3600", "", "SOA 5 3 3600 20000101000000 "
"20000201000000 12345 example.org. FAKEFAKEFAKE"},
{"example.org.", "RRSIG", "3600", "", "NSEC 5 3 3600 20000101000000 "
@@ -208,9 +215,15 @@ const char* const TEST_RECORDS[][5] = {
};
// FIXME: Taken from a different test. Fill with proper data when creating a test.
-const char* const TEST_NSEC3_RECORDS[][5] = {
- {"1BB7SO0452U1QHL98UISNDD9218GELR5", "NSEC3", "3600", "", "1 0 10 FEEDABEE 4KLSVDE8KH8G95VU68R7AHBE1CPQN38J"},
- {"1BB7SO0452U1QHL98UISNDD9218GELR5", "RRSIG", "3600", "", "NSEC3 5 4 7200 20100410172647 20100311172647 63192 example.org. gNIVj4T8t51fEU6kOPpvK7HOGBFZGbalN5ZK mInyrww6UWZsUNdw07ge6/U6HfG+/s61RZ/L is2M6yUWHyXbNbj/QqwqgadG5dhxTArfuR02 xP600x0fWX8LXzW4yLMdKVxGbzYT+vvGz71o 8gHSY5vYTtothcZQa4BMKhmGQEk="},
+const char* TEST_NSEC3_RECORDS[][5] = {
+ {apex_hash, "NSEC3", "300", "", "1 1 12 AABBCCDD 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG"},
+ {apex_hash, "RRSIG", "300", "", "NSEC3 5 4 7200 20100410172647 20100311172647 63192 example.org. gNIVj4T8t51fEU6kOPpvK7HOGBFZGbalN5ZK mInyrww6UWZsUNdw07ge6/U6HfG+/s61RZ/L is2M6yUWHyXbNbj/QqwqgadG5dhxTArfuR02 xP600x0fWX8LXzW4yLMdKVxGbzYT+vvGz71o 8gHSY5vYTtothcZQa4BMKhmGQEk="},
+ {ns1_hash, "NSEC3", "300", "", "1 1 12 AABBCCDD 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG"},
+ {ns1_hash, "RRSIG", "300", "", "NSEC3 5 4 7200 20100410172647 20100311172647 63192 example.org. gNIVj4T8t51fEU6kOPpvK7HOGBFZGbalN5ZK mInyrww6UWZsUNdw07ge6/U6HfG+/s61RZ/L is2M6yUWHyXbNbj/QqwqgadG5dhxTArfuR02 xP600x0fWX8LXzW4yLMdKVxGbzYT+vvGz71o 8gHSY5vYTtothcZQa4BMKhmGQEk="},
+ {w_hash, "NSEC3", "300", "", "1 1 12 AABBCCDD 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG"},
+ {w_hash, "RRSIG", "300", "", "NSEC3 5 4 7200 20100410172647 20100311172647 63192 example.org. gNIVj4T8t51fEU6kOPpvK7HOGBFZGbalN5ZK mInyrww6UWZsUNdw07ge6/U6HfG+/s61RZ/L is2M6yUWHyXbNbj/QqwqgadG5dhxTArfuR02 xP600x0fWX8LXzW4yLMdKVxGbzYT+vvGz71o 8gHSY5vYTtothcZQa4BMKhmGQEk="},
+ {zzz_hash, "NSEC3", "300", "", "1 1 12 AABBCCDD 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG"},
+ {zzz_hash, "RRSIG", "300", "", "NSEC3 5 4 7200 20100410172647 20100311172647 63192 example.org. gNIVj4T8t51fEU6kOPpvK7HOGBFZGbalN5ZK mInyrww6UWZsUNdw07ge6/U6HfG+/s61RZ/L is2M6yUWHyXbNbj/QqwqgadG5dhxTArfuR02 xP600x0fWX8LXzW4yLMdKVxGbzYT+vvGz71o 8gHSY5vYTtothcZQa4BMKhmGQEk="},
{NULL, NULL, NULL, NULL, NULL}
};
@@ -511,62 +524,46 @@ private:
}
// Return faked data for tests
- switch (step ++) {
- case 0:
- data[DatabaseAccessor::NAME_COLUMN] = "example.org";
- data[DatabaseAccessor::TYPE_COLUMN] = "A";
- data[DatabaseAccessor::TTL_COLUMN] = "3600";
- data[DatabaseAccessor::RDATA_COLUMN] = "192.0.2.1";
- return (true);
- case 1:
- data[DatabaseAccessor::NAME_COLUMN] = "example.org";
- data[DatabaseAccessor::TYPE_COLUMN] = "SOA";
- data[DatabaseAccessor::TTL_COLUMN] = "3600";
- data[DatabaseAccessor::RDATA_COLUMN] = "ns1.example.org. admin.example.org. "
- "1234 3600 1800 2419200 7200";
- return (true);
- case 2:
- data[DatabaseAccessor::NAME_COLUMN] = "x.example.org";
- data[DatabaseAccessor::TYPE_COLUMN] = "A";
- data[DatabaseAccessor::TTL_COLUMN] = "300";
- data[DatabaseAccessor::RDATA_COLUMN] = "192.0.2.1";
- return (true);
- case 3:
- data[DatabaseAccessor::NAME_COLUMN] = "x.example.org";
- data[DatabaseAccessor::TYPE_COLUMN] = "A";
- data[DatabaseAccessor::TTL_COLUMN] = "300";
- data[DatabaseAccessor::RDATA_COLUMN] = "192.0.2.2";
- return (true);
- case 4:
- data[DatabaseAccessor::NAME_COLUMN] = "x.example.org";
- data[DatabaseAccessor::TYPE_COLUMN] = "AAAA";
- data[DatabaseAccessor::TTL_COLUMN] = "300";
- data[DatabaseAccessor::RDATA_COLUMN] = "2001:db8::1";
- return (true);
- case 5:
- data[DatabaseAccessor::NAME_COLUMN] = "x.example.org";
- data[DatabaseAccessor::TYPE_COLUMN] = "AAAA";
- data[DatabaseAccessor::TTL_COLUMN] = "300";
- data[DatabaseAccessor::RDATA_COLUMN] = "2001:db8::2";
- return (true);
- case 6:
- data[DatabaseAccessor::NAME_COLUMN] = "ttldiff.example.org";
- data[DatabaseAccessor::TYPE_COLUMN] = "A";
- data[DatabaseAccessor::TTL_COLUMN] = "300";
- data[DatabaseAccessor::RDATA_COLUMN] = "192.0.2.1";
- return (true);
- case 7:
- data[DatabaseAccessor::NAME_COLUMN] = "ttldiff.example.org";
- data[DatabaseAccessor::TYPE_COLUMN] = "A";
- data[DatabaseAccessor::TTL_COLUMN] = "600";
- data[DatabaseAccessor::RDATA_COLUMN] = "192.0.2.2";
- return (true);
- default:
- ADD_FAILURE() <<
- "Request past the end of iterator context";
- case 8:
- return (false);
+ // This is the sequence of zone data in the order of appearance
+ // in the returned sequence from this iterator.
+ typedef const char* ColumnText[4];
+ const ColumnText zone_data[] = {
+ // A couple of basic RRs at the zone origin.
+ {"example.org", "A", "3600", "192.0.2.1"},
+ {"example.org", "SOA", "3600", "ns1.example.org. "
+ "admin.example.org. 1234 3600 1800 2419200 7200"},
+ // RRsets sharing the same owner name with multiple RRs.
+ {"x.example.org", "A", "300", "192.0.2.1"},
+ {"x.example.org", "A", "300", "192.0.2.2"},
+ {"x.example.org", "AAAA", "300", "2001:db8::1"},
+ {"x.example.org", "AAAA", "300", "2001:db8::2"},
+ // RRSIGs. Covered types are different and these two should
+ // be distinguished.
+ {"x.example.org", "RRSIG", "300",
+ "A 5 3 3600 20000101000000 20000201000000 12345 "
+ "example.org. FAKEFAKEFAKE"},
+ {"x.example.org", "RRSIG", "300",
+ "AAAA 5 3 3600 20000101000000 20000201000000 12345 "
+ "example.org. FAKEFAKEFAKEFAKE"},
+ // Mixture of different TTLs. Covering both cases of small
+ // then large and large then small. In either case the smaller
+ // TTL should win.
+ {"ttldiff.example.org", "A", "300", "192.0.2.1"},
+ {"ttldiff.example.org", "A", "600", "192.0.2.2"},
+ {"ttldiff2.example.org", "AAAA", "600", "2001:db8::1"},
+ {"ttldiff2.example.org", "AAAA", "300", "2001:db8::2"}};
+ const size_t num_rrs = sizeof(zone_data) / sizeof(zone_data[0]);
+ if (step > num_rrs) {
+ ADD_FAILURE() << "Request past the end of iterator context";
+ } else if (step < num_rrs) {
+ data[DatabaseAccessor::NAME_COLUMN] = zone_data[step][0];
+ data[DatabaseAccessor::TYPE_COLUMN] = zone_data[step][1];
+ data[DatabaseAccessor::TTL_COLUMN] = zone_data[step][2];
+ data[DatabaseAccessor::RDATA_COLUMN] = zone_data[step][3];
+ ++step;
+ return (true);
}
+ return (false);
}
};
class EmptyIteratorContext : public IteratorContext {
@@ -1062,6 +1059,31 @@ private:
}
addCurHash(prev_name);
}
+
+public:
+ // This adds the NSEC3PARAM into the apex, so we can perform some NSEC3
+ // tests. Note that the NSEC3 namespace is available in other tests, but
+ // it should not be accessed at that time.
+ void enableNSEC3() {
+ // We place the signature first, so it's in the block with the other
+ // signatures
+ vector<string> signature;
+ signature.push_back("RRSIG");
+ signature.push_back("3600");
+ signature.push_back("");
+ signature.push_back("NSEC3PARAM 5 3 3600 20000101000000 20000201000000 "
+ "12345 example.org. FAKEFAKEFAKE");
+ signature.push_back("exmaple.org.");
+ (*readonly_records_)["example.org."].push_back(signature);
+ // Now the NSEC3 param itself
+ vector<string> param;
+ param.push_back("NSEC3PARAM");
+ param.push_back("3600");
+ param.push_back("");
+ param.push_back("1 0 12 aabbccdd");
+ param.push_back("example.org.");
+ (*readonly_records_)["example.org."].push_back(param);
+ }
};
// This tests the default getRecords behaviour, throwing NotImplemented
@@ -1115,6 +1137,11 @@ public:
"FAKEFAKEFAKE"));
}
+ ~ DatabaseClientTest() {
+ // Make sure we return the default creator no matter if we set it or not
+ setNSEC3HashCreator(NULL);
+ }
+
/*
* We initialize the client from a function, so we can call it multiple
* times per test.
@@ -1128,7 +1155,7 @@ public:
// probably move this to some specialized templated method specific
// to SQLite3 (or for even a longer term we should add an API to
// purge the diffs table).
- const char* const install_cmd = INSTALL_PROG " " TEST_DATA_DIR
+ const char* const install_cmd = INSTALL_PROG " " TEST_DATA_COMMONDIR
"/rwtest.sqlite3 " TEST_DATA_BUILDDIR
"/rwtest.sqlite3.copied";
if (system(install_cmd) != 0) {
@@ -1275,6 +1302,9 @@ public:
const std::vector<std::string> empty_rdatas_; // for NXRRSET/NXDOMAIN
std::vector<std::string> expected_rdatas_;
std::vector<std::string> expected_sig_rdatas_;
+
+ // A creator for use in several NSEC3 related tests.
+ TestNSEC3HashCreator test_nsec3_hash_creator_;
};
class TestSQLite3Accessor : public SQLite3Accessor {
@@ -1405,7 +1435,7 @@ checkRRset(isc::dns::ConstRRsetPtr rrset,
rrsetCheck(expected_rrset, rrset);
}
-// Iterate through a zone
+// Iterate through a zone, common case
TYPED_TEST(DatabaseClientTest, iterator) {
ZoneIteratorPtr it(this->client_->getIterator(Name("example.org")));
ConstRRsetPtr rrset(it->getNextRRset());
@@ -1413,47 +1443,100 @@ TYPED_TEST(DatabaseClientTest, iterator) {
// The first name should be the zone origin.
EXPECT_EQ(this->zname_, rrset->getName());
+}
- // The rest of the checks work only for the mock accessor.
- if (!this->is_mock_) {
- return;
- }
-
- this->expected_rdatas_.clear();
- this->expected_rdatas_.push_back("192.0.2.1");
- checkRRset(rrset, Name("example.org"), this->qclass_, RRType::A(),
- this->rrttl_, this->expected_rdatas_);
-
- rrset = it->getNextRRset();
- this->expected_rdatas_.clear();
- this->expected_rdatas_.push_back("ns1.example.org. admin.example.org. "
- "1234 3600 1800 2419200 7200");
- checkRRset(rrset, Name("example.org"), this->qclass_, RRType::SOA(),
- this->rrttl_, this->expected_rdatas_);
-
- rrset = it->getNextRRset();
- this->expected_rdatas_.clear();
- this->expected_rdatas_.push_back("192.0.2.1");
- this->expected_rdatas_.push_back("192.0.2.2");
- checkRRset(rrset, Name("x.example.org"), this->qclass_, RRType::A(),
- RRTTL(300), this->expected_rdatas_);
-
- rrset = it->getNextRRset();
- this->expected_rdatas_.clear();
- this->expected_rdatas_.push_back("2001:db8::1");
- this->expected_rdatas_.push_back("2001:db8::2");
- checkRRset(rrset, Name("x.example.org"), this->qclass_, RRType::AAAA(),
- RRTTL(300), this->expected_rdatas_);
-
- rrset = it->getNextRRset();
- ASSERT_NE(ConstRRsetPtr(), rrset);
- this->expected_rdatas_.clear();
- this->expected_rdatas_.push_back("192.0.2.1");
- this->expected_rdatas_.push_back("192.0.2.2");
- checkRRset(rrset, Name("ttldiff.example.org"), this->qclass_, RRType::A(),
- RRTTL(300), this->expected_rdatas_);
+// Supplemental structure used in the couple of tests below. It represents
+// parameters of an expected RRset containing up to two RDATAs. If it contains
+// only one RDATA, rdata2 is NULL.
+struct ExpectedRRset {
+ const char* const name;
+ const RRType rrtype;
+ const RRTTL rrttl;
+ const char* const rdata1;
+ const char* const rdata2;
+};
- EXPECT_EQ(ConstRRsetPtr(), it->getNextRRset());
+// Common checker for the iterator tests below. It extracts RRsets from the
+// give iterator and compare them to the expected sequence.
+void
+checkIteratorSequence(ZoneIterator& it, ExpectedRRset expected_sequence[],
+ size_t num_rrsets)
+{
+ vector<string> expected_rdatas;
+ for (size_t i = 0; i < num_rrsets; ++i) {
+ const ConstRRsetPtr rrset = it.getNextRRset();
+ ASSERT_TRUE(rrset);
+
+ expected_rdatas.clear();
+ expected_rdatas.push_back(expected_sequence[i].rdata1);
+ if (expected_sequence[i].rdata2 != NULL) {
+ expected_rdatas.push_back(expected_sequence[i].rdata2);
+ }
+ checkRRset(rrset, Name(expected_sequence[i].name), RRClass::IN(),
+ expected_sequence[i].rrtype, expected_sequence[i].rrttl,
+ expected_rdatas);
+ }
+ EXPECT_FALSE(it.getNextRRset());
+}
+
+TEST_F(MockDatabaseClientTest, iterator) {
+ // This version of test creates an iterator that combines same types of
+ // RRs into single RRsets.
+ ExpectedRRset expected_sequence[] = {
+ {"example.org", RRType::A(), rrttl_, "192.0.2.1", NULL},
+ {"example.org", RRType::SOA(), rrttl_,
+ "ns1.example.org. admin.example.org. 1234 3600 1800 2419200 7200",
+ NULL},
+ {"x.example.org", RRType::A(), RRTTL(300), "192.0.2.1", "192.0.2.2"},
+ {"x.example.org", RRType::AAAA(), RRTTL(300),
+ "2001:db8::1", "2001:db8::2"},
+ {"x.example.org", RRType::RRSIG(), RRTTL(300),
+ "A 5 3 3600 20000101000000 20000201000000 12345 example.org. "
+ "FAKEFAKEFAKE", NULL},
+ {"x.example.org", RRType::RRSIG(), RRTTL(300),
+ "AAAA 5 3 3600 20000101000000 20000201000000 12345 example.org. "
+ "FAKEFAKEFAKEFAKE", NULL},
+ {"ttldiff.example.org", RRType::A(), RRTTL(300),
+ "192.0.2.1", "192.0.2.2"},
+ {"ttldiff2.example.org", RRType::AAAA(), RRTTL(300),
+ "2001:db8::1", "2001:db8::2"}
+ };
+ checkIteratorSequence(*client_->getIterator(Name("example.org")),
+ expected_sequence,
+ sizeof(expected_sequence) /
+ sizeof(expected_sequence[0]));
+}
+
+TEST_F(MockDatabaseClientTest, iteratorSeparateRRs) {
+ // This version of test creates an iterator that separates all RRs as
+ // individual RRsets. In particular, it preserves the TTLs of an RRset
+ // even if they are different.
+ ExpectedRRset expected_sequence[] = {
+ {"example.org", RRType::A(), rrttl_, "192.0.2.1", NULL},
+ {"example.org", RRType::SOA(), rrttl_,
+ "ns1.example.org. admin.example.org. 1234 3600 1800 2419200 7200",
+ NULL},
+ {"x.example.org", RRType::A(), RRTTL(300), "192.0.2.1", NULL},
+ {"x.example.org", RRType::A(), RRTTL(300), "192.0.2.2", NULL},
+ {"x.example.org", RRType::AAAA(), RRTTL(300), "2001:db8::1", NULL},
+ {"x.example.org", RRType::AAAA(), RRTTL(300), "2001:db8::2", NULL},
+ {"x.example.org", RRType::RRSIG(), RRTTL(300),
+ "A 5 3 3600 20000101000000 20000201000000 12345 example.org. "
+ "FAKEFAKEFAKE", NULL},
+ {"x.example.org", RRType::RRSIG(), RRTTL(300),
+ "AAAA 5 3 3600 20000101000000 20000201000000 12345 example.org. "
+ "FAKEFAKEFAKEFAKE", NULL},
+ {"ttldiff.example.org", RRType::A(), RRTTL(300), "192.0.2.1", NULL},
+ {"ttldiff.example.org", RRType::A(), RRTTL(600), "192.0.2.2", NULL},
+ {"ttldiff2.example.org", RRType::AAAA(), RRTTL(600), "2001:db8::1",
+ NULL},
+ {"ttldiff2.example.org", RRType::AAAA(), RRTTL(300), "2001:db8::2",
+ NULL}
+ };
+ checkIteratorSequence(*client_->getIterator(Name("example.org"), true),
+ expected_sequence,
+ sizeof(expected_sequence) /
+ sizeof(expected_sequence[0]));
}
// This has inconsistent TTL in the set (the rest, like nonsense in
@@ -1590,12 +1673,14 @@ doFindTest(ZoneFinder& finder,
isc::dns::RRType::RRSIG(), expected_ttl,
expected_sig_rdatas);
} else if (expected_sig_rdatas.empty()) {
- EXPECT_EQ(isc::dns::RRsetPtr(), result->rrset->getRRsig());
+ EXPECT_EQ(isc::dns::RRsetPtr(), result->rrset->getRRsig()) <<
+ "Unexpected RRSIG: " << result->rrset->getRRsig()->toText();
} else {
ADD_FAILURE() << "Missing RRSIG";
}
} else if (expected_rdatas.empty()) {
- EXPECT_EQ(isc::dns::RRsetPtr(), result->rrset);
+ EXPECT_EQ(isc::dns::RRsetPtr(), result->rrset) <<
+ "Unexpected RRset: " << result->rrset->toText();
} else {
ADD_FAILURE() << "Missing result";
}
@@ -1609,7 +1694,9 @@ doFindAllTestResult(ZoneFinder& finder, const isc::dns::Name& name,
const isc::dns::Name& expected_name =
isc::dns::Name::ROOT_NAME(),
const ZoneFinder::FindOptions options =
- ZoneFinder::FIND_DEFAULT)
+ ZoneFinder::FIND_DEFAULT,
+ ZoneFinder::FindResultFlags expected_flags =
+ ZoneFinder::RESULT_DEFAULT)
{
SCOPED_TRACE("All test for " + name.toText());
std::vector<ConstRRsetPtr> target;
@@ -1617,6 +1704,15 @@ doFindAllTestResult(ZoneFinder& finder, const isc::dns::Name& name,
EXPECT_TRUE(target.empty());
EXPECT_EQ(expected_result, result->code);
EXPECT_EQ(expected_type, result->rrset->getType());
+ if (expected_flags != ZoneFinder::RESULT_DEFAULT){
+ EXPECT_EQ((expected_flags & ZoneFinder::RESULT_WILDCARD) != 0,
+ result->isWildcard());
+ EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0,
+ result->isNSECSigned());
+ EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0,
+ result->isNSEC3Signed());
+
+ }
RdataIteratorPtr it(result->rrset->getRdataIterator());
std::vector<std::string> rdata;
while (!it->isLast()) {
@@ -2422,10 +2518,169 @@ TYPED_TEST(DatabaseClientTest, wildcardNXRRSET_NSEC) {
Name("*.wild.example.org"), ZoneFinder::FIND_DNSSEC);
}
+// Subroutine for dnssecFlagCheck defined below. It performs some simple
+// checks regarding DNSSEC related result flags for findAll().
+void
+dnssecFlagCheckForAny(ZoneFinder& finder, const Name& name,
+ ZoneFinder::FindResultFlags sec_flag)
+{
+ std::vector<ConstRRsetPtr> target; // just for placeholder
+ ConstZoneFinderContextPtr all_result =
+ finder.findAll(name, target, ZoneFinder::FIND_DNSSEC);
+ EXPECT_EQ((sec_flag & ZoneFinder::RESULT_NSEC_SIGNED) != 0,
+ all_result->isNSECSigned());
+ EXPECT_EQ((sec_flag & ZoneFinder::RESULT_NSEC3_SIGNED) != 0,
+ all_result->isNSEC3Signed());
+}
+
+// Common tests about DNSSEC related result flags. Shared for the NSEC
+// and NSEC3 cases.
+void
+dnssecFlagCheck(ZoneFinder& finder, ZoneFinder::FindResultFlags sec_flag) {
+ std::vector<std::string> expected_rdatas;
+ std::vector<std::string> expected_sig_rdatas;
+
+ // Check NXDOMAIN case in NSEC signed zone, and RESULT_NSEC_SIGNED flag
+ // should be returned to upper layer caller.
+ if ((sec_flag & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
+ expected_rdatas.push_back("www2.example.org. A AAAA NSEC RRSIG");
+ expected_sig_rdatas.push_back("NSEC 5 3 3600 20000101000000 "
+ "20000201000000 12345 example.org. "
+ "FAKEFAKEFAKE");
+ }
+ doFindTest(finder, Name("www1.example.org"), RRType::A(), RRType::NSEC(),
+ RRTTL(3600), ZoneFinder::NXDOMAIN, expected_rdatas,
+ expected_sig_rdatas, sec_flag, Name("www.example.org."),
+ ZoneFinder::FIND_DNSSEC);
+ dnssecFlagCheckForAny(finder, Name("www1.example.org"), sec_flag);
+
+ // Check NXRRSET case in NSEC signed zone, and RESULT_NSEC_SIGNED flag
+ // should be return.
+ // No "findAll" test case for this because NXRRSET shouldn't happen for it.
+ expected_rdatas.clear();
+ expected_sig_rdatas.clear();
+ if ((sec_flag & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
+ expected_rdatas.push_back("www2.example.org. A AAAA NSEC RRSIG");
+ expected_sig_rdatas.push_back("NSEC 5 3 3600 20000101000000 "
+ "20000201000000 12345 example.org. "
+ "FAKEFAKEFAKE");
+ }
+ doFindTest(finder, Name("www.example.org."), RRType::TXT(), RRType::NSEC(),
+ RRTTL(3600), ZoneFinder::NXRRSET, expected_rdatas,
+ expected_sig_rdatas, sec_flag, Name::ROOT_NAME(),
+ ZoneFinder::FIND_DNSSEC);
+
+ // Empty name, should result in NXRRSET (in this test setup the NSEC
+ // doesn't have RRSIG).
+ expected_rdatas.clear();
+ expected_sig_rdatas.clear();
+ if ((sec_flag & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
+ expected_rdatas.push_back("empty.nonterminal.example.org. NSEC");
+ }
+ doFindTest(finder, Name("nonterminal.example.org."), RRType::A(),
+ RRType::NSEC(), RRTTL(3600), ZoneFinder::NXRRSET,
+ expected_rdatas,expected_sig_rdatas, sec_flag,
+ Name("l.example.org."), ZoneFinder::FIND_DNSSEC);
+ dnssecFlagCheckForAny(finder, Name("nonterminal.example.org"), sec_flag);
+
+ // Wildcard match
+ expected_rdatas.clear();
+ expected_sig_rdatas.clear();
+ expected_rdatas.push_back("192.0.2.5");
+ expected_sig_rdatas.push_back("A 5 3 3600 20000101000000 "
+ "20000201000000 12345 example.org. "
+ "FAKEFAKEFAKE");
+ doFindTest(finder, Name("b.a.wild.example.org"), RRType::A(),
+ RRType::A(), RRTTL(3600), ZoneFinder::SUCCESS, expected_rdatas,
+ expected_sig_rdatas, (ZoneFinder::RESULT_WILDCARD | sec_flag),
+ Name("b.a.wild.example.org"), ZoneFinder::FIND_DNSSEC);
+ dnssecFlagCheckForAny(finder, Name("b.a.wild.example.org"), sec_flag);
+
+ // Wildcard + NXRRSET (no "findAll" test for this case)
+ expected_rdatas.clear();
+ expected_sig_rdatas.clear();
+ if ((sec_flag & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
+ expected_rdatas.push_back("cancel.here.wild.example.org. "
+ "A NSEC RRSIG");
+ expected_sig_rdatas.push_back("NSEC 5 3 3600 20000101000000 "
+ "20000201000000 12345 example.org. "
+ "FAKEFAKEFAKE");
+ }
+ doFindTest(finder, Name("b.a.wild.example.org"),
+ RRType::TXT(), RRType::NSEC(), RRTTL(3600), ZoneFinder::NXRRSET,
+ expected_rdatas, expected_sig_rdatas,
+ (ZoneFinder::RESULT_WILDCARD | sec_flag),
+ Name("*.wild.example.org"), ZoneFinder::FIND_DNSSEC);
+
+ // Empty wildcard (this NSEC doesn't have RRSIG in our test data)
+ expected_rdatas.clear();
+ expected_sig_rdatas.clear();
+ if ((sec_flag & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
+ expected_rdatas.push_back("wild.*.foo.*.bar.example.org. NSEC");
+ }
+ doFindTest(finder, Name("foo.wild.bar.example.org"),
+ RRType::TXT(), RRType::NSEC(), RRTTL(3600), ZoneFinder::NXRRSET,
+ expected_rdatas, expected_sig_rdatas,
+ (ZoneFinder::RESULT_WILDCARD | sec_flag),
+ Name("bao.example.org"), ZoneFinder::FIND_DNSSEC);
+ dnssecFlagCheckForAny(finder, Name("foo.wild.bar.example.org"), sec_flag);
+}
+
+TYPED_TEST(DatabaseClientTest, dnssecResultFlags) {
+ // ZoneFinder::find() for negative cases and wildcard cases should check
+ // whether the zone is signed with NSEC or NSEC3.
+
+ // In the default test setup, the zone should be considered NSEC-signed
+ // (the apex node has an NSEC RR).
+ {
+ SCOPED_TRACE("NSEC only");
+ dnssecFlagCheck(*this->getFinder(), ZoneFinder::RESULT_NSEC_SIGNED);
+ }
+
+ // Then add an NSEC3PARAM RRset at the apex (it may look weird if the
+ // zone only has NSEC3PARM RRset (but no NSEC3s), but it is okay for the
+ // purpose of this test). The zone should now be considered NSEC3-signed.
+ // Note that the apex NSEC still exists; NSEC3 should override NSEC.
+ this->updater_ = this->client_->getUpdater(this->zname_, false);
+ this->rrset_.reset(new RRset(this->zname_, this->qclass_,
+ RRType::NSEC3PARAM(), this->rrttl_));
+ this->rrset_->addRdata(rdata::createRdata(this->rrset_->getType(),
+ this->rrset_->getClass(),
+ "1 0 12 aabbccdd"));
+ this->updater_->addRRset(*this->rrset_);
+ {
+ SCOPED_TRACE("NSEC and NSEC3");
+ dnssecFlagCheck(this->updater_->getFinder(),
+ ZoneFinder::RESULT_NSEC3_SIGNED);
+ }
+
+ // Next, delete the apex NSEC. Since NSEC3PARAM remains, the zone should
+ // still be considered NSEC3-signed.
+ RRsetPtr nsec_rrset(new RRset(this->zname_, this->qclass_, RRType::NSEC(),
+ this->rrttl_));
+ nsec_rrset->addRdata(rdata::createRdata(RRType::NSEC(), this->qclass_,
+ "acnamesig1.example.org. NS A "
+ "NSEC RRSIG"));
+ this->updater_->deleteRRset(*nsec_rrset);
+ {
+ SCOPED_TRACE("NSEC3 only");
+ dnssecFlagCheck(this->updater_->getFinder(),
+ ZoneFinder::RESULT_NSEC3_SIGNED);
+ }
+
+ // Finally, delete the NSEC3PARAM we just added above. The zone should
+ // then be considered unsigned.
+ this->updater_->deleteRRset(*this->rrset_);
+ {
+ SCOPED_TRACE("unsigned");
+ dnssecFlagCheck(this->updater_->getFinder(),
+ ZoneFinder::RESULT_DEFAULT);
+ }
+}
+
TYPED_TEST(DatabaseClientTest, NXDOMAIN_NSEC) {
// The domain doesn't exist, so we must get the right NSEC
boost::shared_ptr<DatabaseClient::Finder> finder(this->getFinder());
-
this->expected_rdatas_.push_back("www2.example.org. A AAAA NSEC RRSIG");
this->expected_sig_rdatas_.push_back("NSEC 5 3 3600 20000101000000 "
"20000201000000 12345 example.org. "
@@ -2452,14 +2707,13 @@ TYPED_TEST(DatabaseClientTest, NXDOMAIN_NSEC) {
if (!this->is_mock_) {
return; // We don't make the real DB to throw
}
- EXPECT_NO_THROW(doFindTest(*finder,
- isc::dns::Name("notimplnsec.example.org."),
- isc::dns::RRType::TXT(),
- isc::dns::RRType::NSEC(), this->rrttl_,
- ZoneFinder::NXDOMAIN, this->empty_rdatas_,
- this->empty_rdatas_,
- ZoneFinder::RESULT_DEFAULT,
- Name::ROOT_NAME(), ZoneFinder::FIND_DNSSEC));
+ // In this case the accessor doesn't support findPreviousName(), but the
+ // zone apex has NSEC, and the zone itself is considered NSEC-signed.
+ doFindTest(*finder, Name("notimplnsec.example.org."),
+ RRType::TXT(), RRType::NSEC(), this->rrttl_,
+ ZoneFinder::NXDOMAIN, this->empty_rdatas_,
+ this->empty_rdatas_, ZoneFinder::RESULT_NSEC_SIGNED,
+ Name::ROOT_NAME(), ZoneFinder::FIND_DNSSEC);
}
TYPED_TEST(DatabaseClientTest, emptyNonterminalNSEC) {
@@ -2479,14 +2733,12 @@ TYPED_TEST(DatabaseClientTest, emptyNonterminalNSEC) {
if (!this->is_mock_) {
return; // We don't make the real DB to throw
}
- EXPECT_NO_THROW(doFindTest(*finder,
- isc::dns::Name("here.wild.example.org."),
- isc::dns::RRType::TXT(),
- isc::dns::RRType::NSEC(),
- this->rrttl_, ZoneFinder::NXRRSET,
- this->empty_rdatas_, this->empty_rdatas_,
- ZoneFinder::RESULT_DEFAULT,
- Name::ROOT_NAME(), ZoneFinder::FIND_DNSSEC));
+ // See the corresponding case of NXDOMAIN_NSEC.
+ doFindTest(*finder, Name("here.wild.example.org."),
+ RRType::TXT(), RRType::NSEC(), this->rrttl_,
+ ZoneFinder::NXRRSET, this->empty_rdatas_,
+ this->empty_rdatas_, ZoneFinder::RESULT_NSEC_SIGNED,
+ Name::ROOT_NAME(), ZoneFinder::FIND_DNSSEC);
}
TYPED_TEST(DatabaseClientTest, anyFromFind) {
@@ -3726,4 +3978,25 @@ TEST_F(MockDatabaseClientTest, journalWithBadData) {
second->getNextDiff(), DataSourceError);
}
+/// Let us test a little bit of NSEC3.
+TEST_F(MockDatabaseClientTest, findNSEC3) {
+ // Set up the faked hash calculator.
+ setNSEC3HashCreator(&test_nsec3_hash_creator_);
+
+ DataSourceClient::FindResult
+ zone(this->client_->findZone(Name("example.org")));
+ ASSERT_EQ(result::SUCCESS, zone.code);
+ boost::shared_ptr<DatabaseClient::Finder> finder(
+ dynamic_pointer_cast<DatabaseClient::Finder>(zone.zone_finder));
+
+ // It'll complain if there is no NSEC3PARAM yet
+ EXPECT_THROW(finder->findNSEC3(Name("example.org"), false),
+ DataSourceError);
+ // And enable NSEC3 in the zone.
+ this->current_accessor_->enableNSEC3();
+
+ // The rest is in the function, it is shared with in-memory tests
+ performNSEC3Test(*finder);
+}
+
}
diff --git a/src/lib/datasrc/tests/faked_nsec3.cc b/src/lib/datasrc/tests/faked_nsec3.cc
new file mode 100644
index 0000000..4ca22a5
--- /dev/null
+++ b/src/lib/datasrc/tests/faked_nsec3.cc
@@ -0,0 +1,196 @@
+// Copyright (C) 2011 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.
+
+#include "faked_nsec3.h"
+
+#include <dns/name.h>
+#include <testutils/dnsmessage_test.h>
+
+#include <map>
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace isc::dns;
+using namespace isc::testutils;
+
+namespace isc {
+namespace datasrc {
+namespace test {
+
+class TestNSEC3HashCreator::TestNSEC3Hash : public NSEC3Hash {
+private:
+ typedef map<Name, string> NSEC3HashMap;
+ typedef NSEC3HashMap::value_type NSEC3HashPair;
+ NSEC3HashMap map_;
+public:
+ TestNSEC3Hash() {
+ // Build pre-defined hash
+ map_[Name("example.org")] = apex_hash;
+ map_[Name("www.example.org")] = "2S9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
+ map_[Name("xxx.example.org")] = "Q09MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
+ map_[Name("yyy.example.org")] = "0A9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
+ map_[Name("x.y.w.example.org")] =
+ "2VPTU5TIMAMQTTGL4LUU9KG21E0AOR3S";
+ map_[Name("y.w.example.org")] = "K8UDEMVP1J2F7EG6JEBPS17VP3N8I58H";
+ map_[Name("w.example.org")] = w_hash;
+ map_[Name("zzz.example.org")] = zzz_hash;
+ map_[Name("smallest.example.org")] =
+ "00000000000000000000000000000000";
+ map_[Name("largest.example.org")] =
+ "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU";
+ }
+ virtual string calculate(const Name& name) const {
+ const NSEC3HashMap::const_iterator found = map_.find(name);
+ if (found != map_.end()) {
+ return (found->second);
+ }
+ isc_throw(isc::Unexpected, "unexpected name for NSEC3 test: "
+ << name);
+ }
+ virtual bool match(const rdata::generic::NSEC3PARAM&) const {
+ return (true);
+ }
+ virtual bool match(const rdata::generic::NSEC3&) const {
+ return (true);
+ }
+};
+
+NSEC3Hash* TestNSEC3HashCreator::create(const rdata::generic::NSEC3PARAM&)
+ const
+{
+ return (new TestNSEC3Hash);
+}
+
+NSEC3Hash* TestNSEC3HashCreator::create(const rdata::generic::NSEC3&) const {
+ return (new TestNSEC3Hash);
+}
+
+void
+findNSEC3Check(bool expected_matched, uint8_t expected_labels,
+ const string& expected_closest,
+ const string& expected_next,
+ const ZoneFinder::FindNSEC3Result& result,
+ bool expected_sig)
+{
+ EXPECT_EQ(expected_matched, result.matched);
+ // Convert to int so the error messages would be more readable:
+ EXPECT_EQ(static_cast<int>(expected_labels),
+ static_cast<int>(result.closest_labels));
+
+ vector<ConstRRsetPtr> actual_rrsets;
+ ASSERT_TRUE(result.closest_proof);
+ actual_rrsets.push_back(result.closest_proof);
+ if (expected_sig) {
+ actual_rrsets.push_back(result.closest_proof->getRRsig());
+ }
+ rrsetsCheck(expected_closest, actual_rrsets.begin(),
+ actual_rrsets.end());
+
+ actual_rrsets.clear();
+ if (expected_next.empty()) {
+ EXPECT_FALSE(result.next_proof);
+ } else {
+ ASSERT_TRUE(result.next_proof);
+ actual_rrsets.push_back(result.next_proof);
+ if (expected_sig) {
+ actual_rrsets.push_back(result.next_proof->getRRsig());
+ }
+ rrsetsCheck(expected_next, actual_rrsets.begin(),
+ actual_rrsets.end());
+ }
+}
+
+void
+performNSEC3Test(ZoneFinder &finder) {
+ // Parameter validation: the query name must be in or below the zone
+ EXPECT_THROW(finder.findNSEC3(Name("example.com"), false), OutOfZone);
+ EXPECT_THROW(finder.findNSEC3(Name("org"), true), OutOfZone);
+
+ Name origin("example.org");
+ const string apex_nsec3_text = string(apex_hash) + ".example.org." +
+ string(nsec3_common);
+ const string ns1_nsec3_text = string(ns1_hash) + ".example.org." +
+ string(nsec3_common);
+ const string w_nsec3_text = string(w_hash) + ".example.org." +
+ string(nsec3_common);
+ const string zzz_nsec3_text = string(zzz_hash) + ".example.org." +
+ string(nsec3_common);
+
+ // Apex name. It should have a matching NSEC3.
+ {
+ SCOPED_TRACE("apex, non recursive mode");
+ findNSEC3Check(true, origin.getLabelCount(), apex_nsec3_text, "",
+ finder.findNSEC3(origin, false));
+ }
+
+ // Recursive mode doesn't change the result in this case.
+ {
+ SCOPED_TRACE("apex, recursive mode");
+ findNSEC3Check(true, origin.getLabelCount(), apex_nsec3_text, "",
+ finder.findNSEC3(origin, true));
+ }
+
+ // Non existent name (in the NSEC3 namespace -- the findNSEC3 does
+ // not look into the normal data). Disabling recursion, a covering
+ // NSEC3 should be returned.
+ const Name www_name("www.example.org");
+ {
+ SCOPED_TRACE("non existent name, non recursive mode");
+ findNSEC3Check(false, www_name.getLabelCount(), apex_nsec3_text, "",
+ finder.findNSEC3(www_name, false));
+ }
+
+ // Non existent name. The closest provable encloser is the apex,
+ // and next closer is the query name itself (which NSEC3 for ns1
+ // covers)
+ // H(ns1) = 2T... < H(xxx) = Q0... < H(zzz) = R5...
+ {
+ SCOPED_TRACE("non existent name, recursive mode");
+ findNSEC3Check(true, origin.getLabelCount(), apex_nsec3_text,
+ ns1_nsec3_text,
+ finder.findNSEC3(Name("xxx.example.org"), true));
+ }
+
+ // Similar to the previous case, but next closer name is different
+ // from the query name. The closet encloser is w.example.org, and
+ // next closer is y.w.example.org.
+ // H(ns1) = 2T.. < H(y.w) = K8.. < H(zzz) = R5
+ {
+ SCOPED_TRACE("non existent name, non qname next closer");
+ findNSEC3Check(true, Name("w.example.org").getLabelCount(),
+ w_nsec3_text, ns1_nsec3_text,
+ finder.findNSEC3(Name("x.y.w.example.org"),
+ true));
+ }
+
+ // In the rest of test we check hash comparison for wrap around cases.
+ {
+ SCOPED_TRACE("very small hash");
+ const Name smallest_name("smallest.example.org");
+ findNSEC3Check(false, smallest_name.getLabelCount(),
+ zzz_nsec3_text, "",
+ finder.findNSEC3(smallest_name, false));
+ }
+ {
+ SCOPED_TRACE("very large hash");
+ const Name largest_name("largest.example.org");
+ findNSEC3Check(false, largest_name.getLabelCount(),
+ zzz_nsec3_text, "",
+ finder.findNSEC3(largest_name, false));
+ }
+}
+
+}
+}
+}
diff --git a/src/lib/datasrc/tests/faked_nsec3.h b/src/lib/datasrc/tests/faked_nsec3.h
new file mode 100644
index 0000000..51b4059
--- /dev/null
+++ b/src/lib/datasrc/tests/faked_nsec3.h
@@ -0,0 +1,86 @@
+// Copyright (C) 2011 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 FAKED_NSEC3_H
+#define FAKED_NSEC3_H
+
+#include <datasrc/zone.h>
+
+#include <dns/nsec3hash.h>
+
+#include <stdint.h>
+#include <string>
+
+namespace isc {
+namespace datasrc {
+namespace test {
+
+//
+// (Faked) NSEC3 hash data. Arbitrarily borrowed from RFC515 examples.
+//
+// Commonly used NSEC3 suffix. It's incorrect to use it for all NSEC3s, but
+// doesn't matter for the purpose of our tests.
+const char* const nsec3_common = " 300 IN NSEC3 1 1 12 aabbccdd "
+ "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG";
+// Likewise, common RRSIG suffix for NSEC3s.
+const char* const nsec3_rrsig_common = " 300 IN RRSIG NSEC3 5 3 3600 "
+ "20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE";
+
+// Some faked NSEC3 hash values commonly used in tests and the faked NSEC3Hash
+// object.
+//
+// For apex (example.org)
+const char* const apex_hash = "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
+const char* const apex_hash_lower = "0p9mhaveqvm6t7vbl5lop2u3t2rp3tom";
+// For ns1.example.org
+const char* const ns1_hash = "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR";
+// For w.example.org
+const char* const w_hash = "01UDEMVP1J2F7EG6JEBPS17VP3N8I58H";
+// For x.y.w.example.org (lower-cased)
+const char* const xyw_hash = "2vptu5timamqttgl4luu9kg21e0aor3s";
+// For zzz.example.org.
+const char* const zzz_hash = "R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN";
+
+// A simple faked NSEC3 hash calculator with a dedicated creator for it.
+//
+// This is used in some NSEC3-related tests below.
+class TestNSEC3HashCreator : public isc::dns::NSEC3HashCreator {
+private:
+ class TestNSEC3Hash;
+public:
+ virtual isc::dns::NSEC3Hash* create(const
+ isc::dns::rdata::generic::NSEC3PARAM&)
+ const;
+ virtual isc::dns::NSEC3Hash* create(const isc::dns::rdata::generic::NSEC3&)
+ const;
+};
+
+// Check the result against expected values. It directly calls EXPECT_ macros
+void
+findNSEC3Check(bool expected_matched, uint8_t expected_labels,
+ const std::string& expected_closest,
+ const std::string& expected_next,
+ const isc::datasrc::ZoneFinder::FindNSEC3Result& result,
+ bool expected_sig = false);
+
+// Perform the shared part of NSEC3 test (shared between in-memory and database
+// tests).
+void
+performNSEC3Test(ZoneFinder &finder);
+
+}
+}
+}
+
+#endif
diff --git a/src/lib/datasrc/tests/memory_datasrc_unittest.cc b/src/lib/datasrc/tests/memory_datasrc_unittest.cc
index fe8c92c..f54af75 100644
--- a/src/lib/datasrc/tests/memory_datasrc_unittest.cc
+++ b/src/lib/datasrc/tests/memory_datasrc_unittest.cc
@@ -12,11 +12,7 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#include <sstream>
-#include <vector>
-
-#include <boost/bind.hpp>
-#include <boost/foreach.hpp>
+#include "faked_nsec3.h"
#include <exceptions/exceptions.h>
@@ -30,19 +26,31 @@
#include <dns/rrttl.h>
#include <dns/masterload.h>
+#include <datasrc/client.h>
#include <datasrc/memory_datasrc.h>
#include <datasrc/data_source.h>
#include <datasrc/iterator.h>
+#include "test_client.h"
+
#include <testutils/dnsmessage_test.h>
#include <gtest/gtest.h>
+#include <boost/bind.hpp>
+#include <boost/foreach.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <sstream>
+#include <vector>
+
using namespace std;
using namespace isc::dns;
using namespace isc::dns::rdata;
using namespace isc::datasrc;
using namespace isc::testutils;
+using boost::shared_ptr;
+using namespace isc::datasrc::test;
namespace {
// Commonly used result codes (Who should write the prefix all the time)
@@ -387,6 +395,8 @@ public:
// Build test RRsets. Below, we construct an RRset for
// each textual RR(s) of zone_data, and assign it to the corresponding
// rr_xxx.
+ // Note that this contains an out-of-zone RR, and due to the
+ // validation check of masterLoad() used below, we cannot add SOA.
const RRsetData zone_data[] = {
{"example.org. 300 IN NS ns.example.org.", &rr_ns_},
{"example.org. 300 IN A 192.0.2.1", &rr_a_},
@@ -534,6 +544,8 @@ public:
ZoneFinder::FindOptions options = ZoneFinder::FIND_DEFAULT,
bool check_wild_answer = false)
{
+ SCOPED_TRACE("findTest for " + name.toText() + "/" + rrtype.toText());
+
if (zone_finder == NULL) {
zone_finder = &zone_finder_;
}
@@ -1082,7 +1094,70 @@ TEST_F(InMemoryZoneFinderTest, load) {
// Try loading zone that is wrong in a different way
EXPECT_THROW(zone_finder_.load(TEST_DATA_DIR "/duplicate_rrset.zone"),
- MasterLoadError);
+ MasterLoadError);
+}
+
+TEST_F(InMemoryZoneFinderTest, loadFromIterator) {
+ // The initial test set doesn't have SOA at the apex.
+ findTest(origin_, RRType::SOA(), ZoneFinder::NXRRSET, false,
+ ConstRRsetPtr());
+
+ // The content of the new version of zone to be first installed to
+ // the SQLite3 data source, then to in-memory via SQLite3. The data are
+ // chosen to cover major check points of the implementation:
+ // - the previously non-existent record is added (SOA)
+ // - An RRSIG is given from the iterator before the RRset it covers
+ // (RRSIG for SOA, because they are sorted by name then rrtype as text)
+ // - An RRset containing multiple RRs (ns1/A)
+ // - RRSIGs for different owner names
+ stringstream ss;
+ const char* const soa_txt = "example.org. 300 IN SOA . . 0 0 0 0 0\n";
+ const char* const soa_sig_txt = "example.org. 300 IN RRSIG SOA 5 3 300 "
+ "20000101000000 20000201000000 12345 example.org. FAKEFAKE\n";
+ const char* const a_txt =
+ "ns1.example.org. 300 IN A 192.0.2.1\n"
+ "ns1.example.org. 300 IN A 192.0.2.2\n";
+ const char* const a_sig_txt = "ns1.example.org. 300 IN RRSIG A 5 3 300 "
+ "20000101000000 20000201000000 12345 example.org. FAKEFAKE\n";
+ ss << soa_txt << soa_sig_txt << a_txt << a_sig_txt;
+ shared_ptr<DataSourceClient> db_client = unittest::createSQLite3Client(
+ class_, origin_, TEST_DATA_BUILDDIR "/contexttest.sqlite3.copied", ss);
+ zone_finder_.load(*db_client->getIterator(origin_));
+
+ // The new content should be visible, including the previously-nonexistent
+ // SOA.
+ RRsetPtr expected_answer = textToRRset(soa_txt, RRClass::IN(), origin_);
+ expected_answer->addRRsig(textToRRset(soa_sig_txt));
+ findTest(origin_, RRType::SOA(), ZoneFinder::SUCCESS, true,
+ expected_answer);
+
+ expected_answer = textToRRset(a_txt);
+ expected_answer->addRRsig(textToRRset(a_sig_txt));
+ findTest(Name("ns1.example.org"), RRType::A(), ZoneFinder::SUCCESS, true,
+ expected_answer);
+
+ // File name should be (re)set to empty.
+ EXPECT_TRUE(zone_finder_.getFileName().empty());
+
+ // Loading the zone with an iterator separating RRs of the same RRset
+ // will fail because the resulting sequence doesn't meet assumptions of
+ // the (current) in-memory implementation.
+ EXPECT_THROW(zone_finder_.load(*db_client->getIterator(origin_, true)),
+ MasterLoadError);
+
+ // Load the zone from a file that contains more realistic data (borrowed
+ // from a different test). There's nothing special in this case for the
+ // purpose of this test, so it should just succeed.
+ db_client = unittest::createSQLite3Client(
+ class_, origin_, TEST_DATA_BUILDDIR "/contexttest.sqlite3.copied",
+ TEST_DATA_DIR "/contexttest.zone");
+ zone_finder_.load(*db_client->getIterator(origin_));
+
+ // just checking a couple of RRs in the new version of zone.
+ findTest(Name("mx1.example.org"), RRType::A(), ZoneFinder::SUCCESS, true,
+ textToRRset("mx1.example.org. 3600 IN A 192.0.2.10"));
+ findTest(Name("ns1.example.org"), RRType::AAAA(), ZoneFinder::SUCCESS,
+ true, textToRRset("ns1.example.org. 3600 IN AAAA 2001:db8::1"));
}
/*
@@ -1623,52 +1698,6 @@ TEST_F(InMemoryZoneFinderTest, addbadRRsig) {
InMemoryZoneFinder::AddError);
}
-//
-// (Faked) NSEC3 hash data. Arbitrarily borrowed from RFC515 examples.
-//
-// Commonly used NSEC3 suffix. It's incorrect to use it for all NSEC3s, but
-// doesn't matter for the purpose of our tests.
-const char* const nsec3_common = " 300 IN NSEC3 1 1 12 aabbccdd "
- "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG";
-// Likewise, common RRSIG suffix for NSEC3s.
-const char* const nsec3_rrsig_common = " 300 IN RRSIG NSEC3 5 3 3600 "
- "20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE";
-
-void
-findNSEC3Check(bool expected_matched, uint8_t expected_labels,
- const string& expected_closest,
- const string& expected_next,
- const ZoneFinder::FindNSEC3Result& result,
- bool expected_sig = false)
-{
- EXPECT_EQ(expected_matched, result.matched);
- // Convert to int so the error messages would be more readable:
- EXPECT_EQ(static_cast<int>(expected_labels),
- static_cast<int>(result.closest_labels));
-
- vector<ConstRRsetPtr> actual_rrsets;
- ASSERT_TRUE(result.closest_proof);
- actual_rrsets.push_back(result.closest_proof);
- if (expected_sig) {
- actual_rrsets.push_back(result.closest_proof->getRRsig());
- }
- rrsetsCheck(expected_closest, actual_rrsets.begin(),
- actual_rrsets.end());
-
- actual_rrsets.clear();
- if (expected_next.empty()) {
- EXPECT_FALSE(result.next_proof);
- } else {
- ASSERT_TRUE(result.next_proof);
- actual_rrsets.push_back(result.next_proof);
- if (expected_sig) {
- actual_rrsets.push_back(result.next_proof->getRRsig());
- }
- rrsetsCheck(expected_next, actual_rrsets.begin(),
- actual_rrsets.end());
- }
-}
-
TEST_F(InMemoryZoneFinderTest, addNSEC3) {
// Set up the faked hash calculator.
setNSEC3HashCreator(&nsec3_hash_creator_);
@@ -1957,71 +1986,7 @@ TEST_F(InMemoryZoneFinderTest, findNSEC3) {
string(nsec3_common);
EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(zzz_nsec3_text)));
- // Parameter validation: the query name must be in or below the zone
- EXPECT_THROW(zone_finder_.findNSEC3(Name("example.com"), false), OutOfZone);
- EXPECT_THROW(zone_finder_.findNSEC3(Name("org"), true), OutOfZone);
-
- // Apex name. It should have a matching NSEC3.
- {
- SCOPED_TRACE("apex, non recursive mode");
- findNSEC3Check(true, origin_.getLabelCount(), apex_nsec3_text, "",
- zone_finder_.findNSEC3(origin_, false));
- }
-
- // Recursive mode doesn't change the result in this case.
- {
- SCOPED_TRACE("apex, recursive mode");
- findNSEC3Check(true, origin_.getLabelCount(), apex_nsec3_text, "",
- zone_finder_.findNSEC3(origin_, true));
- }
-
- // Non existent name. Disabling recursion, a covering NSEC3 should be
- // returned.
- const Name www_name("www.example.org");
- {
- SCOPED_TRACE("non existent name, non recursive mode");
- findNSEC3Check(false, www_name.getLabelCount(), apex_nsec3_text, "",
- zone_finder_.findNSEC3(www_name, false));
- }
-
- // Non existent name. The closest provable encloser is the apex,
- // and next closer is the query name itself (which NSEC3 for ns1
- // covers)
- // H(ns1) = 2T... < H(xxx) = Q0... < H(zzz) = R5...
- {
- SCOPED_TRACE("non existent name, recursive mode");
- findNSEC3Check(true, origin_.getLabelCount(), apex_nsec3_text,
- ns1_nsec3_text,
- zone_finder_.findNSEC3(Name("xxx.example.org"), true));
- }
-
- // Similar to the previous case, but next closer name is different
- // from the query name. The closet encloser is w.example.org, and
- // next closer is y.w.example.org.
- // H(ns1) = 2T.. < H(y.w) = K8.. < H(zzz) = R5
- {
- SCOPED_TRACE("non existent name, non qname next closer");
- findNSEC3Check(true, Name("w.example.org").getLabelCount(),
- w_nsec3_text, ns1_nsec3_text,
- zone_finder_.findNSEC3(Name("x.y.w.example.org"),
- true));
- }
-
- // In the rest of test we check hash comparison for wrap around cases.
- {
- SCOPED_TRACE("very small hash");
- const Name smallest_name("smallest.example.org");
- findNSEC3Check(false, smallest_name.getLabelCount(),
- zzz_nsec3_text, "",
- zone_finder_.findNSEC3(smallest_name, false));
- }
- {
- SCOPED_TRACE("very large hash");
- const Name largest_name("largest.example.org");
- findNSEC3Check(false, largest_name.getLabelCount(),
- zzz_nsec3_text, "",
- zone_finder_.findNSEC3(largest_name, false));
- }
+ performNSEC3Test(zone_finder_);
}
TEST_F(InMemoryZoneFinderTest, findNSEC3ForBadZone) {
diff --git a/src/lib/datasrc/tests/sqlite3_accessor_unittest.cc b/src/lib/datasrc/tests/sqlite3_accessor_unittest.cc
index 6a58c94..c36c94b 100644
--- a/src/lib/datasrc/tests/sqlite3_accessor_unittest.cc
+++ b/src/lib/datasrc/tests/sqlite3_accessor_unittest.cc
@@ -792,18 +792,27 @@ TEST_F(SQLite3Update, rollback) {
checkRecords(*accessor, zone_id, "foo.bar.example.com.", expected_stored);
}
-// TODO: ticket #1845
-TEST_F(SQLite3Update, DISABLED_rollbackFailure) {
+TEST_F(SQLite3Update, rollbackFailure) {
// This test emulates a rare scenario of making rollback attempt fail.
// The iterator is paused in the middle of getting records, which prevents
// the rollback operation at the end of the test.
+ // Since SQLite3 version 3.7.11, rollbacks do not fail on pending
+ // transactions anymore, making this test fail (and moot), but the
+ // transactions will fail after it, so, depending on version,
+ // we test whether that happens and is caught
string columns[DatabaseAccessor::COLUMN_COUNT];
iterator = accessor->getRecords("example.com.", zone_id);
EXPECT_TRUE(iterator->getNext(columns));
accessor->startUpdateZone("example.com.", true);
+#if SQLITE_VERSION_NUMBER < 3007011
EXPECT_THROW(accessor->rollback(), DataSourceError);
+ EXPECT_NO_THROW(iterator->getNext(columns));
+#else
+ EXPECT_NO_THROW(accessor->rollback());
+ EXPECT_THROW(iterator->getNext(columns), DataSourceError);
+#endif
}
TEST_F(SQLite3Update, commitConflict) {
diff --git a/src/lib/datasrc/tests/test_client.cc b/src/lib/datasrc/tests/test_client.cc
new file mode 100644
index 0000000..3974371
--- /dev/null
+++ b/src/lib/datasrc/tests/test_client.cc
@@ -0,0 +1,92 @@
+// Copyright (C) 2012 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.
+
+#include <exceptions/exceptions.h>
+
+#include <dns/masterload.h>
+#include <dns/name.h>
+#include <dns/rrclass.h>
+
+#include <datasrc/client.h>
+#include <datasrc/zone.h>
+#include <datasrc/sqlite3_accessor.h>
+
+#include "test_client.h"
+
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <cstdlib>
+#include <istream>
+#include <fstream>
+
+using namespace std;
+using boost::shared_ptr;
+
+using namespace isc::dns;
+
+namespace isc {
+namespace datasrc {
+namespace unittest {
+
+namespace {
+// A helper subroutine for the SQLite3Client creator.
+void
+addRRset(ZoneUpdaterPtr updater, ConstRRsetPtr rrset) {
+ updater->addRRset(*rrset);
+}
+}
+
+shared_ptr<DataSourceClient>
+createSQLite3Client(RRClass zclass, const Name& zname,
+ const char* const db_file, const char* const zone_file)
+{
+ ifstream ifs(zone_file, ios_base::in);
+ if (ifs.fail()) {
+ isc_throw(isc::Unexpected, "Failed to open test zone file: "
+ << zone_file);
+ }
+ return (createSQLite3Client(zclass, zname, db_file, ifs));
+}
+
+shared_ptr<DataSourceClient>
+createSQLite3Client(RRClass zclass, const Name& zname,
+ const char* const db_file, istream& rr_stream)
+{
+ // We always begin with an empty template SQLite3 DB file and install
+ // the zone data from the zone file to ensure both cases have the
+ // same test data.
+ const char* const install_cmd_prefix = INSTALL_PROG " " TEST_DATA_COMMONDIR
+ "/rwtest.sqlite3 ";
+ const string install_cmd = string(install_cmd_prefix) + db_file;
+ if (system(install_cmd.c_str()) != 0) {
+ isc_throw(isc::Unexpected,
+ "Error setting up; command failed: " << install_cmd);
+ }
+
+ shared_ptr<SQLite3Accessor> accessor(
+ new SQLite3Accessor(db_file, zclass.toText()));
+ shared_ptr<DatabaseClient> client(new DatabaseClient(zclass, accessor));
+
+ ZoneUpdaterPtr updater = client->getUpdater(zname, true);
+ masterLoad(rr_stream, zname, zclass, boost::bind(addRRset, updater, _1));
+
+ updater->commit();
+
+ return (client);
+}
+
+}
+}
+}
diff --git a/src/lib/datasrc/tests/test_client.h b/src/lib/datasrc/tests/test_client.h
new file mode 100644
index 0000000..2c692d3
--- /dev/null
+++ b/src/lib/datasrc/tests/test_client.h
@@ -0,0 +1,71 @@
+// Copyright (C) 2012 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 __TEST_DATA_SOURCE_CLIENT_H
+#define __TEST_DATA_SOURCE_CLIENT_H 1
+
+#include <dns/name.h>
+#include <dns/rrclass.h>
+
+#include <boost/shared_ptr.hpp>
+
+#include <istream>
+
+namespace isc {
+namespace datasrc {
+namespace unittest {
+
+// Here we define utility modules for the convenience of tests that create
+// a data source client according to the specified conditions.
+
+/// \brief Create an SQLite3 data source client from a zone file.
+///
+/// This function creates an SQLite3 client for the specified zone containing
+/// RRs in the specified zone file. The zone will be created in the given
+/// SQLite3 database file. The database file does not have to exist; this
+/// function will automatically create a new file for the test; if the given
+/// file already exists this function overrides the content (so basically the
+/// file must be an ephemeral one only for that test case).
+///
+/// The zone file must be formatted so it's accepted by the dns::masterLoad()
+/// function.
+///
+/// \param zclass The RR class of the zone
+/// \param zname The origin name of the zone
+/// \param db_file The SQLite3 data base file in which the zone data should be
+/// installed.
+/// \param zone_file The filename of the zone data in the textual format.
+/// \return Newly created \c DataSourceClient using the SQLite3 data source
+boost::shared_ptr<DataSourceClient>
+createSQLite3Client(dns::RRClass zclass, const dns::Name& zname,
+ const char* const db_file, const char* const zone_file);
+
+/// \brief Create an SQLite3 data source client from a stream.
+///
+/// This is similar to the other version of the function, but takes an input
+/// stream for the zone data. The stream produces strings as the corresponding
+/// dns::masterLoad() function expects.
+boost::shared_ptr<DataSourceClient>
+createSQLite3Client(dns::RRClass zclass, const dns::Name& zname,
+ const char* const db_file, std::istream& rr_stream);
+
+} // end of unittest
+} // end of datasrc
+} // end of isc
+
+#endif // __TEST_DATA_SOURCE_CLIENT_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/datasrc/tests/testdata/rwtest.sqlite3 b/src/lib/datasrc/tests/testdata/rwtest.sqlite3
deleted file mode 100644
index 5eeb2c3..0000000
Binary files a/src/lib/datasrc/tests/testdata/rwtest.sqlite3 and /dev/null differ
diff --git a/src/lib/datasrc/tests/zone_finder_context_unittest.cc b/src/lib/datasrc/tests/zone_finder_context_unittest.cc
index cb48e7e..50d409e 100644
--- a/src/lib/datasrc/tests/zone_finder_context_unittest.cc
+++ b/src/lib/datasrc/tests/zone_finder_context_unittest.cc
@@ -12,6 +12,8 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
+#include <exceptions/exceptions.h>
+
#include <dns/masterload.h>
#include <dns/name.h>
#include <dns/rrclass.h>
@@ -21,6 +23,7 @@
#include <datasrc/database.h>
#include <datasrc/sqlite3_accessor.h>
+#include "test_client.h"
#include <testutils/dnsmessage_test.h>
#include <gtest/gtest.h>
@@ -29,7 +32,8 @@
#include <boost/foreach.hpp>
#include <boost/shared_ptr.hpp>
-#include <cstdlib>
+#include <fstream>
+#include <sstream>
#include <vector>
using namespace std;
@@ -66,8 +70,6 @@ createInMemoryClient(RRClass zclass, const Name& zname) {
return (client);
}
-// Creator for the SQLite3 client to be tested. addRRset() is a helper
-// subroutine.
void
addRRset(ZoneUpdaterPtr updater, ConstRRsetPtr rrset) {
updater->addRRset(*rrset);
@@ -78,25 +80,14 @@ createSQLite3Client(RRClass zclass, const Name& zname) {
// We always begin with an empty template SQLite3 DB file and install
// the zone data from the zone file to ensure both cases have the
// same test data.
+ DataSourceClientPtr client = unittest::createSQLite3Client(
+ zclass, zname, TEST_DATA_BUILDDIR "/contexttest.sqlite3.copied",
+ TEST_ZONE_FILE);
- const char* const install_cmd = INSTALL_PROG " " TEST_DATA_DIR
- "/rwtest.sqlite3 " TEST_DATA_BUILDDIR "/contexttest.sqlite3.copied";
- if (system(install_cmd) != 0) {
- isc_throw(isc::Unexpected,
- "Error setting up; command failed: " << install_cmd);
- }
-
- shared_ptr<SQLite3Accessor> accessor(
- new SQLite3Accessor(TEST_DATA_BUILDDIR "/contexttest.sqlite3.copied",
- zclass.toText()));
- shared_ptr<DatabaseClient> client(new DatabaseClient(zclass, accessor));
-
- ZoneUpdaterPtr updater = client->getUpdater(zname, true);
- masterLoad(TEST_ZONE_FILE, zname, zclass, boost::bind(addRRset, updater,
- _1));
// Insert an out-of-zone name to test if it's incorrectly returned.
// Note that neither updater nor SQLite3 accessor checks this condition,
// so this should succeed.
+ ZoneUpdaterPtr updater = client->getUpdater(zname, false);
stringstream ss("ns.example.com. 3600 IN A 192.0.2.7");
masterLoad(ss, Name::ROOT_NAME(), zclass,
boost::bind(addRRset, updater, _1));
diff --git a/src/lib/dns/Makefile.am b/src/lib/dns/Makefile.am
index 010c027..39f4429 100644
--- a/src/lib/dns/Makefile.am
+++ b/src/lib/dns/Makefile.am
@@ -88,7 +88,7 @@ BUILT_SOURCES += rdataclass.h rdataclass.cc
lib_LTLIBRARIES = libdns++.la
-libdns___la_LDFLAGS = -no-undefined -version-info 1:0:1
+libdns___la_LDFLAGS = -no-undefined -version-info 2:0:0
libdns___la_SOURCES =
libdns___la_SOURCES += edns.h edns.cc
diff --git a/src/lib/python/isc/config/cfgmgr.py b/src/lib/python/isc/config/cfgmgr.py
index 8934de8..9f9ce68 100644
--- a/src/lib/python/isc/config/cfgmgr.py
+++ b/src/lib/python/isc/config/cfgmgr.py
@@ -189,7 +189,7 @@ class ConfigManager:
"""Initialize the configuration manager. The data_path string
is the path to the directory where the configuration is
stored (in <data_path>/<database_filename> or in
- <database_filename>, if it is absolute). The dabase_filename
+ <database_filename>, if it is absolute). The database_filename
is the config file to load. Session is an optional
cc-channel session. If this is not given, a new one is
created. If clear_config is True, the configuration file is
diff --git a/src/lib/python/isc/config/config_data.py b/src/lib/python/isc/config/config_data.py
index 48d7c1f..346585b 100644
--- a/src/lib/python/isc/config/config_data.py
+++ b/src/lib/python/isc/config/config_data.py
@@ -42,7 +42,7 @@ def spec_part_is_map(spec_part):
def spec_part_is_named_set(spec_part):
"""Returns True if the given spec_part is a dict that contains a
named_set specification, and False otherwise."""
- return (type(spec_part) == dict and 'named_map_item_spec' in spec_part)
+ return (type(spec_part) == dict and 'named_set_item_spec' in spec_part)
def check_type(spec_part, value):
"""Does nothing if the value is of the correct type given the
@@ -730,6 +730,15 @@ class MultiConfigData:
cur_id_part + id,
cur_value)
cur_id_part = cur_id_part + id_part + "/"
+
+ # We also need to copy to local if we are changing a named set,
+ # so that the other items in the set do not disappear
+ if spec_part_is_named_set(self.find_spec_part(cur_id_part)):
+ ns_value, ns_status = self.get_value(cur_id_part)
+ if ns_status != MultiConfigData.LOCAL:
+ isc.cc.data.set(self._local_changes,
+ cur_id_part,
+ ns_value)
isc.cc.data.set(self._local_changes, identifier, value)
def _get_list_items(self, item_name):
diff --git a/src/lib/python/isc/config/tests/config_data_test.py b/src/lib/python/isc/config/tests/config_data_test.py
index 46d27b1..864fe70 100644
--- a/src/lib/python/isc/config/tests/config_data_test.py
+++ b/src/lib/python/isc/config/tests/config_data_test.py
@@ -720,6 +720,12 @@ class TestMultiConfigData(unittest.TestCase):
config_items = self.mcd.get_config_item_list("Spec2", True)
self.assertEqual(['Spec2/item1', 'Spec2/item2', 'Spec2/item3', 'Spec2/item4', 'Spec2/item5', 'Spec2/item6/value1', 'Spec2/item6/value2'], config_items)
+ def test_is_named_set(self):
+ module_spec = isc.config.module_spec_from_file(self.data_path + os.sep + "spec32.spec")
+ self.mcd.set_specification(module_spec)
+ spec_part = self.mcd.find_spec_part("Spec32/named_set_item")
+ self.assertTrue(spec_part_is_named_set(spec_part))
+
def test_get_config_item_list_named_set(self):
config_items = self.mcd.get_config_item_list()
self.assertEqual([], config_items)
@@ -738,6 +744,20 @@ class TestMultiConfigData(unittest.TestCase):
'Spec32/named_set_item/bbbb',
], config_items)
+ def test_set_named_set_nonlocal(self):
+ # Test whether a default named set is copied to local if a subitem
+ # is changed, and that other items in the set do not get lost
+ module_spec = isc.config.module_spec_from_file(self.data_path + os.sep + 'spec32.spec')
+ self.mcd.set_specification(module_spec)
+ value, status = self.mcd.get_value('Spec32/named_set_item')
+ self.assertEqual({'a': 1, 'b': 2}, value)
+ self.assertEqual(MultiConfigData.DEFAULT, status)
+
+ self.mcd.set_value('Spec32/named_set_item/b', 3)
+ value, status = self.mcd.get_value('Spec32/named_set_item')
+ self.assertEqual({'a': 1, 'b': 3}, value)
+ self.assertEqual(MultiConfigData.LOCAL, status)
+
if __name__ == '__main__':
unittest.main()
diff --git a/src/lib/python/isc/datasrc/tests/datasrc_test.py b/src/lib/python/isc/datasrc/tests/datasrc_test.py
index c8823cd..c7bf6b4 100644
--- a/src/lib/python/isc/datasrc/tests/datasrc_test.py
+++ b/src/lib/python/isc/datasrc/tests/datasrc_test.py
@@ -262,16 +262,16 @@ class DataSrcClient(unittest.TestCase):
rrets = dsc.get_iterator(isc.dns.Name("example.com"))
# there are more than 80 RRs in this zone... let's just count them
# (already did a full check of the smaller zone above)
- self.assertEqual(55, len(list(rrets)))
+ # There are 40 non-RRSIG RRsets and 32 dinstinct RRSIGs.
+ self.assertEqual(72, len(list(rrets)))
# same test, but now with explicit False argument for separate_rrs
dsc = isc.datasrc.DataSourceClient("sqlite3", READ_ZONE_DB_CONFIG)
rrets = dsc.get_iterator(isc.dns.Name("example.com"), False)
# there are more than 80 RRs in this zone... let's just count them
# (already did a full check of the smaller zone above)
- self.assertEqual(55, len(list(rrets)))
+ self.assertEqual(72, len(list(rrets)))
- # Count should be 71 if we request individual rrsets for differing ttls
dsc = isc.datasrc.DataSourceClient("sqlite3", READ_ZONE_DB_CONFIG)
rrets = dsc.get_iterator(isc.dns.Name("example.com"), True)
# there are more than 80 RRs in this zone... let's just count them
diff --git a/src/lib/testutils/dnsmessage_test.cc b/src/lib/testutils/dnsmessage_test.cc
index 244f433..ec6914d 100644
--- a/src/lib/testutils/dnsmessage_test.cc
+++ b/src/lib/testutils/dnsmessage_test.cc
@@ -99,11 +99,12 @@ setRRset(RRsetPtr rrset, RRsetPtr* rrsetp) {
}
RRsetPtr
-textToRRset(const string& text_rrset, const RRClass& rrclass) {
+textToRRset(const string& text_rrset, const RRClass& rrclass,
+ const Name& origin)
+{
stringstream ss(text_rrset);
RRsetPtr rrset;
- masterLoad(ss, Name::ROOT_NAME(), rrclass,
- boost::bind(setRRset, _1, &rrset));
+ masterLoad(ss, origin, rrclass, boost::bind(setRRset, _1, &rrset));
return (rrset);
}
diff --git a/src/lib/testutils/dnsmessage_test.h b/src/lib/testutils/dnsmessage_test.h
index 83c9405..57cb72c 100644
--- a/src/lib/testutils/dnsmessage_test.h
+++ b/src/lib/testutils/dnsmessage_test.h
@@ -187,9 +187,15 @@ private:
/// It must meets the assumption of the \c dns::masterLoad() function.
/// \param rrclass The RR class of the RRset. Note that \c text_rrset should
/// contain the RR class, but it's needed for \c dns::masterLoad().
+/// \param origin The zone origin where the RR is expected to belong. This
+/// parameter normally doesn't have to be specified, but for an SOA RR it
+/// must be set to its owner name, due to the internal check of
+/// \c dns::masterLoad().
isc::dns::RRsetPtr textToRRset(const std::string& text_rrset,
const isc::dns::RRClass& rrclass =
- isc::dns::RRClass::IN());
+ isc::dns::RRClass::IN(),
+ const isc::dns::Name& origin =
+ isc::dns::Name::ROOT_NAME());
/// Set of unit tests to check if two sets of RRsets are identical.
///
diff --git a/src/lib/testutils/testdata/Makefile.am b/src/lib/testutils/testdata/Makefile.am
index a6b8206..b9ef53f 100644
--- a/src/lib/testutils/testdata/Makefile.am
+++ b/src/lib/testutils/testdata/Makefile.am
@@ -27,6 +27,7 @@ EXTRA_DIST += rfc5155-example.zone.signed
EXTRA_DIST += example.com
EXTRA_DIST += example.sqlite3
+EXTRA_DIST += rwtest.sqlite3 # SQLite3 DB file as a template data source
EXTRA_DIST += test1.zone.in
EXTRA_DIST += test1-new.zone.in
diff --git a/src/lib/testutils/testdata/auth_test.sqlite3 b/src/lib/testutils/testdata/auth_test.sqlite3
new file mode 100755
index 0000000..5eeb2c3
Binary files /dev/null and b/src/lib/testutils/testdata/auth_test.sqlite3 differ
diff --git a/src/lib/testutils/testdata/auth_test.sqlite3.copied b/src/lib/testutils/testdata/auth_test.sqlite3.copied
new file mode 100755
index 0000000..205e4ef
Binary files /dev/null and b/src/lib/testutils/testdata/auth_test.sqlite3.copied differ
diff --git a/src/lib/testutils/testdata/rwtest.sqlite3 b/src/lib/testutils/testdata/rwtest.sqlite3
new file mode 100644
index 0000000..5eeb2c3
Binary files /dev/null and b/src/lib/testutils/testdata/rwtest.sqlite3 differ
diff --git a/tests/lettuce/configurations/.gitignore b/tests/lettuce/configurations/.gitignore
index bea88b8..69d136f 100644
--- a/tests/lettuce/configurations/.gitignore
+++ b/tests/lettuce/configurations/.gitignore
@@ -1 +1,2 @@
+/bindctl_commands.config
/example.org.config
diff --git a/tests/lettuce/configurations/bindctl_commands.config.orig b/tests/lettuce/configurations/bindctl_commands.config.orig
new file mode 100644
index 0000000..d74b96e
--- /dev/null
+++ b/tests/lettuce/configurations/bindctl_commands.config.orig
@@ -0,0 +1,34 @@
+{
+ "version": 2,
+ "Logging": {
+ "loggers": [ {
+ "debuglevel": 99,
+ "severity": "DEBUG",
+ "name": "*"
+ } ]
+ },
+ "Auth": {
+ "database_file": "data/example.org.sqlite3",
+ "listen_on": [ {
+ "port": 47806,
+ "address": "127.0.0.1"
+ } ]
+ },
+ "StatsHttpd": {
+ "listen_on": [ {
+ "port": 47811,
+ "address": "127.0.0.1"
+ } ]
+ },
+ "Boss": {
+ "components": {
+ "b10-auth": { "kind": "dispensable", "special": "auth" },
+ "b10-xfrin": { "address": "Xfrin", "kind": "dispensable" },
+ "b10-xfrout": { "address": "Xfrout", "kind": "dispensable" },
+ "b10-zonemgr": { "address": "Zonemgr", "kind": "dispensable" },
+ "b10-stats": { "address": "Stats", "kind": "dispensable" },
+ "b10-stats-httpd": { "address": "StatsHttpd", "kind": "dispensable" },
+ "b10-cmdctl": { "special": "cmdctl", "kind": "needed" }
+ }
+ }
+}
diff --git a/tests/lettuce/configurations/default.config b/tests/lettuce/configurations/default.config
new file mode 100644
index 0000000..9e1d3d1
--- /dev/null
+++ b/tests/lettuce/configurations/default.config
@@ -0,0 +1,16 @@
+{
+ "version": 2,
+ "Logging": {
+ "loggers": [ {
+ "debuglevel": 99,
+ "severity": "DEBUG",
+ "name": "*"
+ } ]
+ },
+ "StatsHttpd": {
+ "listen_on": [ {
+ "port": 47811,
+ "address": "127.0.0.1"
+ } ]
+ }
+}
diff --git a/tests/lettuce/configurations/example.org.config.orig b/tests/lettuce/configurations/example.org.config.orig
index 642f2dd..fadb3e2 100644
--- a/tests/lettuce/configurations/example.org.config.orig
+++ b/tests/lettuce/configurations/example.org.config.orig
@@ -4,7 +4,7 @@
"loggers": [ {
"debuglevel": 99,
"severity": "DEBUG",
- "name": "auth"
+ "name": "*"
} ]
},
"Auth": {
@@ -13,5 +13,11 @@
"port": 47806,
"address": "127.0.0.1"
} ]
+ },
+ "Boss": {
+ "components": {
+ "b10-auth": { "kind": "needed", "special": "auth" },
+ "b10-cmdctl": { "special": "cmdctl", "kind": "needed" }
+ }
}
}
diff --git a/tests/lettuce/configurations/example.org.inmem.config b/tests/lettuce/configurations/example.org.inmem.config
index fa5f954..6418c65 100644
--- a/tests/lettuce/configurations/example.org.inmem.config
+++ b/tests/lettuce/configurations/example.org.inmem.config
@@ -1 +1,8 @@
-{"version": 2, "Logging": {"loggers": [{"severity": "DEBUG", "name": "auth", "debuglevel": 99}]}, "Auth": {"database_file": "", "listen_on": [{"port": 47806, "address": "127.0.0.1"}], "datasources": [{"zones": [{"origin": "example.org", "file": "data/example.org"}], "type": "memory"}]}}
+{"version": 2, "Logging": {"loggers": [{"severity": "DEBUG", "name": "*", "debuglevel": 99}]}, "Auth": {"database_file": "", "listen_on": [{"port": 47806, "address": "127.0.0.1"}], "datasources": [{"zones": [{"origin": "example.org", "file": "data/example.org"}], "type": "memory"}]},
+ "Boss": {
+ "components": {
+ "b10-auth": { "kind": "needed", "special": "auth" },
+ "b10-cmdctl": { "special": "cmdctl", "kind": "needed" }
+ }
+ }
+}
diff --git a/tests/lettuce/configurations/example2.org.config b/tests/lettuce/configurations/example2.org.config
index a6afb5b..25314dc 100644
--- a/tests/lettuce/configurations/example2.org.config
+++ b/tests/lettuce/configurations/example2.org.config
@@ -3,7 +3,7 @@
"Logging": {
"loggers": [ {
"severity": "DEBUG",
- "name": "auth",
+ "name": "*",
"debuglevel": 99
}
]
@@ -14,5 +14,11 @@
"port": 47807,
"address": "::1"
} ]
+ },
+ "Boss": {
+ "components": {
+ "b10-auth": { "kind": "needed", "special": "auth" },
+ "b10-cmdctl": { "special": "cmdctl", "kind": "needed" }
+ }
}
}
diff --git a/tests/lettuce/configurations/inmemory_over_sqlite3/secondary.conf b/tests/lettuce/configurations/inmemory_over_sqlite3/secondary.conf
new file mode 100644
index 0000000..a104726
--- /dev/null
+++ b/tests/lettuce/configurations/inmemory_over_sqlite3/secondary.conf
@@ -0,0 +1,32 @@
+{
+ "version": 2,
+ "Logging": {
+ "loggers": [ {
+ "debuglevel": 99,
+ "severity": "DEBUG",
+ "name": "auth"
+ } ]
+ },
+ "Auth": {
+ "datasources": [ {
+ "type": "memory",
+ "zones": [ {
+ "origin": "example.org",
+ "file": "data/example.org.sqlite3",
+ "filetype": "sqlite3"
+ } ]
+ } ],
+ "listen_on": [ {
+ "port": 47806,
+ "address": "127.0.0.1"
+ } ]
+ },
+ "Boss": {
+ "components": {
+ "b10-auth": { "kind": "needed", "special": "auth" },
+ "b10-xfrin": { "address": "Xfrin", "kind": "dispensable" },
+ "b10-zonemgr": { "address": "Zonemgr", "kind": "dispensable" },
+ "b10-cmdctl": { "special": "cmdctl", "kind": "needed" }
+ }
+ }
+}
diff --git a/tests/lettuce/configurations/ixfr-out/testset1-config.db b/tests/lettuce/configurations/ixfr-out/testset1-config.db
index c5fc165..1c1b990 100644
--- a/tests/lettuce/configurations/ixfr-out/testset1-config.db
+++ b/tests/lettuce/configurations/ixfr-out/testset1-config.db
@@ -1 +1,11 @@
-{"Xfrin": {"zones": [{"use_ixfr": true, "class": "IN", "name": "example.com.", "master_addr": "178.18.82.80"}]}, "version": 2, "Logging": {"loggers": [{"debuglevel": 99, "severity": "DEBUG", "output_options": [{"output": "stderr", "flush": true}], "name": "*"}]}, "Auth": {"database_file": "data/ixfr-out/zones.slite3", "listen_on": [{"port": 47806, "address": "::"}, {"port": 47806, "address": "0.0.0.0"}]}}
+{"Xfrin": {"zones": [{"use_ixfr": true, "class": "IN", "name": "example.com.", "master_addr": "178.18.82.80"}]}, "version": 2, "Logging": {"loggers": [{"debuglevel": 99, "severity": "DEBUG", "output_options": [{"output": "stderr", "flush": true}], "name": "*"}]}, "Auth": {"database_file": "data/ixfr-out/zones.sqlite3", "listen_on": [{"port": 47806, "address": "::"}, {"port": 47806, "address": "0.0.0.0"}]},
+ "Boss": {
+ "components": {
+ "b10-auth": { "kind": "needed", "special": "auth" },
+ "b10-xfrin": { "address": "Xfrin", "kind": "dispensable" },
+ "b10-xfrout": { "address": "Xfrout", "kind": "dispensable" },
+ "b10-zonemgr": { "address": "Zonemgr", "kind": "dispensable" },
+ "b10-cmdctl": { "special": "cmdctl", "kind": "needed" }
+ }
+ }
+}
diff --git a/tests/lettuce/configurations/multi_instance/multi_auth.config.orig b/tests/lettuce/configurations/multi_instance/multi_auth.config.orig
index f181d42..53c2b7a 100644
--- a/tests/lettuce/configurations/multi_instance/multi_auth.config.orig
+++ b/tests/lettuce/configurations/multi_instance/multi_auth.config.orig
@@ -1 +1 @@
-{"version": 2, "Auth": {"listen_on": [{"port": 47806, "address": "0.0.0.0"}]}, "Boss": {"components": {"b10-auth-2": {"kind": "needed", "special": "auth"}, "b10-auth": {"kind": "needed", "special": "auth"}, "b10-cmdctl": {"kind": "needed", "special": "cmdctl"}}}}
+{"version": 2, "Logging": {"loggers": [{"severity": "DEBUG", "name": "*", "debuglevel": 99}]}, "Auth": {"listen_on": [{"port": 47806, "address": "0.0.0.0"}]}, "Boss": {"components": {"b10-auth-2": {"kind": "dispensable", "special": "auth"}, "b10-auth": {"kind": "dispensable", "special": "auth"}, "b10-cmdctl": {"kind": "needed", "special": "cmdctl"}}}}
diff --git a/tests/lettuce/configurations/no_db_file.config b/tests/lettuce/configurations/no_db_file.config
index f865354..fc0a25d 100644
--- a/tests/lettuce/configurations/no_db_file.config
+++ b/tests/lettuce/configurations/no_db_file.config
@@ -1,10 +1,24 @@
{
"version": 2,
+ "Logging": {
+ "loggers": [ {
+ "severity": "DEBUG",
+ "name": "*",
+ "debuglevel": 99
+ }
+ ]
+ },
"Auth": {
"database_file": "data/test_nonexistent_db.sqlite3",
"listen_on": [ {
"port": 47806,
"address": "127.0.0.1"
} ]
+ },
+ "Boss": {
+ "components": {
+ "b10-auth": { "kind": "needed", "special": "auth" },
+ "b10-cmdctl": { "special": "cmdctl", "kind": "needed" }
+ }
}
}
diff --git a/tests/lettuce/configurations/nsec3/nsec3_auth.config b/tests/lettuce/configurations/nsec3/nsec3_auth.config
index 2de5284..94514c0 100644
--- a/tests/lettuce/configurations/nsec3/nsec3_auth.config
+++ b/tests/lettuce/configurations/nsec3/nsec3_auth.config
@@ -1 +1 @@
-{"version": 2, "Auth": {"datasources": [{"zones": [{"origin": "example.", "file": "configurations/nsec3/rfc5155-example.zone.signed"}], "type": "memory"}], "listen_on": [{"port": 47806, "address": "0.0.0.0"}]}, "Boss": {"components": {"b10-auth": {"kind": "needed", "special": "auth"}, "b10-cmdctl": {"kind": "needed", "special": "cmdctl"}}}}
+{"version": 2, "Logging": {"loggers": [{"severity": "DEBUG", "name": "*", "debuglevel": 99}]}, "Auth": {"datasources": [{"zones": [{"origin": "example.", "file": "configurations/nsec3/rfc5155-example.zone.signed"}], "type": "memory"}], "listen_on": [{"port": 47806, "address": "0.0.0.0"}]}, "Boss": {"components": {"b10-auth": {"kind": "needed", "special": "auth"}, "b10-cmdctl": {"kind": "needed", "special": "cmdctl"}}}}
diff --git a/tests/lettuce/configurations/resolver/resolver_basic.config.orig b/tests/lettuce/configurations/resolver/resolver_basic.config.orig
index 5664c20..0adca9f 100644
--- a/tests/lettuce/configurations/resolver/resolver_basic.config.orig
+++ b/tests/lettuce/configurations/resolver/resolver_basic.config.orig
@@ -1 +1 @@
-{"version": 2, "Resolver": {"query_acl": [{"action": "REJECT", "from": "127.0.0.1"}], "listen_on": [{"port": 47806, "address": "127.0.0.1"}]}, "Boss": {"components": {"b10-resolver": {"kind": "needed"}, "b10-cmdctl": {"kind": "needed", "special": "cmdctl"}}}}
+{"version": 2, "Logging": {"loggers": [{"severity": "DEBUG", "name": "*", "debuglevel": 99}]}, "Resolver": {"query_acl": [{"action": "REJECT", "from": "127.0.0.1"}], "listen_on": [{"port": 47806, "address": "127.0.0.1"}]}, "Boss": {"components": {"b10-resolver": {"kind": "needed"}, "b10-cmdctl": {"kind": "needed", "special": "cmdctl"}}}}
diff --git a/tests/lettuce/configurations/xfrin/retransfer_master.conf b/tests/lettuce/configurations/xfrin/retransfer_master.conf
index a9d5440..eae47a6 100644
--- a/tests/lettuce/configurations/xfrin/retransfer_master.conf
+++ b/tests/lettuce/configurations/xfrin/retransfer_master.conf
@@ -4,7 +4,7 @@
"loggers": [ {
"debuglevel": 99,
"severity": "DEBUG",
- "name": "auth"
+ "name": "*"
} ]
},
"Auth": {
@@ -18,5 +18,13 @@
"zone_config": [ {
"origin": "example.org"
} ]
+ },
+ "Boss": {
+ "components": {
+ "b10-auth": { "kind": "needed", "special": "auth" },
+ "b10-xfrout": { "address": "Xfrout", "kind": "dispensable" },
+ "b10-zonemgr": { "address": "Zonemgr", "kind": "dispensable" },
+ "b10-cmdctl": { "special": "cmdctl", "kind": "needed" }
+ }
}
}
diff --git a/tests/lettuce/configurations/xfrin/retransfer_slave.conf b/tests/lettuce/configurations/xfrin/retransfer_slave.conf
index 51622cd..2296b8f 100644
--- a/tests/lettuce/configurations/xfrin/retransfer_slave.conf
+++ b/tests/lettuce/configurations/xfrin/retransfer_slave.conf
@@ -4,7 +4,7 @@
"loggers": [ {
"debuglevel": 99,
"severity": "DEBUG",
- "name": "auth"
+ "name": "*"
} ]
},
"Auth": {
@@ -13,5 +13,13 @@
"port": 47806,
"address": "127.0.0.1"
} ]
+ },
+ "Boss": {
+ "components": {
+ "b10-auth": { "kind": "needed", "special": "auth" },
+ "b10-xfrin": { "address": "Xfrin", "kind": "dispensable" },
+ "b10-zonemgr": { "address": "Zonemgr", "kind": "dispensable" },
+ "b10-cmdctl": { "special": "cmdctl", "kind": "needed" }
+ }
}
}
diff --git a/tests/lettuce/data/.gitignore b/tests/lettuce/data/.gitignore
new file mode 100644
index 0000000..299b6d2
--- /dev/null
+++ b/tests/lettuce/data/.gitignore
@@ -0,0 +1 @@
+/test_nonexistent_db.sqlite3
diff --git a/tests/lettuce/data/ixfr-out/zones.slite3 b/tests/lettuce/data/ixfr-out/zones.slite3
deleted file mode 100644
index 311d335..0000000
Binary files a/tests/lettuce/data/ixfr-out/zones.slite3 and /dev/null differ
diff --git a/tests/lettuce/data/ixfr-out/zones.sqlite3 b/tests/lettuce/data/ixfr-out/zones.sqlite3
new file mode 100644
index 0000000..311d335
Binary files /dev/null and b/tests/lettuce/data/ixfr-out/zones.sqlite3 differ
diff --git a/tests/lettuce/features/bindctl_commands.feature b/tests/lettuce/features/bindctl_commands.feature
index 872064f..03a04bf 100644
--- a/tests/lettuce/features/bindctl_commands.feature
+++ b/tests/lettuce/features/bindctl_commands.feature
@@ -8,7 +8,15 @@ Feature: control with bindctl
# modules (note that it 'misuses' the help command for this,
# there is a Boss command 'show_processes' but it's output is
# currently less standardized than 'help')
- Given I have bind10 running with configuration example.org.config
+ Given I have bind10 running with configuration bindctl_commands.config
+ And wait for bind10 stderr message BIND10_STARTED_CC
+ And wait for bind10 stderr message CMDCTL_STARTED
+ And wait for bind10 stderr message ZONEMGR_STARTED
+ And wait for bind10 stderr message AUTH_SERVER_STARTED
+ And wait for bind10 stderr message XFRIN_STARTED
+ And wait for bind10 stderr message XFROUT_STARTED
+ And wait for bind10 stderr message STATS_STARTING
+ And wait for bind10 stderr message STATHTTPD_STARTED
Then remove bind10 configuration Boss/components/NOSUCHMODULE
last bindctl output should contain Error
@@ -19,20 +27,39 @@ Feature: control with bindctl
bind10 module Xfrin should be running
bind10 module Auth should be running
bind10 module StatsHttpd should be running
+ bind10 module Resolver should not be running
Then remove bind10 configuration Boss/components value b10-xfrout
+ And wait for new bind10 stderr message BIND10_PROCESS_ENDED
last bindctl output should not contain Error
+
# assuming it won't error for further modules (if it does, the final
# 'should not be running' tests would fail anyway)
+ Then remove bind10 configuration Boss/components value b10-stats-httpd
+ And wait for new bind10 stderr message BIND10_PROCESS_ENDED
+ last bindctl output should not contain Error
+
Then remove bind10 configuration Boss/components value b10-stats
+ And wait for new bind10 stderr message BIND10_PROCESS_ENDED
+ last bindctl output should not contain Error
+
Then remove bind10 configuration Boss/components value b10-zonemgr
+ And wait for new bind10 stderr message BIND10_PROCESS_ENDED
+ last bindctl output should not contain Error
+
Then remove bind10 configuration Boss/components value b10-xfrin
+ And wait for new bind10 stderr message BIND10_PROCESS_ENDED
+ last bindctl output should not contain Error
+
Then remove bind10 configuration Boss/components value b10-auth
- Then remove bind10 configuration Boss/components value b10-stats-httpd
+ And wait for new bind10 stderr message BIND10_PROCESS_ENDED
+ last bindctl output should not contain Error
+ # After these ^^^ have been stopped...
bind10 module Xfrout should not be running
- bind10 module Stats should not be running
bind10 module Zonemgr should not be running
bind10 module Xfrin should not be running
bind10 module Auth should not be running
bind10 module StatsHttpd should not be running
+ bind10 module Stats should not be running
+ bind10 module Resolver should not be running
diff --git a/tests/lettuce/features/default.feature b/tests/lettuce/features/default.feature
new file mode 100644
index 0000000..daace57
--- /dev/null
+++ b/tests/lettuce/features/default.feature
@@ -0,0 +1,22 @@
+Feature: default bind10 config
+ Tests for the default configuration of bind10.
+
+ Scenario: Check that only the default components are running
+ Given I have bind10 running with configuration default.config
+ And wait for bind10 stderr message BIND10_STARTED_CC
+ And wait for bind10 stderr message CMDCTL_STARTED
+ And wait for bind10 stderr message STATS_STARTING
+ And wait for bind10 stderr message STATHTTPD_STARTED
+
+ # These should be running
+ bind10 module Boss should be running
+ And bind10 module Logging should be running
+ And bind10 module Stats should be running
+ And bind10 module StatsHttpd should be running
+
+ # These should not be running
+ bind10 module Resolver should not be running
+ And bind10 module Xfrout should not be running
+ And bind10 module Zonemgr should not be running
+ And bind10 module Xfrin should not be running
+ And bind10 module Auth should not be running
diff --git a/tests/lettuce/features/example.feature b/tests/lettuce/features/example.feature
index ee388f1..ca5ffbf 100644
--- a/tests/lettuce/features/example.feature
+++ b/tests/lettuce/features/example.feature
@@ -8,6 +8,18 @@ Feature: Example feature
Scenario: A simple example
Given I have bind10 running with configuration example.org.config
+ And wait for bind10 stderr message BIND10_STARTED_CC
+ And wait for bind10 stderr message CMDCTL_STARTED
+ And wait for bind10 stderr message AUTH_SERVER_STARTED
+
+ bind10 module Auth should be running
+ And bind10 module Resolver should not be running
+ And bind10 module Xfrout should not be running
+ And bind10 module Zonemgr should not be running
+ And bind10 module Xfrin should not be running
+ And bind10 module Stats should not be running
+ And bind10 module StatsHttpd should not be running
+
A query for www.example.org should have rcode NOERROR
A query for www.doesnotexist.org should have rcode REFUSED
The SOA serial for example.org should be 1234
@@ -26,8 +38,18 @@ Feature: Example feature
# is actually a compound step consisting of the following two
# one to start the server
When I start bind10 with configuration no_db_file.config
- # And one to wait until it reports that b10-auth has started
- Then wait for bind10 auth to start
+
+ And wait for bind10 stderr message BIND10_STARTED_CC
+ And wait for bind10 stderr message CMDCTL_STARTED
+ And wait for bind10 stderr message AUTH_SERVER_STARTED
+
+ bind10 module Auth should be running
+ And bind10 module Resolver should not be running
+ And bind10 module Xfrout should not be running
+ And bind10 module Zonemgr should not be running
+ And bind10 module Xfrin should not be running
+ And bind10 module Stats should not be running
+ And bind10 module StatsHttpd should not be running
# This is a general step to stop a named process. By convention,
# the default name for any process is the same as the one we
@@ -50,6 +72,17 @@ Feature: Example feature
# This is a compound statement that starts and waits for the
# started message
Given I have bind10 running with configuration example.org.config
+ And wait for bind10 stderr message BIND10_STARTED_CC
+ And wait for bind10 stderr message CMDCTL_STARTED
+ And wait for bind10 stderr message AUTH_SERVER_STARTED
+
+ bind10 module Auth should be running
+ And bind10 module Resolver should not be running
+ And bind10 module Xfrout should not be running
+ And bind10 module Zonemgr should not be running
+ And bind10 module Xfrin should not be running
+ And bind10 module Stats should not be running
+ And bind10 module StatsHttpd should not be running
# Some simple queries that is not examined further
A query for www.example.com should have rcode REFUSED
@@ -113,8 +146,18 @@ Feature: Example feature
# the system
When I start bind10 with configuration example.org.config
- Then wait for bind10 auth to start
- Wait for bind10 stderr message CMDCTL_STARTED
+ And wait for bind10 stderr message BIND10_STARTED_CC
+ And wait for bind10 stderr message CMDCTL_STARTED
+ And wait for bind10 stderr message AUTH_SERVER_STARTED
+
+ bind10 module Auth should be running
+ And bind10 module Resolver should not be running
+ And bind10 module Xfrout should not be running
+ And bind10 module Zonemgr should not be running
+ And bind10 module Xfrin should not be running
+ And bind10 module Stats should not be running
+ And bind10 module StatsHttpd should not be running
+
A query for www.example.org should have rcode NOERROR
Wait for new bind10 stderr message AUTH_SEND_NORMAL_RESPONSE
Then set bind10 configuration Auth/database_file to data/empty_db.sqlite3
@@ -128,10 +171,15 @@ Feature: Example feature
Scenario: two bind10 instances
# This is more a test of the test system, start 2 bind10's
When I start bind10 with configuration example.org.config as bind10_one
+ And wait for bind10_one stderr message BIND10_STARTED_CC
+ And wait for bind10_one stderr message CMDCTL_STARTED
+ And wait for bind10_one stderr message AUTH_SERVER_STARTED
+
And I start bind10 with configuration example2.org.config with cmdctl port 47804 as bind10_two
+ And wait for bind10_two stderr message BIND10_STARTED_CC
+ And wait for bind10_two stderr message CMDCTL_STARTED
+ And wait for bind10_two stderr message AUTH_SERVER_STARTED
- Then wait for bind10 auth of bind10_one to start
- Then wait for bind10 auth of bind10_two to start
A query for www.example.org to 127.0.0.1:47806 should have rcode NOERROR
A query for www.example.org to [::1]:47807 should have rcode NOERROR
diff --git a/tests/lettuce/features/inmemory_over_sqlite3.feature b/tests/lettuce/features/inmemory_over_sqlite3.feature
new file mode 100644
index 0000000..60945c8
--- /dev/null
+++ b/tests/lettuce/features/inmemory_over_sqlite3.feature
@@ -0,0 +1,9 @@
+Feature: In-memory zone using SQLite3 backend
+ This feature tests the authoritative server configured with an in-memory
+ data source that uses the SQLite3 data source as the backend, and tests
+ scenarios that update the zone via incoming zone transfers.
+
+ Scenario: Load and response
+ Given I have bind10 running with configuration inmemory_over_sqlite3/secondary.conf
+ A query for www.example.org should have rcode NOERROR
+ The SOA serial for example.org should be 1234
diff --git a/tests/lettuce/features/ixfr_out_bind10.feature b/tests/lettuce/features/ixfr_out_bind10.feature
index e84ad8c..24a9299 100644
--- a/tests/lettuce/features/ixfr_out_bind10.feature
+++ b/tests/lettuce/features/ixfr_out_bind10.feature
@@ -31,7 +31,14 @@ Feature: IXFR out
Scenario: Test Set 1
Given I have bind10 running with configuration ixfr-out/testset1-config.db
- Then wait for bind10 xfrout to start
+
+ And wait for bind10 stderr message BIND10_STARTED_CC
+ And wait for bind10 stderr message CMDCTL_STARTED
+ And wait for bind10 stderr message AUTH_SERVER_STARTED
+ And wait for bind10 stderr message XFROUT_STARTED
+ And wait for bind10 stderr message XFRIN_STARTED
+ And wait for bind10 stderr message ZONEMGR_STARTED
+
The SOA serial for example.com should be 22
#
@@ -146,7 +153,14 @@ Feature: IXFR out
Scenario: Test Set 2
Given I have bind10 running with configuration ixfr-out/testset1-config.db
- Then wait for bind10 xfrout to start
+
+ And wait for bind10 stderr message BIND10_STARTED_CC
+ And wait for bind10 stderr message CMDCTL_STARTED
+ And wait for bind10 stderr message AUTH_SERVER_STARTED
+ And wait for bind10 stderr message XFROUT_STARTED
+ And wait for bind10 stderr message XFRIN_STARTED
+ And wait for bind10 stderr message ZONEMGR_STARTED
+
The SOA serial for example.com should be 22
#
diff --git a/tests/lettuce/features/multi_instance.feature b/tests/lettuce/features/multi_instance.feature
index 864431d..048e60e 100644
--- a/tests/lettuce/features/multi_instance.feature
+++ b/tests/lettuce/features/multi_instance.feature
@@ -5,7 +5,22 @@ Feature: Multiple instances
Scenario: Multiple instances of Auth
# This config should have two running instances
Given I have bind10 running with configuration multi_instance/multi_auth.config
- And bind10 module Auth should be running
+ And wait for bind10 stderr message BIND10_STARTED_CC
+ And wait for bind10 stderr message CMDCTL_STARTED
+
+ # This is a hack. We should actually check if b10-auth and
+ # b10-auth-2 are started by name. But there's currently no way
+ # for a component to find out its name and log it.
+ And wait 2 times for bind10 stderr message AUTH_SERVER_STARTED
+
+ bind10 module Auth should be running
+ And bind10 module Resolver should not be running
+ And bind10 module Xfrout should not be running
+ And bind10 module Zonemgr should not be running
+ And bind10 module Xfrin should not be running
+ And bind10 module Stats should not be running
+ And bind10 module StatsHttpd should not be running
+
A query for example.com should have rcode REFUSED
# this also checks whether the process is running
@@ -13,6 +28,7 @@ Feature: Multiple instances
And remember the pid of process b10-auth-2
When I remove bind10 configuration Boss/components value b10-auth-2
+ And wait for new bind10 stderr message BIND10_PROCESS_ENDED
Then the pid of process b10-auth should not have changed
And a query for example.com should have rcode REFUSED
@@ -31,5 +47,6 @@ Feature: Multiple instances
A query for example.com should have rcode REFUSED
When I remove bind10 configuration Boss/components value b10-auth
+ And wait for new bind10 stderr message BIND10_PROCESS_ENDED
Then the pid of process b10-auth-2 should not have changed
A query for example.com should have rcode REFUSED
diff --git a/tests/lettuce/features/nsec3_auth.feature b/tests/lettuce/features/nsec3_auth.feature
index 0fbf219..4e5ed5b 100644
--- a/tests/lettuce/features/nsec3_auth.feature
+++ b/tests/lettuce/features/nsec3_auth.feature
@@ -12,6 +12,18 @@ Feature: NSEC3 Authoritative service
Scenario: B.1. Name Error
Given I have bind10 running with configuration nsec3/nsec3_auth.config
+ And wait for bind10 stderr message BIND10_STARTED_CC
+ And wait for bind10 stderr message CMDCTL_STARTED
+ And wait for bind10 stderr message AUTH_SERVER_STARTED
+
+ bind10 module Auth should be running
+ And bind10 module Resolver should not be running
+ And bind10 module Xfrout should not be running
+ And bind10 module Zonemgr should not be running
+ And bind10 module Xfrin should not be running
+ And bind10 module Stats should not be running
+ And bind10 module StatsHttpd should not be running
+
A dnssec query for a.c.x.w.example. should have rcode NXDOMAIN
The last query response should have flags qr aa rd
The last query response should have edns_flags do
@@ -20,18 +32,30 @@ Feature: NSEC3 Authoritative service
The last query response should have adcount 1
The authority section of the last query response should be
"""
- example. 3600 IN SOA ns1.example. bugs.x.w.example. 1 3600 300 3600000 3600
- example. 3600 IN RRSIG SOA 7 1 3600 20150420235959 20051021000000 40430 example. Hu25UIyNPmvPIVBrldN+9Mlp9Zql39qaUd8iq4ZLlYWfUUbbAS41pG+6 8z81q1xhkYAcEyHdVI2LmKusbZsT0Q==
- 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example. 3600 IN NSEC3 1 1 12 aabbccdd 2t7b4g4vsa5smi47k61mv5bv1a22bojr NS SOA MX RRSIG DNSKEY NSEC3PARAM
- 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. OSgWSm26B+cS+dDL8b5QrWr/dEWhtCsKlwKLIBHYH6blRxK9rC0bMJPw Q4mLIuw85H2EY762BOCXJZMnpuwhpA==
- b4um86eghhds6nea196smvmlo4ors995.example. 3600 IN NSEC3 1 1 12 aabbccdd gjeqe526plbf1g8mklp59enfd789njgi MX RRSIG
- b4um86eghhds6nea196smvmlo4ors995.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. ZkPG3M32lmoHM6pa3D6gZFGB/rhL//Bs3Omh5u4m/CUiwtblEVOaAKKZ d7S959OeiX43aLX3pOv0TSTyiTxIZg==
- 35mthgpgcu1qg68fab165klnsnk3dpvl.example. 3600 IN NSEC3 1 1 12 aabbccdd b4um86eghhds6nea196smvmlo4ors995 NS DS RRSIG
- 35mthgpgcu1qg68fab165klnsnk3dpvl.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. g6jPUUpduAJKRljUsN8gB4UagAX0NxY9shwQAynzo8EUWH+z6hEIBlUT PGj15eZll6VhQqgZXtAIR3chwgW+SA==
+ example. 3600 IN SOA ns1.example. bugs.x.w.example. 1 3600 300 3600000 3600
+ example. 3600 IN RRSIG SOA 7 1 3600 20150420235959 20051021000000 40430 example. Hu25UIyNPmvPIVBrldN+9Mlp9Zql39qaUd8iq4ZLlYWfUUbbAS41pG+6 8z81q1xhkYAcEyHdVI2LmKusbZsT0Q==
+ 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example. 3600 IN NSEC3 1 1 12 aabbccdd 2t7b4g4vsa5smi47k61mv5bv1a22bojr NS SOA MX RRSIG DNSKEY NSEC3PARAM
+ 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. OSgWSm26B+cS+dDL8b5QrWr/dEWhtCsKlwKLIBHYH6blRxK9rC0bMJPw Q4mLIuw85H2EY762BOCXJZMnpuwhpA==
+ b4um86eghhds6nea196smvmlo4ors995.example. 3600 IN NSEC3 1 1 12 aabbccdd gjeqe526plbf1g8mklp59enfd789njgi MX RRSIG
+ b4um86eghhds6nea196smvmlo4ors995.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. ZkPG3M32lmoHM6pa3D6gZFGB/rhL//Bs3Omh5u4m/CUiwtblEVOaAKKZ d7S959OeiX43aLX3pOv0TSTyiTxIZg==
+ 35mthgpgcu1qg68fab165klnsnk3dpvl.example. 3600 IN NSEC3 1 1 12 aabbccdd b4um86eghhds6nea196smvmlo4ors995 NS DS RRSIG
+ 35mthgpgcu1qg68fab165klnsnk3dpvl.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. g6jPUUpduAJKRljUsN8gB4UagAX0NxY9shwQAynzo8EUWH+z6hEIBlUT PGj15eZll6VhQqgZXtAIR3chwgW+SA==
"""
Scenario: B.2. No Data Error
Given I have bind10 running with configuration nsec3/nsec3_auth.config
+ And wait for bind10 stderr message BIND10_STARTED_CC
+ And wait for bind10 stderr message CMDCTL_STARTED
+ And wait for bind10 stderr message AUTH_SERVER_STARTED
+
+ bind10 module Auth should be running
+ And bind10 module Resolver should not be running
+ And bind10 module Xfrout should not be running
+ And bind10 module Zonemgr should not be running
+ And bind10 module Xfrin should not be running
+ And bind10 module Stats should not be running
+ And bind10 module StatsHttpd should not be running
+
A dnssec query for ns1.example. type MX should have rcode NOERROR
The last query response should have flags qr aa rd
The last query response should have edns_flags do
@@ -40,14 +64,26 @@ Feature: NSEC3 Authoritative service
The last query response should have adcount 1
The authority section of the last query response should be
"""
- example. 3600 IN SOA ns1.example. bugs.x.w.example. 1 3600 300 3600000 3600
- example. 3600 IN RRSIG SOA 7 1 3600 20150420235959 20051021000000 40430 example. Hu25UIyNPmvPIVBrldN+9Mlp9Zql39qaUd8iq4ZLlYWfUUbbAS41pG+6 8z81q1xhkYAcEyHdVI2LmKusbZsT0Q==
- 2t7b4g4vsa5smi47k61mv5bv1a22bojr.example. 3600 IN NSEC3 1 1 12 aabbccdd 2vptu5timamqttgl4luu9kg21e0aor3s A RRSIG
- 2t7b4g4vsa5smi47k61mv5bv1a22bojr.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. OmBvJ1Vgg1hCKMXHFiNeIYHK9XVW0iLDLwJN4TFoNxZuP03gAXEI634Y wOc4YBNITrj413iqNI6mRk/r1dOSUw==
+ example. 3600 IN SOA ns1.example. bugs.x.w.example. 1 3600 300 3600000 3600
+ example. 3600 IN RRSIG SOA 7 1 3600 20150420235959 20051021000000 40430 example. Hu25UIyNPmvPIVBrldN+9Mlp9Zql39qaUd8iq4ZLlYWfUUbbAS41pG+6 8z81q1xhkYAcEyHdVI2LmKusbZsT0Q==
+ 2t7b4g4vsa5smi47k61mv5bv1a22bojr.example. 3600 IN NSEC3 1 1 12 aabbccdd 2vptu5timamqttgl4luu9kg21e0aor3s A RRSIG
+ 2t7b4g4vsa5smi47k61mv5bv1a22bojr.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. OmBvJ1Vgg1hCKMXHFiNeIYHK9XVW0iLDLwJN4TFoNxZuP03gAXEI634Y wOc4YBNITrj413iqNI6mRk/r1dOSUw==
"""
Scenario: B2.1. No Data Error, Empty Non-Terminal
Given I have bind10 running with configuration nsec3/nsec3_auth.config
+ And wait for bind10 stderr message BIND10_STARTED_CC
+ And wait for bind10 stderr message CMDCTL_STARTED
+ And wait for bind10 stderr message AUTH_SERVER_STARTED
+
+ bind10 module Auth should be running
+ And bind10 module Resolver should not be running
+ And bind10 module Xfrout should not be running
+ And bind10 module Zonemgr should not be running
+ And bind10 module Xfrin should not be running
+ And bind10 module Stats should not be running
+ And bind10 module StatsHttpd should not be running
+
A dnssec query for y.w.example. should have rcode NOERROR
The last query response should have flags qr aa rd
The last query response should have edns_flags do
@@ -56,14 +92,26 @@ Feature: NSEC3 Authoritative service
The last query response should have adcount 1
The authority section of the last query response should be
"""
- example. 3600 IN SOA ns1.example. bugs.x.w.example. 1 3600 300 3600000 3600
- example. 3600 IN RRSIG SOA 7 1 3600 20150420235959 20051021000000 40430 example. Hu25UIyNPmvPIVBrldN+9Mlp9Zql39qaUd8iq4ZLlYWfUUbbAS41pG+6 8z81q1xhkYAcEyHdVI2LmKusbZsT0Q==
- ji6neoaepv8b5o6k4ev33abha8ht9fgc.example. 3600 IN NSEC3 1 1 12 aabbccdd k8udemvp1j2f7eg6jebps17vp3n8i58h
- ji6neoaepv8b5o6k4ev33abha8ht9fgc.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. gPkFp1s2QDQ6wQzcg1uSebZ61W33rUBDcTj72F3kQ490fEdp7k1BUIfb cZtPbX3YCpE+sIt0MpzVSKfTwx4uYA==
+ example. 3600 IN SOA ns1.example. bugs.x.w.example. 1 3600 300 3600000 3600
+ example. 3600 IN RRSIG SOA 7 1 3600 20150420235959 20051021000000 40430 example. Hu25UIyNPmvPIVBrldN+9Mlp9Zql39qaUd8iq4ZLlYWfUUbbAS41pG+6 8z81q1xhkYAcEyHdVI2LmKusbZsT0Q==
+ ji6neoaepv8b5o6k4ev33abha8ht9fgc.example. 3600 IN NSEC3 1 1 12 aabbccdd k8udemvp1j2f7eg6jebps17vp3n8i58h
+ ji6neoaepv8b5o6k4ev33abha8ht9fgc.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. gPkFp1s2QDQ6wQzcg1uSebZ61W33rUBDcTj72F3kQ490fEdp7k1BUIfb cZtPbX3YCpE+sIt0MpzVSKfTwx4uYA==
"""
Scenario: B.3. Referral to an Opt-Out Unsigned Zone
Given I have bind10 running with configuration nsec3/nsec3_auth.config
+ And wait for bind10 stderr message BIND10_STARTED_CC
+ And wait for bind10 stderr message CMDCTL_STARTED
+ And wait for bind10 stderr message AUTH_SERVER_STARTED
+
+ bind10 module Auth should be running
+ And bind10 module Resolver should not be running
+ And bind10 module Xfrout should not be running
+ And bind10 module Zonemgr should not be running
+ And bind10 module Xfrin should not be running
+ And bind10 module Stats should not be running
+ And bind10 module StatsHttpd should not be running
+
A dnssec query for mc.c.example. type MX should have rcode NOERROR
The last query response should have flags qr rd
The last query response should have edns_flags do
@@ -72,12 +120,12 @@ Feature: NSEC3 Authoritative service
The last query response should have adcount 3
The authority section of the last query response should be
"""
- c.example. 3600 IN NS ns1.c.example.
- c.example. 3600 IN NS ns2.c.example.
- 35mthgpgcu1qg68fab165klnsnk3dpvl.example. 3600 IN NSEC3 1 1 12 aabbccdd b4um86eghhds6nea196smvmlo4ors995 NS DS RRSIG
- 35mthgpgcu1qg68fab165klnsnk3dpvl.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. g6jPUUpduAJKRljUsN8gB4UagAX0NxY9shwQAynzo8EUWH+z6hEIBlUT PGj15eZll6VhQqgZXtAIR3chwgW+SA==
- 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example. 3600 IN NSEC3 1 1 12 aabbccdd 2t7b4g4vsa5smi47k61mv5bv1a22bojr NS SOA MX RRSIG DNSKEY NSEC3PARAM
- 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. OSgWSm26B+cS+dDL8b5QrWr/dEWhtCsKlwKLIBHYH6blRxK9rC0bMJPw Q4mLIuw85H2EY762BOCXJZMnpuwhpA==
+ c.example. 3600 IN NS ns1.c.example.
+ c.example. 3600 IN NS ns2.c.example.
+ 35mthgpgcu1qg68fab165klnsnk3dpvl.example. 3600 IN NSEC3 1 1 12 aabbccdd b4um86eghhds6nea196smvmlo4ors995 NS DS RRSIG
+ 35mthgpgcu1qg68fab165klnsnk3dpvl.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. g6jPUUpduAJKRljUsN8gB4UagAX0NxY9shwQAynzo8EUWH+z6hEIBlUT PGj15eZll6VhQqgZXtAIR3chwgW+SA==
+ 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example. 3600 IN NSEC3 1 1 12 aabbccdd 2t7b4g4vsa5smi47k61mv5bv1a22bojr NS SOA MX RRSIG DNSKEY NSEC3PARAM
+ 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. OSgWSm26B+cS+dDL8b5QrWr/dEWhtCsKlwKLIBHYH6blRxK9rC0bMJPw Q4mLIuw85H2EY762BOCXJZMnpuwhpA==
"""
The additional section of the last query response should be
"""
@@ -87,6 +135,18 @@ Feature: NSEC3 Authoritative service
Scenario: B.4. Wildcard Expansion
Given I have bind10 running with configuration nsec3/nsec3_auth.config
+ And wait for bind10 stderr message BIND10_STARTED_CC
+ And wait for bind10 stderr message CMDCTL_STARTED
+ And wait for bind10 stderr message AUTH_SERVER_STARTED
+
+ bind10 module Auth should be running
+ And bind10 module Resolver should not be running
+ And bind10 module Xfrout should not be running
+ And bind10 module Zonemgr should not be running
+ And bind10 module Xfrin should not be running
+ And bind10 module Stats should not be running
+ And bind10 module StatsHttpd should not be running
+
A dnssec query for a.z.w.example. type MX should have rcode NOERROR
The last query response should have flags qr aa rd
The last query response should have edns_flags do
@@ -95,33 +155,45 @@ Feature: NSEC3 Authoritative service
The last query response should have adcount 9
The answer section of the last query response should be
"""
- a.z.w.example. 3600 IN MX 1 ai.example.
- a.z.w.example. 3600 IN RRSIG MX 7 2 3600 20150420235959 20051021000000 40430 example. CikebjQwGQPwijVcxgcZcSJKtfynugtlBiKb9FcBTrmOoyQ4InoWVudh CWsh/URX3lc4WRUMivEBP6+4KS3ldA==
+ a.z.w.example. 3600 IN MX 1 ai.example.
+ a.z.w.example. 3600 IN RRSIG MX 7 2 3600 20150420235959 20051021000000 40430 example. CikebjQwGQPwijVcxgcZcSJKtfynugtlBiKb9FcBTrmOoyQ4InoWVudh CWsh/URX3lc4WRUMivEBP6+4KS3ldA==
"""
The authority section of the last query response should be
"""
- example. 3600 IN NS ns1.example.
- example. 3600 IN NS ns2.example.
- example. 3600 IN RRSIG NS 7 1 3600 20150420235959 20051021000000 40430 example. PVOgtMK1HHeSTau+HwDWC8Ts+6C8qtqd4pQJqOtdEVgg+MA+ai4fWDEh u3qHJyLcQ9tbD2vvCnMXjtz6SyObxA==
- q04jkcevqvmu85r014c7dkba38o0ji5r.example. 3600 IN NSEC3 1 1 12 aabbccdd r53bq7cc2uvmubfu5ocmm6pers9tk9en A RRSIG
- q04jkcevqvmu85r014c7dkba38o0ji5r.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. hV5I89b+4FHJDATp09g4bbN0R1F845CaXpL3ZxlMKimoPAyqletMlEWw LfFia7sdpSzn+ZlNNlkxWcLsIlMmUg==
+ example. 3600 IN NS ns1.example.
+ example. 3600 IN NS ns2.example.
+ example. 3600 IN RRSIG NS 7 1 3600 20150420235959 20051021000000 40430 example. PVOgtMK1HHeSTau+HwDWC8Ts+6C8qtqd4pQJqOtdEVgg+MA+ai4fWDEh u3qHJyLcQ9tbD2vvCnMXjtz6SyObxA==
+ q04jkcevqvmu85r014c7dkba38o0ji5r.example. 3600 IN NSEC3 1 1 12 aabbccdd r53bq7cc2uvmubfu5ocmm6pers9tk9en A RRSIG
+ q04jkcevqvmu85r014c7dkba38o0ji5r.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. hV5I89b+4FHJDATp09g4bbN0R1F845CaXpL3ZxlMKimoPAyqletMlEWw LfFia7sdpSzn+ZlNNlkxWcLsIlMmUg==
"""
# This is slightly different from the example in RFC5155; there are
# more RRs in the additional section.
The additional section of the last query response should be
"""
- ai.example. 3600 IN A 192.0.2.9
- ai.example. 3600 IN AAAA 2001:db8::f00:baa9
- ns1.example. 3600 IN A 192.0.2.1
- ns2.example. 3600 IN A 192.0.2.2
- ai.example. 3600 IN RRSIG A 7 2 3600 20150420235959 20051021000000 40430 example. hVe+wKYMlObTRPhX0NL67GxeZfdxqr/QeR6FtfdAj5+FgYxyzPEjIzvK Wy00hWIl6wD3Vws+rznEn8sQ64UdqA==
- ai.example. 3600 IN RRSIG AAAA 7 2 3600 20150420235959 20051021000000 40430 example. LcdxKaCB5bGZwPDg+3JJ4O02zoMBrjxqlf6WuaHQZZfTUpb9Nf2nxFGe 2XRPfR5tpJT6GdRGcHueLuXkMjBArQ==
- ns1.example. 3600 IN RRSIG A 7 2 3600 20150420235959 20051021000000 40430 example. bu6kx73n6XEunoVGuRfAgY7EF/AJqHy7hj0jkiqJjB0dOrx3wuz9SaBe GfqWIdn/uta3SavN4FRvZR9SCFHF5Q==
- ns2.example. 3600 IN RRSIG A 7 2 3600 20150420235959 20051021000000 40430 example. ktQ3TqE0CfRfki0Rb/Ip5BM0VnxelbuejCC4zpLbFKA/7eD7UNAwxMgx JPtbdST+syjYSJaj4IHfeX6n8vfoGA==
+ ai.example. 3600 IN A 192.0.2.9
+ ai.example. 3600 IN AAAA 2001:db8::f00:baa9
+ ns1.example. 3600 IN A 192.0.2.1
+ ns2.example. 3600 IN A 192.0.2.2
+ ai.example. 3600 IN RRSIG A 7 2 3600 20150420235959 20051021000000 40430 example. hVe+wKYMlObTRPhX0NL67GxeZfdxqr/QeR6FtfdAj5+FgYxyzPEjIzvK Wy00hWIl6wD3Vws+rznEn8sQ64UdqA==
+ ai.example. 3600 IN RRSIG AAAA 7 2 3600 20150420235959 20051021000000 40430 example. LcdxKaCB5bGZwPDg+3JJ4O02zoMBrjxqlf6WuaHQZZfTUpb9Nf2nxFGe 2XRPfR5tpJT6GdRGcHueLuXkMjBArQ==
+ ns1.example. 3600 IN RRSIG A 7 2 3600 20150420235959 20051021000000 40430 example. bu6kx73n6XEunoVGuRfAgY7EF/AJqHy7hj0jkiqJjB0dOrx3wuz9SaBe GfqWIdn/uta3SavN4FRvZR9SCFHF5Q==
+ ns2.example. 3600 IN RRSIG A 7 2 3600 20150420235959 20051021000000 40430 example. ktQ3TqE0CfRfki0Rb/Ip5BM0VnxelbuejCC4zpLbFKA/7eD7UNAwxMgx JPtbdST+syjYSJaj4IHfeX6n8vfoGA==
"""
Scenario: B.5. Wildcard No Data Error
Given I have bind10 running with configuration nsec3/nsec3_auth.config
+ And wait for bind10 stderr message BIND10_STARTED_CC
+ And wait for bind10 stderr message CMDCTL_STARTED
+ And wait for bind10 stderr message AUTH_SERVER_STARTED
+
+ bind10 module Auth should be running
+ And bind10 module Resolver should not be running
+ And bind10 module Xfrout should not be running
+ And bind10 module Zonemgr should not be running
+ And bind10 module Xfrin should not be running
+ And bind10 module Stats should not be running
+ And bind10 module StatsHttpd should not be running
+
A dnssec query for a.z.w.example. type AAAA should have rcode NOERROR
The last query response should have flags qr aa rd
The last query response should have edns_flags do
@@ -130,18 +202,30 @@ Feature: NSEC3 Authoritative service
The last query response should have adcount 1
The authority section of the last query response should be
"""
- example. 3600 IN SOA ns1.example. bugs.x.w.example. 1 3600 300 3600000 3600
- example. 3600 IN RRSIG SOA 7 1 3600 20150420235959 20051021000000 40430 example. Hu25UIyNPmvPIVBrldN+9Mlp9Zql39qaUd8iq4ZLlYWfUUbbAS41pG+6 8z81q1xhkYAcEyHdVI2LmKusbZsT0Q==
- k8udemvp1j2f7eg6jebps17vp3n8i58h.example. 3600 IN NSEC3 1 1 12 aabbccdd kohar7mbb8dc2ce8a9qvl8hon4k53uhi
- k8udemvp1j2f7eg6jebps17vp3n8i58h.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. FtXGbvF0+wf8iWkyo73enAuVx03klN+pILBKS6qCcftVtfH4yVzsEZqu J27NHR7ruxJWDNMtOtx7w9WfcIg62A==
- q04jkcevqvmu85r014c7dkba38o0ji5r.example. 3600 IN NSEC3 1 1 12 aabbccdd r53bq7cc2uvmubfu5ocmm6pers9tk9en A RRSIG
- q04jkcevqvmu85r014c7dkba38o0ji5r.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. hV5I89b+4FHJDATp09g4bbN0R1F845CaXpL3ZxlMKimoPAyqletMlEWw LfFia7sdpSzn+ZlNNlkxWcLsIlMmUg==
- r53bq7cc2uvmubfu5ocmm6pers9tk9en.example. 3600 IN NSEC3 1 1 12 aabbccdd t644ebqk9bibcna874givr6joj62mlhv MX RRSIG
- r53bq7cc2uvmubfu5ocmm6pers9tk9en.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. aupviViruXs4bDg9rCbezzBMf9h1ZlDvbW/CZFKulIGXXLj8B/fsDJar XVDA9bnUoRhEbKp+HF1FWKW7RIJdtQ==
+ example. 3600 IN SOA ns1.example. bugs.x.w.example. 1 3600 300 3600000 3600
+ example. 3600 IN RRSIG SOA 7 1 3600 20150420235959 20051021000000 40430 example. Hu25UIyNPmvPIVBrldN+9Mlp9Zql39qaUd8iq4ZLlYWfUUbbAS41pG+6 8z81q1xhkYAcEyHdVI2LmKusbZsT0Q==
+ k8udemvp1j2f7eg6jebps17vp3n8i58h.example. 3600 IN NSEC3 1 1 12 aabbccdd kohar7mbb8dc2ce8a9qvl8hon4k53uhi
+ k8udemvp1j2f7eg6jebps17vp3n8i58h.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. FtXGbvF0+wf8iWkyo73enAuVx03klN+pILBKS6qCcftVtfH4yVzsEZqu J27NHR7ruxJWDNMtOtx7w9WfcIg62A==
+ q04jkcevqvmu85r014c7dkba38o0ji5r.example. 3600 IN NSEC3 1 1 12 aabbccdd r53bq7cc2uvmubfu5ocmm6pers9tk9en A RRSIG
+ q04jkcevqvmu85r014c7dkba38o0ji5r.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. hV5I89b+4FHJDATp09g4bbN0R1F845CaXpL3ZxlMKimoPAyqletMlEWw LfFia7sdpSzn+ZlNNlkxWcLsIlMmUg==
+ r53bq7cc2uvmubfu5ocmm6pers9tk9en.example. 3600 IN NSEC3 1 1 12 aabbccdd t644ebqk9bibcna874givr6joj62mlhv MX RRSIG
+ r53bq7cc2uvmubfu5ocmm6pers9tk9en.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. aupviViruXs4bDg9rCbezzBMf9h1ZlDvbW/CZFKulIGXXLj8B/fsDJar XVDA9bnUoRhEbKp+HF1FWKW7RIJdtQ==
"""
Scenario: B.6. DS Child Zone No Data Error
Given I have bind10 running with configuration nsec3/nsec3_auth.config
+ And wait for bind10 stderr message BIND10_STARTED_CC
+ And wait for bind10 stderr message CMDCTL_STARTED
+ And wait for bind10 stderr message AUTH_SERVER_STARTED
+
+ bind10 module Auth should be running
+ And bind10 module Resolver should not be running
+ And bind10 module Xfrout should not be running
+ And bind10 module Zonemgr should not be running
+ And bind10 module Xfrin should not be running
+ And bind10 module Stats should not be running
+ And bind10 module StatsHttpd should not be running
+
A dnssec query for example. type DS should have rcode NOERROR
The last query response should have flags qr aa rd
The last query response should have edns_flags do
@@ -150,10 +234,10 @@ Feature: NSEC3 Authoritative service
The last query response should have adcount 1
The authority section of the last query response should be
"""
- example. 3600 IN SOA ns1.example. bugs.x.w.example. 1 3600 300 3600000 3600
- example. 3600 IN RRSIG SOA 7 1 3600 20150420235959 20051021000000 40430 example. Hu25UIyNPmvPIVBrldN+9Mlp9Zql39qaUd8iq4ZLlYWfUUbbAS41pG+6 8z81q1xhkYAcEyHdVI2LmKusbZsT0Q==
- 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example. 3600 IN NSEC3 1 1 12 aabbccdd 2t7b4g4vsa5smi47k61mv5bv1a22bojr NS SOA MX RRSIG DNSKEY NSEC3PARAM
- 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. OSgWSm26B+cS+dDL8b5QrWr/dEWhtCsKlwKLIBHYH6blRxK9rC0bMJPw Q4mLIuw85H2EY762BOCXJZMnpuwhpA==
+ example. 3600 IN SOA ns1.example. bugs.x.w.example. 1 3600 300 3600000 3600
+ example. 3600 IN RRSIG SOA 7 1 3600 20150420235959 20051021000000 40430 example. Hu25UIyNPmvPIVBrldN+9Mlp9Zql39qaUd8iq4ZLlYWfUUbbAS41pG+6 8z81q1xhkYAcEyHdVI2LmKusbZsT0Q==
+ 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example. 3600 IN NSEC3 1 1 12 aabbccdd 2t7b4g4vsa5smi47k61mv5bv1a22bojr NS SOA MX RRSIG DNSKEY NSEC3PARAM
+ 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. OSgWSm26B+cS+dDL8b5QrWr/dEWhtCsKlwKLIBHYH6blRxK9rC0bMJPw Q4mLIuw85H2EY762BOCXJZMnpuwhpA==
"""
#
@@ -162,6 +246,18 @@ Feature: NSEC3 Authoritative service
Scenario: 7.2.2 other; Name Error where one NSEC3 covers multiple parts of proof (closest encloser)
Given I have bind10 running with configuration nsec3/nsec3_auth.config
+ And wait for bind10 stderr message BIND10_STARTED_CC
+ And wait for bind10 stderr message CMDCTL_STARTED
+ And wait for bind10 stderr message AUTH_SERVER_STARTED
+
+ bind10 module Auth should be running
+ And bind10 module Resolver should not be running
+ And bind10 module Xfrout should not be running
+ And bind10 module Zonemgr should not be running
+ And bind10 module Xfrin should not be running
+ And bind10 module Stats should not be running
+ And bind10 module StatsHttpd should not be running
+
A dnssec query for b.x.w.example. should have rcode NXDOMAIN
The last query response should have flags qr aa rd
The last query response should have edns_flags do
@@ -170,16 +266,28 @@ Feature: NSEC3 Authoritative service
The last query response should have adcount 1
The authority section of the last query response should be
"""
- example. 3600 IN SOA ns1.example. bugs.x.w.example. 1 3600 300 3600000 3600
- example. 3600 IN RRSIG SOA 7 1 3600 20150420235959 20051021000000 40430 example. Hu25UIyNPmvPIVBrldN+9Mlp9Zql39qaUd8iq4ZLlYWfUUbbAS41pG+6 8z81q1xhkYAcEyHdVI2LmKusbZsT0Q==
- b4um86eghhds6nea196smvmlo4ors995.example. 3600 IN NSEC3 1 1 12 aabbccdd gjeqe526plbf1g8mklp59enfd789njgi MX RRSIG
- b4um86eghhds6nea196smvmlo4ors995.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. ZkPG3M32lmoHM6pa3D6gZFGB/rhL//Bs3Omh5u4m/CUiwtblEVOaAKKZ d7S959OeiX43aLX3pOv0TSTyiTxIZg==
- 35mthgpgcu1qg68fab165klnsnk3dpvl.example. 3600 IN NSEC3 1 1 12 aabbccdd b4um86eghhds6nea196smvmlo4ors995 NS DS RRSIG
- 35mthgpgcu1qg68fab165klnsnk3dpvl.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. g6jPUUpduAJKRljUsN8gB4UagAX0NxY9shwQAynzo8EUWH+z6hEIBlUT PGj15eZll6VhQqgZXtAIR3chwgW+SA==
+ example. 3600 IN SOA ns1.example. bugs.x.w.example. 1 3600 300 3600000 3600
+ example. 3600 IN RRSIG SOA 7 1 3600 20150420235959 20051021000000 40430 example. Hu25UIyNPmvPIVBrldN+9Mlp9Zql39qaUd8iq4ZLlYWfUUbbAS41pG+6 8z81q1xhkYAcEyHdVI2LmKusbZsT0Q==
+ b4um86eghhds6nea196smvmlo4ors995.example. 3600 IN NSEC3 1 1 12 aabbccdd gjeqe526plbf1g8mklp59enfd789njgi MX RRSIG
+ b4um86eghhds6nea196smvmlo4ors995.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. ZkPG3M32lmoHM6pa3D6gZFGB/rhL//Bs3Omh5u4m/CUiwtblEVOaAKKZ d7S959OeiX43aLX3pOv0TSTyiTxIZg==
+ 35mthgpgcu1qg68fab165klnsnk3dpvl.example. 3600 IN NSEC3 1 1 12 aabbccdd b4um86eghhds6nea196smvmlo4ors995 NS DS RRSIG
+ 35mthgpgcu1qg68fab165klnsnk3dpvl.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. g6jPUUpduAJKRljUsN8gB4UagAX0NxY9shwQAynzo8EUWH+z6hEIBlUT PGj15eZll6VhQqgZXtAIR3chwgW+SA==
"""
Scenario: 7.2.2 other; Name Error where one NSEC3 covers multiple parts of proof (wildcard)
Given I have bind10 running with configuration nsec3/nsec3_auth.config
+ And wait for bind10 stderr message BIND10_STARTED_CC
+ And wait for bind10 stderr message CMDCTL_STARTED
+ And wait for bind10 stderr message AUTH_SERVER_STARTED
+
+ bind10 module Auth should be running
+ And bind10 module Resolver should not be running
+ And bind10 module Xfrout should not be running
+ And bind10 module Zonemgr should not be running
+ And bind10 module Xfrin should not be running
+ And bind10 module Stats should not be running
+ And bind10 module StatsHttpd should not be running
+
A dnssec query for a.w.example. should have rcode NOERROR
The last query response should have flags qr aa rd
The last query response should have edns_flags do
@@ -188,16 +296,28 @@ Feature: NSEC3 Authoritative service
The last query response should have adcount 1
The authority section of the last query response should be
"""
- example. 3600 IN SOA ns1.example. bugs.x.w.example. 1 3600 300 3600000 3600
- example. 3600 IN RRSIG SOA 7 1 3600 20150420235959 20051021000000 40430 example. Hu25UIyNPmvPIVBrldN+9Mlp9Zql39qaUd8iq4ZLlYWfUUbbAS41pG+6 8z81q1xhkYAcEyHdVI2LmKusbZsT0Q==
- k8udemvp1j2f7eg6jebps17vp3n8i58h.example. 3600 IN NSEC3 1 1 12 AABBCCDD KOHAR7MBB8DC2CE8A9QVL8HON4K53UHI
- k8udemvp1j2f7eg6jebps17vp3n8i58h.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. FtXGbvF0+wf8iWkyo73enAuVx03klN+pILBKS6qCcftVtfH4yVzsEZqu J27NHR7ruxJWDNMtOtx7w9WfcIg62A==
- r53bq7cc2uvmubfu5ocmm6pers9tk9en.example. 3600 IN NSEC3 1 1 12 AABBCCDD T644EBQK9BIBCNA874GIVR6JOJ62MLHV MX RRSIG
- r53bq7cc2uvmubfu5ocmm6pers9tk9en.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. aupviViruXs4bDg9rCbezzBMf9h1ZlDvbW/CZFKulIGXXLj8B/fsDJar XVDA9bnUoRhEbKp+HF1FWKW7RIJdtQ==
+ example. 3600 IN SOA ns1.example. bugs.x.w.example. 1 3600 300 3600000 3600
+ example. 3600 IN RRSIG SOA 7 1 3600 20150420235959 20051021000000 40430 example. Hu25UIyNPmvPIVBrldN+9Mlp9Zql39qaUd8iq4ZLlYWfUUbbAS41pG+6 8z81q1xhkYAcEyHdVI2LmKusbZsT0Q==
+ k8udemvp1j2f7eg6jebps17vp3n8i58h.example. 3600 IN NSEC3 1 1 12 AABBCCDD KOHAR7MBB8DC2CE8A9QVL8HON4K53UHI
+ k8udemvp1j2f7eg6jebps17vp3n8i58h.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. FtXGbvF0+wf8iWkyo73enAuVx03klN+pILBKS6qCcftVtfH4yVzsEZqu J27NHR7ruxJWDNMtOtx7w9WfcIg62A==
+ r53bq7cc2uvmubfu5ocmm6pers9tk9en.example. 3600 IN NSEC3 1 1 12 AABBCCDD T644EBQK9BIBCNA874GIVR6JOJ62MLHV MX RRSIG
+ r53bq7cc2uvmubfu5ocmm6pers9tk9en.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. aupviViruXs4bDg9rCbezzBMf9h1ZlDvbW/CZFKulIGXXLj8B/fsDJar XVDA9bnUoRhEbKp+HF1FWKW7RIJdtQ==
"""
Scenario: Wildcard other: Wildcard name itself
Given I have bind10 running with configuration nsec3/nsec3_auth.config
+ And wait for bind10 stderr message BIND10_STARTED_CC
+ And wait for bind10 stderr message CMDCTL_STARTED
+ And wait for bind10 stderr message AUTH_SERVER_STARTED
+
+ bind10 module Auth should be running
+ And bind10 module Resolver should not be running
+ And bind10 module Xfrout should not be running
+ And bind10 module Zonemgr should not be running
+ And bind10 module Xfrin should not be running
+ And bind10 module Stats should not be running
+ And bind10 module StatsHttpd should not be running
+
A dnssec query for *.w.example. type MX should have rcode NOERROR
The last query response should have flags qr aa rd
The last query response should have edns_flags do
@@ -206,29 +326,41 @@ Feature: NSEC3 Authoritative service
The last query response should have adcount 9
The answer section of the last query response should be
"""
- *.w.example. 3600 IN MX 1 ai.example.
- *.w.example. 3600 IN RRSIG MX 7 2 3600 20150420235959 20051021000000 40430 example. CikebjQwGQPwijVcxgcZcSJKtfynugtlBiKb9FcBTrmOoyQ4InoWVudh CWsh/URX3lc4WRUMivEBP6+4KS3ldA==
+ *.w.example. 3600 IN MX 1 ai.example.
+ *.w.example. 3600 IN RRSIG MX 7 2 3600 20150420235959 20051021000000 40430 example. CikebjQwGQPwijVcxgcZcSJKtfynugtlBiKb9FcBTrmOoyQ4InoWVudh CWsh/URX3lc4WRUMivEBP6+4KS3ldA==
"""
The authority section of the last query response should be
"""
- example. 3600 IN NS ns1.example.
- example. 3600 IN NS ns2.example.
- example. 3600 IN RRSIG NS 7 1 3600 20150420235959 20051021000000 40430 example. PVOgtMK1HHeSTau+HwDWC8Ts+6C8qtqd4pQJqOtdEVgg+MA+ai4fWDEh u3qHJyLcQ9tbD2vvCnMXjtz6SyObxA==
+ example. 3600 IN NS ns1.example.
+ example. 3600 IN NS ns2.example.
+ example. 3600 IN RRSIG NS 7 1 3600 20150420235959 20051021000000 40430 example. PVOgtMK1HHeSTau+HwDWC8Ts+6C8qtqd4pQJqOtdEVgg+MA+ai4fWDEh u3qHJyLcQ9tbD2vvCnMXjtz6SyObxA==
"""
The additional section of the last query response should be
"""
- ai.example. 3600 IN A 192.0.2.9
- ai.example. 3600 IN AAAA 2001:db8::f00:baa9
- ns1.example. 3600 IN A 192.0.2.1
- ns2.example. 3600 IN A 192.0.2.2
- ai.example. 3600 IN RRSIG A 7 2 3600 20150420235959 20051021000000 40430 example. hVe+wKYMlObTRPhX0NL67GxeZfdxqr/QeR6FtfdAj5+FgYxyzPEjIzvK Wy00hWIl6wD3Vws+rznEn8sQ64UdqA==
- ai.example. 3600 IN RRSIG AAAA 7 2 3600 20150420235959 20051021000000 40430 example. LcdxKaCB5bGZwPDg+3JJ4O02zoMBrjxqlf6WuaHQZZfTUpb9Nf2nxFGe 2XRPfR5tpJT6GdRGcHueLuXkMjBArQ==
- ns1.example. 3600 IN RRSIG A 7 2 3600 20150420235959 20051021000000 40430 example. bu6kx73n6XEunoVGuRfAgY7EF/AJqHy7hj0jkiqJjB0dOrx3wuz9SaBe GfqWIdn/uta3SavN4FRvZR9SCFHF5Q==
- ns2.example. 3600 IN RRSIG A 7 2 3600 20150420235959 20051021000000 40430 example. ktQ3TqE0CfRfki0Rb/Ip5BM0VnxelbuejCC4zpLbFKA/7eD7UNAwxMgx JPtbdST+syjYSJaj4IHfeX6n8vfoGA==
+ ai.example. 3600 IN A 192.0.2.9
+ ai.example. 3600 IN AAAA 2001:db8::f00:baa9
+ ns1.example. 3600 IN A 192.0.2.1
+ ns2.example. 3600 IN A 192.0.2.2
+ ai.example. 3600 IN RRSIG A 7 2 3600 20150420235959 20051021000000 40430 example. hVe+wKYMlObTRPhX0NL67GxeZfdxqr/QeR6FtfdAj5+FgYxyzPEjIzvK Wy00hWIl6wD3Vws+rznEn8sQ64UdqA==
+ ai.example. 3600 IN RRSIG AAAA 7 2 3600 20150420235959 20051021000000 40430 example. LcdxKaCB5bGZwPDg+3JJ4O02zoMBrjxqlf6WuaHQZZfTUpb9Nf2nxFGe 2XRPfR5tpJT6GdRGcHueLuXkMjBArQ==
+ ns1.example. 3600 IN RRSIG A 7 2 3600 20150420235959 20051021000000 40430 example. bu6kx73n6XEunoVGuRfAgY7EF/AJqHy7hj0jkiqJjB0dOrx3wuz9SaBe GfqWIdn/uta3SavN4FRvZR9SCFHF5Q==
+ ns2.example. 3600 IN RRSIG A 7 2 3600 20150420235959 20051021000000 40430 example. ktQ3TqE0CfRfki0Rb/Ip5BM0VnxelbuejCC4zpLbFKA/7eD7UNAwxMgx JPtbdST+syjYSJaj4IHfeX6n8vfoGA==
"""
Scenario: Wildcard other: Wildcard name itself nodata
Given I have bind10 running with configuration nsec3/nsec3_auth.config
+ And wait for bind10 stderr message BIND10_STARTED_CC
+ And wait for bind10 stderr message CMDCTL_STARTED
+ And wait for bind10 stderr message AUTH_SERVER_STARTED
+
+ bind10 module Auth should be running
+ And bind10 module Resolver should not be running
+ And bind10 module Xfrout should not be running
+ And bind10 module Zonemgr should not be running
+ And bind10 module Xfrin should not be running
+ And bind10 module Stats should not be running
+ And bind10 module StatsHttpd should not be running
+
A dnssec query for *.w.example. type A should have rcode NOERROR
The last query response should have flags qr aa rd
The last query response should have edns_flags do
@@ -237,14 +369,26 @@ Feature: NSEC3 Authoritative service
The last query response should have adcount 1
The authority section of the last query response should be
"""
- example. 3600 IN SOA ns1.example. bugs.x.w.example. 1 3600 300 3600000 3600
- example. 3600 IN RRSIG SOA 7 1 3600 20150420235959 20051021000000 40430 example. Hu25UIyNPmvPIVBrldN+9Mlp9Zql39qaUd8iq4ZLlYWfUUbbAS41pG+6 8z81q1xhkYAcEyHdVI2LmKusbZsT0Q==
- r53bq7cc2uvmubfu5ocmm6pers9tk9en.example. 3600 IN NSEC3 1 1 12 AABBCCDD T644EBQK9BIBCNA874GIVR6JOJ62MLHV MX RRSIG
- r53bq7cc2uvmubfu5ocmm6pers9tk9en.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. aupviViruXs4bDg9rCbezzBMf9h1ZlDvbW/CZFKulIGXXLj8B/fsDJar XVDA9bnUoRhEbKp+HF1FWKW7RIJdtQ==
+ example. 3600 IN SOA ns1.example. bugs.x.w.example. 1 3600 300 3600000 3600
+ example. 3600 IN RRSIG SOA 7 1 3600 20150420235959 20051021000000 40430 example. Hu25UIyNPmvPIVBrldN+9Mlp9Zql39qaUd8iq4ZLlYWfUUbbAS41pG+6 8z81q1xhkYAcEyHdVI2LmKusbZsT0Q==
+ r53bq7cc2uvmubfu5ocmm6pers9tk9en.example. 3600 IN NSEC3 1 1 12 AABBCCDD T644EBQK9BIBCNA874GIVR6JOJ62MLHV MX RRSIG
+ r53bq7cc2uvmubfu5ocmm6pers9tk9en.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. aupviViruXs4bDg9rCbezzBMf9h1ZlDvbW/CZFKulIGXXLj8B/fsDJar XVDA9bnUoRhEbKp+HF1FWKW7RIJdtQ==
"""
Scenario: Direct query for NSEC3 record
Given I have bind10 running with configuration nsec3/nsec3_auth.config
+ And wait for bind10 stderr message BIND10_STARTED_CC
+ And wait for bind10 stderr message CMDCTL_STARTED
+ And wait for bind10 stderr message AUTH_SERVER_STARTED
+
+ bind10 module Auth should be running
+ And bind10 module Resolver should not be running
+ And bind10 module Xfrout should not be running
+ And bind10 module Zonemgr should not be running
+ And bind10 module Xfrin should not be running
+ And bind10 module Stats should not be running
+ And bind10 module StatsHttpd should not be running
+
A dnssec query for 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example. type NSEC3 should have rcode NXDOMAIN
The last query response should have flags qr aa rd
The last query response should have edns_flags do
@@ -253,18 +397,30 @@ Feature: NSEC3 Authoritative service
The last query response should have adcount 1
The authority section of the last query response should be
"""
- example. 3600 IN SOA ns1.example. bugs.x.w.example. 1 3600 300 3600000 3600
- example. 3600 IN RRSIG SOA 7 1 3600 20150420235959 20051021000000 40430 example. Hu25UIyNPmvPIVBrldN+9Mlp9Zql39qaUd8iq4ZLlYWfUUbbAS41pG+6 8z81q1xhkYAcEyHdVI2LmKusbZsT0Q==
- 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example. 3600 IN NSEC3 1 1 12 AABBCCDD 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR NS SOA MX RRSIG DNSKEY NSEC3PARAM
- 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. OSgWSm26B+cS+dDL8b5QrWr/dEWhtCsKlwKLIBHYH6blRxK9rC0bMJPw Q4mLIuw85H2EY762BOCXJZMnpuwhpA==
- q04jkcevqvmu85r014c7dkba38o0ji5r.example. 3600 IN NSEC3 1 1 12 AABBCCDD R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN A RRSIG
- q04jkcevqvmu85r014c7dkba38o0ji5r.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. hV5I89b+4FHJDATp09g4bbN0R1F845CaXpL3ZxlMKimoPAyqletMlEWw LfFia7sdpSzn+ZlNNlkxWcLsIlMmUg==
- gjeqe526plbf1g8mklp59enfd789njgi.example. 3600 IN NSEC3 1 1 12 AABBCCDD JI6NEOAEPV8B5O6K4EV33ABHA8HT9FGC A HINFO AAAA RRSIG
- gjeqe526plbf1g8mklp59enfd789njgi.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. IVnezTJ9iqblFF97vPSmfXZ5Zozngx3KX3byLTZC4QBH2dFWhf6scrGF ZB980AfCxoD9qbbKDy+rdGIeRSVNyw==
+ example. 3600 IN SOA ns1.example. bugs.x.w.example. 1 3600 300 3600000 3600
+ example. 3600 IN RRSIG SOA 7 1 3600 20150420235959 20051021000000 40430 example. Hu25UIyNPmvPIVBrldN+9Mlp9Zql39qaUd8iq4ZLlYWfUUbbAS41pG+6 8z81q1xhkYAcEyHdVI2LmKusbZsT0Q==
+ 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example. 3600 IN NSEC3 1 1 12 AABBCCDD 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR NS SOA MX RRSIG DNSKEY NSEC3PARAM
+ 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. OSgWSm26B+cS+dDL8b5QrWr/dEWhtCsKlwKLIBHYH6blRxK9rC0bMJPw Q4mLIuw85H2EY762BOCXJZMnpuwhpA==
+ q04jkcevqvmu85r014c7dkba38o0ji5r.example. 3600 IN NSEC3 1 1 12 AABBCCDD R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN A RRSIG
+ q04jkcevqvmu85r014c7dkba38o0ji5r.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. hV5I89b+4FHJDATp09g4bbN0R1F845CaXpL3ZxlMKimoPAyqletMlEWw LfFia7sdpSzn+ZlNNlkxWcLsIlMmUg==
+ gjeqe526plbf1g8mklp59enfd789njgi.example. 3600 IN NSEC3 1 1 12 AABBCCDD JI6NEOAEPV8B5O6K4EV33ABHA8HT9FGC A HINFO AAAA RRSIG
+ gjeqe526plbf1g8mklp59enfd789njgi.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. IVnezTJ9iqblFF97vPSmfXZ5Zozngx3KX3byLTZC4QBH2dFWhf6scrGF ZB980AfCxoD9qbbKDy+rdGIeRSVNyw==
"""
Scenario: No data, type DS, in-zone
Given I have bind10 running with configuration nsec3/nsec3_auth.config
+ And wait for bind10 stderr message BIND10_STARTED_CC
+ And wait for bind10 stderr message CMDCTL_STARTED
+ And wait for bind10 stderr message AUTH_SERVER_STARTED
+
+ bind10 module Auth should be running
+ And bind10 module Resolver should not be running
+ And bind10 module Xfrout should not be running
+ And bind10 module Zonemgr should not be running
+ And bind10 module Xfrin should not be running
+ And bind10 module Stats should not be running
+ And bind10 module StatsHttpd should not be running
+
A dnssec query for ai.example. type DS should have rcode NOERROR
The last query response should have flags qr aa rd
The last query response should have edns_flags do
@@ -273,14 +429,26 @@ Feature: NSEC3 Authoritative service
The last query response should have adcount 1
The authority section of the last query response should be
"""
- example. 3600 IN SOA ns1.example. bugs.x.w.example. 1 3600 300 3600000 3600
- example. 3600 IN RRSIG SOA 7 1 3600 20150420235959 20051021000000 40430 example. Hu25UIyNPmvPIVBrldN+9Mlp9Zql39qaUd8iq4ZLlYWfUUbbAS41pG+6 8z81q1xhkYAcEyHdVI2LmKusbZsT0Q==
- gjeqe526plbf1g8mklp59enfd789njgi.example. 3600 IN NSEC3 1 1 12 AABBCCDD JI6NEOAEPV8B5O6K4EV33ABHA8HT9FGC A HINFO AAAA RRSIG
- gjeqe526plbf1g8mklp59enfd789njgi.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. IVnezTJ9iqblFF97vPSmfXZ5Zozngx3KX3byLTZC4QBH2dFWhf6scrGF ZB980AfCxoD9qbbKDy+rdGIeRSVNyw==
+ example. 3600 IN SOA ns1.example. bugs.x.w.example. 1 3600 300 3600000 3600
+ example. 3600 IN RRSIG SOA 7 1 3600 20150420235959 20051021000000 40430 example. Hu25UIyNPmvPIVBrldN+9Mlp9Zql39qaUd8iq4ZLlYWfUUbbAS41pG+6 8z81q1xhkYAcEyHdVI2LmKusbZsT0Q==
+ gjeqe526plbf1g8mklp59enfd789njgi.example. 3600 IN NSEC3 1 1 12 AABBCCDD JI6NEOAEPV8B5O6K4EV33ABHA8HT9FGC A HINFO AAAA RRSIG
+ gjeqe526plbf1g8mklp59enfd789njgi.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. IVnezTJ9iqblFF97vPSmfXZ5Zozngx3KX3byLTZC4QBH2dFWhf6scrGF ZB980AfCxoD9qbbKDy+rdGIeRSVNyw==
"""
Scenario: No data, type DS, optout delegation
Given I have bind10 running with configuration nsec3/nsec3_auth.config
+ And wait for bind10 stderr message BIND10_STARTED_CC
+ And wait for bind10 stderr message CMDCTL_STARTED
+ And wait for bind10 stderr message AUTH_SERVER_STARTED
+
+ bind10 module Auth should be running
+ And bind10 module Resolver should not be running
+ And bind10 module Xfrout should not be running
+ And bind10 module Zonemgr should not be running
+ And bind10 module Xfrin should not be running
+ And bind10 module Stats should not be running
+ And bind10 module StatsHttpd should not be running
+
A dnssec query for c.example. type DS should have rcode NOERROR
The last query response should have flags qr aa rd
The last query response should have edns_flags do
@@ -289,10 +457,10 @@ Feature: NSEC3 Authoritative service
The last query response should have adcount 1
The authority section of the last query response should be
"""
- example. 3600 IN SOA ns1.example. bugs.x.w.example. 1 3600 300 3600000 3600
- example. 3600 IN RRSIG SOA 7 1 3600 20150420235959 20051021000000 40430 example. Hu25UIyNPmvPIVBrldN+9Mlp9Zql39qaUd8iq4ZLlYWfUUbbAS41pG+6 8z81q1xhkYAcEyHdVI2LmKusbZsT0Q==
- 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example. 3600 IN NSEC3 1 1 12 AABBCCDD 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR NS SOA MX RRSIG DNSKEY NSEC3PARAM
- 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. OSgWSm26B+cS+dDL8b5QrWr/dEWhtCsKlwKLIBHYH6blRxK9rC0bMJPw Q4mLIuw85H2EY762BOCXJZMnpuwhpA==
- 35mthgpgcu1qg68fab165klnsnk3dpvl.example. 3600 IN NSEC3 1 1 12 AABBCCDD B4UM86EGHHDS6NEA196SMVMLO4ORS995 NS DS RRSIG
- 35mthgpgcu1qg68fab165klnsnk3dpvl.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. g6jPUUpduAJKRljUsN8gB4UagAX0NxY9shwQAynzo8EUWH+z6hEIBlUT PGj15eZll6VhQqgZXtAIR3chwgW+SA==
+ example. 3600 IN SOA ns1.example. bugs.x.w.example. 1 3600 300 3600000 3600
+ example. 3600 IN RRSIG SOA 7 1 3600 20150420235959 20051021000000 40430 example. Hu25UIyNPmvPIVBrldN+9Mlp9Zql39qaUd8iq4ZLlYWfUUbbAS41pG+6 8z81q1xhkYAcEyHdVI2LmKusbZsT0Q==
+ 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example. 3600 IN NSEC3 1 1 12 AABBCCDD 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR NS SOA MX RRSIG DNSKEY NSEC3PARAM
+ 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. OSgWSm26B+cS+dDL8b5QrWr/dEWhtCsKlwKLIBHYH6blRxK9rC0bMJPw Q4mLIuw85H2EY762BOCXJZMnpuwhpA==
+ 35mthgpgcu1qg68fab165klnsnk3dpvl.example. 3600 IN NSEC3 1 1 12 AABBCCDD B4UM86EGHHDS6NEA196SMVMLO4ORS995 NS DS RRSIG
+ 35mthgpgcu1qg68fab165klnsnk3dpvl.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. g6jPUUpduAJKRljUsN8gB4UagAX0NxY9shwQAynzo8EUWH+z6hEIBlUT PGj15eZll6VhQqgZXtAIR3chwgW+SA==
"""
diff --git a/tests/lettuce/features/queries.feature b/tests/lettuce/features/queries.feature
index 24c18f0..f549f2d 100644
--- a/tests/lettuce/features/queries.feature
+++ b/tests/lettuce/features/queries.feature
@@ -5,6 +5,18 @@ Feature: Querying feature
Scenario: Repeated queries
Given I have bind10 running with configuration example.org.inmem.config
+ And wait for bind10 stderr message BIND10_STARTED_CC
+ And wait for bind10 stderr message CMDCTL_STARTED
+ And wait for bind10 stderr message AUTH_SERVER_STARTED
+
+ bind10 module Auth should be running
+ And bind10 module Resolver should not be running
+ And bind10 module Xfrout should not be running
+ And bind10 module Zonemgr should not be running
+ And bind10 module Xfrin should not be running
+ And bind10 module Stats should not be running
+ And bind10 module StatsHttpd should not be running
+
A query for www.example.org should have rcode NOERROR
The last query response should have flags qr aa rd
The last query response should have ancount 1
@@ -13,17 +25,17 @@ Feature: Querying feature
The answer section of the last query response should be
"""
- www.example.org. 3600 IN A 192.0.2.1
+ www.example.org. 3600 IN A 192.0.2.1
"""
The authority section of the last query response should be
"""
- example.org. 3600 IN NS ns1.example.org.
- example.org. 3600 IN NS ns2.example.org.
+ example.org. 3600 IN NS ns1.example.org.
+ example.org. 3600 IN NS ns2.example.org.
"""
The additional section of the last query response should be
"""
- ns1.example.org. 3600 IN A 192.0.2.3
- ns2.example.org. 3600 IN A 192.0.2.4
+ ns1.example.org. 3600 IN A 192.0.2.3
+ ns2.example.org. 3600 IN A 192.0.2.4
"""
# Repeat of the above
@@ -35,17 +47,17 @@ Feature: Querying feature
The answer section of the last query response should be
"""
- www.example.org. 3600 IN A 192.0.2.1
+ www.example.org. 3600 IN A 192.0.2.1
"""
The authority section of the last query response should be
"""
- example.org. 3600 IN NS ns1.example.org.
- example.org. 3600 IN NS ns2.example.org.
+ example.org. 3600 IN NS ns1.example.org.
+ example.org. 3600 IN NS ns2.example.org.
"""
The additional section of the last query response should be
"""
- ns1.example.org. 3600 IN A 192.0.2.3
- ns2.example.org. 3600 IN A 192.0.2.4
+ ns1.example.org. 3600 IN A 192.0.2.3
+ ns2.example.org. 3600 IN A 192.0.2.4
"""
# And now query something completely different
@@ -56,11 +68,23 @@ Feature: Querying feature
The last query response should have adcount 0
The authority section of the last query response should be
"""
- example.org. 3600 IN SOA ns1.example.org. admin.example.org. 1234 3600 1800 2419200 7200
+ example.org. 3600 IN SOA ns1.example.org. admin.example.org. 1234 3600 1800 2419200 7200
"""
Scenario: ANY query
Given I have bind10 running with configuration example.org.inmem.config
+ And wait for bind10 stderr message BIND10_STARTED_CC
+ And wait for bind10 stderr message CMDCTL_STARTED
+ And wait for bind10 stderr message AUTH_SERVER_STARTED
+
+ bind10 module Auth should be running
+ And bind10 module Resolver should not be running
+ And bind10 module Xfrout should not be running
+ And bind10 module Zonemgr should not be running
+ And bind10 module Xfrin should not be running
+ And bind10 module Stats should not be running
+ And bind10 module StatsHttpd should not be running
+
A query for example.org type ANY should have rcode NOERROR
The last query response should have flags qr aa rd
The last query response should have ancount 4
@@ -68,16 +92,16 @@ Feature: Querying feature
The last query response should have adcount 3
The answer section of the last query response should be
"""
- example.org. 3600 IN NS ns1.example.org.
- example.org. 3600 IN NS ns2.example.org.
- example.org. 3600 IN SOA ns1.example.org. admin.example.org. 1234 3600 1800 2419200 7200
- example.org. 3600 IN MX 10 mail.example.org.
+ example.org. 3600 IN NS ns1.example.org.
+ example.org. 3600 IN NS ns2.example.org.
+ example.org. 3600 IN SOA ns1.example.org. admin.example.org. 1234 3600 1800 2419200 7200
+ example.org. 3600 IN MX 10 mail.example.org.
"""
The additional section of the last query response should be
"""
- ns1.example.org. 3600 IN A 192.0.2.3
- ns2.example.org. 3600 IN A 192.0.2.4
- mail.example.org. 3600 IN A 192.0.2.10
+ ns1.example.org. 3600 IN A 192.0.2.3
+ ns2.example.org. 3600 IN A 192.0.2.4
+ mail.example.org. 3600 IN A 192.0.2.10
"""
Scenario: Delegation query for unsigned child zone
Given I have bind10 running with configuration example.org.inmem.config
diff --git a/tests/lettuce/features/resolver_basic.feature b/tests/lettuce/features/resolver_basic.feature
index c759971..4092101 100644
--- a/tests/lettuce/features/resolver_basic.feature
+++ b/tests/lettuce/features/resolver_basic.feature
@@ -11,7 +11,17 @@ Feature: Basic Resolver
# to be revised (as it would then leak, which is probably true
# for any resolver system test)
When I start bind10 with configuration resolver/resolver_basic.config
- And wait for new bind10 stderr message RESOLVER_STARTED
+ And wait for bind10 stderr message BIND10_STARTED_CC
+ And wait for bind10 stderr message CMDCTL_STARTED
+ And wait for bind10 stderr message RESOLVER_STARTED
+
+ bind10 module Resolver should be running
+ And bind10 module Auth should not be running
+ And bind10 module Xfrout should not be running
+ And bind10 module Zonemgr should not be running
+ And bind10 module Xfrin should not be running
+ And bind10 module Stats should not be running
+ And bind10 module StatsHttpd should not be running
# The ACL is set to reject any queries
A query for l.root-servers.net. should have rcode REFUSED
diff --git a/tests/lettuce/features/terrain/bind10_control.py b/tests/lettuce/features/terrain/bind10_control.py
index b2a367c..c56afb7 100644
--- a/tests/lettuce/features/terrain/bind10_control.py
+++ b/tests/lettuce/features/terrain/bind10_control.py
@@ -14,10 +14,19 @@
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
from lettuce import *
+import time
import subprocess
import re
import json
+ at step('sleep for (\d+) seconds')
+def wait_seconds(step, seconds):
+ """Sleep for some seconds.
+ Parameters:
+ seconds number of seconds to sleep for.
+ """
+ time.sleep(float(seconds))
+
@step('start bind10(?: with configuration (\S+))?' +\
'(?: with cmdctl port (\d+))?' +\
'(?: with msgq socket file (\S+))?' +\
@@ -100,18 +109,15 @@ def wait_for_xfrout(step, process_name):
def have_bind10_running(step, config_file, cmdctl_port, process_name):
"""
Compound convenience step for running bind10, which consists of
- start_bind10 and wait_for_auth.
+ start_bind10.
Currently only supports the 'with configuration' option.
"""
start_step = 'start bind10 with configuration ' + config_file
- wait_step = 'wait for bind10 auth to start'
if cmdctl_port is not None:
start_step += ' with cmdctl port ' + str(cmdctl_port)
if process_name is not None:
start_step += ' as ' + process_name
- wait_step = 'wait for bind10 auth of ' + process_name + ' to start'
step.given(start_step)
- step.given(wait_step)
# function to send lines to bindctl, and store the result
def run_bindctl(commands, cmdctl_port=None):
@@ -142,8 +148,8 @@ def run_bindctl(commands, cmdctl_port=None):
"stderr:\n" + str(stderr)
- at step('last bindctl( stderr)? output should( not)? contain (\S+)')
-def check_bindctl_output(step, stderr, notv, string):
+ at step('last bindctl( stderr)? output should( not)? contain (\S+)( exactly)?')
+def check_bindctl_output(step, stderr, notv, string, exactly):
"""Checks the stdout (or stderr) stream of the last run of bindctl,
fails if the given string is not found in it (or fails if 'not' was
set and it is found
@@ -151,14 +157,19 @@ def check_bindctl_output(step, stderr, notv, string):
stderr ('stderr'): Check stderr instead of stdout output
notv ('not'): reverse the check (fail if string is found)
string ('contain <string>') string to look for
+ exactly ('exactly'): Make an exact match delimited by whitespace
"""
if stderr is None:
output = world.last_bindctl_stdout
else:
output = world.last_bindctl_stderr
found = False
- if string in output:
- found = True
+ if exactly is None:
+ if string in output:
+ found = True
+ else:
+ if re.search(r'^\s+' + string + r'\s+', output, re.IGNORECASE | re.MULTILINE) is not None:
+ found = True
if notv is None:
assert found == True, "'" + string +\
"' was not found in bindctl output:\n" +\
@@ -322,4 +333,4 @@ def module_is_running(step, name, not_str):
if not_str is None:
not_str = ""
step.given('send bind10 the command help')
- step.given('last bindctl output should' + not_str + ' contain ' + name)
+ step.given('last bindctl output should' + not_str + ' contain ' + name + ' exactly')
diff --git a/tests/lettuce/features/terrain/steps.py b/tests/lettuce/features/terrain/steps.py
index 4b199d6..8df0bae 100644
--- a/tests/lettuce/features/terrain/steps.py
+++ b/tests/lettuce/features/terrain/steps.py
@@ -30,12 +30,13 @@ def stop_a_named_process(step, process_name):
"""
world.processes.stop_process(process_name)
- at step('wait for (new )?(\w+) stderr message (\w+)(?: not (\w+))?')
-def wait_for_message(step, new, process_name, message, not_message):
+ at step('wait (?:(\d+) times )?for (new )?(\w+) stderr message (\w+)(?: not (\w+))?')
+def wait_for_stderr_message(step, times, new, process_name, message, not_message):
"""
Block until the given message is printed to the given process's stderr
output.
Parameter:
+ times: Check for the string this many times.
new: (' new', optional): Only check the output printed since last time
this step was used for this process.
process_name ('<name> stderr'): Name of the process to check the output of.
@@ -46,16 +47,19 @@ def wait_for_message(step, new, process_name, message, not_message):
strings = [message]
if not_message is not None:
strings.append(not_message)
- (found, line) = world.processes.wait_for_stderr_str(process_name, strings, new)
+ if times is None:
+ times = 1
+ (found, line) = world.processes.wait_for_stderr_str(process_name, strings, new, int(times))
if not_message is not None:
assert found != not_message, line
- at step('wait for (new )?(\w+) stdout message (\w+)(?: not (\w+))?')
-def wait_for_message(step, process_name, message, not_message):
+ at step('wait (?:(\d+) times )?for (new )?(\w+) stdout message (\w+)(?: not (\w+))?')
+def wait_for_stdout_message(step, times, new, process_name, message, not_message):
"""
Block until the given message is printed to the given process's stdout
output.
Parameter:
+ times: Check for the string this many times.
new: (' new', optional): Only check the output printed since last time
this step was used for this process.
process_name ('<name> stderr'): Name of the process to check the output of.
@@ -66,7 +70,9 @@ def wait_for_message(step, process_name, message, not_message):
strings = [message]
if not_message is not None:
strings.append(not_message)
- (found, line) = world.processes.wait_for_stdout_str(process_name, strings, new)
+ if times is None:
+ times = 1
+ (found, line) = world.processes.wait_for_stdout_str(process_name, strings, new, int(times))
if not_message is not None:
assert found != not_message, line
diff --git a/tests/lettuce/features/terrain/terrain.py b/tests/lettuce/features/terrain/terrain.py
index 2bfddd6..753d912 100644
--- a/tests/lettuce/features/terrain/terrain.py
+++ b/tests/lettuce/features/terrain/terrain.py
@@ -42,6 +42,8 @@ import time
# The first element is the original, the second is the target that will be
# used by the tests that need them
copylist = [
+ ["configurations/bindctl_commands.config.orig",
+ "configurations/bindctl_commands.config"],
["configurations/example.org.config.orig",
"configurations/example.org.config"],
["configurations/resolver/resolver_basic.config.orig",
@@ -164,7 +166,7 @@ class RunningProcess:
os.remove(self.stderr_filename)
os.remove(self.stdout_filename)
- def _wait_for_output_str(self, filename, running_file, strings, only_new):
+ def _wait_for_output_str(self, filename, running_file, strings, only_new, matches = 1):
"""
Wait for a line of output in this process. This will (if only_new is
False) first check all previous output from the process, and if not
@@ -178,18 +180,22 @@ class RunningProcess:
strings: Array of strings to look for.
only_new: If true, only check output since last time this method was
called. If false, first check earlier output.
+ matches: Check for the string this many times.
Returns a tuple containing the matched string, and the complete line
it was found in.
Fails if none of the strings was read after 10 seconds
(OUTPUT_WAIT_INTERVAL * OUTPUT_WAIT_MAX_INTERVALS).
"""
+ match_count = 0
if not only_new:
full_file = open(filename, "r")
for line in full_file:
for string in strings:
if line.find(string) != -1:
- full_file.close()
- return (string, line)
+ match_count += 1
+ if match_count >= matches:
+ full_file.close()
+ return (string, line)
wait_count = 0
while wait_count < OUTPUT_WAIT_MAX_INTERVALS:
where = running_file.tell()
@@ -197,42 +203,46 @@ class RunningProcess:
if line:
for string in strings:
if line.find(string) != -1:
- return (string, line)
+ match_count += 1
+ if match_count >= matches:
+ return (string, line)
else:
wait_count += 1
time.sleep(OUTPUT_WAIT_INTERVAL)
running_file.seek(where)
assert False, "Timeout waiting for process output: " + str(strings)
- def wait_for_stderr_str(self, strings, only_new = True):
+ def wait_for_stderr_str(self, strings, only_new = True, matches = 1):
"""
Wait for one of the given strings in this process's stderr output.
Parameters:
strings: Array of strings to look for.
only_new: If true, only check output since last time this method was
called. If false, first check earlier output.
+ matches: Check for the string this many times.
Returns a tuple containing the matched string, and the complete line
it was found in.
Fails if none of the strings was read after 10 seconds
(OUTPUT_WAIT_INTERVAL * OUTPUT_WAIT_MAX_INTERVALS).
"""
return self._wait_for_output_str(self.stderr_filename, self.stderr,
- strings, only_new)
+ strings, only_new, matches)
- def wait_for_stdout_str(self, strings, only_new = True):
+ def wait_for_stdout_str(self, strings, only_new = True, matches = 1):
"""
Wait for one of the given strings in this process's stdout output.
Parameters:
strings: Array of strings to look for.
only_new: If true, only check output since last time this method was
called. If false, first check earlier output.
+ matches: Check for the string this many times.
Returns a tuple containing the matched string, and the complete line
it was found in.
Fails if none of the strings was read after 10 seconds
(OUTPUT_WAIT_INTERVAL * OUTPUT_WAIT_MAX_INTERVALS).
"""
return self._wait_for_output_str(self.stdout_filename, self.stdout,
- strings, only_new)
+ strings, only_new, matches)
# Container class for a number of running processes
# i.e. servers like bind10, etc
@@ -298,7 +308,7 @@ class RunningProcesses:
for process in self.processes.values():
process.remove_files_on_exit = False
- def wait_for_stderr_str(self, process_name, strings, only_new = True):
+ def wait_for_stderr_str(self, process_name, strings, only_new = True, matches = 1):
"""
Wait for one of the given strings in the given process's stderr output.
Parameters:
@@ -306,6 +316,7 @@ class RunningProcesses:
strings: Array of strings to look for.
only_new: If true, only check output since last time this method was
called. If false, first check earlier output.
+ matches: Check for the string this many times.
Returns the matched string.
Fails if none of the strings was read after 10 seconds
(OUTPUT_WAIT_INTERVAL * OUTPUT_WAIT_MAX_INTERVALS).
@@ -314,9 +325,10 @@ class RunningProcesses:
assert process_name in self.processes,\
"Process " + process_name + " unknown"
return self.processes[process_name].wait_for_stderr_str(strings,
- only_new)
+ only_new,
+ matches)
- def wait_for_stdout_str(self, process_name, strings, only_new = True):
+ def wait_for_stdout_str(self, process_name, strings, only_new = True, matches = 1):
"""
Wait for one of the given strings in the given process's stdout output.
Parameters:
@@ -324,6 +336,7 @@ class RunningProcesses:
strings: Array of strings to look for.
only_new: If true, only check output since last time this method was
called. If false, first check earlier output.
+ matches: Check for the string this many times.
Returns the matched string.
Fails if none of the strings was read after 10 seconds
(OUTPUT_WAIT_INTERVAL * OUTPUT_WAIT_MAX_INTERVALS).
@@ -332,7 +345,8 @@ class RunningProcesses:
assert process_name in self.processes,\
"Process " + process_name + " unknown"
return self.processes[process_name].wait_for_stdout_str(strings,
- only_new)
+ only_new,
+ matches)
@before.each_scenario
def initialize(scenario):
diff --git a/tests/lettuce/features/xfrin_bind10.feature b/tests/lettuce/features/xfrin_bind10.feature
index 9970396..69043d8 100644
--- a/tests/lettuce/features/xfrin_bind10.feature
+++ b/tests/lettuce/features/xfrin_bind10.feature
@@ -3,7 +3,19 @@ Feature: Xfrin
Scenario: Retransfer command
Given I have bind10 running with configuration xfrin/retransfer_master.conf with cmdctl port 47804 as master
+ And wait for master stderr message BIND10_STARTED_CC
+ And wait for master stderr message CMDCTL_STARTED
+ And wait for master stderr message AUTH_SERVER_STARTED
+ And wait for master stderr message XFROUT_STARTED
+ And wait for master stderr message ZONEMGR_STARTED
+
And I have bind10 running with configuration xfrin/retransfer_slave.conf
+ And wait for bind10 stderr message BIND10_STARTED_CC
+ And wait for bind10 stderr message CMDCTL_STARTED
+ And wait for bind10 stderr message AUTH_SERVER_STARTED
+ And wait for bind10 stderr message XFRIN_STARTED
+ And wait for bind10 stderr message ZONEMGR_STARTED
+
A query for www.example.org should have rcode REFUSED
Wait for bind10 stderr message CMDCTL_STARTED
When I send bind10 the command Xfrin retransfer example.org IN ::1 47807
diff --git a/tests/lettuce/setup_intree_bind10.sh.in b/tests/lettuce/setup_intree_bind10.sh.in
index b1f17bc..9d72778 100755
--- a/tests/lettuce/setup_intree_bind10.sh.in
+++ b/tests/lettuce/setup_intree_bind10.sh.in
@@ -23,7 +23,7 @@ BIND10_PATH=@abs_top_builddir@/src/bin/bind10
PATH=@abs_top_builddir@/src/bin/bind10:@abs_top_builddir@/src/bin/bindctl:@abs_top_builddir@/src/bin/msgq:@abs_top_builddir@/src/bin/auth:@abs_top_builddir@/src/bin/resolver:@abs_top_builddir@/src/bin/cfgmgr:@abs_top_builddir@/src/bin/cmdctl:@abs_top_builddir@/src/bin/stats:@abs_top_builddir@/src/bin/xfrin:@abs_top_builddir@/src/bin/xfrout:@abs_top_builddir@/src/bin/zonemgr:@abs_top_builddir@/src/bin/ddns:@abs_top_builddir@/src/bin/dhcp6:@abs_top_builddir@/src/bin/sockcreator:$PATH
export PATH
-PYTHONPATH=@abs_top_builddir@/src/bin:@abs_top_builddir@/src/lib/python/isc/log_messages:@abs_top_builddir@/src/lib/python:@abs_top_builddir@/src/lib/dns/python/.libs:@abs_top_builddir@/src/lib/xfr/.libs:@abs_top_builddir@/src/lib/log/.libs:@abs_top_builddir@/src/lib/util/io/.libs:@abs_top_builddir@/src/lib/python/isc/config:@abs_top_builddir@/src/lib/python/isc/acl/.libs:@abs_top_builddir@/src/lib/python/isc/datasrc/.libs
+PYTHONPATH=@abs_top_builddir@/src/bin:@abs_top_builddir@/src/lib/python/isc/log_messages:@abs_top_builddir@/src/lib/python:@abs_top_builddir@/src/lib/dns/python/.libs:@abs_top_builddir@/src/lib/xfr/.libs:@abs_top_builddir@/src/lib/log/.libs:@abs_top_builddir@/src/lib/util/io/.libs:@abs_top_builddir@/src/lib/python/isc/config:@abs_top_builddir@/src/lib/python/isc/acl/.libs:@abs_top_builddir@/src/lib/python/isc/datasrc/.libs:$PYTHONPATH
export PYTHONPATH
# If necessary (rare cases), explicitly specify paths to dynamic libraries
diff --git a/tests/system/bindctl/tests.sh b/tests/system/bindctl/tests.sh
index cb9d8be..352642e 100755
--- a/tests/system/bindctl/tests.sh
+++ b/tests/system/bindctl/tests.sh
@@ -32,7 +32,18 @@ cnt_value1=0
cnt_value2=0
cnt_value3=0
-echo "I:Checking b10-auth is working by default ($n)"
+echo "I:Checking b10-auth is disabled by default ($n)"
+$DIG +norec @10.53.0.1 -p 53210 ns.example.com. A > /dev/null && status=1
+if [ $status != 0 ]; then echo "I:failed"; fi
+n=`expr $n + 1`
+
+echo "I:Starting b10-auth and checking that it works ($n)"
+echo 'config add Boss/components b10-auth
+config set Boss/components/b10-auth { "special": "auth", "kind": "needed" }
+config commit
+quit
+' | $RUN_BINDCTL \
+ --csv-file-dir=$BINDCTL_CSV_DIR 2>&1 > /dev/null || status=1
$DIG +norec @10.53.0.1 -p 53210 ns.example.com. A >dig.out.$n || status=1
# perform a simple check on the output (digcomp would be too much for this)
grep 192.0.2.1 dig.out.$n > /dev/null || status=1
@@ -46,9 +57,9 @@ sleep 2
echo 'Stats show
' | $RUN_BINDCTL \
--csv-file-dir=$BINDCTL_CSV_DIR > bindctl.out.$n || status=1
-# the server should have received 1 UDP and 1 TCP queries (TCP query was
-# sent from the server startup script)
-cnt_value1=`expr $cnt_value1 + 1`
+# the server should have received 1 UDP and 0 TCP queries (the server
+# startup script no longer sends any TCP queries)
+cnt_value1=`expr $cnt_value1 + 0`
cnt_value2=`expr $cnt_value2 + 1`
cnt_value3=`expr $cnt_value1 + $cnt_value2`
grep $cnt_name1".*\<"$cnt_value1"\>" bindctl.out.$n > /dev/null || status=1
@@ -64,7 +75,7 @@ quit
' | $RUN_BINDCTL \
--csv-file-dir=$BINDCTL_CSV_DIR 2>&1 > /dev/null || status=1
# dig should exit with a failure code.
-$DIG +tcp +norec @10.53.0.1 -p 53210 ns.example.com. A && status=1
+$DIG +tcp +norec @10.53.0.1 -p 53210 ns.example.com. A > /dev/null && status=1
if [ $status != 0 ]; then echo "I:failed"; fi
n=`expr $n + 1`
@@ -76,6 +87,7 @@ quit
' | $RUN_BINDCTL \
--csv-file-dir=$BINDCTL_CSV_DIR 2>&1 > /dev/null || status=1
$DIG +norec @10.53.0.1 -p 53210 ns.example.com. A >dig.out.$n || status=1
+# perform a simple check on the output (digcomp would be too much for this)
grep 192.0.2.1 dig.out.$n > /dev/null || status=1
if [ $status != 0 ]; then echo "I:failed"; fi
n=`expr $n + 1`
diff --git a/tests/system/glue/nsx1/b10-config.db.in b/tests/system/glue/nsx1/b10-config.db.in
index 0d5a324..660183b 100644
--- a/tests/system/glue/nsx1/b10-config.db.in
+++ b/tests/system/glue/nsx1/b10-config.db.in
@@ -2,5 +2,15 @@
"Auth": {
"listen_on": [{"address": "10.53.0.1", "port": 53210}],
"database_file": "@abs_builddir@/zone.sqlite3"
+ },
+ "Boss": {
+ "components": {
+ "b10-auth": {"kind": "needed", "special": "auth" },
+ "b10-xfrin": { "address": "Xfrin", "kind": "dispensable" },
+ "b10-xfrout": { "address": "Xfrout", "kind": "dispensable" },
+ "b10-zonemgr": { "address": "Zonemgr", "kind": "dispensable" },
+ "b10-stats": { "address": "Stats", "kind": "dispensable" },
+ "b10-cmdctl": { "special": "cmdctl", "kind": "needed" }
+ }
}
}
diff --git a/tests/system/ixfr/b10-config.db.in b/tests/system/ixfr/b10-config.db.in
index 946d80f..156c959 100644
--- a/tests/system/ixfr/b10-config.db.in
+++ b/tests/system/ixfr/b10-config.db.in
@@ -19,5 +19,15 @@
"name": "example.",
"class": "IN"
}]
+ },
+ "Boss": {
+ "components": {
+ "b10-auth": {"kind": "needed", "special": "auth" },
+ "b10-xfrin": { "address": "Xfrin", "kind": "dispensable" },
+ "b10-xfrout": { "address": "Xfrout", "kind": "dispensable" },
+ "b10-zonemgr": { "address": "Zonemgr", "kind": "dispensable" },
+ "b10-stats": { "address": "Stats", "kind": "dispensable" },
+ "b10-cmdctl": { "special": "cmdctl", "kind": "needed" }
+ }
}
}
diff --git a/tests/system/start.pl b/tests/system/start.pl
index daa4577..32284de 100755
--- a/tests/system/start.pl
+++ b/tests/system/start.pl
@@ -53,6 +53,8 @@ if ($server && !-d "$test/$server") {
my $topdir = abs_path("$test/..");
my $testdir = abs_path("$test");
my $RUN_BIND10 = $ENV{'RUN_BIND10'};
+my $RUN_BINDCTL = $ENV{'RUN_BINDCTL'};
+my $BINDCTL_CSV_DIR = $ENV{'BINDCTL_CSV_DIR'};
my $NAMED = $ENV{'BIND9_NAMED'};
my $LWRESD = $ENV{'LWRESD'};
my $DIG = $ENV{'DIG'};
@@ -211,14 +213,15 @@ sub verify_server {
my $tries = 0;
while (1) {
- my $return = system("$DIG +tcp +noadd +nosea +nostat +noquest +nocomm +nocmd -p 53210 version.bind. chaos txt \@10.53.0.$n > dig.out");
+ my $return = system("echo \"Stats show\" | $RUN_BINDCTL --csv-file-dir=$BINDCTL_CSV_DIR > bindctl.out");
last if ($return == 0);
- print `grep ";" dig.out`;
if (++$tries >= 30) {
print "I:no response from $server\n";
print "R:FAIL\n";
system("$PERL $topdir/stop.pl $testdir");
exit 1;
+ } else {
+ print "I:no response from $server. retrying.\n";
}
sleep 2;
}
More information about the bind10-changes
mailing list