BIND 10 vorner-tmp-sync, updated. 4152bc4b9b40e4ccb6a44f9c692224eb07e77ae6 TMP COMMIT

BIND 10 source code commits bind10-changes at lists.isc.org
Fri Jul 13 14:17:29 UTC 2012


The branch, vorner-tmp-sync has been updated
  discards  190ddd2b8185f090ad835f9aec035323f06f36c0 (commit)
  discards  e675dc75b6fbe186980798b8e3c7106a17de40dd (commit)
  discards  77cc51898582ef249035a5ea3b99501d76143bde (commit)
  discards  d31754477ab0136864aa6d85ce2936e5a5e02ffc (commit)
  discards  be031e34e7fc50522908b39f897cb7865a055b0e (commit)
  discards  eabb375e7dfc94f67aab7e4d8e372d71db9885c1 (commit)
  discards  a0607f2c1a78586f6f54490c5a0c9e284a2caefc (commit)
  discards  95833885795b723c5c1586d23827ea42c37b1789 (commit)
  discards  97659d0862864670a3b45e8ae2c672b0d7029b2b (commit)
  discards  b7c8ced3bac54e5e4560bdc39d15a74f4636fd88 (commit)
  discards  90593cc3f05fbd272f11fc57c876487f9dbc3813 (commit)
  discards  5fba01f28ca9b4a07417b40c0fc016eed2cdc7fa (commit)
  discards  4f90ffd6c73b67efc830da23a101f9095b2540f8 (commit)
  discards  6dc6d1f5d551d833a86b38297b9e209271fbdea3 (commit)
  discards  af4e7787d37b951f9a48e992f0e2c6f4e4a28c22 (commit)
  discards  27b68b4cbeb6ed397baf40221b9dda915230dcf6 (commit)
  discards  be542e8e2c04b89bc6788112e4006e91bcff2418 (commit)
  discards  5ed0c62ab3febe9f5310006fe3dedf52928fa79f (commit)
  discards  f5db3a25bbac60c241acc36ba9869f72b4db18a9 (commit)
  discards  1af29fce7c3ed236d2db21289f8fcf76af15724c (commit)
  discards  6a56ac9b0e5bd227af1730fe4cd8adbd36d03d00 (commit)
  discards  6107757547e99687e84c8c19f412801ac926a342 (commit)
  discards  c3badfe37d74047f7b6b1f7f4ec03d30e7164296 (commit)
  discards  327c71c61633f0d60163ac0cf38ce3954547c60f (commit)
  discards  1124a637dfa3b123519bbd0e5e28d3b370c0bf4e (commit)
  discards  59a8af594d8c0a0ea672dece5d10cd995fb4c0c2 (commit)
  discards  9d269c5437c03247628e8d73ebda85a2e1e7ef72 (commit)
  discards  18da2727080b2f1c4fbac21fb46371fb11311264 (commit)
  discards  0e5ceb2ea0871dfd07db2eb8548ba7454df0fa02 (commit)
  discards  343dc8e1fefc65298ddf3cc7d82adf8b6b9a60bf (commit)
  discards  2536cfbce01e0fdd5b3d891beeedf2105ec8178c (commit)
  discards  7ef59689d4277f0fa9fa43996c7c19ac509e741d (commit)
  discards  07236d6cc1068f21d8362c5bb47c4928741d5421 (commit)
  discards  f7de4b58b26e102920ce67597be8dfa8908f1a1e (commit)
  discards  8fa13ec3115f58573bc2fd6213a99be1c8435462 (commit)
  discards  c558fd6d7a67fa70d3ba78f43c6536f5c006fd3d (commit)
       via  4152bc4b9b40e4ccb6a44f9c692224eb07e77ae6 (commit)
       via  7fca81716ad3a755bf5744e88c3adeef15b04450 (commit)
       via  3fac7d5579c5f51b8e952b50db510b45bfa986f3 (commit)
       via  c0fe24753fceb4186417cfa34fa838560d733fbb (commit)
       via  da6e2d28b4cc44f8969b10d2c7f12b421d84ddb2 (commit)
       via  af89cdb039dadd62476f212e67a2eec0dad8f7fa (commit)
       via  02d998f59517c181fedc2321d6541f15aebc12f5 (commit)
       via  231408d546153bffd573f1417c8c6bf8a451b6e7 (commit)
       via  8b731b4250b47f8e4ef6367609dce21a221aee82 (commit)
       via  3198b650ccc2be44c93a380c3db4d5fe6429e940 (commit)
       via  0684f354d89fda12a3146050a55eacbb0a8c5071 (commit)
       via  6b80e1e57145e8b0796d872f51ca39a0f4bbc17a (commit)
       via  220c1dff5491042a8fd325503c3bd30ce973d3bb (commit)
       via  93ec40dd0a1df963c676037cc60c066c748b3030 (commit)
       via  1793d893ccb043537810cbed80079b7d373ef6d0 (commit)
       via  6498dfa5915fbca86d839b73490320360111e24e (commit)
       via  8eaa01c8bc19861c1ad146f3099e6636cb3d48d4 (commit)
       via  400da17fc216ce60be368e20dabdca638c81b45d (commit)
       via  71c5bdbe0993f0f1df977f7ac89e0eda9b3526c9 (commit)
       via  50dc1afa945214cf133502ea600c48bfeb363a7d (commit)
       via  66d9922628755b55d297c03e02d5c7fb2614f8ac (commit)
       via  a47a1d516432f50c5cf989b5c14326606fee80e3 (commit)
       via  d4ba721af6702333ee6f6130f0f0fe2efc3ff859 (commit)
       via  abf5722f11570ebcd303d67d0877efab8015e9d8 (commit)
       via  dadce810b431c69b7d80b4ec06e44774f4806a38 (commit)
       via  7197d4f537cf2e2931ad17370eeaf34154479dea (commit)
       via  1fc2b06b57a008ec602daa2dac79939b3cc6b65d (commit)
       via  9771dfb067dc0bf250d69bc4c07c811573d2c656 (commit)
       via  398b2215386cb1c28d764333404c1389cb87999c (commit)
       via  23ae3c2bbdf1a9f22c124aeeac2ac3c1692deb76 (commit)
       via  3a1e804a487e5406ec11bd62ae4ed76a15c49970 (commit)
       via  d83d9fe8ef6beaebe03fd486ca9b203aa60b4891 (commit)
       via  fdcc93e8ee07547f9fe86d56999b9ed5b5ac78d2 (commit)
       via  09d780b7f01d9f94e0da683ddc2539f2f5b03d1a (commit)
       via  e20691f8d713bb257033db96533fff11f5872752 (commit)
       via  15364a524a668d37a4fd63427f4eda5fd79e60e6 (commit)
       via  6c78bb408db659d97a4af548da504175a22bfabe (commit)
       via  d5ec81ad8f86f860c2b8e5c9980268da2efdd94e (commit)
       via  cdada0b63865c20370d42715df72d90f8e59e8bb (commit)
       via  4b90f2ac3b8de3f1a61d7b5f743f2721c6dd34b3 (commit)
       via  144e80212746f8d55e6a59edcf689fec9f32ae95 (commit)
       via  a64cb609ee3d2004212634685dc8a9cae46ea617 (commit)
       via  e26eb608b1feb0dcd764a1efa1dd89561b651e19 (commit)
       via  1170780af08a0de33e882da5409776fe0e7f2a11 (commit)
       via  1e85f1ea840dcd93f80f154600d762b030888f8f (commit)
       via  b945fd1c9eee6fd70016a24b547426e1633faf8f (commit)
       via  304e2b97b852eeaee4d6be57d54dc30a413dbbd1 (commit)
       via  c7017fc5e4fb0ec1b7b3fa84f96e91d68e0a46f2 (commit)
       via  fdc9afcf5e90f2d6cacf9da65cb8ab1d7e515fd0 (commit)
       via  83e396404b5f484f1d2462664948ee6031abe638 (commit)
       via  99d2c13f8d73b423fde8e557f8775e4c24ca6d03 (commit)
       via  efb3f3344d624ca830d07798948e01f07e118820 (commit)
       via  dbef0e25199a8694e57e03fba704d5aa839ab3b7 (commit)
       via  6b32945256d568825b2c0c07fd84d96efedd85bf (commit)
       via  87e091a226590e11fea99cc16af4c03a25f0b840 (commit)
       via  81ea7538383e7f27b062ec0a3cdacaed11e449a9 (commit)
       via  e8a89f139ab66a59895fd6b5a1469344a211758f (commit)
       via  7e93a92e0d3f54263bd0d72cbdcb06c30229ac1f (commit)
       via  9dfb07c8ce80f1082f1d493705d95ece544dd1ca (commit)
       via  f4e22ffd7bfb3ffbc024d801f3c6dbb7312261ec (commit)
       via  fb5902b031a00a249a32c7561b71e951e1aad6f0 (commit)
       via  36d3b727081be4b49bdb1dc78f71fb231605c057 (commit)
       via  0bebde9e2558dd2303c8b522dfff54281cb5aa0a (commit)
       via  1a0fc96ac4cf6f324631e67ac391b85d6eec5b08 (commit)
       via  c6385a4f54979296a9eb50da73d9fccddff81ff6 (commit)
       via  bed40730d9387775ad655427420157d6d18b33b1 (commit)
       via  04fd11bf0539ea3ace1c103cf4488cb965aec659 (commit)
       via  5c6c47046be1da96c581693c500461dff5ba9304 (commit)
       via  c09a49cd3d1cd3498a7c7fb778abbe5485989e65 (commit)
       via  491a0e2f9cd8a8c72bd9ae5c1650e523ca8afab9 (commit)
       via  02f0aa67d53e253855814e88e885cf19e6dfdf96 (commit)
       via  83d31781cfeb717a84e916b1a08522664dd7b590 (commit)
       via  3dab9ab4947300e8d5b9cf8d4544d9491c65038c (commit)
       via  8acfde4201f10d86ee53d2c60701b222896fe088 (commit)
       via  b574c191d04f51d21c97979546c5641582d1bdf5 (commit)
       via  2498f05b7afa17431e9f3f4d6109e995fbec6514 (commit)
       via  b4b7d4a332fb63aa73b5be24be59ff9866c46ed6 (commit)
       via  483f1075942965f0340291e7ff7dae7806df22af (commit)
       via  d1e088cf6ecc8d99c293d195a05433d9d3742ba4 (commit)
       via  6276f4098c51d0f8b8703aa3a6cbf56f07264959 (commit)
       via  18bcce8781a3b410b0d6f8712495da27a28b9fc5 (commit)
       via  b2a7049b19584687962588cd5695748541ddfc32 (commit)
       via  e4743cb6128e5a2a346fcbcbef7a8c9796934e01 (commit)
       via  d8a478581147fe220b6b4e5425e2570021a7d2b5 (commit)
       via  35b4c61aa77ffef14b5060709c03bc196ce19646 (commit)
       via  86b50d54a6e3eac0275314ddeb77eb8ad5fbab73 (commit)
       via  9b410a87bfebfb3329e30f5949070a81bb22235a (commit)
       via  dc2f6aabc9b1f28136e4513f46eb43c235bf505e (commit)
       via  cd2f58725f050e19cca4acc69d3388a1e4fda2f3 (commit)
       via  d6c5f0605f3d7ad837905a13d1d46fe41f3cf7f7 (commit)
       via  05b81acbc6b6504b9d5f869465266b8cfa45ace1 (commit)
       via  3dea78e6159c63d47ec887fa70c056753f84c41d (commit)
       via  84d243249151b4f949eb88ae16ded1e46f1f2943 (commit)
       via  61667bcc9c013ce7d105609404c32cd5d83fa02c (commit)
       via  57c61f2f457ac99686706d05dda5cd39737c6bd0 (commit)
       via  24c9af463a1087f54918f6e1206f72b50b43d9bf (commit)
       via  bf0f1e06d99d7f4fc36a0eb53e1bf8420e86bb35 (commit)
       via  846dbfde91d54302568407175b54bc3cfb0f6bae (commit)
       via  31ee75a034bad0d43d30368fa1ed7a3643aea402 (commit)
       via  de9c0a0b8ce9eb7b7aa7319aef68a209f27f1421 (commit)
       via  0cd3e789df96be0f94030fffbdfa5675a76ea6a2 (commit)
       via  1b235c7827500aace4402a601b5110638214e028 (commit)
       via  8e376a021e24671fb9818dd58ff5c1157286b990 (commit)
       via  2f691c28713f4c9be59012ed55353c2f10de967c (commit)
       via  73d710471643958ac39c8825e1df3d6c0d61a68b (commit)
       via  d249e34178e27afde1858b28ee7d0e42d847525c (commit)
       via  ca4a4409f4e7af3bc11eec3d6d40c6a682f17678 (commit)
       via  930e5b9931e061578f77ac3acc9d796459c13633 (commit)
       via  f3e904c386e2a0d93cba0c7df8698c5ba1b441ce (commit)
       via  ed608bae6873c4597f2136804758d68da84754c2 (commit)
       via  ef571c297aabab0808ac3eecf3c457fdce55a73d (commit)
       via  0e1996af4d06ab528f76e13a3ce7c4c29b12d046 (commit)
       via  41f4bacdf9f658999d94f36a2925dc5e0c62dcfd (commit)
       via  53ae982184ecea7ee8efb8e1a78c6a62dc76212c (commit)
       via  6df91c2dc854f8068a7f8aceb6b28ce380267ac1 (commit)
       via  b8306189256e5bceeb3017817681ecb9c39b5736 (commit)
       via  c4901d0f8f158eccafcc7d968b3253297a224272 (commit)

This update added new revisions after undoing existing revisions.  That is
to say, the old revision is not a strict subset of the new revision.  This
situation occurs when you --force push a change and generate a repository
containing something like this:

 * -- * -- B -- O -- O -- O (190ddd2b8185f090ad835f9aec035323f06f36c0)
            \
             N -- N -- N (4152bc4b9b40e4ccb6a44f9c692224eb07e77ae6)

When this happens we assume that you've already had alert emails for all
of the O revisions, and so we here report only the revisions in the N
branch from the common base, B.

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 4152bc4b9b40e4ccb6a44f9c692224eb07e77ae6
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date:   Fri Jul 13 16:17:04 2012 +0200

    TMP COMMIT

-----------------------------------------------------------------------

Summary of changes:
 ChangeLog                                          |   14 +
 configure.ac                                       |    7 +-
 doc/guide/bind10-guide.xml                         |  290 ++++++------
 src/bin/Makefile.am                                |    3 +-
 src/bin/auth/Makefile.am                           |    1 -
 src/bin/auth/auth_config.cc                        |   99 +++-
 src/bin/auth/auth_messages.mes                     |    3 +
 src/bin/auth/auth_srv.cc                           |  172 +++++--
 src/bin/auth/auth_srv.h                            |  108 +++--
 src/bin/auth/command.cc                            |    8 +-
 src/bin/auth/datasrc_configurator.h                |  223 ---------
 src/bin/auth/main.cc                               |   11 +-
 src/bin/auth/query.cc                              |   54 +--
 src/bin/auth/query.h                               |   20 +-
 src/bin/auth/tests/Makefile.am                     |    5 -
 src/bin/auth/tests/auth_srv_unittest.cc            |  479 ++++++++------------
 src/bin/auth/tests/command_unittest.cc             |   55 +--
 src/bin/auth/tests/config_unittest.cc              |  386 +++++++++++++++-
 .../auth/tests/datasrc_configurator_unittest.cc    |  292 ------------
 src/bin/auth/tests/query_unittest.cc               |  203 ++++-----
 src/bin/auth/tests/testdata/Makefile.am            |    1 -
 src/bin/auth/tests/testdata/spec.spec              |    6 -
 src/bin/cfgmgr/plugins/Makefile.am                 |    7 +-
 src/bin/cfgmgr/plugins/datasrc.py                  |   36 --
 src/bin/cfgmgr/plugins/datasrc.spec.pre.in         |   66 ---
 src/bin/cfgmgr/plugins/tests/Makefile.am           |    2 +-
 src/bin/cfgmgr/plugins/tests/datasrc_test.py       |   36 --
 src/bin/cmdctl/cmdctl.py.in                        |    2 +-
 src/bin/msgq/msgq.xml                              |    8 +-
 src/bin/showtech/.gitignore                        |    2 +
 src/bin/showtech/Makefile.am                       |   28 ++
 .../{dhcp4/b10-dhcp4.8 => showtech/b10-showtech.1} |   38 +-
 .../b10-dhcp6.xml => showtech/b10-showtech.xml}    |   48 +-
 src/bin/showtech/showtech.py.in                    |  127 ++++++
 src/bin/xfrin/xfrin.py.in                          |    4 +
 src/bin/xfrout/xfrout.py.in                        |    3 +
 src/bin/xfrout/xfrout.spec.pre.in                  |   27 ++
 src/lib/config/module_spec.cc                      |    2 +-
 src/lib/config/tests/ccsession_unittests.cc        |   11 +-
 src/lib/config/tests/module_spec_unittests.cc      |    1 -
 src/lib/config/tests/testdata/Makefile.am          |    1 -
 src/lib/config/tests/testdata/spec40.spec          |   13 -
 src/lib/datasrc/client_list.cc                     |   85 ++--
 src/lib/datasrc/client_list.h                      |   49 +-
 src/lib/datasrc/database.cc                        |   57 +--
 src/lib/datasrc/database.h                         |   15 +-
 src/lib/datasrc/datasrc_messages.mes               |    7 +
 src/lib/datasrc/rbtree.h                           |    3 +
 src/lib/datasrc/static.zone.pre                    |    2 -
 src/lib/datasrc/tests/client_list_unittest.cc      |   79 +---
 src/lib/datasrc/tests/database_unittest.cc         |   37 +-
 .../datasrc/tests/zone_finder_context_unittest.cc  |   13 -
 src/lib/datasrc/zone.h                             |   10 +
 src/lib/dhcp/iface_mgr.cc                          |  140 +++++-
 src/lib/dhcp/iface_mgr.h                           |   70 ++-
 src/lib/dhcp/tests/iface_mgr_unittest.cc           |   92 +++-
 src/lib/dns/labelsequence.cc                       |  228 +++++++++-
 src/lib/dns/labelsequence.h                        |  123 ++++-
 src/lib/dns/messagerenderer.cc                     |    6 +-
 src/lib/dns/name.cc                                |  161 +------
 src/lib/dns/name.h                                 |   24 +-
 src/lib/dns/name_internal.h                        |    2 +-
 src/lib/dns/python/name_python.cc                  |    5 +-
 src/lib/dns/python/pydnspp_common.h                |   55 +++
 src/lib/dns/python/rrclass_python.cc               |    4 +-
 src/lib/dns/python/rrtype_python.cc                |    8 +-
 src/lib/dns/python/tests/rrtype_python_test.py     |    9 +
 src/lib/dns/tests/labelsequence_unittest.cc        |  426 ++++++++++++++++-
 src/lib/python/isc/Makefile.am                     |    2 +-
 .../configurableclientlist_python.cc}              |  149 +++---
 .../isc/datasrc/configurableclientlist_python.h}   |   25 +-
 src/lib/python/isc/ddns/tests/.gitignore           |    1 +
 src/lib/python/isc/notify/notify_out.py            |    6 +
 src/lib/python/isc/{dns => sysinfo}/Makefile.am    |    7 +-
 src/lib/python/isc/sysinfo/__init__.py             |    1 +
 src/lib/python/isc/sysinfo/sysinfo.py              |  286 ++++++++++++
 .../python/isc/{ddns => sysinfo}/tests/Makefile.am |    9 +-
 src/lib/python/isc/sysinfo/tests/sysinfo_test.py   |  197 ++++++++
 .../lettuce/configurations/xfrin/inmem_slave.conf  |    4 +-
 .../configurations/xfrin/retransfer_master.conf    |    8 +-
 .../configurations/xfrin/retransfer_slave.conf     |    4 +-
 ...fer_slave.conf => retransfer_slave_notify.conf} |   19 +-
 tests/lettuce/data/.gitignore                      |    1 +
 ...frin.sqlite3.orig => xfrin-notify.sqlite3.orig} |  Bin 13312 -> 13312 bytes
 .../lettuce/features/inmemory_over_sqlite3.feature |    8 +-
 tests/lettuce/features/queries.feature             |    3 +
 tests/lettuce/features/terrain/bind10_control.py   |    4 +-
 tests/lettuce/features/terrain/terrain.py          |    2 +
 tests/lettuce/features/terrain/transfer.py         |    4 +-
 tests/lettuce/features/xfrin_bind10.feature        |    4 +-
 .../lettuce/features/xfrin_notify_handling.feature |   29 ++
 91 files changed, 3353 insertions(+), 2032 deletions(-)
 delete mode 100644 src/bin/auth/datasrc_configurator.h
 delete mode 100644 src/bin/auth/tests/datasrc_configurator_unittest.cc
 delete mode 100644 src/bin/auth/tests/testdata/spec.spec
 delete mode 100644 src/bin/cfgmgr/plugins/datasrc.py
 delete mode 100644 src/bin/cfgmgr/plugins/datasrc.spec.pre.in
 delete mode 100644 src/bin/cfgmgr/plugins/tests/datasrc_test.py
 create mode 100644 src/bin/showtech/.gitignore
 create mode 100644 src/bin/showtech/Makefile.am
 copy src/bin/{dhcp4/b10-dhcp4.8 => showtech/b10-showtech.1} (57%)
 copy src/bin/{dhcp6/b10-dhcp6.xml => showtech/b10-showtech.xml} (60%)
 create mode 100755 src/bin/showtech/showtech.py.in
 delete mode 100644 src/lib/config/tests/testdata/spec40.spec
 copy src/lib/python/isc/{acl/dns_requestacl_python.cc => datasrc/configurableclientlist_python.cc} (56%)
 copy src/lib/{dns/python/nsec3hash_python.h => python/isc/datasrc/configurableclientlist_python.h} (70%)
 create mode 100644 src/lib/python/isc/ddns/tests/.gitignore
 copy src/lib/python/isc/{dns => sysinfo}/Makefile.am (51%)
 create mode 100644 src/lib/python/isc/sysinfo/__init__.py
 create mode 100644 src/lib/python/isc/sysinfo/sysinfo.py
 copy src/lib/python/isc/{ddns => sysinfo}/tests/Makefile.am (73%)
 create mode 100644 src/lib/python/isc/sysinfo/tests/sysinfo_test.py
 copy tests/lettuce/configurations/xfrin/{retransfer_slave.conf => retransfer_slave_notify.conf} (58%)
 copy tests/lettuce/data/{inmem-xfrin.sqlite3.orig => xfrin-notify.sqlite3.orig} (71%)
 create mode 100644 tests/lettuce/features/xfrin_notify_handling.feature

-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index 8fb267f..fa85446 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+452.	[func]*		muks
+	b10-showtech: An initial implementation of the b10-showtech tool
+	is now available. It gathers and outputs system information which
+	can be used by future tech support staff.
+	(Trac #2062, git 144e80212746f8d55e6a59edcf689fec9f32ae95)
+
+451.	[bug]		muks, jinmei
+	libdatasrc: the database-based data source now correctly returns
+	glue records on (not under) a zone cut, such as in the case where
+	the NS name of an NS record is identical to its owner name. (Note:
+	libdatasrc itself doesn't judge what kind of record type can be a
+	"glue"; it's the caller's responsibility.)
+	(Trac #1771, git 483f1075942965f0340291e7ff7dae7806df22af)
+
 450.	[func]*		tomek
 	b10-dhcp4: DHCPv4 server component is now integrated into
 	BIND10 framework. It can be started from BIND10 (using bindctl)
diff --git a/configure.ac b/configure.ac
index cc68f4b..af350a8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@
 # Process this file with autoconf to produce a configure script.
 
 AC_PREREQ([2.59])
-AC_INIT(bind10-devel, 20120405, bind10-dev at isc.org)
+AC_INIT(bind10-devel, 20120712, bind10-dev at isc.org)
 AC_CONFIG_SRCDIR(README)
 AM_INIT_AUTOMAKE
 m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])dnl be backward compatible
@@ -1027,6 +1027,7 @@ AC_CONFIG_FILES([Makefile
                  src/bin/dhcp4/tests/Makefile
                  src/bin/resolver/Makefile
                  src/bin/resolver/tests/Makefile
+                 src/bin/showtech/Makefile
                  src/bin/sockcreator/Makefile
                  src/bin/sockcreator/tests/Makefile
                  src/bin/xfrin/Makefile
@@ -1082,6 +1083,8 @@ AC_CONFIG_FILES([Makefile
                  src/lib/python/isc/xfrin/tests/Makefile
                  src/lib/python/isc/server_common/Makefile
                  src/lib/python/isc/server_common/tests/Makefile
+                 src/lib/python/isc/sysinfo/Makefile
+                 src/lib/python/isc/sysinfo/tests/Makefile
                  src/lib/config/Makefile
                  src/lib/config/tests/Makefile
                  src/lib/config/tests/testdata/Makefile
@@ -1137,7 +1140,6 @@ AC_CONFIG_FILES([Makefile
 AC_OUTPUT([doc/version.ent
            src/bin/cfgmgr/b10-cfgmgr.py
            src/bin/cfgmgr/tests/b10-cfgmgr_test.py
-           src/bin/cfgmgr/plugins/datasrc.spec.pre
            src/bin/cmdctl/cmdctl.py
            src/bin/cmdctl/run_b10-cmdctl.sh
            src/bin/cmdctl/tests/cmdctl_test
@@ -1160,6 +1162,7 @@ AC_OUTPUT([doc/version.ent
            src/bin/zonemgr/zonemgr.spec.pre
            src/bin/zonemgr/tests/zonemgr_test
            src/bin/zonemgr/run_b10-zonemgr.sh
+           src/bin/showtech/showtech.py
            src/bin/stats/stats.py
            src/bin/stats/stats_httpd.py
            src/bin/bind10/bind10_src.py
diff --git a/doc/guide/bind10-guide.xml b/doc/guide/bind10-guide.xml
index 1463284..040b109 100644
--- a/doc/guide/bind10-guide.xml
+++ b/doc/guide/bind10-guide.xml
@@ -92,7 +92,7 @@
       <title>Supported Platforms</title>
       <para>
   BIND 10 builds have been tested on (in no particular order)
-  Debian GNU/Linux 5 and unstable, Ubuntu 9.10, NetBSD 5,
+  Debian GNU/Linux 6 and unstable, Ubuntu 9.10, NetBSD 5,
   Solaris 10 and 11, FreeBSD 7 and 8, CentOS Linux 5.3,
   MacOS 10.6 and 10.7, and OpenBSD 5.1.
 
@@ -105,7 +105,17 @@
     </section>
 
     <section id="required-software">
-      <title>Required Software</title>
+      <title>Required Software at Run-time</title>
+
+      <para>
+        Running BIND 10 uses various extra software which may
+        not be provided in some operating systems' default
+        installations nor standard packages collections. You may
+        need to install this required software separately.
+        (For the build requirements, also see
+        <xref linkend="build-requirements"/>.)
+      </para>
+
       <para>
         BIND 10 requires at least Python 3.1
         (<ulink url="http://www.python.org/"/>).
@@ -140,15 +150,6 @@
         Python modules need to be built for the corresponding Python 3.
       </para>
 <!-- TODO: this will change ... -->
-
-      <note>
-        <para>
-          Some operating systems do not provide these dependencies
-          in their default installation nor standard packages
-          collections.
-          You may need to install them separately.
-        </para>
-      </note>
     </section>
 
     <section id="starting_stopping">
@@ -808,8 +809,9 @@ as a dependency earlier -->
       The <command>b10-cfgmgr</command> daemon is always needed by every
       module, if only to send information about themselves somewhere,
       but more importantly to ask about their own settings, and
-      about other modules. The <command>b10-sockcreator</command> will
-      allocate sockets for the rest of the system.
+      about other modules. The <command>b10-sockcreator</command> daemon
+      helps allocate Internet addresses and ports as needed for BIND 10
+      network services.
     </para>
 
     <para>
@@ -840,23 +842,22 @@ as a dependency earlier -->
 
     </section>
     <section id="bind10.config">
-      <title>Configuration of started processes</title>
-      <para>
-        The processes to be started can be configured, with the exception
-        of the <command>b10-sockcreator</command>, <command>b10-msgq</command>
-        and <command>b10-cfgmgr</command>.
-      </para>
+      <title>Configuration to start processes</title>
 
       <para>
-        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).
+	The processes to be used can be configured for
+	<command>bind10</command> to start, with the exception
+	of the required <command>b10-sockcreator</command>,
+	<command>b10-msgq</command> and <command>b10-cfgmgr</command>
+	components.
+	The configuration is in the <varname>Boss/components</varname>
+	section. Each element represents one component, which is
+	an abstraction of a process.
       </para>
 
       <para>
-        To add a process to the set, let's say the resolver (which not started
-        by default), you would do this:
+	To add a process to the set, let's say the resolver (which
+	is not started by default), you would do this:
         <screen>> <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>
@@ -864,17 +865,21 @@ as a dependency earlier -->
 > <userinput>config commit</userinput></screen></para>
 
       <para>
-        Now, what it means. We add an entry called b10-resolver. It is both a
-        name used to reference this component in the configuration and the
-        name of the process to start. Then we set some parameters on how to
-        start it.
+	Now, what it means. We add an entry called
+	<quote>b10-resolver</quote>. It is both a name used to
+	reference this component in the configuration and the name
+	of the process to start. Then we set some parameters on
+	how to start it.
       </para>
 
       <para>
-        The special one is for components that need some kind of special care
-        during startup or shutdown. Unless specified, the component is started
-        in usual way. This is the list of components that need to be started
-        in a special way, with the value of special used for them:
+	The <varname>special</varname> setting is for components
+	that need some kind of special care during startup or
+	shutdown. Unless specified, the component is started in a
+	usual way. This is the list of components that need to be
+	started in a special way, with the value of special used
+	for them:
+<!-- TODO: this still doesn't explain why they are special -->
         <table>
           <title>Special startup components</title>
           <tgroup cols='3' align='left'>
@@ -883,9 +888,9 @@ as a dependency earlier -->
           <colspec colname='description'/>
           <thead><row><entry>Component</entry><entry>Special</entry><entry>Description</entry></row></thead>
           <tbody>
-            <row><entry>b10-auth</entry><entry>auth</entry><entry>Authoritative server</entry></row>
-            <row><entry>b10-resolver</entry><entry>resolver</entry><entry>The resolver</entry></row>
-            <row><entry>b10-cmdctl</entry><entry>cmdctl</entry><entry>The command control (remote control interface)</entry></row>
+            <row><entry>b10-auth</entry><entry>auth</entry><entry>Authoritative DNS server</entry></row>
+            <row><entry>b10-resolver</entry><entry>resolver</entry><entry>DNS resolver</entry></row>
+            <row><entry>b10-cmdctl</entry><entry>cmdctl</entry><entry>Command control (remote control interface)</entry></row>
             <!-- TODO Either add xfrin and xfrout as well or clean up the workarounds in boss before the release -->
           </tbody>
           </tgroup>
@@ -893,32 +898,34 @@ as a dependency earlier -->
       </para>
 
       <para>
-        The kind specifies how a failure of the component should
-        be handled.  If it is set to <quote>dispensable</quote>
-        (the default unless you set something else), it will get
-        started again if it fails. If it is set to <quote>needed</quote>
-        and it fails at startup, the whole <command>bind10</command>
-        shuts down and exits with error exit code. But if it fails
-        some time later, it is just started again. If you set it
-        to <quote>core</quote>, you indicate that the system is
-        not usable without the component and if such component
-        fails, the system shuts down no matter when the failure
-        happened.  This is the behaviour of the core components
-        (the ones you can't turn off), but you can declare any
-        other components as core as well if you wish (but you can
-        turn these off, they just can't fail).
+	The <varname>kind</varname> specifies how a failure of the
+	component should be handled.  If it is set to
+	<quote>dispensable</quote> (the default unless you set
+	something else), it will get started again if it fails. If
+	it is set to <quote>needed</quote> and it fails at startup,
+	the whole <command>bind10</command> shuts down and exits
+	with an error exit code. But if it fails some time later, it
+	is just started again. If you set it to <quote>core</quote>,
+	you indicate that the system is not usable without the
+	component and if such component fails, the system shuts
+	down no matter when the failure happened.  This is the
+	behaviour of the core components (the ones you can't turn
+	off), but you can declare any other components as core as
+	well if you wish (but you can turn these off, they just
+	can't fail).
       </para>
 
       <para>
-        The priority defines order in which the components should start.
-        The ones with higher number are started sooner than the ones with
-        lower ones. If you don't set it, 0 (zero) is used as the priority.
-        Usually, leaving it at the default is enough.
+	The <varname>priority</varname> defines order in which the
+	components should start.  The ones with higher numbers are
+	started sooner than the ones with lower ones. If you don't
+	set it, 0 (zero) is used as the priority.  Usually, leaving
+	it at the default is enough.
       </para>
 
       <para>
         There are other parameters we didn't use in our example.
-        One of them is <quote>address</quote>. It is the address
+        One of them is <varname>address</varname>. It is the address
         used by the component on the <command>b10-msgq</command>
         message bus. The special components already know their
         address, but the usual ones don't. The address is by
@@ -934,25 +941,17 @@ address, but the usual ones don't." mean? -->
 <!-- TODO: document params when is enabled -->
 
       <para>
-        The last one is process. It is the name of the process to be started.
-        It defaults to the name of the component if not set, but you can use
-        this to override it.
+	The last one is <varname>process</varname>. It is the name
+	of the process to be started.  It defaults to the name of
+	the component if not set, but you can use this to override
+	it. (The special components also already know their
+        executable name.)
       </para>
 
       <!-- TODO Add parameters when they work, not implemented yet-->
 
       <note>
         <para>
-          This system allows you to start the same component multiple times
-          (by including it in the configuration with different names, but the
-          same process setting). However, the rest of the system doesn't expect
-          such a situation, so it would probably not do what you want. Such
-          support is yet to be implemented.
-        </para>
-      </note>
-
-      <note>
-        <para>
           The configuration is quite powerful, but that includes
           a lot of space for mistakes. You could turn off the
           <command>b10-cmdctl</command>, but then you couldn't
@@ -972,7 +971,7 @@ address, but the usual ones don't." mean? -->
       </note>
       <para>
         It is possible to start some components multiple times (currently
-        <command>b10-auth</command> and <command>b10-resolzer</command>).
+        <command>b10-auth</command> and <command>b10-resolver</command>).
         You might want to do that to gain more performance (each one uses only
         single core). Just put multiple entries under different names, like
         this, with the same config:
@@ -987,6 +986,9 @@ address, but the usual ones don't." mean? -->
         server will keep its own copy of in-memory data and there could be
         problems with locking the sqlite database, if used. The configuration
         might be changed to something more convenient in future.
+	Other components don't expect such a situation, so it would
+	probably not do what you want. Such support is yet to be
+	implemented.
       </para>
     </section>
 
@@ -1011,23 +1013,11 @@ address, but the usual ones don't." mean? -->
       <para>
         Administrators do not communicate directly with the
         <command>b10-msgq</command> daemon.
-        By default, BIND 10 uses port 9912 for the
-        <command>b10-msgq</command> service.
-        It listens on 127.0.0.1.
+        By default, BIND 10 uses a UNIX domain socket file named
+        <filename>/usr/local/var/bind10-devel/msg_socket</filename>
+        for this interprocess communication.
       </para>
 
-<!-- TODO: this is broken, see Trac #111
-      <para>
-        To select an alternate port for the <command>b10-msgq</command> to
-        use, run <command>bind10</command> specifying the option:
-        <screen> $ <userinput>bind10 -TODO-msgq-port 9912</userinput></screen>
-      </para>
--->
-
-<!-- TODO: upcoming plans:
-Unix domain sockets
--->
-
   </chapter>
 
   <chapter id="cfgmgr">
@@ -1069,9 +1059,6 @@ Unix domain sockets
         specifications and all current settings to the
         <command>bindctl</command> client (via
         <command>b10-cmdctl</command>).
-      </para>
-
-      <para>
         <command>b10-cfgmgr</command> relays configurations received
         from <command>b10-cmdctl</command> to the appropriate modules.
       </para>
@@ -1090,7 +1077,7 @@ config changes are actually commands to cfgmgr
       <para>
         The stored configuration file is at
         <filename>/usr/local/var/bind10-devel/b10-config.db</filename>.
-        (The full path is what was defined at build configure time for
+        (The directory is what was defined at build configure time for
         <option>--localstatedir</option>.
         The default is <filename>/usr/local/var/</filename>.)
         The format is loosely based on JSON and is directly parseable
@@ -1208,7 +1195,7 @@ but you might wanna check with likun
 
 <!-- TODO
 openssl req -new -x509 -keyout server.pem -out server.pem -days 365 -nodes
-but that is a single file, maybethis should go back to that format?
+but that is a single file, maybe this should go back to that format?
 -->
 
 <!--
@@ -1256,26 +1243,23 @@ or accounts database -->
       <title>Configuration specification for b10-cmdctl</title>
       <para>
         The configuration items for <command>b10-cmdctl</command> are:
-key_file
-cert_file
-accounts_file
+        <varname>accounts_file</varname> which defines the path to the
+        user accounts database (the default is
+        <filename>/usr/local/etc/bind10-devel/cmdctl-accounts.csv</filename>);
+        <varname>cert_file</varname> which defines the path to the
+        PEM certificate file (the default is
+        <filename>/usr/local/etc/bind10-devel/cmdctl-certfile.pem</filename>);
+        and
+	<varname>key_file</varname> which defines the path to the
+	PEM private key file (the default is
+        <filename>/usr/local/etc/bind10-devel/cmdctl-keyfile.pem</filename>).
       </para>
-<!-- TODO -->
-
-      <para>
-        The control commands are:
-print_settings
-<!-- TODO: remove that -->
 
-shutdown
-      </para>
-<!-- TODO -->
     </section>
 
 <!--
 TODO
 (12:21:30) jinmei: I'd like to have sample session using a command line www client such as wget
-(12:21:33) jinmei: btw
 -->
 
   </chapter>
@@ -1323,7 +1307,8 @@ TODO
 
     <para>
       The <command>b10-auth</command> is the authoritative DNS server.
-      It supports EDNS0 and DNSSEC. It supports IPv6.
+      It supports EDNS0, DNSSEC, IPv6, and SQLite3 and in-memory zone
+      data backends.
       Normally it is started by the <command>bind10</command> master
       process.
     </para>
@@ -1348,8 +1333,8 @@ since we used bind10 -->
               <simpara>This is an optional string to define the path to find
                  the SQLite3 database file.
 <!-- TODO: -->
-Note: Later the DNS server will use various data source backends.
-This may be a temporary setting until then.
+Note: This may be a temporary setting because the DNS server
+can use various data source backends.
               </simpara>
             </listitem>
           </varlistentry>
@@ -1370,7 +1355,9 @@ This may be a temporary setting until then.
       and
       <varname>zones</varname> to define
       the <varname>file</varname> path name,
-      the <varname>filetype</varname> (e.g., <varname>sqlite3</varname>),
+      the <varname>filetype</varname> (<quote>sqlite3</quote> to load
+      from a SQLite3 database file or <quote>text</quote> to
+      load from a master text file),
       and the <varname>origin</varname> (default domain).
 
       By default, this is empty.
@@ -1542,13 +1529,13 @@ This may be a temporary setting until then.
 > <userinput>config commit</userinput></screen>
 
 	  The authoritative server will begin serving it immediately
-	  after it is loaded.
+	  after the zone data is loaded from the master text file.
 	</para>
 
       </section>
 
       <section id="in-memory-datasource-with-sqlite3-backend">
-	<title>In-memory Data Source With SQLite3 Backend</title>
+	<title>In-memory Data Source with SQLite3 Backend</title>
 
 	<para>
 <!--	  How to configure it. -->
@@ -1570,7 +1557,7 @@ This may be a temporary setting until then.
 > <userinput>config commit</userinput></screen>
 
 	  The authoritative server will begin serving it immediately
-	  after it is loaded.
+	  after the zone data is loaded from the database file.
 	</para>
 
       </section>
@@ -1721,7 +1708,7 @@ TODO
       <command>b10-auth</command>.
       In combination with <command>b10-zonemgr</command> (for
       automated SOA checks), this allows the BIND 10 server to
-      provide <quote>secondary</quote> service.
+      provide <emphasis>secondary</emphasis> service.
     </para>
 
     <para>
@@ -1823,11 +1810,8 @@ what if a NOTIFY is sent?
 
       <screen>> <userinput>config add Zonemgr/secondary_zones</userinput>
 > <userinput>config set Zonemgr/secondary_zones[0]/name "<option>example.com</option>"</userinput>
-> <userinput>config set Zonemgr/secondary_zones[0]/class "<option>IN</option>"</userinput>
 > <userinput>config commit</userinput></screen>
 
-<!-- TODO: remove the IN class example above when it is the default -->
-
       </para>
 
       <para>
@@ -1862,6 +1846,9 @@ what if a NOTIFY is sent?
         automatically sent a <varname>loadzone</varname> command to
         reload the corresponding zone into memory from the backend.
       </para>
+<!-- TODO: currently it delays the queries; see
+http://bind10.isc.org/wiki/ScalableZoneLoadDesign#a7.2UpdatingaZone
+-->
 
       <para>
 	The administrator doesn't have to do anything for
@@ -1884,7 +1871,7 @@ what if a NOTIFY is sent?
       When the <command>b10-auth</command> authoritative DNS server
       receives an AXFR or IXFR request, <command>b10-auth</command>
       internally forwards the request to <command>b10-xfrout</command>,
-      which handles the rest of request processing.
+      which handles the rest of this request processing.
       This is used to provide primary DNS service to share zones
       to secondary name servers.
       The <command>b10-xfrout</command> is also used to send
@@ -1933,8 +1920,9 @@ Xfrout/transfer_acl[0]	{"action": "ACCEPT"}	any	(default)</screen>
 > <userinput>config set Xfrout/zone_config[0]/transfer_acl [{"action": "ACCEPT", "from": "192.0.2.1", "key": "key.example"}]</userinput>
 > <userinput>config commit</userinput></screen>
 
-    <para>Both Xfrout and Auth will use the system wide keyring to check
-    TSIGs in the incoming messages and to sign responses.</para>
+    <para>Both <command>b10-xfrout</command> and <command>b10-auth</command>
+      will use the system wide keyring to check
+      TSIGs in the incoming messages and to sign responses.</para>
 
     <note><simpara>
         The way to specify zone specific configuration (ACLs, etc) is
@@ -1968,14 +1956,14 @@ what is XfroutClient xfr_client??
       When the <command>b10-auth</command> authoritative DNS server
       receives an UPDATE request, it internally forwards the request
       to <command>b10-ddns</command>, which handles the rest of
-      request processing.
-      When the processing is completed <command>b10-ddns</command>
-      will send a response to the client with the RCODE set to the
-      value as specified in RFC 2136 (NOERROR for successful update,
-      REFUSED if rejected due to ACL check, etc).
+      this request processing.
+      When the processing is completed, <command>b10-ddns</command>
+      will send a response to the client as specified in RFC 2136
+      (NOERROR for successful update, REFUSED if rejected due to
+      ACL check, etc).
       If the zone has been changed as a result, it will internally
       notify <command>b10-xfrout</command> so that other secondary
-      servers will be notified via the DNS notify protocol.
+      servers will be notified via the DNS NOTIFY protocol.
       In addition, if <command>b10-auth</command> serves the updated
       zone from its in-memory cache (as described in
       <xref linkend="in-memory-datasource-with-sqlite3-backend" />),
@@ -2001,10 +1989,10 @@ what is XfroutClient xfr_client??
       As of this writing <command>b10-ddns</command> does not support
       update forwarding for secondary zones.
       If it receives an update request for a secondary zone, it will
-      immediately return a response with an RCODE of NOTIMP.
+      immediately return a <quote>not implemented</quote> response.
       <note><simpara>
-	  For feature completeness update forwarding should be
-	  eventually supported.  But right now it's considered a lower
+	  For feature completeness, update forwarding should be
+	  eventually supported.  But currently it's considered a lower
 	  priority task and there is no specific plan of implementing
 	  this feature.
 <!-- See Trac #2063 -->
@@ -2034,9 +2022,9 @@ what is XfroutClient xfr_client??
         underlying data source storing the zone data be writable.
         In the current implementation this means the zone must be stored
         in an SQLite3-based data source.
-        Also, right now, the <command>b10-ddns</command> component
-        configures itself with the data source referring to the
-        <quote>database_file</quote> configuration parameter of
+	Also, in this development version, the <command>b10-ddns</command>
+	component configures itself with the data source referring to the
+        <varname>database_file</varname> configuration parameter of
         <command>b10-auth</command>.
         So this information must be configured correctly before starting
         <command>b10-ddns</command>.
@@ -2070,14 +2058,16 @@ what is XfroutClient xfr_client??
 > <userinput>config commit</userinput>
 </screen>
       <note><simpara>
-	  In theory "kind" could be omitted because "dispensable" is its
-	  default.  But there's some peculiar behavior (which should
-	  be a bug and should be fixed eventually; see Trac ticket
-	  #2064) with bindctl and you'll still need to specify that explicitly.
-	  Likewise, "address" may look unnecessary because
-	  <command>b10-ddns</command> would start and work without
-	  specifying it.  But for it to shutdown gracefully this
-	  parameter should also be specified.
+	  In theory <varname>kind</varname> could be omitted because
+	  "dispensable" is its default.
+	  But there's some peculiar behavior (which should be a
+	  bug and should be fixed eventually; see Trac ticket #2064)
+	  with <command>bindctl</command> and you'll still need to
+	  specify that explicitly.  Likewise, <varname>address</varname>
+	  may look unnecessary because <command>b10-ddns</command>
+	  would start and work without specifying it.  But for it
+	  to shutdown gracefully this parameter should also be
+	  specified.
       </simpara></note>
       </para>
     </section>
@@ -2085,14 +2075,13 @@ what is XfroutClient xfr_client??
     <section>
       <title>Access Control</title>
       <para>
-        By default <command>b10-ddns</command> rejects any update
-        requests from any clients by returning a response with an RCODE
-        of REFUSED.
+        By default, <command>b10-ddns</command> rejects any update
+        requests from any clients by returning a REFUSED response.
         To allow updates to take effect, an access control rule
         (called update ACL) with a policy allowing updates must explicitly be
         configured.
         Update ACL must be configured per zone basis in the
-        <quote>zones</quote> configuration parameter of
+        <varname>zones</varname> configuration parameter of
         <command>b10-ddns</command>.
         This is a list of per-zone configurations regarding DDNS.
         Each list element consists of the following parameters:
@@ -2127,14 +2116,12 @@ what is XfroutClient xfr_client??
         In general, an update ACL rule that allows an update request
         should be configured with a TSIG key.
         This is an example update ACL that allows updates to the zone
-        named <quote>example.org</quote> of RR class <quote>IN</quote>
+        named <quote>example.org</quote> (of default RR class <quote>IN</quote>)
         from clients that send requests signed with a TSIG whose
         key name is "key.example.org" (and refuses all others):
       <screen>
 > <userinput>config add DDNS/zones</userinput>
 > <userinput>config set DDNS/zones[0]/origin example.org</userinput>
-> <userinput>config set DDNS/zones[0]/class IN</userinput>
-(Note: "class" can be omitted)
 > <userinput>config add DDNS/zones[0]/update_acl {"action": "ACCEPT", "key": "key.example.org"}</userinput>
 > <userinput>config commit</userinput>
 </screen>
@@ -2159,11 +2146,13 @@ DDNS/zones[0]/update_acl[1]     {"action": "ACCEPT", "from": "::1", "key": "key.
 > <userinput>config commit</userinput>
 </screen>
       (Note the "add" in the first line.  Before this sequence, we
-      have had only entry in zones[0]/update_acl.  The "add" command
-      with a value (rule) adds a new entry and sets it to the given rule.
+      have had only entry in <varname>zones[0]/update_acl</varname>.
+      The <command>add</command> command with a value (rule) adds
+      a new entry and sets it to the given rule.
+
       Due to a limitation of the current implementation, it doesn't
       work if you first try to just add a new entry and then set it to
-      a given rule).
+      a given rule.)
       </para>
 
       <note><simpara>
@@ -2185,6 +2174,7 @@ DDNS/zones[0]/update_acl[1]     {"action": "ACCEPT", "from": "::1", "key": "key.
 	which is rejecting any requests in the case of
 	<command>b10-ddns</command>.
       </para>
+<!-- TODO: what are the other defaults? -->
 
       <para>
 	Other actions than "ACCEPT", namely "REJECT" and "DROP", can be
@@ -2223,8 +2213,8 @@ DDNS/zones[0]/update_acl[1]     {"action": "ACCEPT", "from": "::1", "key": "key.
       <title>Miscellaneous Operational Issues</title>
       <para>
         Unlike BIND 9, BIND 10 currently does not support automatic
-        resigning of DNSSEC-signed zone when it's updated via DDNS.
-        It could be possible to resign the updated zone afterwards
+        re-signing of DNSSEC-signed zone when it's updated via DDNS.
+        It could be possible to re-sign the updated zone afterwards
         or make sure the update request also updates related DNSSEC
         records, but that will be pretty error-prone operation.
         In general, it's not advisable to allow DDNS for a signed zone
@@ -2248,8 +2238,8 @@ DDNS/zones[0]/update_acl[1]     {"action": "ACCEPT", "from": "::1", "key": "key.
         <command>b10-zonemgr</command>.  Zones listed in
         <quote>secondary_zones</quote> will never be updated via DDNS
         regardless of the update ACL configuration;
-	<command>b10-ddns</command> will return a response with an
-	RCODE of NOTAUTH as specified in RFC 2136.
+	<command>b10-ddns</command> will return a NOTAUTH (server
+        not authoritative for the zone) response.
         If you have a "conceptual" secondary zone whose content is a
         copy of some external source but is not updated via the
         standard zone transfers and therefore not listed in
diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am
index 499e209..c821b9f 100644
--- a/src/bin/Makefile.am
+++ b/src/bin/Makefile.am
@@ -1,4 +1,5 @@
 SUBDIRS = bind10 bindctl cfgmgr ddns loadzone msgq host cmdctl auth xfrin \
-	xfrout usermgr zonemgr stats tests resolver sockcreator dhcp4 dhcp6 dbutil
+	xfrout usermgr zonemgr stats tests resolver sockcreator dhcp4 dhcp6 \
+	dbutil showtech
 
 check-recursive: all-recursive
diff --git a/src/bin/auth/Makefile.am b/src/bin/auth/Makefile.am
index 1f0fbbf..34b5155 100644
--- a/src/bin/auth/Makefile.am
+++ b/src/bin/auth/Makefile.am
@@ -48,7 +48,6 @@ b10_auth_SOURCES += auth_config.cc auth_config.h
 b10_auth_SOURCES += command.cc command.h
 b10_auth_SOURCES += common.h common.cc
 b10_auth_SOURCES += statistics.cc statistics.h
-b10_auth_SOURCES += datasrc_configurator.h
 b10_auth_SOURCES += main.cc
 # This is a temporary workaround for #1206, where the InMemoryClient has been
 # moved to an ldopened library. We could add that library to LDADD, but that
diff --git a/src/bin/auth/auth_config.cc b/src/bin/auth/auth_config.cc
index d7266e5..c85a4ee 100644
--- a/src/bin/auth/auth_config.cc
+++ b/src/bin/auth/auth_config.cc
@@ -43,6 +43,20 @@ using namespace isc::datasrc;
 using namespace isc::server_common::portconfig;
 
 namespace {
+/// A derived \c AuthConfigParser class for the "datasources" configuration
+/// identifier.
+class DatasourcesConfig : public AuthConfigParser {
+public:
+    DatasourcesConfig(AuthSrv& server) : server_(server)
+    {}
+    virtual void build(ConstElementPtr config_value);
+    virtual void commit();
+private:
+    AuthSrv& server_;
+    vector<boost::shared_ptr<AuthConfigParser> > datasources_;
+    set<string> configured_sources_;
+    vector<pair<RRClass, DataSourceClientContainerPtr> > clients_;
+};
 
 /// A derived \c AuthConfigParser for the version value
 /// (which is not used at this moment)
@@ -53,6 +67,79 @@ public:
     virtual void commit() {};
 };
 
+void
+DatasourcesConfig::build(ConstElementPtr config_value) {
+    BOOST_FOREACH(ConstElementPtr datasrc_elem, config_value->listValue()) {
+        // The caller is supposed to perform syntax-level checks, but we'll
+        // do minimum level of validation ourselves so that we won't crash due
+        // to a buggy application.
+        ConstElementPtr datasrc_type = datasrc_elem->get("type");
+        if (!datasrc_type) {
+            isc_throw(AuthConfigError, "Missing data source type");
+        }
+
+        if (configured_sources_.find(datasrc_type->stringValue()) !=
+            configured_sources_.end()) {
+            isc_throw(AuthConfigError, "Data source type '" <<
+                      datasrc_type->stringValue() << "' already configured");
+        }
+
+        // Apart from that it's not really easy to get at the default
+        // class value for the class here, it should probably really
+        // be a property of the instantiated data source. For now
+        // use hardcoded default IN.
+        const RRClass rrclass =
+            datasrc_elem->contains("class") ?
+            RRClass(datasrc_elem->get("class")->stringValue()) : RRClass::IN();
+
+        // Right now, we only support the in-memory data source for the
+        // RR class of IN.  We reject other cases explicitly by hardcoded
+        // checks.  This will soon be generalized, at which point these
+        // checks will also have to be cleaned up.
+        if (rrclass != RRClass::IN()) {
+            isc_throw(isc::InvalidParameter, "Unsupported data source class: "
+                      << rrclass);
+        }
+        if (datasrc_type->stringValue() != "memory") {
+            isc_throw(AuthConfigError, "Unsupported data source type: "
+                      << datasrc_type->stringValue());
+        }
+
+        // Create a new client for the specified data source and store it
+        // in the local vector.  For now, we always build a new client
+        // from the scratch, and replace any existing ones with the new ones.
+        // We might eventually want to optimize building zones (in case of
+        // reloading) by selectively loading fresh zones for data source
+        // where zone loading is expensive (such as in-memory).
+        clients_.push_back(
+            pair<RRClass, DataSourceClientContainerPtr>(
+                rrclass,
+                DataSourceClientContainerPtr(new DataSourceClientContainer(
+                                                 datasrc_type->stringValue(),
+                                                 datasrc_elem))));
+
+        configured_sources_.insert(datasrc_type->stringValue());
+    }
+}
+
+void
+DatasourcesConfig::commit() {
+    // As noted in build(), the current implementation only supports the
+    // in-memory data source for class IN, and build() should have ensured
+    // it.  So, depending on the vector is empty or not, we either clear
+    // or install an in-memory data source for the server.
+    //
+    // When we generalize it, we'll somehow install all data source clients
+    // built in the vector, clearing deleted ones from the server.
+    if (clients_.empty()) {
+        server_.setInMemoryClient(RRClass::IN(),
+                                  DataSourceClientContainerPtr());
+    } else {
+        server_.setInMemoryClient(clients_.front().first,
+                                  clients_.front().second);
+    }
+}
+
 /// A derived \c AuthConfigParser class for the "statistics-internal"
 /// configuration identifier.
 class StatisticsIntervalConfig : public AuthConfigParser {
@@ -155,7 +242,9 @@ createAuthConfigParser(AuthSrv& server, const std::string& config_id) {
     // simplicity.  In future we'll probably generalize it using map-like
     // data structure, and may even provide external register interface so
     // that it can be dynamically customized.
-    if (config_id == "statistics-interval") {
+    if (config_id == "datasources") {
+        return (new DatasourcesConfig(server));
+    } else if (config_id == "statistics-interval") {
         return (new StatisticsIntervalConfig(server));
     } else if (config_id == "listen_on") {
         return (new ListenAddressConfig(server));
@@ -172,14 +261,6 @@ createAuthConfigParser(AuthSrv& server, const std::string& config_id) {
         // later be used to mark backwards incompatible changes in the
         // config data
         return (new VersionConfig());
-    } else if (config_id == "datasources") {
-        // TODO: Ignored for now, since the value is probably used by
-        // other modules. Once they have been removed from there, remove
-        // it from here and the spec file.
-
-        // We need to return something. The VersionConfig is empty now,
-        // so we may abuse that one, as it is a short-term solution only.
-        return (new VersionConfig());
     } else {
         isc_throw(AuthConfigError, "Unknown configuration identifier: " <<
                   config_id);
diff --git a/src/bin/auth/auth_messages.mes b/src/bin/auth/auth_messages.mes
index 9ac2c49..61de3ee 100644
--- a/src/bin/auth/auth_messages.mes
+++ b/src/bin/auth/auth_messages.mes
@@ -110,6 +110,9 @@ look into the cause and address the issue.  The log message includes
 the client's address (and port), and the error message sent from the
 lower layer that detects the failure.
 
+% AUTH_RECEIVED_NOTIFY received incoming NOTIFY for zone name %1, zone class %2
+This is a debug message reporting that an incoming NOTIFY was received.
+
 % AUTH_NOTIFY_QUESTIONS invalid number of questions (%1) in incoming NOTIFY
 This debug message is logged by the authoritative server when it receives
 a NOTIFY packet that contains zero or more than one question. (A valid
diff --git a/src/bin/auth/auth_srv.cc b/src/bin/auth/auth_srv.cc
index dbba26f..7b8e963 100644
--- a/src/bin/auth/auth_srv.cc
+++ b/src/bin/auth/auth_srv.cc
@@ -43,9 +43,9 @@
 
 #include <datasrc/query.h>
 #include <datasrc/data_source.h>
+#include <datasrc/memory_datasrc.h>
 #include <datasrc/static_datasrc.h>
 #include <datasrc/sqlite3_datasrc.h>
-#include <datasrc/client_list.h>
 
 #include <xfr/xfrout_client.h>
 
@@ -248,6 +248,9 @@ public:
     AbstractSession* xfrin_session_;
 
     /// In-memory data source.  Currently class IN only for simplicity.
+    const RRClass memory_client_class_;
+    isc::datasrc::DataSourceClientContainerPtr memory_client_container_;
+
     /// Hot spot cache
     isc::datasrc::HotCache cache_;
 
@@ -263,21 +266,6 @@ public:
     /// The TSIG keyring
     const boost::shared_ptr<TSIGKeyRing>* keyring_;
 
-    /// The client list
-    map<RRClass, boost::shared_ptr<ConfigurableClientList> > client_lists_;
-
-    boost::shared_ptr<ConfigurableClientList> getClientList(const RRClass&
-                                                            rrclass)
-    {
-        const map<RRClass, boost::shared_ptr<ConfigurableClientList> >::
-            const_iterator it(client_lists_.find(rrclass));
-        if (it == client_lists_.end()) {
-            return (boost::shared_ptr<ConfigurableClientList>());
-        } else {
-            return (it->second);
-        }
-    }
-
     /// Bind the ModuleSpec object in config_session_ with
     /// isc:config::ModuleSpec::validateStatistics.
     void registerStatisticsValidator();
@@ -298,6 +286,14 @@ public:
                       isc::dns::Message& message,
                       bool done);
 private:
+    std::string db_file_;
+
+    MetaDataSrc data_sources_;
+    /// We keep a pointer to the currently running sqlite datasource
+    /// so that we can specifically remove that one should the database
+    /// file change
+    ConstDataSrcPtr cur_datasrc_;
+
     bool xfrout_connected_;
     AbstractXfroutClient& xfrout_client_;
 
@@ -318,6 +314,7 @@ AuthSrvImpl::AuthSrvImpl(const bool use_cache,
                          BaseSocketSessionForwarder& ddns_forwarder) :
     config_session_(NULL),
     xfrin_session_(NULL),
+    memory_client_class_(RRClass::IN()),
     statistics_timer_(io_service_),
     counters_(),
     keyring_(NULL),
@@ -325,6 +322,13 @@ AuthSrvImpl::AuthSrvImpl(const bool use_cache,
     xfrout_client_(xfrout_client),
     ddns_forwarder_("update", ddns_forwarder)
 {
+    // cur_datasrc_ is automatically initialized by the default constructor,
+    // effectively being an empty (sqlite) data source.  once ccsession is up
+    // the datasource will be set by the configuration setting
+
+    // add static data source
+    data_sources_.addDataSrc(ConstDataSrcPtr(new StaticDataSrc));
+
     // enable or disable the cache
     cache_.setEnabled(use_cache);
 }
@@ -500,6 +504,48 @@ AuthSrv::getConfigSession() const {
     return (impl_->config_session_);
 }
 
+isc::datasrc::DataSourceClientContainerPtr
+AuthSrv::getInMemoryClientContainer(const RRClass& rrclass) {
+    if (rrclass != impl_->memory_client_class_) {
+        isc_throw(InvalidParameter,
+                  "Memory data source is not supported for RR class "
+                  << rrclass);
+    }
+    return (impl_->memory_client_container_);
+}
+
+isc::datasrc::DataSourceClient*
+AuthSrv::getInMemoryClient(const RRClass& rrclass) {
+    if (hasInMemoryClient()) {
+        return (&getInMemoryClientContainer(rrclass)->getInstance());
+    } else {
+        return (NULL);
+    }
+}
+
+bool
+AuthSrv::hasInMemoryClient() const {
+    return (impl_->memory_client_container_);
+}
+
+void
+AuthSrv::setInMemoryClient(const isc::dns::RRClass& rrclass,
+                           DataSourceClientContainerPtr memory_client)
+{
+    if (rrclass != impl_->memory_client_class_) {
+        isc_throw(InvalidParameter,
+                  "Memory data source is not supported for RR class "
+                  << rrclass);
+    } else if (!impl_->memory_client_container_ && memory_client) {
+        LOG_DEBUG(auth_logger, DBG_AUTH_OPS, AUTH_MEM_DATASRC_ENABLED)
+                  .arg(rrclass);
+    } else if (impl_->memory_client_container_ && !memory_client) {
+        LOG_DEBUG(auth_logger, DBG_AUTH_OPS, AUTH_MEM_DATASRC_DISABLED)
+                  .arg(rrclass);
+    }
+    impl_->memory_client_container_ = memory_client;
+}
+
 uint32_t
 AuthSrv::getStatisticsTimerInterval() const {
     return (impl_->statistics_timer_.getInterval() / 1000);
@@ -666,16 +712,18 @@ AuthSrvImpl::processNormalQuery(const IOMessage& io_message, Message& message,
     }
 
     try {
+        // If a memory data source is configured call the separate
+        // Query::process()
         const ConstQuestionPtr question = *message.beginQuestion();
-        const boost::shared_ptr<datasrc::ClientList>
-            list(getClientList(question->getClass()));
-        if (list) {
+        if (memory_client_container_ &&
+            memory_client_class_ == question->getClass()) {
             const RRType& qtype = question->getType();
             const Name& qname = question->getName();
-            query_.process(*list, qname, qtype, message, dnssec_ok);
+            query_.process(memory_client_container_->getInstance(),
+                           qname, qtype, message, dnssec_ok);
         } else {
-            makeErrorMessage(renderer_, message, buffer, Rcode::REFUSED());
-            return (true);
+            datasrc::Query query(message, cache_, dnssec_ok);
+            data_sources_.doQuery(query);
         }
     } catch (const Exception& ex) {
         LOG_ERROR(auth_logger, AUTH_PROCESS_FAIL).arg(ex.what());
@@ -780,6 +828,9 @@ AuthSrvImpl::processNotify(const IOMessage& io_message, Message& message,
         return (false);
     }
 
+    LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_RECEIVED_NOTIFY)
+      .arg(question->getName()).arg(question->getClass());
+
     const string remote_ip_address =
         io_message.getRemoteEndpoint().getAddress().toText();
     static const string command_template_start =
@@ -862,6 +913,56 @@ AuthSrvImpl::validateStatistics(isc::data::ConstElementPtr data) const {
             data, true));
 }
 
+ConstElementPtr
+AuthSrvImpl::setDbFile(ConstElementPtr config) {
+    ConstElementPtr answer = isc::config::createAnswer();
+
+    if (config && config->contains("database_file")) {
+        db_file_ = config->get("database_file")->stringValue();
+    } else if (config_session_ != NULL) {
+        bool is_default;
+        string item("database_file");
+        ConstElementPtr value = config_session_->getValue(is_default, item);
+        ElementPtr final = Element::createMap();
+
+        // If the value is the default, and we are running from
+        // a specific directory ('from build'), we need to use
+        // a different value than the default (which may not exist)
+        // (btw, this should not be done here in the end, i think
+        //  the from-source script should have a check for this,
+        //  but for that we need offline access to config, so for
+        //  now this is a decent solution)
+        if (is_default && getenv("B10_FROM_BUILD")) {
+            value = Element::create(string(getenv("B10_FROM_BUILD")) +
+                                    "/bind10_zones.sqlite3");
+        }
+        final->set(item, value);
+        config = final;
+
+        db_file_ = value->stringValue();
+    } else {
+        return (answer);
+    }
+    LOG_DEBUG(auth_logger, DBG_AUTH_OPS, AUTH_DATA_SOURCE).arg(db_file_);
+
+    // create SQL data source
+    // Note: the following step is tricky to be exception-safe and to ensure
+    // exception guarantee: We first need to perform all operations that can
+    // fail, while acquiring resources in the RAII manner.  We then perform
+    // delete and swap operations which should not fail.
+    DataSrcPtr datasrc_ptr(DataSrcPtr(new Sqlite3DataSrc));
+    datasrc_ptr->init(config);
+    data_sources_.addDataSrc(datasrc_ptr);
+
+    // The following code should be exception free.
+    if (cur_datasrc_ != NULL) {
+        data_sources_.removeDataSrc(cur_datasrc_);
+    }
+    cur_datasrc_ = datasrc_ptr;
+
+    return (answer);
+}
+
 void
 AuthSrvImpl::resumeServer(DNSServer* server, Message& message, bool done) {
     if (done) {
@@ -878,7 +979,7 @@ AuthSrv::updateConfig(ConstElementPtr new_config) {
         if (new_config) {
             configureAuthServer(*this, new_config);
         }
-        return (isc::config::createAnswer());
+        return (impl_->setDbFile(new_config));
     } catch (const isc::Exception& error) {
         LOG_ERROR(auth_logger, AUTH_CONFIG_UPDATE_FAIL).arg(error.what());
         return (isc::config::createAnswer(1, error.what()));
@@ -926,28 +1027,3 @@ void
 AuthSrv::setTSIGKeyRing(const boost::shared_ptr<TSIGKeyRing>* keyring) {
     impl_->keyring_ = keyring;
 }
-
-void
-AuthSrv::setClientList(const RRClass& rrclass,
-                       const boost::shared_ptr<ConfigurableClientList>& list) {
-    if (list) {
-        impl_->client_lists_[rrclass] = list;
-    } else {
-        impl_->client_lists_.erase(rrclass);
-    }
-}
-boost::shared_ptr<ConfigurableClientList>
-AuthSrv::getClientList(const RRClass& rrclass) {
-    return (impl_->getClientList(rrclass));
-}
-
-vector<RRClass>
-AuthSrv::getClientListClasses() const {
-    vector<RRClass> result;
-    for (map<RRClass, boost::shared_ptr<ConfigurableClientList> >::
-         const_iterator it(impl_->client_lists_.begin());
-         it != impl_->client_lists_.end(); ++it) {
-        result.push_back(it->first);
-    }
-    return (result);
-}
diff --git a/src/bin/auth/auth_srv.h b/src/bin/auth/auth_srv.h
index ef2f121..18d7503 100644
--- a/src/bin/auth/auth_srv.h
+++ b/src/bin/auth/auth_srv.h
@@ -43,7 +43,7 @@ class BaseSocketSessionForwarder;
 }
 }
 namespace datasrc {
-class ConfigurableClientList;
+class InMemoryClient;
 }
 namespace xfr {
 class AbstractXfroutClient;
@@ -129,7 +129,20 @@ public:
                         isc::util::OutputBuffer& buffer,
                         isc::asiodns::DNSServer* server);
 
-    /// \brief Updates the configuration for the \c AuthSrv object.
+    /// \brief Updates the data source for the \c AuthSrv object.
+    ///
+    /// This method installs or replaces the data source that the \c AuthSrv
+    /// object refers to for query processing.
+    /// Although the method name is generic, the only thing it does is to
+    /// update the data source information.
+    /// If there is a data source installed, it will be replaced with the
+    /// new one.
+    ///
+    /// In the current implementation, the SQLite data source and InMemoryClient
+    /// are assumed.
+    /// We can enable memory data source and get the path of SQLite database by
+    /// the \c config parameter.  If we disabled memory data source, the SQLite
+    /// data source will be used.
     ///
     /// On success this method returns a data \c Element (in the form of a
     /// pointer like object) indicating the successful result,
@@ -225,6 +238,71 @@ public:
     ///
     void setXfrinSession(isc::cc::AbstractSession* xfrin_session);
 
+    /// Returns the in-memory data source configured for the \c AuthSrv,
+    /// if any, as a pointer.
+    ///
+    /// This is mostly a convenience function around
+    /// \c getInMemoryClientContainer, which saves the caller the step
+    /// of having to call getInstance().
+    /// The pointer is of course only valid as long as the container
+    /// exists.
+    ///
+    /// The in-memory data source is configured per RR class.  However,
+    /// the data source may not be available for all RR classes.
+    /// If it is not available for the specified RR class, an exception of
+    /// class \c InvalidParameter will be thrown.
+    /// This method never throws an exception otherwise.
+    ///
+    /// Even for supported RR classes, the in-memory data source is not
+    /// configured by default.  In that case a NULL (shared) pointer will
+    /// be returned.
+    ///
+    /// \param rrclass The RR class of the requested in-memory data source.
+    /// \return A pointer to the in-memory data source, if configured;
+    /// otherwise NULL.
+    isc::datasrc::DataSourceClient* getInMemoryClient(
+        const isc::dns::RRClass& rrclass);
+
+    /// Returns the DataSourceClientContainer of the in-memory datasource
+    ///
+    /// \exception InvalidParameter if the given class does not match
+    ///            the one in the memory data source, or if the memory
+    ///            datasource has not been set (callers can check with
+    ///            \c hasMemoryDataSource())
+    ///
+    /// \param rrclass The RR class of the requested in-memory data source.
+    /// \return A shared pointer to the in-memory data source, if configured;
+    /// otherwise an empty shared pointer.
+    isc::datasrc::DataSourceClientContainerPtr getInMemoryClientContainer(
+        const isc::dns::RRClass& rrclass);
+
+    /// Checks if the in-memory data source has been set.
+    ///
+    /// Right now, only one datasource at a time is effectively supported.
+    /// This is a helper method to check whether it is the in-memory one.
+    /// This is mostly useful for current testing, and is expected to be
+    /// removed (or changed in behaviour) soon, when the general
+    /// multi-data-source framework is completed.
+    ///
+    /// \return True if the in-memory datasource has been set.
+    bool hasInMemoryClient() const;
+
+    /// Sets or replaces the in-memory data source of the specified RR class.
+    ///
+    /// Some RR classes may not be supported, in which case an exception
+    /// of class \c InvalidParameter will be thrown.
+    /// This method never throws an exception otherwise.
+    ///
+    /// If there is already an in memory data source configured, it will be
+    /// replaced with the newly specified one.
+    /// \c memory_client can be an empty shared pointer, in which case it
+    /// will (re)disable the in-memory data source.
+    ///
+    /// \param rrclass The RR class of the in-memory data source to be set.
+    /// \param memory_client A (shared) pointer to \c InMemoryClient to be set.
+    void setInMemoryClient(const isc::dns::RRClass& rrclass,
+        isc::datasrc::DataSourceClientContainerPtr memory_client);
+
     /// \brief Set the communication session with Statistics.
     ///
     /// This function never throws an exception as far as
@@ -340,32 +418,6 @@ public:
     void setTSIGKeyRing(const boost::shared_ptr<isc::dns::TSIGKeyRing>*
                         keyring);
 
-    /// \brief Sets the currently used list for data sources of given
-    ///     class.
-    ///
-    /// Replaces the internally used client list with a new one. Other
-    /// classes are not changed.
-    ///
-    /// \param rrclass The class to modify.
-    /// \param list Shared pointer to the client list. If it is NULL,
-    ///     the list is removed instead.
-    void setClientList(const isc::dns::RRClass& rrclass, const
-                       boost::shared_ptr<isc::datasrc::ConfigurableClientList>&
-                       list);
-
-    /// \brief Returns the currently used client list for the class.
-    ///
-    /// \param rrclass The class for which to get the list.
-    /// \return The list, or NULL if no list is set for the class.
-    boost::shared_ptr<isc::datasrc::ConfigurableClientList>
-        getClientList(const isc::dns::RRClass& rrclass);
-
-    /// \brief Returns a list of classes that have a client list.
-    ///
-    /// \return List of classes for which a non-NULL client list
-    ///     has been set by setClientList.
-    std::vector<isc::dns::RRClass> getClientListClasses() const;
-
 private:
     AuthSrvImpl* impl_;
     isc::asiolink::SimpleCallback* checkin_;
diff --git a/src/bin/auth/command.cc b/src/bin/auth/command.cc
index 2036ff3..750ea28 100644
--- a/src/bin/auth/command.cc
+++ b/src/bin/auth/command.cc
@@ -185,9 +185,7 @@ private:
     // On success, it sets 'old_zone_finder_' to the zone to be updated.
     // It returns true if everything is okay; and false if the command is
     // valid but there's no need for further process.
-    bool validate(AuthSrv& , isc::data::ConstElementPtr ) {
-#if 0
-        TODO: Rewrite
+    bool validate(AuthSrv& server, isc::data::ConstElementPtr args) {
         if (args == NULL) {
             isc_throw(AuthCommandError, "Null argument");
         }
@@ -237,7 +235,6 @@ private:
         old_zone_finder_ = boost::static_pointer_cast<InMemoryZoneFinder>(
             result.zone_finder);
 
-#endif
         return (true);
     }
 
@@ -310,11 +307,8 @@ createAuthCommand(const string& command_id) {
         return (new ShutdownCommand());
     } else if (command_id == "sendstats") {
         return (new SendStatsCommand());
-#if 0
-    // FIXME: The loadzone command will use #2046
     } else if (command_id == "loadzone") {
         return (new LoadZoneCommand());
-#endif
     } else if (false && command_id == "_throw_exception") {
         // This is for testing purpose only and should not appear in the
         // actual configuration syntax.
diff --git a/src/bin/auth/datasrc_configurator.h b/src/bin/auth/datasrc_configurator.h
deleted file mode 100644
index a4fb2a0..0000000
--- a/src/bin/auth/datasrc_configurator.h
+++ /dev/null
@@ -1,223 +0,0 @@
-// 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 DATASRC_CONFIGURATOR_H
-#define DATASRC_CONFIGURATOR_H
-
-#include "auth_srv.h"
-
-#include <datasrc/client_list.h>
-#include <config/ccsession.h>
-#include <cc/data.h>
-
-#include <set>
-
-/// \brief A class to configure the authoritative server's data source lists
-///
-/// This will hook into the data_sources module configuration and it will
-/// keep the local copy of data source clients in the list in the authoritative
-/// server.
-///
-/// The class is slightly unusual. Due to some technical limitations, the hook
-/// needs to be static method. Therefore it is not possible to create instances
-/// of the class.
-///
-/// Also, the class is a template. This is simply because of easier testing.
-/// You don't need to pay attention to it, use the DataSourceConfigurator
-/// type alias instead.
-template<class Server, class List>
-class DataSourceConfiguratorGeneric {
-private:
-    /// \brief Disallow creation of instances
-    DataSourceConfiguratorGeneric();
-    /// \brief Internal method to hook into the ModuleCCSession
-    ///
-    /// It simply calls reconfigure.
-    static void reconfigureInternal(const std::string&,
-                                    isc::data::ConstElementPtr config,
-                                    const isc::config::ConfigData&)
-    {
-        if (config->contains("classes")) {
-            reconfigure(config->get("classes"));
-        }
-    }
-    static Server* server_;
-    static isc::config::ModuleCCSession* session_;
-    typedef boost::shared_ptr<List> ListPtr;
-public:
-    /// \brief Initializes the class.
-    ///
-    /// This configures which session and server should be used.
-    /// It hooks to the session now and downloads the configuration.
-    /// It is synchronous (it may block for some time).
-    ///
-    /// Note that you need to call deinit before the server or
-    /// session dies, otherwise it might access them after they
-    /// are destroyed.
-    ///
-    /// \param session The session to hook into and to access the configuration
-    ///     through.
-    /// \param server It is the server to configure.
-    /// \throw isc::InvalidOperation if this is called when already initialized.
-    /// \throw isc::InvalidParameter if any of the parameters is NULL
-    /// \throw isc::config::ModuleCCError if the remote configuration is not
-    ///     available for some reason.
-    static void init(isc::config::ModuleCCSession *session,
-                     Server *server)
-    {
-        if (session == NULL) {
-            isc_throw(isc::InvalidParameter, "The session must not be NULL");
-        }
-        if (server == NULL) {
-            isc_throw(isc::InvalidParameter, "The server must not be NULL");
-        }
-        if (server_ != NULL) {
-            isc_throw(isc::InvalidOperation,
-                      "The configurator is already initialized");
-        }
-        server_ = server;
-        session_ = session;
-        session->addRemoteConfig("data_sources", reconfigureInternal, false);
-    }
-    /// \brief Deinitializes the class.
-    ///
-    /// This detaches from the session and removes the server from internal
-    /// storage. The current configuration in the server is preserved.
-    ///
-    /// This can be called even if it is not initialized currently. You
-    /// can initialize it again after this.
-    static void deinit() {
-        if (session_ != NULL) {
-            session_->removeRemoteConfig("data_sources");
-        }
-        session_ = NULL;
-        server_ = NULL;
-    }
-    /// \brief Reads new configuration and replaces the old one.
-    ///
-    /// It instructs the server to replace the lists with new ones as needed.
-    /// You don't need to call it directly (but you could, though the benefit
-    /// is unkown and it would be questionable at least). It is called
-    /// automatically on normal updates.
-    ///
-    /// \param config The configuration value to parse. It is in the form
-    ///     as an update from the config manager.
-    /// \throw InvalidOperation if it is called when not initialized.
-    static void reconfigure(const isc::data::ConstElementPtr& config) {
-        if (server_ == NULL) {
-            isc_throw(isc::InvalidOperation,
-                      "Can't reconfigure while not inited");
-        }
-        typedef std::map<std::string, isc::data::ConstElementPtr> Map;
-        typedef std::pair<isc::dns::RRClass, ListPtr> RollbackPair;
-        typedef std::pair<isc::dns::RRClass, isc::data::ConstElementPtr>
-            RollbackConfiguration;
-        // Some structures to be able to perform a rollback
-        std::vector<RollbackPair> rollback_sets;
-        std::vector<RollbackConfiguration> rollback_configurations;
-        try {
-            // Get the configuration and current state.
-            const Map& map(config->mapValue());
-            const std::vector<isc::dns::RRClass>
-                activeVector(server_->getClientListClasses());
-            std::set<isc::dns::RRClass> active(activeVector.begin(),
-                                               activeVector.end());
-            // Go through the configuration and change everything.
-            for (Map::const_iterator it(map.begin()); it != map.end(); ++it) {
-                isc::dns::RRClass rrclass(it->first);
-                active.erase(rrclass);
-                ListPtr list(server_->getClientList(rrclass));
-                bool need_set(false);
-                if (list) {
-                    rollback_configurations.
-                        push_back(RollbackConfiguration(rrclass,
-                            list->getConfiguration()));
-                } else {
-                    list.reset(new List(rrclass));
-                    need_set = true;
-                    rollback_sets.push_back(RollbackPair(rrclass, ListPtr()));
-                }
-                list->configure(it->second, true);
-                if (need_set) {
-                    server_->setClientList(rrclass, list);
-                }
-            }
-            // Remove the ones that are not in the configuration.
-            for (std::set<isc::dns::RRClass>::iterator it(active.begin());
-                 it != active.end(); ++it) {
-                // There seems to be no way the setClientList could throw.
-                // But this is just to make sure in case it did to restore
-                // the original.
-                rollback_sets.push_back(
-                    RollbackPair(*it, server_->getClientList(*it)));
-                server_->setClientList(*it, ListPtr());
-            }
-        } catch (...) {
-            // Perform a rollback of the changes. The old configuration should
-            // work.
-            for (typename std::vector<RollbackPair>::const_iterator
-                 it(rollback_sets.begin()); it != rollback_sets.end(); ++it) {
-                server_->setClientList(it->first, it->second);
-            }
-            for (typename std::vector<RollbackConfiguration>::const_iterator
-                 it(rollback_configurations.begin());
-                 it != rollback_configurations.end(); ++it) {
-                server_->getClientList(it->first)->configure(it->second, true);
-            }
-            throw;
-        }
-    }
-    /// \brief Version of reconfigure for easier testing.
-    ///
-    /// This method can be used to reconfigure a server without first
-    /// initializing the configurator. This does not need a session.
-    /// Otherwise, it acts the same as reconfigure.
-    ///
-    /// This is not meant for production code. Do not use there.
-    ///
-    /// \param server The server to configure.
-    /// \param config The config to use.
-    /// \throw isc::InvalidOperation if the configurator is initialized.
-    /// \throw anything that reconfigure does.
-    static void testReconfigure(Server* server,
-                                const isc::data::ConstElementPtr& config)
-    {
-        if (server_ != NULL) {
-            isc_throw(isc::InvalidOperation, "Currently initialized.");
-        }
-        try {
-            server_ = server;
-            reconfigure(config);
-            server_ = NULL;
-        } catch (...) {
-            server_ = NULL;
-            throw;
-        }
-    }
-};
-
-template<class Server, class List>
-isc::config::ModuleCCSession*
-DataSourceConfiguratorGeneric<Server, List>::session_(NULL);
-
-template<class Server, class List>
-Server* DataSourceConfiguratorGeneric<Server, List>::server_(NULL);
-
-/// \brief Concrete version of DataSourceConfiguratorGeneric for the
-///     use in authoritative server.
-typedef DataSourceConfiguratorGeneric<AuthSrv,
-        isc::datasrc::ConfigurableClientList>
-    DataSourceConfigurator;
-
-#endif
diff --git a/src/bin/auth/main.cc b/src/bin/auth/main.cc
index be854c9..cf4f52e 100644
--- a/src/bin/auth/main.cc
+++ b/src/bin/auth/main.cc
@@ -45,7 +45,6 @@
 #include <auth/command.h>
 #include <auth/auth_srv.h>
 #include <auth/auth_log.h>
-#include <auth/datasrc_configurator.h>
 #include <asiodns/asiodns.h>
 #include <asiolink/asiolink.h>
 #include <log/logger_support.h>
@@ -205,14 +204,6 @@ main(int argc, char* argv[]) {
         isc::server_common::initKeyring(*config_session);
         auth_server->setTSIGKeyRing(&isc::server_common::keyring);
 
-        // Start the data source configuration
-        DataSourceConfigurator::init(config_session, auth_server);
-        // HACK: The default is not passed to the handler. This one will
-        // get the default (or, current value). Further updates will work
-        // the usual way.
-        DataSourceConfigurator::reconfigure(
-            config_session->getRemoteConfigValue("data_sources", "classes"));
-
         // Now start asynchronous read.
         config_session->start();
         LOG_DEBUG(auth_logger, DBG_AUTH_START, AUTH_CONFIG_CHANNEL_STARTED);
@@ -220,6 +211,7 @@ main(int argc, char* argv[]) {
         // Successfully initialized.
         LOG_INFO(auth_logger, AUTH_SERVER_STARTED);
         io_service.run();
+
     } catch (const std::exception& ex) {
         LOG_FATAL(auth_logger, AUTH_SERVER_FAILED).arg(ex.what());
         ret = 1;
@@ -233,7 +225,6 @@ main(int argc, char* argv[]) {
         xfrin_session->disconnect();
     }
 
-    DataSourceConfigurator::deinit();
     delete statistics_session;
     delete xfrin_session;
     delete config_session;
diff --git a/src/bin/auth/query.cc b/src/bin/auth/query.cc
index 1eb6228..f215c04 100644
--- a/src/bin/auth/query.cc
+++ b/src/bin/auth/query.cc
@@ -19,7 +19,6 @@
 #include <dns/rdataclass.h>
 
 #include <datasrc/client.h>
-#include <datasrc/client_list.h>
 
 #include <auth/query.h>
 
@@ -342,17 +341,17 @@ namespace {
 // the qname consists of a single label, which also means it's the root name),
 // we should search the deepest zone we have (which should be the root zone;
 // otherwise it's a query error).
-ClientList::FindResult
-findZone(const ClientList& list, const Name& qname, RRType qtype) {
+DataSourceClient::FindResult
+findZone(const DataSourceClient& client, const Name& qname, RRType qtype) {
     if (qtype != RRType::DS() || qname.getLabelCount() == 1) {
-        return (list.find(qname));
+        return (client.findZone(qname));
     }
-    return (list.find(qname.split(1)));
+    return (client.findZone(qname.split(1)));
 }
 }
 
 void
-Query::process(datasrc::ClientList& client_list,
+Query::process(datasrc::DataSourceClient& datasrc_client,
                const isc::dns::Name& qname, const isc::dns::RRType& qtype,
                isc::dns::Message& response, bool dnssec)
 {
@@ -361,18 +360,19 @@ Query::process(datasrc::ClientList& client_list,
     QueryCleaner cleaner(*this);
 
     // Set up query parameters for the rest of the (internal) methods
-    initialize(client_list, qname, qtype, response, dnssec);
+    initialize(datasrc_client, qname, qtype, response, dnssec);
 
     // Found a zone which is the nearest ancestor to QNAME
-    const ClientList::FindResult result = findZone(*client_list_, *qname_,
-                                                   *qtype_);
+    const DataSourceClient::FindResult result = findZone(*datasrc_client_,
+                                                         *qname_, *qtype_);
 
     // If we have no matching authoritative zone for the query name, return
     // REFUSED.  In short, this is to be compatible with BIND 9, but the
     // background discussion is not that simple.  See the relevant topic
     // at the BIND 10 developers's ML:
     // https://lists.isc.org/mailman/htdig/bind10-dev/2010-December/001633.html
-    if (result.dsrc_client_ == NULL) {
+    if (result.code != result::SUCCESS &&
+        result.code != result::PARTIALMATCH) {
         // If we tried to find a "parent zone" for a DS query and failed,
         // we may still have authority at the child side.  If we do, the query
         // has to be handled there.
@@ -384,7 +384,7 @@ Query::process(datasrc::ClientList& client_list,
         response_->setRcode(Rcode::REFUSED());
         return;
     }
-    ZoneFinder& zfinder = *result.finder_;
+    ZoneFinder& zfinder = *result.zone_finder;
 
     // We have authority for a zone that contain the query name (possibly
     // indirectly via delegation).  Look into the zone.
@@ -457,7 +457,7 @@ Query::process(datasrc::ClientList& client_list,
             // If the answer is a result of wildcard substitution,
             // add a proof that there's no closer name.
             if (dnssec_ && db_context->isWildcard()) {
-                addWildcardProof(*result.finder_, *db_context);
+                addWildcardProof(*result.zone_finder, *db_context);
             }
             break;
         case ZoneFinder::SUCCESS:
@@ -475,17 +475,17 @@ Query::process(datasrc::ClientList& client_list,
             // section.
             // Checking the findZone() is a lightweight check to see if
             // qname is the zone origin.
-            if (!result.exact_match_ ||
+            if (result.code != result::SUCCESS ||
                 db_context->code != ZoneFinder::SUCCESS ||
                 (*qtype_ != RRType::NS() && !qtype_is_any))
             {
-                addAuthAdditional(*result.finder_, additionals_);
+                addAuthAdditional(*result.zone_finder, additionals_);
             }
 
             // If the answer is a result of wildcard substitution,
             // add a proof that there's no closer name.
             if (dnssec_ && db_context->isWildcard()) {
-                addWildcardProof(*result.finder_, *db_context);
+                addWildcardProof(*result.zone_finder, *db_context);
             }
             break;
         case ZoneFinder::DELEGATION:
@@ -505,12 +505,12 @@ Query::process(datasrc::ClientList& client_list,
             // If DNSSEC is requested, see whether there is a DS
             // record for this delegation.
             if (dnssec_) {
-                addDS(*result.finder_, db_context->rrset->getName());
+                addDS(*result.zone_finder, db_context->rrset->getName());
             }
             break;
         case ZoneFinder::NXDOMAIN:
             response_->setRcode(Rcode::NXDOMAIN());
-            addSOA(*result.finder_);
+            addSOA(*result.zone_finder);
             if (dnssec_) {
                 if (db_context->isNSECSigned() && db_context->rrset) {
                     addNXDOMAINProofByNSEC(zfinder, db_context->rrset);
@@ -520,7 +520,7 @@ Query::process(datasrc::ClientList& client_list,
             }
             break;
         case ZoneFinder::NXRRSET:
-            addSOA(*result.finder_);
+            addSOA(*result.zone_finder);
             if (dnssec_) {
                 addNXRRsetProof(zfinder, *db_context);
             }
@@ -538,11 +538,11 @@ Query::process(datasrc::ClientList& client_list,
 }
 
 void
-Query::initialize(datasrc::ClientList& client_list,
+Query::initialize(datasrc::DataSourceClient& datasrc_client,
                   const isc::dns::Name& qname, const isc::dns::RRType& qtype,
                   isc::dns::Message& response, bool dnssec)
 {
-    client_list_ = &client_list;
+    datasrc_client_ = &datasrc_client;
     qname_ = &qname;
     qtype_ = &qtype;
     response_ = &response;
@@ -553,7 +553,7 @@ Query::initialize(datasrc::ClientList& client_list,
 
 void
 Query::reset() {
-    client_list_ = NULL;
+    datasrc_client_ = NULL;
     qname_ = NULL;
     qtype_ = NULL;
     response_ = NULL;
@@ -565,10 +565,10 @@ Query::reset() {
 
 bool
 Query::processDSAtChild() {
-    const ClientList::FindResult zresult =
-        client_list_->find(*qname_, true);
+    const DataSourceClient::FindResult zresult =
+        datasrc_client_->findZone(*qname_);
 
-    if (zresult.dsrc_client_ == NULL) {
+    if (zresult.code != result::SUCCESS) {
         return (false);
     }
 
@@ -583,12 +583,12 @@ Query::processDSAtChild() {
     // by seeing the SOA.
     response_->setHeaderFlag(Message::HEADERFLAG_AA);
     response_->setRcode(Rcode::NOERROR());
-    addSOA(*zresult.finder_);
+    addSOA(*zresult.zone_finder);
     ConstZoneFinderContextPtr ds_context =
-        zresult.finder_->find(*qname_, RRType::DS(), dnssec_opt_);
+        zresult.zone_finder->find(*qname_, RRType::DS(), dnssec_opt_);
     if (ds_context->code == ZoneFinder::NXRRSET) {
         if (dnssec_) {
-            addNXRRsetProof(*zresult.finder_, *ds_context);
+            addNXRRsetProof(*zresult.zone_finder, *ds_context);
         }
     }
 
diff --git a/src/bin/auth/query.h b/src/bin/auth/query.h
index 1dc5ec0..dce19f7 100644
--- a/src/bin/auth/query.h
+++ b/src/bin/auth/query.h
@@ -32,7 +32,7 @@ class RRset;
 }
 
 namespace datasrc {
-class ClientList;
+class DataSourceClient;
 }
 
 namespace auth {
@@ -55,6 +55,8 @@ namespace auth {
 ///   separate attribute setter.
 /// - likewise, we'll eventually need to do per zone access control, for which
 ///   we need querier's information such as its IP address.
+/// - datasrc_client and response may better be parameters to process() instead
+///   of the constructor.
 ///
 /// <b>Note:</b> The class name is intentionally the same as the one used in
 /// the datasrc library.  This is because the plan is to eventually merge
@@ -238,14 +240,14 @@ private:
     /// This is the first step of the process() method, and initializes
     /// the member data
     ///
-    /// \param client_list The datasource list wherein the answer to the query
-    /// is to be found.
+    /// \param datasrc_client The datasource wherein the answer to the query is
+    /// to be found.
     /// \param qname The query name
     /// \param qtype The RR type of the query
     /// \param response The response message to store the answer to the query.
     /// \param dnssec If the answer should include signatures and NSEC/NSEC3 if
     ///     possible.
-    void initialize(datasrc::ClientList& client_list,
+    void initialize(datasrc::DataSourceClient& datasrc_client,
                     const isc::dns::Name& qname, const isc::dns::RRType& qtype,
                     isc::dns::Message& response, bool dnssec = false);
 
@@ -279,7 +281,7 @@ public:
     /// Query parameters will be set by the call to process()
     ///
     Query() :
-        client_list_(NULL), qname_(NULL), qtype_(NULL),
+        datasrc_client_(NULL), qname_(NULL), qtype_(NULL),
         dnssec_(false), dnssec_opt_(isc::datasrc::ZoneFinder::FIND_DEFAULT),
         response_(NULL)
     {
@@ -316,14 +318,14 @@ public:
     /// shouldn't happen in real-life (as BadZone means wrong data, it should
     /// have been rejected upon loading).
     ///
-    /// \param client_list The datasource list wherein the answer to the query
-    /// is to be found.
+    /// \param datasrc_client The datasource wherein the answer to the query is
+    /// to be found.
     /// \param qname The query name
     /// \param qtype The RR type of the query
     /// \param response The response message to store the answer to the query.
     /// \param dnssec If the answer should include signatures and NSEC/NSEC3 if
     ///     possible.
-    void process(datasrc::ClientList& client_list,
+    void process(datasrc::DataSourceClient& datasrc_client,
                  const isc::dns::Name& qname, const isc::dns::RRType& qtype,
                  isc::dns::Message& response, bool dnssec = false);
 
@@ -481,7 +483,7 @@ public:
     };
 
 private:
-    const isc::datasrc::ClientList* client_list_;
+    const isc::datasrc::DataSourceClient* datasrc_client_;
     const isc::dns::Name* qname_;
     const isc::dns::RRType* qtype_;
     bool dnssec_;
diff --git a/src/bin/auth/tests/Makefile.am b/src/bin/auth/tests/Makefile.am
index c6b199a..1a5836b 100644
--- a/src/bin/auth/tests/Makefile.am
+++ b/src/bin/auth/tests/Makefile.am
@@ -5,10 +5,7 @@ AM_CPPFLAGS += -I$(top_builddir)/src/lib/cc
 AM_CPPFLAGS += $(BOOST_INCLUDES)
 AM_CPPFLAGS += -DAUTH_OBJ_DIR=\"$(abs_top_builddir)/src/bin/auth\"
 AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(abs_top_srcdir)/src/lib/testutils/testdata\"
-AM_CPPFLAGS += -DTEST_OWN_DATA_DIR=\"$(abs_top_srcdir)/src/bin/auth/tests/testdata\"
 AM_CPPFLAGS += -DTEST_DATA_BUILDDIR=\"$(abs_top_builddir)/src/lib/testutils/testdata\"
-AM_CPPFLAGS += -DDSRC_DIR=\"$(abs_top_builddir)/src/lib/datasrc\"
-AM_CPPFLAGS += -DPLUGIN_DATA_PATH=\"$(abs_top_srcdir)/src/bin/cfgmgr/plugins\"
 AM_CPPFLAGS += -DINSTALL_PROG=\"$(abs_top_srcdir)/install-sh\"
 
 AM_CXXFLAGS = $(B10_CXXFLAGS)
@@ -47,7 +44,6 @@ run_unittests_SOURCES += command_unittest.cc
 run_unittests_SOURCES += common_unittest.cc
 run_unittests_SOURCES += query_unittest.cc
 run_unittests_SOURCES += statistics_unittest.cc
-run_unittests_SOURCES += datasrc_configurator_unittest.cc
 run_unittests_SOURCES += run_unittests.cc
 # This is a temporary workaround for #1206, where the InMemoryClient has been
 # moved to an ldopened library. We could add that library to LDADD, but that
@@ -76,7 +72,6 @@ run_unittests_LDADD += $(top_builddir)/src/lib/server_common/libserver_common.la
 run_unittests_LDADD += $(top_builddir)/src/lib/nsas/libnsas.la
 run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
 run_unittests_LDADD += $(top_builddir)/src/lib/statistics/libstatistics.la
-run_unittests_LDADD += $(top_builddir)/src/lib/config/tests/libfake_session.la
 run_unittests_LDADD += $(GTEST_LDADD)
 run_unittests_LDADD += $(SQLITE_LIBS)
 
diff --git a/src/bin/auth/tests/auth_srv_unittest.cc b/src/bin/auth/tests/auth_srv_unittest.cc
index bd31504..0a41f5d 100644
--- a/src/bin/auth/tests/auth_srv_unittest.cc
+++ b/src/bin/auth/tests/auth_srv_unittest.cc
@@ -30,11 +30,9 @@
 #include <server_common/keyring.h>
 
 #include <datasrc/memory_datasrc.h>
-#include <datasrc/client_list.h>
 #include <auth/auth_srv.h>
 #include <auth/common.h>
 #include <auth/statistics.h>
-#include <auth/datasrc_configurator.h>
 
 #include <util/unittests/mock_socketsession.h>
 #include <dns/tests/unittest_util.h>
@@ -49,7 +47,6 @@
 #include <boost/lexical_cast.hpp>
 #include <boost/shared_ptr.hpp>
 #include <boost/scoped_ptr.hpp>
-#include <boost/foreach.hpp>
 
 #include <vector>
 
@@ -81,11 +78,12 @@ const char* const CONFIG_TESTDB =
 const char* const BADCONFIG_TESTDB =
     "{ \"database_file\": \"" TEST_DATA_DIR "/nodir/notexist\"}";
 
-const char* const STATIC_DSRC_FILE = DSRC_DIR "/static.zone";
-
 // This is a configuration that uses the in-memory data source containing
 // a signed example zone.
-const char* const CONFIG_INMEMORY_EXAMPLE = TEST_DATA_DIR "/rfc5155-example.zone.signed";
+const char* const CONFIG_INMEMORY_EXAMPLE =
+    "{\"datasources\": [{\"type\": \"memory\","
+    "\"zones\": [{\"origin\": \"example\","
+    "\"file\": \"" TEST_DATA_DIR "/rfc5155-example.zone.signed\"}]}]}";
 
 class AuthSrvTest : public SrvTestBase {
 protected:
@@ -193,8 +191,7 @@ protected:
 // by default.  The resulting wire-format data will be stored in 'data'.
 void
 createBuiltinVersionResponse(const qid_t qid, vector<uint8_t>& data) {
-    const Name version_name("VERSION.BIND.");
-    const Name apex_name("BIND.");
+    const Name version_name("version.bind");
     Message message(Message::RENDER);
 
     UnitTestUtil::createRequestMessage(message, Opcode::QUERY(),
@@ -207,9 +204,9 @@ createBuiltinVersionResponse(const qid_t qid, vector<uint8_t>& data) {
     rrset_version->addRdata(generic::TXT(PACKAGE_STRING));
     message.addRRset(Message::SECTION_ANSWER, rrset_version);
 
-    RRsetPtr rrset_version_ns = RRsetPtr(new RRset(apex_name, RRClass::CH(),
+    RRsetPtr rrset_version_ns = RRsetPtr(new RRset(version_name, RRClass::CH(),
                                                    RRType::NS(), RRTTL(0)));
-    rrset_version_ns->addRdata(generic::NS(apex_name));
+    rrset_version_ns->addRdata(generic::NS(version_name));
     message.addRRset(Message::SECTION_AUTHORITY, rrset_version_ns);
 
     MessageRenderer renderer;
@@ -221,18 +218,69 @@ createBuiltinVersionResponse(const qid_t qid, vector<uint8_t>& data) {
                 renderer.getLength());
 }
 
-// We did not configure any client lists. Therefore it should be REFUSED
-TEST_F(AuthSrvTest, noClientList) {
+// In the following tests we confirm the response data is rendered in
+// wire format in the expected way.
+
+// The most primitive check: checking the result of the processMessage()
+// method
+TEST_F(AuthSrvTest, builtInQuery) {
     UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
                                        default_qid, Name("version.bind"),
                                        RRClass::CH(), RRType::TXT());
     createRequestPacket(request_message, IPPROTO_UDP);
     server.processMessage(*io_message, *parse_message, *response_obuffer,
                           &dnsserv);
+    createBuiltinVersionResponse(default_qid, response_data);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        response_obuffer->getData(),
+                        response_obuffer->getLength(),
+                        &response_data[0], response_data.size());
+    checkAllRcodeCountersZeroExcept(Rcode::NOERROR(), 1);
+}
 
-    EXPECT_TRUE(dnsserv.hasAnswer());
-    headerCheck(*parse_message, default_qid, Rcode::REFUSED(),
-                opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
+// Same test emulating the UDPServer class behavior (defined in libasiolink).
+// This is not a good test in that it assumes internal implementation details
+// of UDPServer, but we've encountered a regression due to the introduction
+// of that class, so we add a test for that case to prevent such a regression
+// in future.
+// Besides, the generalization of UDPServer is probably too much for the
+// authoritative only server in terms of performance, and it's quite likely
+// we need to drop it for the authoritative server implementation.
+// At that point we can drop this test, too.
+TEST_F(AuthSrvTest, builtInQueryViaDNSServer) {
+    UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
+                                       default_qid, Name("version.bind"),
+                                       RRClass::CH(), RRType::TXT());
+    createRequestPacket(request_message, IPPROTO_UDP);
+
+    (*server.getDNSLookupProvider())(*io_message, parse_message,
+                                     response_message,
+                                     response_obuffer, &dnsserv);
+    (*server.getDNSAnswerProvider())(*io_message, parse_message,
+                                     response_message, response_obuffer);
+
+    createBuiltinVersionResponse(default_qid, response_data);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        response_obuffer->getData(),
+                        response_obuffer->getLength(),
+                        &response_data[0], response_data.size());
+}
+
+// Same type of test as builtInQueryViaDNSServer but for an error response.
+TEST_F(AuthSrvTest, iqueryViaDNSServer) {
+    createDataFromFile("iquery_fromWire.wire");
+    (*server.getDNSLookupProvider())(*io_message, parse_message,
+                                     response_message,
+                                     response_obuffer, &dnsserv);
+    (*server.getDNSAnswerProvider())(*io_message, parse_message,
+                                     response_message, response_obuffer);
+
+    UnitTestUtil::readWireData("iquery_response_fromWire.wire",
+                               response_data);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        response_obuffer->getData(),
+                        response_obuffer->getLength(),
+                        &response_data[0], response_data.size());
 }
 
 // Unsupported requests.  Should result in NOTIMP.
@@ -299,6 +347,43 @@ TEST_F(AuthSrvTest, AXFRSuccess) {
     checkAllRcodeCountersZero();
 }
 
+// Try giving the server a TSIG signed request and see it can anwer signed as
+// well
+TEST_F(AuthSrvTest, TSIGSigned) {
+    // Prepare key, the client message, etc
+    const TSIGKey key("key:c2VjcmV0Cg==:hmac-sha1");
+    TSIGContext context(key);
+    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
+                                       Name("version.bind"), RRClass::CH(),
+                                       RRType::TXT());
+    createRequestPacket(request_message, IPPROTO_UDP, &context);
+
+    // Run the message through the server
+    boost::shared_ptr<TSIGKeyRing> keyring(new TSIGKeyRing);
+    keyring->add(key);
+    server.setTSIGKeyRing(&keyring);
+    server.processMessage(*io_message, *parse_message, *response_obuffer,
+                          &dnsserv);
+
+    // What did we get?
+    EXPECT_TRUE(dnsserv.hasAnswer());
+    headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
+                opcode.getCode(), QR_FLAG | AA_FLAG, 1, 1, 1, 0);
+    // We need to parse the message ourself, or getTSIGRecord won't work
+    InputBuffer ib(response_obuffer->getData(), response_obuffer->getLength());
+    Message m(Message::PARSE);
+    m.fromWire(ib);
+
+    const TSIGRecord* tsig = m.getTSIGRecord();
+    ASSERT_TRUE(tsig != NULL) << "Missing TSIG signature";
+    TSIGError error(context.verify(tsig, response_obuffer->getData(),
+                                   response_obuffer->getLength()));
+    EXPECT_EQ(TSIGError::NOERROR(), error) <<
+        "The server signed the response, but it doesn't seem to be valid";
+
+    checkAllRcodeCountersZeroExcept(Rcode::NOERROR(), 1);
+}
+
 // Give the server a signed request, but don't give it the key. It will
 // not be able to verify it, returning BADKEY
 TEST_F(AuthSrvTest, TSIGSignedBadKey) {
@@ -739,172 +824,9 @@ updateConfig(AuthSrv* server, const char* const config_data,
         "Bad result from updateConfig: " << result->str();
 }
 
-void
-updateDatabase(AuthSrv* server, const char* params) {
-    const ConstElementPtr config(Element::fromJSON("{"
-        "\"IN\": [{"
-        "    \"type\": \"sqlite3\","
-        "    \"params\": " + string(params) +
-        "}]}"));
-    DataSourceConfigurator::testReconfigure(server, config);
-}
-
-void
-updateInMemory(AuthSrv* server, const char* origin, const char* filename) {
-    const ConstElementPtr config(Element::fromJSON("{"
-        "\"IN\": [{"
-        "   \"type\": \"MasterFiles\","
-        "   \"params\": {"
-        "       \"" + string(origin) + "\": \"" + string(filename) + "\""
-        "   },"
-        "   \"cache-enable\": true"
-        "}],"
-        "\"CH\": [{"
-        "   \"type\": \"static\","
-        "   \"params\": \"" + string(STATIC_DSRC_FILE) + "\""
-        "}]}"));
-    DataSourceConfigurator::testReconfigure(server, config);
-}
-
-void
-updateBuiltin(AuthSrv* server) {
-    const ConstElementPtr config(Element::fromJSON("{"
-        "\"CH\": [{"
-        "   \"type\": \"static\","
-        "   \"params\": \"" + string(STATIC_DSRC_FILE) + "\""
-        "}]}"));
-    DataSourceConfigurator::testReconfigure(server, config);
-}
-
-// Try giving the server a TSIG signed request and see it can anwer signed as
-// well
-#ifdef USE_STATIC_LINK
-TEST_F(AuthSrvTest, DISABLED_TSIGSigned) { // Needs builtin
-#else
-TEST_F(AuthSrvTest, TSIGSigned) {
-#endif
-    // Prepare key, the client message, etc
-    updateBuiltin(&server);
-    const TSIGKey key("key:c2VjcmV0Cg==:hmac-sha1");
-    TSIGContext context(key);
-    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
-                                       Name("VERSION.BIND."), RRClass::CH(),
-                                       RRType::TXT());
-    createRequestPacket(request_message, IPPROTO_UDP, &context);
-
-    // Run the message through the server
-    boost::shared_ptr<TSIGKeyRing> keyring(new TSIGKeyRing);
-    keyring->add(key);
-    server.setTSIGKeyRing(&keyring);
-    server.processMessage(*io_message, *parse_message, *response_obuffer,
-                          &dnsserv);
-
-    // What did we get?
-    EXPECT_TRUE(dnsserv.hasAnswer());
-    headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
-                opcode.getCode(), QR_FLAG | AA_FLAG, 1, 1, 1, 0);
-    // We need to parse the message ourself, or getTSIGRecord won't work
-    InputBuffer ib(response_obuffer->getData(), response_obuffer->getLength());
-    Message m(Message::PARSE);
-    m.fromWire(ib);
-
-    const TSIGRecord* tsig = m.getTSIGRecord();
-    ASSERT_TRUE(tsig != NULL) << "Missing TSIG signature";
-    TSIGError error(context.verify(tsig, response_obuffer->getData(),
-                                   response_obuffer->getLength()));
-    EXPECT_EQ(TSIGError::NOERROR(), error) <<
-        "The server signed the response, but it doesn't seem to be valid";
-
-    checkAllRcodeCountersZeroExcept(Rcode::NOERROR(), 1);
-}
-
-// Same test emulating the UDPServer class behavior (defined in libasiolink).
-// This is not a good test in that it assumes internal implementation details
-// of UDPServer, but we've encountered a regression due to the introduction
-// of that class, so we add a test for that case to prevent such a regression
-// in future.
-// Besides, the generalization of UDPServer is probably too much for the
-// authoritative only server in terms of performance, and it's quite likely
-// we need to drop it for the authoritative server implementation.
-// At that point we can drop this test, too.
-#ifdef USE_STATIC_LINK
-TEST_F(AuthSrvTest, DISABLED_builtInQueryViaDNSServer) {
-#else
-TEST_F(AuthSrvTest, builtInQueryViaDNSServer) {
-#endif
-    updateBuiltin(&server);
-    UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
-                                       default_qid, Name("VERSION.BIND."),
-                                       RRClass::CH(), RRType::TXT());
-    createRequestPacket(request_message, IPPROTO_UDP);
-
-    (*server.getDNSLookupProvider())(*io_message, parse_message,
-                                     response_message,
-                                     response_obuffer, &dnsserv);
-    (*server.getDNSAnswerProvider())(*io_message, parse_message,
-                                     response_message, response_obuffer);
-
-    createBuiltinVersionResponse(default_qid, response_data);
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        response_obuffer->getData(),
-                        response_obuffer->getLength(),
-                        &response_data[0], response_data.size());
-}
-
-// In the following tests we confirm the response data is rendered in
-// wire format in the expected way.
-
-// The most primitive check: checking the result of the processMessage()
-// method
-#ifdef USE_STATIC_LINK
-TEST_F(AuthSrvTest, DISABLED_builtInQuery) {
-#else
-TEST_F(AuthSrvTest, builtInQuery) {
-#endif
-    updateBuiltin(&server);
-    UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
-                                       default_qid, Name("VERSION.BIND."),
-                                       RRClass::CH(), RRType::TXT());
-    createRequestPacket(request_message, IPPROTO_UDP);
-    server.processMessage(*io_message, *parse_message, *response_obuffer,
-                          &dnsserv);
-    createBuiltinVersionResponse(default_qid, response_data);
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        response_obuffer->getData(),
-                        response_obuffer->getLength(),
-                        &response_data[0], response_data.size());
-    checkAllRcodeCountersZeroExcept(Rcode::NOERROR(), 1);
-}
-
-// Same type of test as builtInQueryViaDNSServer but for an error response.
-#ifdef USE_STATIC_LINK
-TEST_F(AuthSrvTest, DISABLED_iqueryViaDNSServer) { // Needs builtin
-#else
-TEST_F(AuthSrvTest, iqueryViaDNSServer) { // Needs builtin
-#endif
-    updateBuiltin(&server);
-    createDataFromFile("iquery_fromWire.wire");
-    (*server.getDNSLookupProvider())(*io_message, parse_message,
-                                     response_message,
-                                     response_obuffer, &dnsserv);
-    (*server.getDNSAnswerProvider())(*io_message, parse_message,
-                                     response_message, response_obuffer);
-
-    UnitTestUtil::readWireData("iquery_response_fromWire.wire",
-                               response_data);
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        response_obuffer->getData(),
-                        response_obuffer->getLength(),
-                        &response_data[0], response_data.size());
-}
-
 // Install a Sqlite3 data source with testing data.
-#ifdef USE_STATIC_LINK
-TEST_F(AuthSrvTest, DISABLED_updateConfig) {
-#else
 TEST_F(AuthSrvTest, updateConfig) {
-#endif
-    updateDatabase(&server, CONFIG_TESTDB);
+    updateConfig(&server, CONFIG_TESTDB, true);
 
     // query for existent data in the installed data source.  The resulting
     // response should have the AA flag on, and have an RR in each answer
@@ -917,12 +839,8 @@ TEST_F(AuthSrvTest, updateConfig) {
                 QR_FLAG | AA_FLAG, 1, 1, 1, 0);
 }
 
-#ifdef USE_STATIC_LINK
-TEST_F(AuthSrvTest, DISABLED_datasourceFail) {
-#else
 TEST_F(AuthSrvTest, datasourceFail) {
-#endif
-    updateDatabase(&server, CONFIG_TESTDB);
+    updateConfig(&server, CONFIG_TESTDB, true);
 
     // This query will hit a corrupted entry of the data source (the zoneload
     // tool and the data source itself naively accept it).  This will result
@@ -936,40 +854,40 @@ TEST_F(AuthSrvTest, datasourceFail) {
                 opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
 }
 
-#ifdef USE_STATIC_LINK
-TEST_F(AuthSrvTest, DISABLED_updateConfigFail) {
-#else
 TEST_F(AuthSrvTest, updateConfigFail) {
-#endif
     // First, load a valid data source.
-    updateDatabase(&server, CONFIG_TESTDB);
+    updateConfig(&server, CONFIG_TESTDB, true);
 
     // Next, try to update it with a non-existent one.  This should fail.
-    EXPECT_THROW(updateDatabase(&server, BADCONFIG_TESTDB),
-                 isc::datasrc::DataSourceError);
+    updateConfig(&server, BADCONFIG_TESTDB, false);
 
     // The original data source should still exist.
     createDataFromFile("examplequery_fromWire.wire");
     server.processMessage(*io_message, *parse_message, *response_obuffer,
                           &dnsserv);
     EXPECT_TRUE(dnsserv.hasAnswer());
-    headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
-                opcode.getCode(), QR_FLAG | AA_FLAG, 1, 1, 1, 0);
+    headerCheck(*parse_message, default_qid, Rcode::NOERROR(), opcode.getCode(),
+                QR_FLAG | AA_FLAG, 1, 1, 1, 0);
 }
 
-TEST_F(AuthSrvTest, updateWithInMemoryClient) {
+TEST_F(AuthSrvTest,
+#ifdef USE_STATIC_LINK
+       DISABLED_updateWithInMemoryClient
+#else
+       updateWithInMemoryClient
+#endif
+    )
+{
     // Test configuring memory data source.  Detailed test cases are covered
     // in the configuration tests.  We only check the AuthSrv interface here.
 
-    // Create an empty in-memory
-    const ConstElementPtr config(Element::fromJSON("{"
-        "\"IN\": [{"
-        "   \"type\": \"MasterFiles\","
-        "   \"params\": {},"
-        "   \"cache-enable\": true"
-        "}]}"));
-    DataSourceConfigurator::testReconfigure(&server, config);
+    // By default memory data source isn't enabled
+    EXPECT_FALSE(server.hasInMemoryClient());
+    updateConfig(&server,
+                 "{\"datasources\": [{\"type\": \"memory\"}]}", true);
     // after successful configuration, we should have one (with empty zoneset).
+    EXPECT_TRUE(server.hasInMemoryClient());
+    EXPECT_EQ(0, server.getInMemoryClient(rrclass)->getZoneCount());
 
     // The memory data source is empty, should return REFUSED rcode.
     createDataFromFile("examplequery_fromWire.wire");
@@ -980,12 +898,21 @@ TEST_F(AuthSrvTest, updateWithInMemoryClient) {
                 opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
 }
 
-TEST_F(AuthSrvTest, queryWithInMemoryClientNoDNSSEC) {
+TEST_F(AuthSrvTest,
+#ifdef USE_STATIC_LINK
+       DISABLED_queryWithInMemoryClientNoDNSSEC
+#else
+       queryWithInMemoryClientNoDNSSEC
+#endif
+    )
+{
     // In this example, we do simple check that query is handled from the
     // query handler class, and confirm it returns no error and a non empty
     // answer section.  Detailed examination on the response content
     // for various types of queries are tested in the query tests.
-    updateInMemory(&server, "example.", CONFIG_INMEMORY_EXAMPLE);
+    updateConfig(&server, CONFIG_INMEMORY_EXAMPLE, true);
+    EXPECT_TRUE(server.hasInMemoryClient());
+    EXPECT_EQ(1, server.getInMemoryClient(rrclass)->getZoneCount());
 
     createDataFromFile("nsec3query_nodnssec_fromWire.wire");
     server.processMessage(*io_message, *parse_message, *response_obuffer,
@@ -996,11 +923,20 @@ TEST_F(AuthSrvTest, queryWithInMemoryClientNoDNSSEC) {
                 opcode.getCode(), QR_FLAG | AA_FLAG, 1, 1, 2, 1);
 }
 
-TEST_F(AuthSrvTest, queryWithInMemoryClientDNSSEC) {
+TEST_F(AuthSrvTest,
+#ifdef USE_STATIC_LINK
+       DISABLED_queryWithInMemoryClientDNSSEC
+#else
+       queryWithInMemoryClientDNSSEC
+#endif
+    )
+{
     // Similar to the previous test, but the query has the DO bit on.
     // The response should contain RRSIGs, and should have more RRs than
     // the previous case.
-    updateInMemory(&server, "example.", CONFIG_INMEMORY_EXAMPLE);
+    updateConfig(&server, CONFIG_INMEMORY_EXAMPLE, true);
+    EXPECT_TRUE(server.hasInMemoryClient());
+    EXPECT_EQ(1, server.getInMemoryClient(rrclass)->getZoneCount());
 
     createDataFromFile("nsec3query_fromWire.wire");
     server.processMessage(*io_message, *parse_message, *response_obuffer,
@@ -1019,12 +955,13 @@ TEST_F(AuthSrvTest,
 #endif
     )
 {
-    // Set up the in-memory
-    updateInMemory(&server, "example.", CONFIG_INMEMORY_EXAMPLE);
+    // Configure memory data source for class IN
+    updateConfig(&server, "{\"datasources\": "
+                 "[{\"class\": \"IN\", \"type\": \"memory\"}]}", true);
 
     // This shouldn't affect the result of class CH query
     UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
-                                       default_qid, Name("VERSION.BIND."),
+                                       default_qid, Name("version.bind"),
                                        RRClass::CH(), RRType::TXT());
     createRequestPacket(request_message, IPPROTO_UDP);
     server.processMessage(*io_message, *parse_message, *response_obuffer,
@@ -1350,7 +1287,7 @@ public:
     ///                      throw std::exception
     /// \param fake_rrset If non NULL, it will be used as an answer to
     /// find() for that name and type.
-    FakeClient(const DataSourceClient* real_client,
+    FakeClient(isc::datasrc::DataSourceClientContainerPtr real_client,
                ThrowWhen throw_when, bool isc_exception,
                ConstRRsetPtr fake_rrset = ConstRRsetPtr()) :
         real_client_ptr_(real_client),
@@ -1369,7 +1306,7 @@ public:
     findZone(const isc::dns::Name& name) const {
         checkThrow(THROW_AT_FIND_ZONE, throw_when_, isc_exception_);
         const FindResult result =
-            real_client_ptr_->findZone(name);
+            real_client_ptr_->getInstance().findZone(name);
         return (FindResult(result.code, isc::datasrc::ZoneFinderPtr(
                                         new FakeZoneFinder(result.zone_finder,
                                                            throw_when_,
@@ -1389,39 +1326,38 @@ public:
                   "fake data source");
     }
 private:
-    const DataSourceClient* real_client_ptr_;
+    const isc::datasrc::DataSourceClientContainerPtr real_client_ptr_;
     ThrowWhen throw_when_;
     bool isc_exception_;
     ConstRRsetPtr fake_rrset_;
 };
 
-class FakeList : public isc::datasrc::ConfigurableClientList {
+class FakeContainer : public isc::datasrc::DataSourceClientContainer {
 public:
-    /// \brief Creates a fake list for the given in-memory client
+    /// \brief Creates a fake container for the given in-memory client
     ///
-    /// It will create a FakeClient for each client in the original list,
-    /// with the given arguments, which is used when searching for the
-    /// corresponding data source.
-    FakeList(const boost::shared_ptr<isc::datasrc::ConfigurableClientList>
-             real_list, ThrowWhen throw_when, bool isc_exception,
-             ConstRRsetPtr fake_rrset = ConstRRsetPtr()) :
-        ConfigurableClientList(RRClass::IN()),
-        real_(real_list)
-    {
-        BOOST_FOREACH(const DataSourceInfo& info, real_->getDataSources()) {
-             const isc::datasrc::DataSourceClientPtr
-                 client(new FakeClient(info.data_src_client_ != NULL ?
-                                       info.data_src_client_ :
-                                       info.cache_.get(),
-                                       throw_when, isc_exception, fake_rrset));
-             clients_.push_back(client);
-             data_sources_.push_back(DataSourceInfo(client.get(),
-                 isc::datasrc::DataSourceClientContainerPtr(), false));
-        }
+    /// The initializer creates a fresh instance of a memory datasource,
+    /// which is ignored for the rest (but we do not allow 'null' containers
+    /// atm, and this is only needed in these tests, this may be changed
+    /// if we generalize the container class a bit more)
+    ///
+    /// It will also create a FakeClient, with the given arguments, which
+    /// is actually used when the instance is requested.
+    FakeContainer(isc::datasrc::DataSourceClientContainerPtr real_client,
+                  ThrowWhen throw_when, bool isc_exception,
+                  ConstRRsetPtr fake_rrset = ConstRRsetPtr()) :
+        DataSourceClientContainer("memory",
+                                  Element::fromJSON("{\"type\": \"memory\"}")),
+        client_(new FakeClient(real_client, throw_when, isc_exception,
+                               fake_rrset))
+    {}
+
+    isc::datasrc::DataSourceClient& getInstance() {
+        return (*client_);
     }
+
 private:
-    const boost::shared_ptr<isc::datasrc::ConfigurableClientList> real_;
-    vector<isc::datasrc::DataSourceClientPtr> clients_;
+    const boost::scoped_ptr<isc::datasrc::DataSourceClient> client_;
 };
 
 } // end anonymous namespace for throwing proxy classes
@@ -1439,11 +1375,13 @@ TEST_F(AuthSrvTest,
     )
 {
     // Set real inmem client to proxy
-    updateInMemory(&server, "example.", CONFIG_INMEMORY_EXAMPLE);
-    boost::shared_ptr<isc::datasrc::ConfigurableClientList>
-        list(new FakeList(server.getClientList(RRClass::IN()), THROW_NEVER,
-                          false));
-    server.setClientList(RRClass::IN(), list);
+    updateConfig(&server, CONFIG_INMEMORY_EXAMPLE, true);
+    EXPECT_TRUE(server.hasInMemoryClient());
+
+    isc::datasrc::DataSourceClientContainerPtr fake_client_container(
+        new FakeContainer(server.getInMemoryClientContainer(rrclass),
+                          THROW_NEVER, false));
+    server.setInMemoryClient(rrclass, fake_client_container);
 
     createDataFromFile("nsec3query_nodnssec_fromWire.wire");
     server.processMessage(*io_message, *parse_message, *response_obuffer,
@@ -1461,15 +1399,21 @@ TEST_F(AuthSrvTest,
 // If non null rrset is given, it will be passed to the proxy so it can
 // return some faked response.
 void
-setupThrow(AuthSrv* server, ThrowWhen throw_when, bool isc_exception,
-           ConstRRsetPtr rrset = ConstRRsetPtr())
+setupThrow(AuthSrv* server, const char *config, ThrowWhen throw_when,
+           bool isc_exception, ConstRRsetPtr rrset = ConstRRsetPtr())
 {
-    updateInMemory(server, "example.", CONFIG_INMEMORY_EXAMPLE);
+    // Set real inmem client to proxy
+    updateConfig(server, config, true);
+
+    // Set it to throw on findZone(), this should result in
+    // SERVFAIL on any exception
+    isc::datasrc::DataSourceClientContainerPtr fake_client_container(
+        new FakeContainer(
+            server->getInMemoryClientContainer(isc::dns::RRClass::IN()),
+            throw_when, isc_exception, rrset));
 
-    boost::shared_ptr<isc::datasrc::ConfigurableClientList>
-        list(new FakeList(server->getClientList(RRClass::IN()), throw_when,
-                          isc_exception, rrset));
-    server->setClientList(RRClass::IN(), list);
+    ASSERT_TRUE(server->hasInMemoryClient());
+    server->setInMemoryClient(isc::dns::RRClass::IN(), fake_client_container);
 }
 
 TEST_F(AuthSrvTest,
@@ -1492,11 +1436,11 @@ TEST_F(AuthSrvTest,
                                              RRClass::IN(), RRType::TXT());
     for (ThrowWhen* when(throws); *when != THROW_NEVER; ++when) {
         createRequestPacket(request_message, IPPROTO_UDP);
-        setupThrow(&server, *when, true);
+        setupThrow(&server, CONFIG_INMEMORY_EXAMPLE, *when, true);
         processAndCheckSERVFAIL();
         // To be sure, check same for non-isc-exceptions
         createRequestPacket(request_message, IPPROTO_UDP);
-        setupThrow(&server, *when, false);
+        setupThrow(&server, CONFIG_INMEMORY_EXAMPLE, *when, false);
         processAndCheckSERVFAIL();
     }
 }
@@ -1512,7 +1456,7 @@ TEST_F(AuthSrvTest,
     )
 {
     createDataFromFile("nsec3query_nodnssec_fromWire.wire");
-    setupThrow(&server, THROW_AT_GET_CLASS, true);
+    setupThrow(&server, CONFIG_INMEMORY_EXAMPLE, THROW_AT_GET_CLASS, true);
 
     // getClass is not called so it should just answer
     server.processMessage(*io_message, *parse_message, *response_obuffer,
@@ -1536,7 +1480,8 @@ TEST_F(AuthSrvTest,
     ConstRRsetPtr empty_rrset(new RRset(Name("foo.example"),
                                         RRClass::IN(), RRType::TXT(),
                                         RRTTL(0)));
-    setupThrow(&server, THROW_NEVER, true, empty_rrset);
+    setupThrow(&server, CONFIG_INMEMORY_EXAMPLE, THROW_NEVER, true,
+               empty_rrset);
 
     // Repeat the query processing two times.  Due to the faked RRset,
     // toWire() should throw, and it should result in SERVFAIL.
@@ -1694,36 +1639,4 @@ TEST_F(AuthSrvTest, DDNSForwardClose) {
     EXPECT_FALSE(ddns_forwarder.isConnected());
 }
 
-// Check the client list accessors
-TEST_F(AuthSrvTest, clientList) {
-    // The lists don't exist. Therefore, the list of RRClasses is empty.
-    // We also have no IN list.
-    EXPECT_TRUE(server.getClientListClasses().empty());
-    EXPECT_EQ(boost::shared_ptr<const isc::datasrc::ClientList>(),
-              server.getClientList(RRClass::IN()));
-    // Put something in.
-    const boost::shared_ptr<isc::datasrc::ConfigurableClientList>
-        list(new isc::datasrc::ConfigurableClientList(RRClass::IN()));
-    const boost::shared_ptr<isc::datasrc::ConfigurableClientList>
-        list2(new isc::datasrc::ConfigurableClientList(RRClass::CH()));
-    server.setClientList(RRClass::IN(), list);
-    server.setClientList(RRClass::CH(), list2);
-    // There are two things in the list and they are IN and CH
-    vector<RRClass> classes(server.getClientListClasses());
-    ASSERT_EQ(2, classes.size());
-    EXPECT_EQ(RRClass::IN(), classes[0]);
-    EXPECT_EQ(RRClass::CH(), classes[1]);
-    // And the lists can be retrieved.
-    EXPECT_EQ(list, server.getClientList(RRClass::IN()));
-    EXPECT_EQ(list2, server.getClientList(RRClass::CH()));
-    // Remove one of them
-    server.setClientList(RRClass::CH(),
-        boost::shared_ptr<isc::datasrc::ConfigurableClientList>());
-    // This really got deleted, including the class.
-    classes = server.getClientListClasses();
-    ASSERT_EQ(1, classes.size());
-    EXPECT_EQ(RRClass::IN(), classes[0]);
-    EXPECT_EQ(list, server.getClientList(RRClass::IN()));
-}
-
 }
diff --git a/src/bin/auth/tests/command_unittest.cc b/src/bin/auth/tests/command_unittest.cc
index a5130ff..ec00d11 100644
--- a/src/bin/auth/tests/command_unittest.cc
+++ b/src/bin/auth/tests/command_unittest.cc
@@ -177,9 +177,6 @@ TEST_F(AuthCommandTest, shutdownIncorrectPID) {
     EXPECT_EQ(0, rcode_);
 }
 
-#if 0
-TODO: This needs to be rewritten
-Also, reenable everywhere
 // A helper function commonly used for the "loadzone" command tests.
 // It configures the server with a memory data source containing two
 // zones, and checks the zones are correctly loaded.
@@ -199,7 +196,6 @@ zoneChecks(AuthSrv& server) {
               findZone(Name("ns.test2.example")).zone_finder->
               find(Name("ns.test2.example"), RRType::AAAA())->code);
 }
-#endif
 
 void
 configureZones(AuthSrv& server) {
@@ -218,11 +214,9 @@ configureZones(AuthSrv& server) {
                             "  \"file\": \""
                                TEST_DATA_BUILDDIR "/test2.zone.copied\"}"
                             "]}]}"));
-    //TODO: zoneChecks(server);
+    zoneChecks(server);
 }
 
-#if 0
-TODO: This needs to be rewritten and re-enabled
 void
 newZoneChecks(AuthSrv& server) {
     EXPECT_TRUE(server.getInMemoryClient(RRClass::IN()));
@@ -242,13 +236,12 @@ newZoneChecks(AuthSrv& server) {
               findZone(Name("ns.test2.example")).zone_finder->
               find(Name("ns.test2.example"), RRType::AAAA())->code);
 }
-#endif
 
 TEST_F(AuthCommandTest,
 #ifdef USE_STATIC_LINK
        DISABLED_loadZone
 #else
-       DISABLED_loadZone // Needs #2046
+       loadZone
 #endif
     )
 {
@@ -265,14 +258,14 @@ TEST_F(AuthCommandTest,
                                     Element::fromJSON(
                                         "{\"origin\": \"test1.example\"}"));
     checkAnswer(0);
-    //TODO: newZoneChecks(server_);
+    newZoneChecks(server_);
 }
 
 TEST_F(AuthCommandTest,
 #ifdef USE_STATIC_LINK
        DISABLED_loadZoneSQLite3
 #else
-       DISABLED_loadZoneSQLite3 // Needs #2044
+       loadZoneSQLite3
 #endif
     )
 {
@@ -313,14 +306,11 @@ TEST_F(AuthCommandTest,
 
     server_.updateConfig(map);
 
-#if 0
-    FIXME: This needs to be done slightly differently
     // Check that the A record at www.example.org does not exist
     ASSERT_TRUE(server_.hasInMemoryClient());
     EXPECT_EQ(ZoneFinder::NXDOMAIN, server_.getInMemoryClient(RRClass::IN())->
               findZone(Name("example.org")).zone_finder->
               find(Name("www.example.org"), RRType::A())->code);
-#endif
 
     // Add the record to the underlying sqlite database, by loading
     // it as a separate datasource, and updating it
@@ -338,14 +328,11 @@ TEST_F(AuthCommandTest,
     sql_updater->addRRset(*rrset);
     sql_updater->commit();
 
-#if 0
-    TODO:
     // This new record is in the database now, but should not be in the
     // memory-datasource yet, so check again
     EXPECT_EQ(ZoneFinder::NXDOMAIN, server_.getInMemoryClient(RRClass::IN())->
               findZone(Name("example.org")).zone_finder->
               find(Name("www.example.org"), RRType::A())->code);
-#endif
 
     // Now send the command to reload it
     result_ = execAuthServerCommand(server_, "loadzone",
@@ -353,24 +340,19 @@ TEST_F(AuthCommandTest,
                                         "{\"origin\": \"example.org\"}"));
     checkAnswer(0);
 
-#if 0
     // And now it should be present too.
     EXPECT_EQ(ZoneFinder::SUCCESS, server_.getInMemoryClient(RRClass::IN())->
               findZone(Name("example.org")).zone_finder->
               find(Name("www.example.org"), RRType::A())->code);
-#endif
 
     // Some error cases. First, the zone has no configuration. (note .com here)
     result_ = execAuthServerCommand(server_, "loadzone",
         Element::fromJSON("{\"origin\": \"example.com\"}"));
     checkAnswer(1);
-#if 0
-    FIXME
     // The previous zone is not hurt in any way
     EXPECT_EQ(ZoneFinder::SUCCESS, server_.getInMemoryClient(RRClass::IN())->
               findZone(Name("example.org")).zone_finder->
               find(Name("example.org"), RRType::SOA())->code);
-#endif
 
     module_session.setLocalConfig(Element::fromJSON("{\"datasources\": []}"));
     result_ = execAuthServerCommand(server_, "loadzone",
@@ -378,13 +360,10 @@ TEST_F(AuthCommandTest,
                                         "{\"origin\": \"example.org\"}"));
     checkAnswer(1);
 
-#if 0
-    FIXME
     // The previous zone is not hurt in any way
     EXPECT_EQ(ZoneFinder::SUCCESS, server_.getInMemoryClient(RRClass::IN())->
               findZone(Name("example.org")).zone_finder->
               find(Name("example.org"), RRType::SOA())->code);
-#endif
     // Configure an unreadable zone. Should fail, but leave the original zone
     // data there
     const ElementPtr
@@ -404,13 +383,10 @@ TEST_F(AuthCommandTest,
     result_ = execAuthServerCommand(server_, "loadzone",
         Element::fromJSON("{\"origin\": \"example.com\"}"));
     checkAnswer(1);
-#if 0
-    FIXME
     // The previous zone is not hurt in any way
     EXPECT_EQ(ZoneFinder::SUCCESS, server_.getInMemoryClient(RRClass::IN())->
               findZone(Name("example.org")).zone_finder->
               find(Name("example.org"), RRType::SOA())->code);
-#endif
 
     // Broken configuration (not valid against the spec)
     const ElementPtr
@@ -422,20 +398,17 @@ TEST_F(AuthCommandTest,
                                  "]}"));
     module_session.setLocalConfig(broken);
     checkAnswer(1);
-#if 0
-    FIXME
     // The previous zone is not hurt in any way
     EXPECT_EQ(ZoneFinder::SUCCESS, server_.getInMemoryClient(RRClass::IN())->
               findZone(Name("example.org")).zone_finder->
               find(Name("example.org"), RRType::SOA())->code);
-#endif
 }
 
 TEST_F(AuthCommandTest,
 #ifdef USE_STATIC_LINK
        DISABLED_loadBrokenZone
 #else
-       DISABLED_loadBrokenZone // Needs #2046
+       loadBrokenZone
 #endif
     )
 {
@@ -448,14 +421,14 @@ TEST_F(AuthCommandTest,
                                     Element::fromJSON(
                                         "{\"origin\": \"test1.example\"}"));
     checkAnswer(1);
-    //zoneChecks(server_);     // zone shouldn't be replaced
+    zoneChecks(server_);     // zone shouldn't be replaced
 }
 
 TEST_F(AuthCommandTest,
 #ifdef USE_STATIC_LINK
        DISABLED_loadUnreadableZone
 #else
-       DISABLED_loadUnreadableZone // Needs #2046
+       loadUnreadableZone
 #endif
     )
 {
@@ -469,7 +442,7 @@ TEST_F(AuthCommandTest,
                                     Element::fromJSON(
                                         "{\"origin\": \"test1.example\"}"));
     checkAnswer(1);
-    //zoneChecks(server_);     // zone shouldn't be replaced
+    zoneChecks(server_);     // zone shouldn't be replaced
 }
 
 TEST_F(AuthCommandTest, loadZoneWithoutDataSrc) {
@@ -481,11 +454,21 @@ TEST_F(AuthCommandTest, loadZoneWithoutDataSrc) {
     checkAnswer(1);
 }
 
+TEST_F(AuthCommandTest, loadSqlite3DataSrc) {
+    // For sqlite3 data source we don't have to do anything (the data source
+    // (re)loads itself automatically)
+    result_ = execAuthServerCommand(server_, "loadzone",
+                                    Element::fromJSON(
+                                        "{\"origin\": \"test1.example\","
+                                        " \"datasrc\": \"sqlite3\"}"));
+    checkAnswer(0);
+}
+
 TEST_F(AuthCommandTest,
 #ifdef USE_STATIC_LINK
        DISABLED_loadZoneInvalidParams
 #else
-       DISABLED_loadZoneInvalidParams // Needs #2046
+       loadZoneInvalidParams
 #endif
     )
 {
diff --git a/src/bin/auth/tests/config_unittest.cc b/src/bin/auth/tests/config_unittest.cc
index 748e63b..e2d193a 100644
--- a/src/bin/auth/tests/config_unittest.cc
+++ b/src/bin/auth/tests/config_unittest.cc
@@ -72,6 +72,32 @@ private:
     isc::testutils::TestSocketRequestor sock_requestor_;
 };
 
+TEST_F(AuthConfigTest,
+#ifdef USE_STATIC_LINK
+       DISABLED_datasourceConfig
+#else
+       datasourceConfig
+#endif
+    )
+{
+    // By default, we don't have any in-memory data source.
+    EXPECT_FALSE(server.hasInMemoryClient());
+    configureAuthServer(server, Element::fromJSON(
+                            "{\"datasources\": [{\"type\": \"memory\"}]}"));
+    // after successful configuration, we should have one (with empty zoneset).
+    EXPECT_TRUE(server.hasInMemoryClient());
+    EXPECT_EQ(0, server.getInMemoryClient(rrclass)->getZoneCount());
+}
+
+TEST_F(AuthConfigTest, databaseConfig) {
+    // right now, "database_file" is handled separately, so the parser
+    // doesn't recognize it, but it shouldn't throw an exception due to that.
+    EXPECT_NO_THROW(configureAuthServer(
+                        server,
+                        Element::fromJSON(
+                            "{\"database_file\": \"should_be_ignored\"}")));
+}
+
 TEST_F(AuthConfigTest, versionConfig) {
     // make sure it does not throw on 'version'
     EXPECT_NO_THROW(configureAuthServer(
@@ -80,17 +106,32 @@ TEST_F(AuthConfigTest, versionConfig) {
 }
 
 TEST_F(AuthConfigTest, exceptionGuarantee) {
-    server.setStatisticsTimerInterval(1234);
-    EXPECT_EQ(1234, server.getStatisticsTimerInterval());
+    EXPECT_FALSE(server.hasInMemoryClient());
     // This configuration contains an invalid item, which will trigger
     // an exception.
     EXPECT_THROW(configureAuthServer(
                      server,
                      Element::fromJSON(
-                         "{ \"no_such_config_var\": 1}")),
+                         "{\"datasources\": [{\"type\": \"memory\"}], "
+                         " \"no_such_config_var\": 1}")),
                  AuthConfigError);
     // The server state shouldn't change
-    EXPECT_EQ(1234, server.getStatisticsTimerInterval());
+    EXPECT_FALSE(server.hasInMemoryClient());
+}
+
+TEST_F(AuthConfigTest, exceptionConversion) {
+    // This configuration contains a bogus RR class, which will trigger an
+    // exception from libdns++.  configureAuthServer() should convert this
+    // to AuthConfigError and rethrow the converted one.
+    EXPECT_THROW(configureAuthServer(
+                     server,
+                     Element::fromJSON(
+                         "{\"datasources\": "
+                         " [{\"type\": \"memory\","
+                         "   \"class\": \"BADCLASS\","
+                         "   \"zones\": [{\"origin\": \"example.com\","
+                         "                \"file\": \"example.zone\"}]}]}")),
+                 AuthConfigError);
 }
 
 TEST_F(AuthConfigTest, badConfig) {
@@ -131,6 +172,343 @@ TEST_F(AuthConfigTest, listenAddressConfig) {
     EXPECT_EQ(DNSService::SERVER_SYNC_OK, dnss_.getUDPFdParams().at(1).options);
 }
 
+class MemoryDatasrcConfigTest : public AuthConfigTest {
+protected:
+    MemoryDatasrcConfigTest() :
+        parser(createAuthConfigParser(server, "datasources"))
+    {}
+    ~MemoryDatasrcConfigTest() {
+        delete parser;
+    }
+    AuthConfigParser* parser;
+};
+
+TEST_F(MemoryDatasrcConfigTest, addZeroDataSrc) {
+    parser->build(Element::fromJSON("[]"));
+    parser->commit();
+    EXPECT_FALSE(server.hasInMemoryClient());
+}
+
+TEST_F(MemoryDatasrcConfigTest,
+#ifdef USE_STATIC_LINK
+       DISABLED_addEmpty
+#else
+       addEmpty
+#endif
+    )
+{
+    // By default, we don't have any in-memory data source.
+    EXPECT_FALSE(server.hasInMemoryClient());
+    parser->build(Element::fromJSON("[{\"type\": \"memory\"}]"));
+    parser->commit();
+    EXPECT_EQ(0, server.getInMemoryClient(rrclass)->getZoneCount());
+}
+
+TEST_F(MemoryDatasrcConfigTest,
+#ifdef USE_STATIC_LINK
+       DISABLED_addZeroZone
+#else
+       addZeroZone
+#endif
+    )
+{
+    parser->build(Element::fromJSON("[{\"type\": \"memory\","
+                                    "  \"zones\": []}]"));
+    parser->commit();
+    EXPECT_EQ(0, server.getInMemoryClient(rrclass)->getZoneCount());
+}
+
+TEST_F(MemoryDatasrcConfigTest,
+#ifdef USE_STATIC_LINK
+       DISABLED_addOneZone
+#else
+       addOneZone
+#endif
+    )
+{
+    EXPECT_NO_THROW(parser->build(Element::fromJSON(
+                      "[{\"type\": \"memory\","
+                      "  \"zones\": [{\"origin\": \"example.com\","
+                      "               \"file\": \"" TEST_DATA_DIR
+                      "/example.zone\"}]}]")));
+    EXPECT_NO_THROW(parser->commit());
+    EXPECT_EQ(1, server.getInMemoryClient(rrclass)->getZoneCount());
+    // Check it actually loaded something
+    EXPECT_EQ(ZoneFinder::SUCCESS, server.getInMemoryClient(rrclass)->findZone(
+        Name("ns.example.com.")).zone_finder->find(Name("ns.example.com."),
+        RRType::A())->code);
+}
+
+// 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_db +  "\","
+                         "               \"filetype\": \"sqlite3\"}]}]")),
+                 DataSourceError);
+}
+
+TEST_F(MemoryDatasrcConfigTest,
+#ifdef USE_STATIC_LINK
+       DISABLED_addOneWithFiletypeText
+#else
+       addOneWithFiletypeText
+#endif
+    )
+{
+    // Explicitly specifying "text" is okay.
+    parser->build(Element::fromJSON(
+                      "[{\"type\": \"memory\","
+                      "  \"zones\": [{\"origin\": \"example.com\","
+                      "               \"file\": \""
+                      TEST_DATA_DIR "/example.zone\","
+                      "               \"filetype\": \"text\"}]}]"));
+    parser->commit();
+    EXPECT_EQ(1, server.getInMemoryClient(rrclass)->getZoneCount());
+}
+
+TEST_F(MemoryDatasrcConfigTest,
+#ifdef USE_STATIC_LINK
+       DISABLED_addMultiZones
+#else
+       addMultiZones
+#endif
+    )
+{
+    EXPECT_NO_THROW(parser->build(Element::fromJSON(
+                      "[{\"type\": \"memory\","
+                      "  \"zones\": [{\"origin\": \"example.com\","
+                      "               \"file\": \"" TEST_DATA_DIR
+                      "/example.zone\"},"
+                      "              {\"origin\": \"example.org\","
+                      "               \"file\": \"" TEST_DATA_DIR
+                      "/example.org.zone\"},"
+                      "              {\"origin\": \"example.net\","
+                      "               \"file\": \"" TEST_DATA_DIR
+                      "/example.net.zone\"}]}]")));
+    EXPECT_NO_THROW(parser->commit());
+    EXPECT_EQ(3, server.getInMemoryClient(rrclass)->getZoneCount());
+}
+
+TEST_F(MemoryDatasrcConfigTest,
+#ifdef USE_STATIC_LINK
+       DISABLED_replace
+#else
+       replace
+#endif
+    )
+{
+    EXPECT_NO_THROW(parser->build(Element::fromJSON(
+                      "[{\"type\": \"memory\","
+                      "  \"zones\": [{\"origin\": \"example.com\","
+                      "               \"file\": \"" TEST_DATA_DIR
+                      "/example.zone\"}]}]")));
+    EXPECT_NO_THROW(parser->commit());
+    EXPECT_EQ(1, server.getInMemoryClient(rrclass)->getZoneCount());
+    EXPECT_EQ(isc::datasrc::result::SUCCESS,
+              server.getInMemoryClient(rrclass)->findZone(
+                  Name("example.com")).code);
+
+    // create a new parser, and install a new set of configuration.  It
+    // should replace the old one.
+    delete parser;
+    parser = createAuthConfigParser(server, "datasources"); 
+    EXPECT_NO_THROW(parser->build(Element::fromJSON(
+                      "[{\"type\": \"memory\","
+                      "  \"zones\": [{\"origin\": \"example.org\","
+                      "               \"file\": \"" TEST_DATA_DIR
+                      "/example.org.zone\"},"
+                      "              {\"origin\": \"example.net\","
+                      "               \"file\": \"" TEST_DATA_DIR
+                      "/example.net.zone\"}]}]")));
+    EXPECT_NO_THROW(parser->commit());
+    EXPECT_EQ(2, server.getInMemoryClient(rrclass)->getZoneCount());
+    EXPECT_EQ(isc::datasrc::result::NOTFOUND,
+              server.getInMemoryClient(rrclass)->findZone(
+                  Name("example.com")).code);
+}
+
+TEST_F(MemoryDatasrcConfigTest,
+#ifdef USE_STATIC_LINK
+       DISABLED_exception
+#else
+       exception
+#endif
+    )
+{
+    // Load a zone
+    EXPECT_NO_THROW(parser->build(Element::fromJSON(
+                      "[{\"type\": \"memory\","
+                      "  \"zones\": [{\"origin\": \"example.com\","
+                      "               \"file\": \"" TEST_DATA_DIR
+                      "/example.zone\"}]}]")));
+    EXPECT_NO_THROW(parser->commit());
+    EXPECT_EQ(1, server.getInMemoryClient(rrclass)->getZoneCount());
+    EXPECT_EQ(isc::datasrc::result::SUCCESS,
+              server.getInMemoryClient(rrclass)->findZone(
+                  Name("example.com")).code);
+
+    // create a new parser, and try to load something. It will throw,
+    // the given master file should not exist
+    delete parser;
+    parser = createAuthConfigParser(server, "datasources");
+    EXPECT_THROW(parser->build(Element::fromJSON(
+                      "[{\"type\": \"memory\","
+                      "  \"zones\": [{\"origin\": \"example.org\","
+                      "               \"file\": \"" TEST_DATA_DIR
+                      "/example.org.zone\"},"
+                      "              {\"origin\": \"example.net\","
+                      "               \"file\": \"" TEST_DATA_DIR
+                      "/nonexistent.zone\"}]}]")),
+                 isc::datasrc::DataSourceError);
+    // As that one throwed exception, it is not expected from us to
+    // commit it
+
+    // The original should be untouched
+    EXPECT_EQ(1, server.getInMemoryClient(rrclass)->getZoneCount());
+    EXPECT_EQ(isc::datasrc::result::SUCCESS,
+              server.getInMemoryClient(rrclass)->findZone(
+                  Name("example.com")).code);
+}
+
+TEST_F(MemoryDatasrcConfigTest,
+#ifdef USE_STATIC_LINK
+       DISABLED_remove
+#else
+       remove
+#endif
+    )
+{
+    EXPECT_NO_THROW(parser->build(Element::fromJSON(
+                      "[{\"type\": \"memory\","
+                      "  \"zones\": [{\"origin\": \"example.com\","
+                      "               \"file\": \"" TEST_DATA_DIR
+                      "/example.zone\"}]}]")));
+    EXPECT_NO_THROW(parser->commit());
+    EXPECT_EQ(1, server.getInMemoryClient(rrclass)->getZoneCount());
+
+    delete parser;
+    parser = createAuthConfigParser(server, "datasources"); 
+    EXPECT_NO_THROW(parser->build(Element::fromJSON("[]")));
+    EXPECT_NO_THROW(parser->commit());
+    EXPECT_FALSE(server.hasInMemoryClient());
+}
+
+TEST_F(MemoryDatasrcConfigTest, addDuplicateZones) {
+    EXPECT_THROW(parser->build(
+                     Element::fromJSON(
+                         "[{\"type\": \"memory\","
+                         "  \"zones\": [{\"origin\": \"example.com\","
+                         "               \"file\": \"" TEST_DATA_DIR
+                         "/example.zone\"},"
+                         "              {\"origin\": \"example.com\","
+                         "               \"file\": \"" TEST_DATA_DIR
+                         "/example.com.zone\"}]}]")),
+                 DataSourceError);
+}
+
+TEST_F(MemoryDatasrcConfigTest, addBadZone) {
+    // origin and file are missing
+    EXPECT_THROW(parser->build(
+                     Element::fromJSON(
+                         "[{\"type\": \"memory\","
+                         "  \"zones\": [{}]}]")),
+                 DataSourceError);
+
+    // origin is missing
+    EXPECT_THROW(parser->build(
+                     Element::fromJSON(
+                         "[{\"type\": \"memory\","
+                         "  \"zones\": [{\"file\": \"example.zone\"}]}]")),
+                 DataSourceError);
+
+    // file is missing
+    EXPECT_THROW(parser->build(
+                     Element::fromJSON(
+                         "[{\"type\": \"memory\","
+                         "  \"zones\": [{\"origin\": \"example.com\"}]}]")),
+                 DataSourceError);
+
+    // missing zone file
+    EXPECT_THROW(parser->build(
+                     Element::fromJSON(
+                         "[{\"type\": \"memory\","
+                         "  \"zones\": [{\"origin\": \"example.com\"}]}]")),
+                 DataSourceError);
+
+    // bogus origin name
+    EXPECT_THROW(parser->build(Element::fromJSON(
+                      "[{\"type\": \"memory\","
+                      "  \"zones\": [{\"origin\": \"example..com\","
+                      "               \"file\": \"example.zone\"}]}]")),
+                 DataSourceError);
+
+    // bogus RR class name
+    EXPECT_THROW(parser->build(
+                     Element::fromJSON(
+                         "[{\"type\": \"memory\","
+                         "  \"class\": \"BADCLASS\","
+                         "  \"zones\": [{\"origin\": \"example.com\","
+                         "               \"file\": \"example.zone\"}]}]")),
+                 InvalidRRClass);
+
+    // valid RR class, but not currently supported
+    EXPECT_THROW(parser->build(
+                     Element::fromJSON(
+                         "[{\"type\": \"memory\","
+                         "  \"class\": \"CH\","
+                         "  \"zones\": [{\"origin\": \"example.com\","
+                         "               \"file\": \"example.zone\"}]}]")),
+                 isc::InvalidParameter);
+}
+
+TEST_F(MemoryDatasrcConfigTest,
+#ifdef USE_STATIC_LINK
+       DISABLED_badDatasrcType
+#else
+       badDatasrcType
+#endif
+    )
+{
+    EXPECT_THROW(parser->build(Element::fromJSON("[{\"type\": \"badsrc\"}]")),
+                 AuthConfigError);
+    EXPECT_THROW(parser->build(Element::fromJSON("[{\"notype\": \"memory\"}]")),
+                 AuthConfigError);
+    EXPECT_THROW(parser->build(Element::fromJSON("[{\"type\": 1}]")),
+                                      isc::data::TypeError);
+    EXPECT_THROW(parser->build(Element::fromJSON("[{\"type\": \"memory\"},"
+                                                 " {\"type\": \"memory\"}]")),
+                 AuthConfigError);
+}
+
 class StatisticsIntervalConfigTest : public AuthConfigTest {
 protected:
     StatisticsIntervalConfigTest() :
diff --git a/src/bin/auth/tests/datasrc_configurator_unittest.cc b/src/bin/auth/tests/datasrc_configurator_unittest.cc
deleted file mode 100644
index 9c009fd..0000000
--- a/src/bin/auth/tests/datasrc_configurator_unittest.cc
+++ /dev/null
@@ -1,292 +0,0 @@
-// 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 <auth/datasrc_configurator.h>
-
-#include <config/tests/fake_session.h>
-#include <config/ccsession.h>
-
-#include <gtest/gtest.h>
-#include <memory>
-#include <boost/shared_ptr.hpp>
-
-using namespace isc;
-using namespace isc::cc;
-using namespace isc::config;
-using namespace isc::data;
-using namespace isc::dns;
-using namespace std;
-using namespace boost;
-
-namespace {
-
-class DatasrcConfiguratorTest;
-
-class FakeList {
-public:
-    FakeList(const RRClass&) :
-        configuration_(new ListElement)
-    {}
-    void configure(const ConstElementPtr& configuration, bool allow_cache) {
-        EXPECT_TRUE(allow_cache);
-        conf_ = configuration->get(0)->get("type")->stringValue();
-        configuration_ = configuration;
-    }
-    const string& getConf() const {
-        return (conf_);
-    }
-    ConstElementPtr getConfiguration() const {
-        return (configuration_);
-    }
-private:
-    string conf_;
-    ConstElementPtr configuration_;
-};
-
-typedef shared_ptr<FakeList> ListPtr;
-
-// We use the test fixture as both parameters, this makes it possible
-// to easily fake all needed methods and look that they were called.
-typedef DataSourceConfiguratorGeneric<DatasrcConfiguratorTest,
-        FakeList> Configurator;
-
-class DatasrcConfiguratorTest : public ::testing::Test {
-public:
-    // These pretend to be the server
-    ListPtr getClientList(const RRClass& rrclass) {
-        log_ += "get " + rrclass.toText() + "\n";
-        return (lists_[rrclass]);
-    }
-    void setClientList(const RRClass& rrclass, const ListPtr& list) {
-        log_ += "set " + rrclass.toText() + " " +
-            (list ? list->getConf() : "") + "\n";
-        lists_[rrclass] = list;
-    }
-    vector<RRClass> getClientListClasses() const {
-        vector<RRClass> result;
-        for (map<RRClass, ListPtr>::const_iterator it(lists_.begin());
-             it != lists_.end(); ++it) {
-            result.push_back(it->first);
-        }
-        return (result);
-    }
-protected:
-    DatasrcConfiguratorTest() :
-        session(ElementPtr(new ListElement), ElementPtr(new ListElement),
-                ElementPtr(new ListElement)),
-        specfile(string(TEST_OWN_DATA_DIR) + "/spec.spec")
-    {
-        initSession();
-    }
-    void initSession() {
-        session.getMessages()->add(createAnswer());
-        mccs.reset(new ModuleCCSession(specfile, session, NULL, NULL, false,
-                                       false));
-    }
-    void TearDown() {
-        // Make sure no matter what we did, it is cleaned up.
-        Configurator::deinit();
-    }
-    void init(const ElementPtr& config = ElementPtr()) {
-        session.getMessages()->
-            add(createAnswer(0,
-                             moduleSpecFromFile(string(PLUGIN_DATA_PATH) +
-                                                "/datasrc.spec").
-                             getFullSpec()));
-        if (config) {
-            session.getMessages()->add(createAnswer(0, config));
-        } else {
-            session.getMessages()->
-                add(createAnswer(0, ElementPtr(new MapElement)));
-        }
-        Configurator::init(mccs.get(), this);
-    }
-    void SetUp() {
-        init();
-    }
-    ElementPtr buildConfig(const string& config) const {
-        const ElementPtr internal(Element::fromJSON(config));
-        const ElementPtr external(Element::fromJSON("{\"version\": 1}"));
-        external->set("classes", internal);
-        return (external);
-    }
-    void doInInit() {
-        const ElementPtr
-            config(buildConfig("{\"IN\": [{\"type\": \"xxx\"}]}"));
-        session.addMessage(createCommand("config_update", config), "data_sources",
-                           "*");
-        mccs->checkCommand();
-        // Check it called the correct things (check that there's no IN yet and
-        // set a new one.
-        EXPECT_EQ("get IN\nset IN xxx\n", log_);
-    }
-    FakeSession session;
-    auto_ptr<ModuleCCSession> mccs;
-    const string specfile;
-    map<RRClass, ListPtr> lists_;
-    string log_;
-};
-
-// Check the initialization (and deinitialization)
-TEST_F(DatasrcConfiguratorTest, initialization) {
-    // It can't be initialized again
-    EXPECT_THROW(init(), InvalidOperation);
-    EXPECT_TRUE(session.haveSubscription("data_sources", "*"));
-    // Deinitialize to make the tests reasonable
-    Configurator::deinit();
-    EXPECT_FALSE(session.haveSubscription("data_sources", "*"));
-    // We can't reconfigure now (not even manually)
-    EXPECT_THROW(Configurator::reconfigure(ElementPtr(new MapElement())),
-                 InvalidOperation);
-    // If one of them is NULL, it does not work
-    EXPECT_THROW(Configurator::init(NULL, this), InvalidParameter);
-    EXPECT_FALSE(session.haveSubscription("data_sources", "*"));
-    EXPECT_THROW(Configurator::init(mccs.get(), NULL), InvalidParameter);
-    EXPECT_FALSE(session.haveSubscription("data_sources", "*"));
-    // But we can initialize it again now
-    EXPECT_NO_THROW(init());
-    EXPECT_TRUE(session.haveSubscription("data_sources", "*"));
-}
-
-// Push there a configuration with a single list.
-TEST_F(DatasrcConfiguratorTest, createList) {
-    doInInit();
-}
-
-TEST_F(DatasrcConfiguratorTest, modifyList) {
-    // First, initialize the list
-    doInInit();
-    // And now change the configuration of the list
-    const ElementPtr
-        config(buildConfig("{\"IN\": [{\"type\": \"yyy\"}]}"));
-    session.addMessage(createCommand("config_update", config), "data_sources",
-                       "*");
-    log_ = "";
-    mccs->checkCommand();
-    // This one does not set
-    EXPECT_EQ("get IN\n", log_);
-    // But this should contain the yyy configuration
-    EXPECT_EQ("yyy", lists_[RRClass::IN()]->getConf());
-}
-
-// Check we can have multiple lists at once
-TEST_F(DatasrcConfiguratorTest, multiple) {
-    const ElementPtr
-        config(buildConfig("{\"IN\": [{\"type\": \"yyy\"}], "
-                                 "\"CH\": [{\"type\": \"xxx\"}]}"));
-    session.addMessage(createCommand("config_update", config), "data_sources",
-                       "*");
-    mccs->checkCommand();
-    // This one does not set
-    EXPECT_EQ("get CH\nset CH xxx\nget IN\nset IN yyy\n", log_);
-    // We should have both there
-    EXPECT_EQ("yyy", lists_[RRClass::IN()]->getConf());
-    EXPECT_EQ("xxx", lists_[RRClass::CH()]->getConf());
-    EXPECT_EQ(2, lists_.size());
-}
-
-// Check we can add another one later and the old one does not get
-// overwritten.
-//
-// It's almost like above, but we initialize first with single-list
-// config.
-TEST_F(DatasrcConfiguratorTest, updateAdd) {
-    doInInit();
-    const ElementPtr
-        config(buildConfig("{\"IN\": [{\"type\": \"yyy\"}], "
-                           "\"CH\": [{\"type\": \"xxx\"}]}"));
-    session.addMessage(createCommand("config_update", config), "data_sources",
-                       "*");
-    log_ = "";
-    mccs->checkCommand();
-    // This one does not set
-    EXPECT_EQ("get CH\nset CH xxx\nget IN\n", log_);
-    // But this should contain the yyy configuration
-    EXPECT_EQ("xxx", lists_[RRClass::CH()]->getConf());
-    EXPECT_EQ("yyy", lists_[RRClass::IN()]->getConf());
-    EXPECT_EQ(2, lists_.size());
-}
-
-// We delete a class list in this test.
-TEST_F(DatasrcConfiguratorTest, updateDelete) {
-    doInInit();
-    const ElementPtr
-        config(buildConfig("{}"));
-    session.addMessage(createCommand("config_update", config), "data_sources",
-                       "*");
-    log_ = "";
-    mccs->checkCommand();
-    EXPECT_EQ("get IN\nset IN \n", log_);
-    EXPECT_FALSE(lists_[RRClass::IN()]);
-}
-
-// Check that we can rollback an addition if something else fails
-TEST_F(DatasrcConfiguratorTest, rollbackAddition) {
-    doInInit();
-    // The configuration is wrong. However, the CH one will get done first.
-    const ElementPtr
-        config(buildConfig("{\"IN\": [{\"type\": 13}], "
-                           "\"CH\": [{\"type\": \"xxx\"}]}"));
-    session.addMessage(createCommand("config_update", config), "data_sources",
-                       "*");
-    log_ = "";
-    // It does not throw, as it is handled in the ModuleCCSession.
-    // Throwing from the reconfigure is checked in other tests.
-    EXPECT_NO_THROW(mccs->checkCommand());
-    // Anyway, the result should not contain CH now and the original IN should
-    // be there.
-    EXPECT_EQ("xxx", lists_[RRClass::IN()]->getConf());
-    EXPECT_FALSE(lists_[RRClass::CH()]);
-}
-
-// Check that we can rollback a deletion if something else fails
-TEST_F(DatasrcConfiguratorTest, rollbackDeletion) {
-    doInInit();
-    // Put the CH there
-    const ElementPtr
-        config1(Element::fromJSON("{\"IN\": [{\"type\": \"yyy\"}], "
-                                  "\"CH\": [{\"type\": \"xxx\"}]}"));
-    Configurator::reconfigure(config1);
-    const ElementPtr
-        config2(Element::fromJSON("{\"IN\": [{\"type\": 13}]}"));
-    // This would delete CH. However, the IN one fails.
-    // As the deletions happen after the additions/settings
-    // and there's no known way to cause an exception during the
-    // deletions, it is not a true rollback, but the result should
-    // be the same.
-    EXPECT_THROW(Configurator::reconfigure(config2), TypeError);
-    EXPECT_EQ("yyy", lists_[RRClass::IN()]->getConf());
-    EXPECT_EQ("xxx", lists_[RRClass::CH()]->getConf());
-}
-
-// Check that we can roll back configuration change if something
-// fails later on.
-TEST_F(DatasrcConfiguratorTest, rollbackConfiguration) {
-    doInInit();
-    // Put the CH there
-    const ElementPtr
-        config1(Element::fromJSON("{\"IN\": [{\"type\": \"yyy\"}], "
-                                  "\"CH\": [{\"type\": \"xxx\"}]}"));
-    Configurator::reconfigure(config1);
-    // Now, the CH happens first. But nevertheless, it should be
-    // restored to the previoeus version.
-    const ElementPtr
-        config2(Element::fromJSON("{\"IN\": [{\"type\": 13}], "
-                                  "\"CH\": [{\"type\": \"yyy\"}]}"));
-    EXPECT_THROW(Configurator::reconfigure(config2), TypeError);
-    EXPECT_EQ("yyy", lists_[RRClass::IN()]->getConf());
-    EXPECT_EQ("xxx", lists_[RRClass::CH()]->getConf());
-}
-
-}
diff --git a/src/bin/auth/tests/query_unittest.cc b/src/bin/auth/tests/query_unittest.cc
index 81e19e3..4c404e6 100644
--- a/src/bin/auth/tests/query_unittest.cc
+++ b/src/bin/auth/tests/query_unittest.cc
@@ -32,7 +32,6 @@
 #include <dns/rdataclass.h>
 
 #include <datasrc/memory_datasrc.h>
-#include <datasrc/client_list.h>
 
 #include <auth/query.h>
 
@@ -49,32 +48,6 @@ using namespace isc::testutils;
 
 namespace {
 
-// Simple wrapper for a sincle data source client.
-// The list simply delegates all the answers to the single
-// client.
-class SingletonList : public ClientList {
-public:
-    SingletonList(DataSourceClient& client) :
-        client_(client)
-    {}
-    virtual FindResult find(const Name& zone, bool exact, bool) const {
-        DataSourceClient::FindResult result(client_.findZone(zone));
-        switch (result.code) {
-            case result::SUCCESS:
-                return (FindResult(&client_, result.zone_finder, true));
-            case result::PARTIALMATCH:
-                if (!exact) {
-                    return (FindResult(&client_, result.zone_finder, false));
-                }
-            default:
-                return (FindResult());
-        }
-    }
-private:
-    DataSourceClient& client_;
-};
-
-
 // This is the content of the mock zone (see below).
 // It's a sequence of textual RRs that is supposed to be parsed by
 // dns::masterLoad().  Some of the RRs are also used as the expected
@@ -902,7 +875,6 @@ MockZoneFinder::find(const Name& name, const RRType& type,
 class QueryTest : public ::testing::Test {
 protected:
     QueryTest() :
-        list(memory_client),
         qname(Name("www.example.com")), qclass(RRClass::IN()),
         qtype(RRType::A()), response(Message::RENDER),
         qid(response.getQid()), query_code(Opcode::QUERY().getCode()),
@@ -926,8 +898,6 @@ protected:
     // (originally named MemoryDataSrc) and was tested with it, so we keep
     // it like this for now.
     InMemoryClient memory_client;
-    // A wrapper client list to wrap the single data source.
-    SingletonList list;
     const Name qname;
     const RRClass qclass;
     const RRType qtype;
@@ -979,21 +949,20 @@ TEST_F(QueryTest, noZone) {
     // There's no zone in the memory datasource.  So the response should have
     // REFUSED.
     InMemoryClient empty_memory_client;
-    SingletonList empty_list(empty_memory_client);
-    EXPECT_NO_THROW(query.process(empty_list, qname, qtype,
+    EXPECT_NO_THROW(query.process(empty_memory_client, qname, qtype,
                                   response));
     EXPECT_EQ(Rcode::REFUSED(), response.getRcode());
 }
 
 TEST_F(QueryTest, exactMatch) {
-    EXPECT_NO_THROW(query.process(list, qname, qtype, response));
+    EXPECT_NO_THROW(query.process(memory_client, qname, qtype, response));
     // find match rrset
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
                   www_a_txt, zone_ns_txt, ns_addrs_txt);
 }
 
 TEST_F(QueryTest, exactMatchMultipleQueries) {
-    EXPECT_NO_THROW(query.process(list, qname, qtype, response));
+    EXPECT_NO_THROW(query.process(memory_client, qname, qtype, response));
     // find match rrset
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
                   www_a_txt, zone_ns_txt, ns_addrs_txt);
@@ -1002,7 +971,7 @@ TEST_F(QueryTest, exactMatchMultipleQueries) {
     response.clear(isc::dns::Message::RENDER);
     response.setRcode(Rcode::NOERROR());
     response.setOpcode(Opcode::QUERY());
-    EXPECT_NO_THROW(query.process(list, qname, qtype, response));
+    EXPECT_NO_THROW(query.process(memory_client, qname, qtype, response));
     // find match rrset
     SCOPED_TRACE("Second query");
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
@@ -1013,7 +982,7 @@ TEST_F(QueryTest, exactMatchIgnoreSIG) {
     // Check that we do not include the RRSIG when not requested even when
     // we receive it from the data source.
     mock_finder->setIncludeRRSIGAnyway(true);
-    EXPECT_NO_THROW(query.process(list, qname, qtype, response));
+    EXPECT_NO_THROW(query.process(memory_client, qname, qtype, response));
     // find match rrset
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
                   www_a_txt, zone_ns_txt, ns_addrs_txt);
@@ -1021,7 +990,7 @@ TEST_F(QueryTest, exactMatchIgnoreSIG) {
 
 TEST_F(QueryTest, dnssecPositive) {
     // Just like exactMatch, but the signatures should be included as well
-    EXPECT_NO_THROW(query.process(list, qname, qtype, response,
+    EXPECT_NO_THROW(query.process(memory_client, qname, qtype, response,
                                   true));
     // find match rrset
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 4, 6,
@@ -1040,7 +1009,7 @@ TEST_F(QueryTest, dnssecPositive) {
 TEST_F(QueryTest, exactAddrMatch) {
     // find match rrset, omit additional data which has already been provided
     // in the answer section from the additional.
-    EXPECT_NO_THROW(query.process(list,
+    EXPECT_NO_THROW(query.process(memory_client,
                                   Name("noglue.example.com"),
                                   qtype, response));
 
@@ -1053,7 +1022,7 @@ TEST_F(QueryTest, exactAddrMatch) {
 TEST_F(QueryTest, apexNSMatch) {
     // find match rrset, omit authority data which has already been provided
     // in the answer section from the authority section.
-    EXPECT_NO_THROW(query.process(list, Name("example.com"),
+    EXPECT_NO_THROW(query.process(memory_client, Name("example.com"),
                                   RRType::NS(), response));
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 3, 0, 3,
@@ -1064,7 +1033,7 @@ TEST_F(QueryTest, apexNSMatch) {
 TEST_F(QueryTest, exactAnyMatch) {
     // find match rrset, omit additional data which has already been provided
     // in the answer section from the additional.
-    EXPECT_NO_THROW(query.process(list, Name("noglue.example.com"),
+    EXPECT_NO_THROW(query.process(memory_client, Name("noglue.example.com"),
                                   RRType::ANY(), response));
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 3, 2,
@@ -1078,7 +1047,7 @@ TEST_F(QueryTest, exactAnyMatch) {
 TEST_F(QueryTest, apexAnyMatch) {
     // find match rrset, omit additional data which has already been provided
     // in the answer section from the additional.
-    EXPECT_NO_THROW(query.process(list, Name("example.com"),
+    EXPECT_NO_THROW(query.process(memory_client, Name("example.com"),
                                   RRType::ANY(), response));
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 5, 0, 3,
                   (string(soa_txt) + string(zone_ns_txt) +
@@ -1087,7 +1056,7 @@ TEST_F(QueryTest, apexAnyMatch) {
 }
 
 TEST_F(QueryTest, mxANYMatch) {
-    EXPECT_NO_THROW(query.process(list, Name("mx.example.com"),
+    EXPECT_NO_THROW(query.process(memory_client, Name("mx.example.com"),
                                   RRType::ANY(), response));
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 4, 3, 4,
                   (string(mx_txt) + string(nsec_mx_txt)).c_str(), zone_ns_txt,
@@ -1095,14 +1064,14 @@ TEST_F(QueryTest, mxANYMatch) {
 }
 
 TEST_F(QueryTest, glueANYMatch) {
-    EXPECT_NO_THROW(query.process(list, Name("delegation.example.com"),
+    EXPECT_NO_THROW(query.process(memory_client, Name("delegation.example.com"),
                                   RRType::ANY(), response));
     responseCheck(response, Rcode::NOERROR(), 0, 0, 4, 3,
                   NULL, delegation_txt, ns_addrs_txt);
 }
 
 TEST_F(QueryTest, nodomainANY) {
-    EXPECT_NO_THROW(query.process(list, Name("nxdomain.example.com"),
+    EXPECT_NO_THROW(query.process(memory_client, Name("nxdomain.example.com"),
                                   RRType::ANY(), response));
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 1, 0,
                   NULL, soa_txt, NULL, mock_finder->getOrigin());
@@ -1115,13 +1084,13 @@ TEST_F(QueryTest, noApexNS) {
     // Disable apex NS record
     mock_finder->setApexNSFlag(false);
 
-    EXPECT_THROW(query.process(list, Name("noglue.example.com"), qtype,
+    EXPECT_THROW(query.process(memory_client, Name("noglue.example.com"), qtype,
                                response), Query::NoApexNS);
     // We don't look into the response, as it threw
 }
 
 TEST_F(QueryTest, delegation) {
-    EXPECT_NO_THROW(query.process(list,
+    EXPECT_NO_THROW(query.process(memory_client,
                                   Name("delegation.example.com"),
                                   qtype, response));
 
@@ -1133,7 +1102,7 @@ TEST_F(QueryTest, delegationWithDNSSEC) {
     // Similar to the previous one, but with requesting DNSSEC.
     // In this case the parent zone would behave as unsigned, so the result
     // should be just like non DNSSEC delegation.
-    query.process(list, Name("www.nosec-delegation.example.com"),
+    query.process(memory_client, Name("www.nosec-delegation.example.com"),
                   qtype, response, true);
 
     responseCheck(response, Rcode::NOERROR(), 0, 0, 1, 0,
@@ -1141,7 +1110,7 @@ TEST_F(QueryTest, delegationWithDNSSEC) {
 }
 
 TEST_F(QueryTest, secureDelegation) {
-    EXPECT_NO_THROW(query.process(list,
+    EXPECT_NO_THROW(query.process(memory_client,
                                   Name("foo.signed-delegation.example.com"),
                                   qtype, response, true));
 
@@ -1156,7 +1125,7 @@ TEST_F(QueryTest, secureDelegation) {
 }
 
 TEST_F(QueryTest, secureUnsignedDelegation) {
-    EXPECT_NO_THROW(query.process(list,
+    EXPECT_NO_THROW(query.process(memory_client,
                                   Name("foo.unsigned-delegation.example.com"),
                                   qtype, response, true));
 
@@ -1177,7 +1146,7 @@ TEST_F(QueryTest, secureUnsignedDelegationWithNSEC3) {
     mock_finder->setNSEC3Flag(true);
     mock_finder->addRecord(unsigned_delegation_nsec3_txt);
 
-    query.process(list,
+    query.process(memory_client,
                   Name("foo.unsigned-delegation.example.com"),
                   qtype, response, true);
 
@@ -1196,7 +1165,7 @@ TEST_F(QueryTest, secureUnsignedDelegationWithNSEC3OptOut) {
     // Similar to the previous case, but the delegation is an optout.
     mock_finder->setNSEC3Flag(true);
 
-    query.process(list,
+    query.process(memory_client,
                   Name("foo.unsigned-delegation.example.com"),
                   qtype, response, true);
 
@@ -1221,20 +1190,20 @@ TEST_F(QueryTest, secureUnsignedDelegationWithNSEC3OptOut) {
 TEST_F(QueryTest, badSecureDelegation) {
     // Test whether exception is raised if DS query at delegation results in
     // something different than SUCCESS or NXRRSET
-    EXPECT_THROW(query.process(list,
+    EXPECT_THROW(query.process(memory_client,
                                Name("bad-delegation.example.com"),
                                qtype, response, true), Query::BadDS);
 
     // But only if DNSSEC is requested (it shouldn't even try to look for
     // the DS otherwise)
-    EXPECT_NO_THROW(query.process(list,
+    EXPECT_NO_THROW(query.process(memory_client,
                                   Name("bad-delegation.example.com"),
                                   qtype, response));
 }
 
 
 TEST_F(QueryTest, nxdomain) {
-    EXPECT_NO_THROW(query.process(list,
+    EXPECT_NO_THROW(query.process(memory_client,
                                   Name("nxdomain.example.com"), qtype,
                                   response));
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 1, 0,
@@ -1245,7 +1214,7 @@ TEST_F(QueryTest, nxdomainWithNSEC) {
     // NXDOMAIN with DNSSEC proof.  We should have SOA, NSEC that proves
     // NXDOMAIN and NSEC that proves nonexistence of matching wildcard,
     // as well as their RRSIGs.
-    EXPECT_NO_THROW(query.process(list,
+    EXPECT_NO_THROW(query.process(memory_client,
                                   Name("nxdomain.example.com"), qtype,
                                   response, true));
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 6, 0,
@@ -1266,7 +1235,7 @@ TEST_F(QueryTest, nxdomainWithNSEC2) {
     // is derived from the next domain of the NSEC that proves NXDOMAIN, and
     // the NSEC to provide the non existence of wildcard is different from
     // the first NSEC.
-    query.process(list, Name("(.no.example.com"), qtype, response,
+    query.process(memory_client, Name("(.no.example.com"), qtype, response,
                   true);
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 6, 0,
                   NULL, (string(soa_txt) +
@@ -1284,7 +1253,7 @@ TEST_F(QueryTest, nxdomainWithNSEC2) {
 TEST_F(QueryTest, nxdomainWithNSECDuplicate) {
     // See comments about nz_txt.  In this case we only need one NSEC,
     // which proves both NXDOMAIN and the non existence of wildcard.
-    query.process(list, Name("nx.no.example.com"), qtype, response,
+    query.process(memory_client, Name("nx.no.example.com"), qtype, response,
                   true);
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 4, 0,
                   NULL, (string(soa_txt) +
@@ -1301,7 +1270,7 @@ TEST_F(QueryTest, nxdomainBadNSEC1) {
     mock_finder->setNSECResult(Name("badnsec.example.com"),
                                ZoneFinder::NXDOMAIN,
                                mock_finder->dname_rrset_);
-    EXPECT_THROW(query.process(list, Name("badnsec.example.com"),
+    EXPECT_THROW(query.process(memory_client, Name("badnsec.example.com"),
                                qtype, response, true),
                  std::bad_cast);
 }
@@ -1311,7 +1280,7 @@ TEST_F(QueryTest, nxdomainBadNSEC2) {
     mock_finder->setNSECResult(Name("emptynsec.example.com"),
                                ZoneFinder::NXDOMAIN,
                                mock_finder->empty_nsec_rrset_);
-    EXPECT_THROW(query.process(list, Name("emptynsec.example.com"),
+    EXPECT_THROW(query.process(memory_client, Name("emptynsec.example.com"),
                                qtype, response, true),
                  Query::BadNSEC);
 }
@@ -1321,7 +1290,7 @@ TEST_F(QueryTest, nxdomainBadNSEC3) {
     mock_finder->setNSECResult(Name("*.example.com"),
                                ZoneFinder::SUCCESS,
                                mock_finder->dname_rrset_);
-    EXPECT_THROW(query.process(list, Name("nxdomain.example.com"),
+    EXPECT_THROW(query.process(memory_client, Name("nxdomain.example.com"),
                                qtype, response, true),
                  Query::BadNSEC);
 }
@@ -1330,7 +1299,7 @@ TEST_F(QueryTest, nxdomainBadNSEC4) {
     // "no-wildcard proof" doesn't return RRset.
     mock_finder->setNSECResult(Name("*.example.com"),
                                ZoneFinder::NXDOMAIN, ConstRRsetPtr());
-    EXPECT_THROW(query.process(list, Name("nxdomain.example.com"),
+    EXPECT_THROW(query.process(memory_client, Name("nxdomain.example.com"),
                                qtype, response, true),
                  Query::BadNSEC);
 }
@@ -1341,7 +1310,7 @@ TEST_F(QueryTest, nxdomainBadNSEC5) {
                                ZoneFinder::NXDOMAIN,
                                mock_finder->dname_rrset_);
     // This is a bit odd, but we'll simply include the returned RRset.
-    query.process(list, Name("nxdomain.example.com"), qtype,
+    query.process(memory_client, Name("nxdomain.example.com"), qtype,
                   response, true);
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 6, 0,
                   NULL, (string(soa_txt) +
@@ -1361,13 +1330,13 @@ TEST_F(QueryTest, nxdomainBadNSEC6) {
     mock_finder->setNSECResult(Name("*.example.com"),
                                ZoneFinder::NXDOMAIN,
                                mock_finder->empty_nsec_rrset_);
-    EXPECT_THROW(query.process(list, Name("nxdomain.example.com"),
+    EXPECT_THROW(query.process(memory_client, Name("nxdomain.example.com"),
                                qtype, response, true),
                  Query::BadNSEC);
 }
 
 TEST_F(QueryTest, nxrrset) {
-    EXPECT_NO_THROW(query.process(list, Name("www.example.com"),
+    EXPECT_NO_THROW(query.process(memory_client, Name("www.example.com"),
                                   RRType::TXT(), response));
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 1, 0,
@@ -1377,7 +1346,7 @@ TEST_F(QueryTest, nxrrset) {
 TEST_F(QueryTest, nxrrsetWithNSEC) {
     // NXRRSET with DNSSEC proof.  We should have SOA, NSEC that proves the
     // NXRRSET and their RRSIGs.
-    query.process(list, Name("www.example.com"), RRType::TXT(),
+    query.process(memory_client, Name("www.example.com"), RRType::TXT(),
                   response, true);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
@@ -1398,7 +1367,7 @@ TEST_F(QueryTest, emptyNameWithNSEC) {
     // exact match), so we only need one NSEC.
     // From the point of the Query::process(), this is actually no different
     // from the other NXRRSET case, but we check that explicitly just in case.
-    query.process(list, Name("no.example.com"), RRType::A(),
+    query.process(memory_client, Name("no.example.com"), RRType::A(),
                   response, true);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
@@ -1414,7 +1383,7 @@ TEST_F(QueryTest, nxrrsetWithoutNSEC) {
     // NXRRSET with DNSSEC proof requested, but there's no NSEC at that node.
     // This is an unexpected event (if the zone is supposed to be properly
     // signed with NSECs), but we accept and ignore the oddity.
-    query.process(list, Name("nonsec.example.com"), RRType::TXT(),
+    query.process(memory_client, Name("nonsec.example.com"), RRType::TXT(),
                   response, true);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 2, 0, NULL,
@@ -1426,7 +1395,7 @@ TEST_F(QueryTest, nxrrsetWithoutNSEC) {
 TEST_F(QueryTest, wildcardNSEC) {
     // The qname matches *.wild.example.com.  The response should contain
     // an NSEC that proves the non existence of a closer name.
-    query.process(list, Name("www.wild.example.com"), RRType::A(),
+    query.process(memory_client, Name("www.wild.example.com"), RRType::A(),
                   response, true);
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 6, 6,
                   (string(wild_txt).replace(0, 1, "www") +
@@ -1446,7 +1415,7 @@ TEST_F(QueryTest, wildcardNSEC) {
 TEST_F(QueryTest, CNAMEwildNSEC) {
     // Similar to the previous case, but the matching wildcard record is
     // CNAME.
-    query.process(list, Name("www.cnamewild.example.com"),
+    query.process(memory_client, Name("www.cnamewild.example.com"),
                   RRType::A(), response, true);
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 2, 0,
                   (string(cnamewild_txt).replace(0, 1, "www") +
@@ -1469,7 +1438,7 @@ TEST_F(QueryTest, wildcardNSEC3) {
     // of identifying the next closer name.
     mock_finder->addRecord(nsec3_atwild_txt);
 
-    query.process(list, Name("x.y.wild.example.com"), RRType::A(),
+    query.process(memory_client, Name("x.y.wild.example.com"), RRType::A(),
                   response, true);
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 6, 6,
                   (string(wild_txt).replace(0, 1, "x.y") +
@@ -1494,7 +1463,7 @@ TEST_F(QueryTest, CNAMEwildNSEC3) {
     mock_finder->setNSEC3Flag(true);
     mock_finder->addRecord(nsec3_atcnamewild_txt);
 
-    query.process(list, Name("www.cnamewild.example.com"),
+    query.process(memory_client, Name("www.cnamewild.example.com"),
                   RRType::A(), response, true);
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 2, 0,
                   (string(cnamewild_txt).replace(0, 1, "www") +
@@ -1517,7 +1486,7 @@ TEST_F(QueryTest, badWildcardNSEC3) {
                                       ConstRRsetPtr());
     mock_finder->setNSEC3Result(&nsec3);
 
-    EXPECT_THROW(query.process(list, Name("www.wild.example.com"),
+    EXPECT_THROW(query.process(memory_client, Name("www.wild.example.com"),
                                RRType::A(), response, true),
                  Query::BadNSEC3);
 }
@@ -1528,7 +1497,7 @@ TEST_F(QueryTest, badWildcardProof1) {
     mock_finder->setNSECResult(Name("www.wild.example.com"),
                                ZoneFinder::SUCCESS,
                                mock_finder->dname_rrset_);
-    EXPECT_THROW(query.process(list, Name("www.wild.example.com"),
+    EXPECT_THROW(query.process(memory_client, Name("www.wild.example.com"),
                                RRType::A(), response, true),
                  Query::BadNSEC);
 }
@@ -1537,7 +1506,7 @@ TEST_F(QueryTest, badWildcardProof2) {
     // "wildcard proof" doesn't return RRset.
     mock_finder->setNSECResult(Name("www.wild.example.com"),
                                ZoneFinder::NXDOMAIN, ConstRRsetPtr());
-    EXPECT_THROW(query.process(list, Name("www.wild.example.com"),
+    EXPECT_THROW(query.process(memory_client, Name("www.wild.example.com"),
                                RRType::A(), response, true),
                  Query::BadNSEC);
 }
@@ -1547,7 +1516,7 @@ TEST_F(QueryTest, badWildcardProof3) {
     mock_finder->setNSECResult(Name("www.wild.example.com"),
                                ZoneFinder::NXDOMAIN,
                                mock_finder->empty_nsec_rrset_);
-    EXPECT_THROW(query.process(list, Name("www.wild.example.com"),
+    EXPECT_THROW(query.process(memory_client, Name("www.wild.example.com"),
                                RRType::A(), response, true),
                  Query::BadNSEC);
 }
@@ -1556,7 +1525,7 @@ TEST_F(QueryTest, wildcardNxrrsetWithDuplicateNSEC) {
     // NXRRSET on WILDCARD with DNSSEC proof.  We should have SOA, NSEC that
     // proves the NXRRSET and their RRSIGs. In this case we only need one NSEC,
     // which proves both NXDOMAIN and the non existence RRSETs of wildcard.
-    query.process(list, Name("www.wild.example.com"), RRType::TXT(),
+    query.process(memory_client, Name("www.wild.example.com"), RRType::TXT(),
                   response, true);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
@@ -1573,7 +1542,7 @@ TEST_F(QueryTest, wildcardNxrrsetWithNSEC) {
     // proves the NXRRSET and their RRSIGs. In this case we need two NSEC RRs,
     // one proves NXDOMAIN and the other proves non existence RRSETs of
     // wildcard.
-    query.process(list, Name("www1.uwild.example.com"),
+    query.process(memory_client, Name("www1.uwild.example.com"),
                   RRType::TXT(), response, true);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 6, 0, NULL,
@@ -1596,7 +1565,7 @@ TEST_F(QueryTest, wildcardNxrrsetWithNSEC3) {
     mock_finder->addRecord(nsec3_uwild_txt);
     mock_finder->setNSEC3Flag(true);
 
-    query.process(list, Name("www1.uwild.example.com"),
+    query.process(memory_client, Name("www1.uwild.example.com"),
                   RRType::TXT(), response, true);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 8, 0, NULL,
@@ -1630,7 +1599,7 @@ TEST_F(QueryTest, wildcardNxrrsetWithNSEC3Collision) {
                                       ConstRRsetPtr());
     mock_finder->setNSEC3Result(&nsec3);
 
-    EXPECT_THROW(query.process(list, Name("www1.uwild.example.com"),
+    EXPECT_THROW(query.process(memory_client, Name("www1.uwild.example.com"),
                                RRType::TXT(), response, true),
                  Query::BadNSEC3);
 }
@@ -1647,7 +1616,7 @@ TEST_F(QueryTest, wildcardNxrrsetWithNSEC3Broken) {
     mock_finder->addRecord(nsec3_wild_txt);
     mock_finder->addRecord(nsec3_uwild_txt);
 
-    EXPECT_THROW(query.process(list, Name("www1.uwild.example.com"),
+    EXPECT_THROW(query.process(memory_client, Name("www1.uwild.example.com"),
                                RRType::TXT(), response, true),
                  Query::BadNSEC3);
 }
@@ -1656,7 +1625,7 @@ TEST_F(QueryTest, wildcardEmptyWithNSEC) {
     // Empty WILDCARD with DNSSEC proof.  We should have SOA, NSEC that proves
     // the NXDOMAIN and their RRSIGs. In this case we need two NSEC RRs,
     // one proves NXDOMAIN and the other proves non existence wildcard.
-    query.process(list, Name("a.t.example.com"), RRType::A(),
+    query.process(memory_client, Name("a.t.example.com"), RRType::A(),
                   response, true);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 6, 0, NULL,
@@ -1680,19 +1649,19 @@ TEST_F(QueryTest, noSOA) {
     mock_finder->setSOAFlag(false);
 
     // The NX Domain
-    EXPECT_THROW(query.process(list, Name("nxdomain.example.com"),
+    EXPECT_THROW(query.process(memory_client, Name("nxdomain.example.com"),
                                qtype, response), Query::NoSOA);
     // Of course, we don't look into the response, as it throwed
 
     // NXRRSET
-    EXPECT_THROW(query.process(list, Name("nxrrset.example.com"),
+    EXPECT_THROW(query.process(memory_client, Name("nxrrset.example.com"),
                                qtype, response), Query::NoSOA);
 }
 
 TEST_F(QueryTest, noMatchZone) {
     // there's a zone in the memory datasource but it doesn't match the qname.
     // should result in REFUSED.
-    query.process(list, Name("example.org"), qtype, response);
+    query.process(memory_client, Name("example.org"), qtype, response);
     EXPECT_EQ(Rcode::REFUSED(), response.getRcode());
 }
 
@@ -1703,7 +1672,7 @@ TEST_F(QueryTest, noMatchZone) {
  * A record, other to unknown out of zone one.
  */
 TEST_F(QueryTest, MX) {
-    query.process(list, Name("mx.example.com"), RRType::MX(),
+    query.process(memory_client, Name("mx.example.com"), RRType::MX(),
                   response);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 3, 3, 4,
@@ -1717,7 +1686,7 @@ TEST_F(QueryTest, MX) {
  * This should not trigger the additional processing for the exchange.
  */
 TEST_F(QueryTest, MXAlias) {
-    query.process(list, Name("cnamemx.example.com"), RRType::MX(),
+    query.process(memory_client, Name("cnamemx.example.com"), RRType::MX(),
                   response);
 
     // there shouldn't be no additional RRs for the exchanges (we have 3
@@ -1737,7 +1706,7 @@ TEST_F(QueryTest, MXAlias) {
  * returned.
  */
 TEST_F(QueryTest, CNAME) {
-    query.process(list, Name("cname.example.com"), RRType::A(),
+    query.process(memory_client, Name("cname.example.com"), RRType::A(),
                   response);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 0, 0,
@@ -1747,7 +1716,7 @@ TEST_F(QueryTest, CNAME) {
 TEST_F(QueryTest, explicitCNAME) {
     // same owner name as the CNAME test but explicitly query for CNAME RR.
     // expect the same response as we don't provide a full chain yet.
-    query.process(list, Name("cname.example.com"), RRType::CNAME(),
+    query.process(memory_client, Name("cname.example.com"), RRType::CNAME(),
                   response);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
@@ -1759,7 +1728,7 @@ TEST_F(QueryTest, CNAME_NX_RRSET) {
     // note: with chaining, what should be expected is not trivial:
     // BIND 9 returns the CNAME in answer and SOA in authority, no additional.
     // NSD returns the CNAME, NS in authority, A/AAAA for NS in additional.
-    query.process(list, Name("cname.example.com"), RRType::TXT(),
+    query.process(memory_client, Name("cname.example.com"), RRType::TXT(),
                   response);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 0, 0,
@@ -1768,7 +1737,7 @@ TEST_F(QueryTest, CNAME_NX_RRSET) {
 
 TEST_F(QueryTest, explicitCNAME_NX_RRSET) {
     // same owner name as the NXRRSET test but explicitly query for CNAME RR.
-    query.process(list, Name("cname.example.com"), RRType::CNAME(),
+    query.process(memory_client, Name("cname.example.com"), RRType::CNAME(),
                   response);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
@@ -1782,7 +1751,7 @@ TEST_F(QueryTest, CNAME_NX_DOMAIN) {
     // RCODE being NXDOMAIN.
     // NSD returns the CNAME, NS in authority, A/AAAA for NS in additional,
     // RCODE being NOERROR.
-    query.process(list, Name("cnamenxdom.example.com"), RRType::A(),
+    query.process(memory_client, Name("cnamenxdom.example.com"), RRType::A(),
                   response);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 0, 0,
@@ -1791,7 +1760,7 @@ TEST_F(QueryTest, CNAME_NX_DOMAIN) {
 
 TEST_F(QueryTest, explicitCNAME_NX_DOMAIN) {
     // same owner name as the NXDOMAIN test but explicitly query for CNAME RR.
-    query.process(list, Name("cnamenxdom.example.com"),
+    query.process(memory_client, Name("cnamenxdom.example.com"),
                   RRType::CNAME(), response);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
@@ -1807,7 +1776,7 @@ TEST_F(QueryTest, CNAME_OUT) {
      * Then the same test should be done with .org included there and
      * see what it does (depends on what we want to do)
      */
-    query.process(list, Name("cnameout.example.com"), RRType::A(),
+    query.process(memory_client, Name("cnameout.example.com"), RRType::A(),
                   response);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 0, 0,
@@ -1816,7 +1785,7 @@ TEST_F(QueryTest, CNAME_OUT) {
 
 TEST_F(QueryTest, explicitCNAME_OUT) {
     // same owner name as the OUT test but explicitly query for CNAME RR.
-    query.process(list, Name("cnameout.example.com"), RRType::CNAME(),
+    query.process(memory_client, Name("cnameout.example.com"), RRType::CNAME(),
                   response);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
@@ -1832,7 +1801,7 @@ TEST_F(QueryTest, explicitCNAME_OUT) {
  * pointing to NXRRSET and NXDOMAIN cases (similarly as with CNAME).
  */
 TEST_F(QueryTest, DNAME) {
-    query.process(list, Name("www.dname.example.com"), RRType::A(),
+    query.process(memory_client, Name("www.dname.example.com"), RRType::A(),
                   response);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 0, 0,
@@ -1848,7 +1817,7 @@ TEST_F(QueryTest, DNAME) {
  * DNAME.
  */
 TEST_F(QueryTest, DNAME_ANY) {
-    query.process(list, Name("www.dname.example.com"), RRType::ANY(),
+    query.process(memory_client, Name("www.dname.example.com"), RRType::ANY(),
                   response);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 0, 0,
@@ -1857,7 +1826,7 @@ TEST_F(QueryTest, DNAME_ANY) {
 
 // Test when we ask for DNAME explicitly, it does no synthetizing.
 TEST_F(QueryTest, explicitDNAME) {
-    query.process(list, Name("dname.example.com"), RRType::DNAME(),
+    query.process(memory_client, Name("dname.example.com"), RRType::DNAME(),
                   response);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
@@ -1869,7 +1838,7 @@ TEST_F(QueryTest, explicitDNAME) {
  * the CNAME, it should return the RRset.
  */
 TEST_F(QueryTest, DNAME_A) {
-    query.process(list, Name("dname.example.com"), RRType::A(),
+    query.process(memory_client, Name("dname.example.com"), RRType::A(),
                   response);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
@@ -1881,7 +1850,7 @@ TEST_F(QueryTest, DNAME_A) {
  * It should not synthetize the CNAME.
  */
 TEST_F(QueryTest, DNAME_NX_RRSET) {
-    EXPECT_NO_THROW(query.process(list, Name("dname.example.com"),
+    EXPECT_NO_THROW(query.process(memory_client, Name("dname.example.com"),
                     RRType::TXT(), response));
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 1, 0,
@@ -1901,7 +1870,7 @@ TEST_F(QueryTest, LongDNAME) {
         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
         "dname.example.com.");
-    EXPECT_NO_THROW(query.process(list, longname, RRType::A(),
+    EXPECT_NO_THROW(query.process(memory_client, longname, RRType::A(),
                     response));
 
     responseCheck(response, Rcode::YXDOMAIN(), AA_FLAG, 1, 0, 0,
@@ -1920,7 +1889,7 @@ TEST_F(QueryTest, MaxLenDNAME) {
         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
         "dname.example.com.");
-    EXPECT_NO_THROW(query.process(list, longname, RRType::A(),
+    EXPECT_NO_THROW(query.process(memory_client, longname, RRType::A(),
                     response));
 
     // Check the answer is OK
@@ -2106,7 +2075,7 @@ TEST_F(QueryTest, dsAboveDelegation) {
 
     // The following will succeed only if the search goes to the parent
     // zone, not the child one we added above.
-    EXPECT_NO_THROW(query.process(list,
+    EXPECT_NO_THROW(query.process(memory_client,
                                   Name("delegation.example.com"),
                                   RRType::DS(), response, true));
 
@@ -2130,7 +2099,7 @@ TEST_F(QueryTest, dsAboveDelegationNoData) {
 
     // The following will succeed only if the search goes to the parent
     // zone, not the child one we added above.
-    EXPECT_NO_THROW(query.process(list,
+    EXPECT_NO_THROW(query.process(memory_client,
                                   Name("unsigned-delegation.example.com"),
                                   RRType::DS(), response, true));
 
@@ -2148,7 +2117,7 @@ TEST_F(QueryTest, dsAboveDelegationNoData) {
 // when it happens to be sent to the child zone, as described in RFC 4035,
 // section 3.1.4.1. The example is inspired by the B.8. example from the RFC.
 TEST_F(QueryTest, dsBelowDelegation) {
-    EXPECT_NO_THROW(query.process(list, Name("example.com"),
+    EXPECT_NO_THROW(query.process(memory_client, Name("example.com"),
                                   RRType::DS(), response, true));
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
@@ -2165,7 +2134,7 @@ TEST_F(QueryTest, dsBelowDelegation) {
 // In our implementation NSEC/NSEC3 isn't attached in this case.
 TEST_F(QueryTest, dsBelowDelegationWithDS) {
     mock_finder->addRecord(zone_ds_txt); // add the DS to the child's apex
-    EXPECT_NO_THROW(query.process(list, Name("example.com"),
+    EXPECT_NO_THROW(query.process(memory_client, Name("example.com"),
                                   RRType::DS(), response, true));
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 2, 0, NULL,
@@ -2178,7 +2147,7 @@ TEST_F(QueryTest, dsBelowDelegationWithDS) {
 // server.  It should just like the "noZone" test case, but DS query involves
 // special processing, so we test it explicitly.
 TEST_F(QueryTest, dsNoZone) {
-    query.process(list, Name("example"), RRType::DS(), response,
+    query.process(memory_client, Name("example"), RRType::DS(), response,
                   true);
     responseCheck(response, Rcode::REFUSED(), 0, 0, 0, 0, NULL, NULL, NULL);
 }
@@ -2186,7 +2155,7 @@ TEST_F(QueryTest, dsNoZone) {
 // DS query for a "grandchild" zone.  This should result in normal
 // delegation (unless this server also has authority of the grandchild zone).
 TEST_F(QueryTest, dsAtGrandParent) {
-    query.process(list, Name("grand.delegation.example.com"),
+    query.process(memory_client, Name("grand.delegation.example.com"),
                   RRType::DS(), response, true);
     responseCheck(response, Rcode::NOERROR(), 0, 0, 6, 6, NULL,
                   (string(delegation_txt) + string(delegation_ds_txt) +
@@ -2205,7 +2174,7 @@ TEST_F(QueryTest, dsAtGrandParentAndChild) {
     const Name childname("grand.delegation.example.com");
     memory_client.addZone(ZoneFinderPtr(
                               new AlternateZoneFinder(childname)));
-    query.process(list, childname, RRType::DS(), response, true);
+    query.process(memory_client, childname, RRType::DS(), response, true);
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
                   (childname.toText() + " 3600 IN SOA . . 0 0 0 0 0\n" +
                    childname.toText() + " 3600 IN RRSIG " +
@@ -2223,7 +2192,7 @@ TEST_F(QueryTest, dsAtRoot) {
     // Pretend to be a root server.
     memory_client.addZone(ZoneFinderPtr(
                               new AlternateZoneFinder(Name::ROOT_NAME())));
-    query.process(list, Name::ROOT_NAME(), RRType::DS(), response,
+    query.process(memory_client, Name::ROOT_NAME(), RRType::DS(), response,
                   true);
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
                   (string(". 3600 IN SOA . . 0 0 0 0 0\n") +
@@ -2240,7 +2209,7 @@ TEST_F(QueryTest, dsAtRootWithDS) {
     memory_client.addZone(ZoneFinderPtr(
                               new AlternateZoneFinder(Name::ROOT_NAME(),
                                                       true)));
-    query.process(list, Name::ROOT_NAME(), RRType::DS(), response,
+    query.process(memory_client, Name::ROOT_NAME(), RRType::DS(), response,
                   true);
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 2, 0,
                   (string(". 3600 IN DS 57855 5 1 49FD46E6C4B45C55D4AC69CBD"
@@ -2257,7 +2226,7 @@ TEST_F(QueryTest, nxrrsetWithNSEC3) {
 
     // NXRRSET with DNSSEC proof.  We should have SOA, NSEC3 that proves the
     // NXRRSET and their RRSIGs.
-    query.process(list, Name("www.example.com"), RRType::TXT(),
+    query.process(memory_client, Name("www.example.com"), RRType::TXT(),
                   response, true);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
@@ -2280,7 +2249,7 @@ TEST_F(QueryTest, nxrrsetMissingNSEC3) {
                                       ConstRRsetPtr());
     mock_finder->setNSEC3Result(&nsec3);
 
-    EXPECT_THROW(query.process(list, Name("www.example.com"),
+    EXPECT_THROW(query.process(memory_client, Name("www.example.com"),
                                RRType::TXT(), response, true),
                  Query::BadNSEC3);
 }
@@ -2291,7 +2260,7 @@ TEST_F(QueryTest, nxrrsetWithNSEC3_ds_exact) {
 
     // This delegation has no DS, but does have a matching NSEC3 record
     // (See RFC5155 section 7.2.4)
-    query.process(list, Name("unsigned-delegation.example.com."),
+    query.process(memory_client, Name("unsigned-delegation.example.com."),
                   RRType::DS(), response, true);
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
                   (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
@@ -2313,7 +2282,7 @@ TEST_F(QueryTest, nxrrsetWithNSEC3_ds_no_exact) {
     // 'next closer' should have opt-out set, though that is not
     // actually checked)
     // (See RFC5155 section 7.2.4)
-    query.process(list, Name("unsigned-delegation-optout.example.com."),
+    query.process(memory_client, Name("unsigned-delegation-optout.example.com."),
                   RRType::DS(), response, true);
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 6, 0, NULL,
                   (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
@@ -2340,7 +2309,7 @@ TEST_F(QueryTest, nxdomainWithNSEC3Proof) {
     // This will be the covering NSEC3 for the possible wildcard
     mock_finder->addRecord(unsigned_delegation_nsec3_txt);
 
-    query.process(list, Name("nxdomain.example.com"), qtype,
+    query.process(memory_client, Name("nxdomain.example.com"), qtype,
                   response, true);
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 8, 0, NULL,
                   // SOA + its RRSIG
@@ -2375,7 +2344,7 @@ TEST_F(QueryTest, nxdomainWithBadNextNSEC3Proof) {
                                       ConstRRsetPtr());
     mock_finder->setNSEC3Result(&nsec3);
 
-    EXPECT_THROW(query.process(list, Name("nxdomain.example.com"),
+    EXPECT_THROW(query.process(memory_client, Name("nxdomain.example.com"),
                                RRType::TXT(), response, true),
                  Query::BadNSEC3);
 }
@@ -2394,7 +2363,7 @@ TEST_F(QueryTest, nxdomainWithBadWildcardNSEC3Proof) {
                                       ConstRRsetPtr());
     mock_finder->setNSEC3Result(&nsec3, &wname);
 
-    EXPECT_THROW(query.process(list, Name("nxdomain.example.com"), qtype,
+    EXPECT_THROW(query.process(memory_client, Name("nxdomain.example.com"), qtype,
                                response, true),
                  Query::BadNSEC3);
 }
diff --git a/src/bin/auth/tests/testdata/Makefile.am b/src/bin/auth/tests/testdata/Makefile.am
index 7e42b70..c86722f 100644
--- a/src/bin/auth/tests/testdata/Makefile.am
+++ b/src/bin/auth/tests/testdata/Makefile.am
@@ -18,7 +18,6 @@ EXTRA_DIST += shortquestion_fromWire
 EXTRA_DIST += shortresponse_fromWire
 EXTRA_DIST += simplequery_fromWire.spec
 EXTRA_DIST += simpleresponse_fromWire.spec
-EXTRA_DIST += spec.spec
 
 EXTRA_DIST += example.com
 EXTRA_DIST += example.sqlite3
diff --git a/src/bin/auth/tests/testdata/spec.spec b/src/bin/auth/tests/testdata/spec.spec
deleted file mode 100644
index 3e0a822..0000000
--- a/src/bin/auth/tests/testdata/spec.spec
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-    "module_spec": {
-        "module_name": "test"
-    }
-}
-
diff --git a/src/bin/cfgmgr/plugins/Makefile.am b/src/bin/cfgmgr/plugins/Makefile.am
index 4431127..5a4cfef 100644
--- a/src/bin/cfgmgr/plugins/Makefile.am
+++ b/src/bin/cfgmgr/plugins/Makefile.am
@@ -2,13 +2,10 @@ SUBDIRS = tests
 
 EXTRA_DIST = README logging.spec tsig_keys.spec
 
-datasrc.spec: datasrc.spec.pre
-	$(SED) -e "s|@@PKGDATADIR@@|$(pkgdatadir)|" datasrc.spec.pre >$@
-
 config_plugindir = @prefix@/share/@PACKAGE@/config_plugins
-config_plugin_DATA = logging.spec tsig_keys.spec datasrc.spec
+config_plugin_DATA = logging.spec tsig_keys.spec
 
-python_PYTHON = b10logging.py tsig_keys.py datasrc.py
+python_PYTHON = b10logging.py tsig_keys.py
 pythondir = $(config_plugindir)
 
 CLEANFILES = b10logging.pyc tsig_keys.pyc
diff --git a/src/bin/cfgmgr/plugins/datasrc.py b/src/bin/cfgmgr/plugins/datasrc.py
deleted file mode 100644
index f675aba..0000000
--- a/src/bin/cfgmgr/plugins/datasrc.py
+++ /dev/null
@@ -1,36 +0,0 @@
-# Copyright (C) 2012  Internet Systems Consortium.
-#
-# Permission to use, copy, modify, and distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
-# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
-# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
-# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
-# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
-# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
-# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-from isc.config.module_spec import module_spec_from_file
-from isc.util.file import path_search
-from bind10_config import PLUGIN_PATHS
-spec = module_spec_from_file(path_search('datasrc.spec', PLUGIN_PATHS))
-
-def check(config):
-    """
-    Check the configuration.
-    """
-    # TODO: Once we have solved ticket #2051, create the list and
-    # fill it with the configuration. We probably want to have some way
-    # to not load the data sources, just the configuration. It could
-    # be hacked together by subclassing ConfigurableClientList and
-    # having empty getDataSource method. But it looks like a hack and it
-    # won't really check the params configuration.
-    #
-    # For now, we let everything pass.
-    return None
-
-def load():
-    return (spec, check)
diff --git a/src/bin/cfgmgr/plugins/datasrc.spec.pre.in b/src/bin/cfgmgr/plugins/datasrc.spec.pre.in
deleted file mode 100644
index 5bd20bb..0000000
--- a/src/bin/cfgmgr/plugins/datasrc.spec.pre.in
+++ /dev/null
@@ -1,66 +0,0 @@
-{
-    "module_spec": {
-        "module_name": "data_sources",
-        "module_description": "The sources of authoritative DNS data",
-        "config_data": [
-            {
-                "item_name": "classes",
-                "item_type": "named_set",
-                "item_optional": false,
-                "item_default": {
-                    "CH": [
-                        {
-                            "type": "static",
-                            "cache-enable": false,
-                            "params": "@@PKGDATADIR@@/static.zone"
-                        }
-                    ]
-                },
-                "named_set_item_spec": {
-                    "item_name": "class",
-                    "item_type": "list",
-                    "item_optional": false,
-                    "item_default": [],
-                    "list_item_spec": {
-                        "item_name": "source",
-                        "item_type": "map",
-                        "item_optional": false,
-                        "item_default": {},
-                        "map_item_spec": [
-                            {
-                                "item_name": "type",
-                                "item_type": "string",
-                                "item_optional": false,
-                                "item_default": ""
-                            },
-                            {
-                                "item_name": "params",
-                                "item_type": "any",
-                                "item_optional": false,
-                                "item_default": null
-                            },
-                            {
-                                "item_name": "cache-enable",
-                                "item_type": "boolean",
-                                "item_optional": false,
-                                "item_default": false
-                            },
-                            {
-                                "item_name": "cache-zones",
-                                "item_type": "list",
-                                "item_optional": true,
-                                "list_item_spec": {
-                                    "item_name": "zone",
-                                    "item_type": "string",
-                                    "item_optional": false,
-                                    "item_default": ""
-                                }
-                            }
-                        ]
-                    }
-                }
-            }
-        ],
-        "commands": []
-    }
-}
diff --git a/src/bin/cfgmgr/plugins/tests/Makefile.am b/src/bin/cfgmgr/plugins/tests/Makefile.am
index 9b8b925..ffea2d7 100644
--- a/src/bin/cfgmgr/plugins/tests/Makefile.am
+++ b/src/bin/cfgmgr/plugins/tests/Makefile.am
@@ -1,5 +1,5 @@
 PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
-PYTESTS = tsig_keys_test.py logging_test.py datasrc_test.py
+PYTESTS = tsig_keys_test.py logging_test.py
 
 EXTRA_DIST = $(PYTESTS)
 
diff --git a/src/bin/cfgmgr/plugins/tests/datasrc_test.py b/src/bin/cfgmgr/plugins/tests/datasrc_test.py
deleted file mode 100644
index 6047c44..0000000
--- a/src/bin/cfgmgr/plugins/tests/datasrc_test.py
+++ /dev/null
@@ -1,36 +0,0 @@
-# Copyright (C) 2011  Internet Systems Consortium.
-#
-# Permission to use, copy, modify, and distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
-# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
-# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
-# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
-# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
-# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
-# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-# Make sure we can load the module, put it into path
-import sys
-import os
-sys.path.extend(os.environ["B10_TEST_PLUGIN_DIR"].split(':'))
-
-import datasrc
-import unittest
-
-class DatasrcTest(unittest.TestCase):
-    def test_load(self):
-        """
-        Checks the entry point returns the correct values.
-        """
-        (spec, check) = datasrc.load()
-        # It returns the checking function
-        self.assertEqual(check, datasrc.check)
-        # The plugin stores it's spec
-        self.assertEqual(spec, datasrc.spec)
-
-if __name__ == '__main__':
-        unittest.main()
diff --git a/src/bin/cmdctl/cmdctl.py.in b/src/bin/cmdctl/cmdctl.py.in
index 74fc364..4076f4c 100755
--- a/src/bin/cmdctl/cmdctl.py.in
+++ b/src/bin/cmdctl/cmdctl.py.in
@@ -541,7 +541,7 @@ class SecureHTTPServer(socketserver_mixin.NoPollMixIn,
                                       ssl_version = ssl.PROTOCOL_SSLv23)
             return ssl_sock
         except (ssl.SSLError, CmdctlException) as err :
-            logger.info(CMDCTL_SSL_SETUP_FAILURE_USER_DENIED, err)
+            logger.error(CMDCTL_SSL_SETUP_FAILURE_USER_DENIED, err)
             self.close_request(sock)
             # raise socket error to finish the request
             raise socket.error
diff --git a/src/bin/msgq/msgq.xml b/src/bin/msgq/msgq.xml
index fd9518d..fed4c27 100644
--- a/src/bin/msgq/msgq.xml
+++ b/src/bin/msgq/msgq.xml
@@ -20,7 +20,7 @@
 <refentry>
 
   <refentryinfo>
-    <date>August 4, 2010</date>
+    <date>June 25, 2012</date>
   </refentryinfo>
 
   <refmeta>
@@ -92,10 +92,6 @@
     </para>
 
     <para>
-      It listens on 127.0.0.1.
-    </para>
-
-    <para>
       The <command>b10-msgq</command> daemon may be cleanly stopped by
       sending the SIGTERM signal to the process.
       This shutdown does not notify the subscribers.
@@ -168,5 +164,3 @@
  - End:
 -->
 
-
-
diff --git a/src/bin/showtech/.gitignore b/src/bin/showtech/.gitignore
new file mode 100644
index 0000000..f3d5873
--- /dev/null
+++ b/src/bin/showtech/.gitignore
@@ -0,0 +1,2 @@
+/b10-showtech
+/showtech.py
diff --git a/src/bin/showtech/Makefile.am b/src/bin/showtech/Makefile.am
new file mode 100644
index 0000000..cc9923c
--- /dev/null
+++ b/src/bin/showtech/Makefile.am
@@ -0,0 +1,28 @@
+bin_SCRIPTS = b10-showtech
+
+CLEANFILES = b10-showtech showtech.pyc
+
+# this is done here since configure.ac AC_OUTPUT doesn't expand exec_prefix
+b10-showtech: showtech.py
+	$(SED) -e "s|@@PYTHONPATH@@|@pyexecdir@|" showtech.py >$@
+	chmod a+x $@
+
+MAN1_FILES = \
+	b10-showtech.xml
+
+man_MANS = \
+	$(MAN1_FILES:.xml=.1)
+
+if ENABLE_MAN
+
+.xml.1:
+	xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $<
+
+endif
+
+EXTRA_DIST = $(man_MANS) $(MAN1_FILES)
+
+CLEANDIRS = __pycache__
+
+clean-local:
+	rm -rf $(CLEANDIRS)
diff --git a/src/bin/showtech/b10-showtech.1 b/src/bin/showtech/b10-showtech.1
new file mode 100644
index 0000000..b331713
--- /dev/null
+++ b/src/bin/showtech/b10-showtech.1
@@ -0,0 +1,66 @@
+'\" t
+.\"     Title: b10-showtech
+.\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.76.1 <http://docbook.sf.net/>
+.\"      Date: June 26, 2012
+.\"    Manual: BIND10
+.\"    Source: BIND10
+.\"  Language: English
+.\"
+.TH "B10\-SHOWTECH" "1" "June 26, 2012" "BIND10" "BIND10"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+b10-showtech \- BIND 10 system information display tool
+.SH "SYNOPSIS"
+.HP \w'\fBb10\-showtech\fR\ 'u
+\fBb10\-showtech\fR
+.SH "DESCRIPTION"
+.PP
+The
+\fBb10\-showtech\fR
+program collects and outputs a variety of information about the system that BIND 10 is running on\&. This information can be useful to people involved in debugging and technical support\&.
+.SH "ARGUMENTS"
+.PP
+\-h
+.RS 4
+Displays usage instructions\&.
+.RE
+.PP
+\-o \fIoutput\-file\fR
+.RS 4
+If an output file is specified, the output of
+\fBb10\-showtech\fR
+is written to this file\&. By default, the output is written to standard output\&.
+.RE
+.SH "SEE ALSO"
+.PP
+
+\fBbind10\fR(8),
+BIND 10 Guide\&.
+.SH "HISTORY"
+.PP
+The
+\fBb10\-showtech\fR
+daemon was initially implemented by ISC staff in June, 2012\&.
+.SH "COPYRIGHT"
+.br
+Copyright \(co 2012 Internet Systems Consortium, Inc. ("ISC")
+.br
diff --git a/src/bin/showtech/b10-showtech.xml b/src/bin/showtech/b10-showtech.xml
new file mode 100644
index 0000000..fe11ed1
--- /dev/null
+++ b/src/bin/showtech/b10-showtech.xml
@@ -0,0 +1,106 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+               "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
+	       [<!ENTITY mdash "—">]>
+<!--
+ - 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.
+-->
+
+<refentry>
+
+  <refentryinfo>
+    <date>June 26, 2012</date>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>b10-showtech</refentrytitle>
+    <manvolnum>1</manvolnum>
+    <refmiscinfo>BIND10</refmiscinfo>
+  </refmeta>
+
+  <refnamediv>
+    <refname>b10-showtech</refname>
+    <refpurpose>BIND 10 system information display tool</refpurpose>
+  </refnamediv>
+
+  <docinfo>
+    <copyright>
+      <year>2012</year>
+      <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
+    </copyright>
+  </docinfo>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>b10-showtech</command>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>DESCRIPTION</title>
+    <para>
+      The <command>b10-showtech</command> program collects and outputs a
+      variety of information about the system that BIND 10 is running
+      on. This information can be useful to people involved in debugging
+      and technical support.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title>ARGUMENTS</title>
+
+    <variablelist>
+
+      <varlistentry>
+        <term>-h</term>
+        <listitem><para>
+          Displays usage instructions.
+        </para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>-o <replaceable class="parameter">output-file</replaceable></term>
+        <listitem><para>
+          If an output file is specified, the output
+          of <command>b10-showtech</command> is written to this file. By
+          default, the output is written to standard output.
+        </para></listitem>
+      </varlistentry>
+
+    </variablelist>
+
+  </refsect1>
+
+  <refsect1>
+    <title>SEE ALSO</title>
+    <para>
+      <citerefentry>
+        <refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citetitle>BIND 10 Guide</citetitle>.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title>HISTORY</title>
+    <para>
+      The <command>b10-showtech</command> daemon was initially
+      implemented by ISC staff in June, 2012.
+    </para>
+  </refsect1>
+</refentry><!--
+ - Local variables:
+ - mode: sgml
+ - End:
+-->
diff --git a/src/bin/showtech/showtech.py.in b/src/bin/showtech/showtech.py.in
new file mode 100755
index 0000000..5b67847
--- /dev/null
+++ b/src/bin/showtech/showtech.py.in
@@ -0,0 +1,127 @@
+#!@PYTHON@
+
+# Copyright (C) 2012  Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+"""
+BIND 10 showtech program.
+
+"""
+
+import sys; sys.path.append ('@@PYTHONPATH@@')
+import getopt
+import isc.util.process
+from isc.sysinfo import *
+
+isc.util.process.rename()
+
+def usage():
+    print("Usage: %s [-h] [-o <output-file>]" % sys.argv[0], \
+              file=sys.stderr)
+    exit(1)
+
+def main():
+    try:
+        opts, args = getopt.getopt(sys.argv[1:], "o:h", \
+                                       ["output", "help"])
+    except getopt.GetoptError as e:
+        print(str(e))
+        usage()
+        exit(1)
+
+    output_filename = None
+    for option, arg in opts:
+        if option in ("-o", "--output"):
+            output_filename = arg
+        elif option in ("-h", "--help"):
+            usage()
+        else:
+            assert False, "unhandled option"
+
+    if output_filename is None:
+        f = sys.stdout
+    else:
+        f = open(output_filename, 'w')
+
+    s = SysInfoFromFactory()
+
+    f.write('BIND 10 ShowTech tool\n')
+    f.write('=====================\n')
+
+    f.write('\nCPU\n');
+    f.write(' + Number of processors: %d\n' % (s.get_num_processors()))
+    f.write(' + Endianness: %s\n' % (s.get_endianness()))
+
+    f.write('\nPlatform\n');
+    f.write(' + Operating system: %s\n' % (s.get_platform_name()))
+    f.write(' + Distribution: %s\n' % (s.get_platform_distro()))
+    f.write(' + Kernel version: %s\n' % (s.get_platform_version()))
+
+    f.write(' + SMP kernel: ')
+    if s.get_platform_is_smp():
+        f.write('yes')
+    else:
+        f.write('no')
+    f.write('\n')
+
+    f.write(' + Machine name: %s\n' % (s.get_platform_machine()))
+    f.write(' + Hostname: %s\n' % (s.get_platform_hostname()))
+    f.write(' + Uptime: %d seconds\n' % (s.get_uptime()))
+
+    l = s.get_loadavg()
+    f.write(' + Loadavg: %f %f %f\n' % (l[0], l[1], l[2]))
+
+    f.write('\nMemory\n');
+    f.write(' + Total: %d bytes\n' % (s.get_mem_total()))
+    f.write(' + Free: %d bytes\n' % (s.get_mem_free()))
+    f.write(' + Cached: %d bytes\n' % (s.get_mem_cached()))
+    f.write(' + Buffers: %d bytes\n' % (s.get_mem_buffers()))
+    f.write(' + Swap total: %d bytes\n' % (s.get_mem_swap_total()))
+    f.write(' + Swap free: %d bytes\n' % (s.get_mem_swap_free()))
+
+    f.write('\n\nNetwork\n');
+    f.write('-------\n\n');
+
+    f.write('Interfaces\n')
+    f.write('~~~~~~~~~~\n\n')
+
+    f.write(s.get_net_interfaces())
+
+    f.write('\nRouting table\n')
+    f.write('~~~~~~~~~~~~~\n\n')
+    f.write(s.get_net_routing_table())
+
+    f.write('\nStatistics\n')
+    f.write('~~~~~~~~~~\n\n')
+    f.write(s.get_net_stats())
+
+    f.write('\nConnections\n')
+    f.write('~~~~~~~~~~~\n\n')
+    f.write(s.get_net_connections())
+
+    try:
+        if os.getuid() != 0:
+            sys.stderr.write('\n')
+            sys.stderr.write('NOTE: You have to run this program as the root user so that it can\n')
+            sys.stderr.write('      collect all the information it requires. Some information is\n')
+            sys.stderr.write('      only available to the root user.\n\n')
+    except Exception:
+        pass
+
+    if f != sys.stdout:
+        f.close()
+
+if __name__ == '__main__':
+    main()
diff --git a/src/bin/xfrin/xfrin.py.in b/src/bin/xfrin/xfrin.py.in
index 652f870..1f04bee 100755
--- a/src/bin/xfrin/xfrin.py.in
+++ b/src/bin/xfrin/xfrin.py.in
@@ -889,6 +889,10 @@ class XfrinConnection(asyncore.dispatcher):
             req_str = 'IXFR' if request_type == RRType.IXFR() else 'AXFR'
             if check_soa:
                 self._check_soa_serial()
+                self.close()
+                self.init_socket()
+                if not self.connect_to_master():
+                    raise XfrinException('Unable to reconnect to master')
 
             logger.info(XFRIN_XFR_TRANSFER_STARTED, req_str, self.zone_str())
             self._send_query(self._request_type)
diff --git a/src/bin/xfrout/xfrout.py.in b/src/bin/xfrout/xfrout.py.in
index 46ae687..6576432 100755
--- a/src/bin/xfrout/xfrout.py.in
+++ b/src/bin/xfrout/xfrout.py.in
@@ -952,6 +952,9 @@ class XfroutServer:
     def _start_notifier(self):
         datasrc = self._unix_socket_server.get_db_file()
         self._notifier = notify_out.NotifyOut(datasrc)
+        if 'also_notify' in self._config_data:
+            for slave in self._config_data['also_notify']:
+                self._notifier.add_slave(slave['address'], slave['port'])
         self._notifier.dispatcher()
 
     def send_notify(self, zone_name, zone_class):
diff --git a/src/bin/xfrout/xfrout.spec.pre.in b/src/bin/xfrout/xfrout.spec.pre.in
index 30c9d56..dfcc6d9 100644
--- a/src/bin/xfrout/xfrout.spec.pre.in
+++ b/src/bin/xfrout/xfrout.spec.pre.in
@@ -21,6 +21,33 @@
          }
        },
        {
+         "item_name": "also_notify",
+         "item_type": "list",
+         "item_optional": true,
+         "item_default": [],
+         "list_item_spec":
+         {
+             "item_name": "also_notify_element",
+             "item_type": "map",
+             "item_optional": true,
+             "item_default": {},
+             "map_item_spec": [
+               {
+                   "item_name": "address",
+                   "item_type": "string",
+                   "item_optional": false,
+                   "item_default": ""
+               },
+               {
+                   "item_name": "port",
+                   "item_type": "integer",
+                   "item_optional": false,
+                   "item_default": 0
+               }
+             ]
+         }
+       },
+       {
          "item_name": "zone_config",
          "item_type": "list",
          "item_optional": true,
diff --git a/src/lib/config/module_spec.cc b/src/lib/config/module_spec.cc
index 4414c5d..98a991d 100644
--- a/src/lib/config/module_spec.cc
+++ b/src/lib/config/module_spec.cc
@@ -37,7 +37,7 @@ check_leaf_item(ConstElementPtr spec, const std::string& name,
                 Element::types type, bool mandatory)
 {
     if (spec->contains(name)) {
-        if (type == Element::any || spec->get(name)->getType() == type) {
+        if (spec->get(name)->getType() == type) {
             return;
         } else {
             isc_throw(ModuleSpecError,
diff --git a/src/lib/config/tests/ccsession_unittests.cc b/src/lib/config/tests/ccsession_unittests.cc
index 3fca741..e07c5a3 100644
--- a/src/lib/config/tests/ccsession_unittests.cc
+++ b/src/lib/config/tests/ccsession_unittests.cc
@@ -33,7 +33,6 @@ using namespace isc::data;
 using namespace isc::config;
 using namespace isc::cc;
 using namespace std;
-using namespace boost;
 
 namespace {
 std::string
@@ -52,6 +51,7 @@ protected:
                       root_name(isc::log::getRootLoggerName())
     {
         // upon creation of a ModuleCCSession, the class
+
         // sends its specification to the config manager.
         // it expects an ok answer back, so everytime we
         // create a ModuleCCSession, we must set an initial
@@ -740,8 +740,9 @@ protected:
         registerCommand(const string& recipient)
     {
         return (mccs_.groupRecvMsgAsync(
-            bind(&AsyncReceiveCCSessionTest::callback, this, next_flag_ ++, _1,
-                 _2, _3), false, -1, recipient));
+                    boost::bind(&AsyncReceiveCCSessionTest::callback, this,
+                                next_flag_++, _1, _2, _3), false, -1,
+                    recipient));
     }
     /// \brief Convenience function to queue a request to get a reply
     ///     message.
@@ -749,8 +750,8 @@ protected:
         registerReply(int seq)
     {
         return (mccs_.groupRecvMsgAsync(
-            bind(&AsyncReceiveCCSessionTest::callback, this, next_flag_ ++, _1,
-                 _2, _3), true, seq));
+                    boost::bind(&AsyncReceiveCCSessionTest::callback, this,
+                                next_flag_++, _1, _2, _3), true, seq));
     }
     /// \brief Check the next called callback was with this flag
     void called(int flag) {
diff --git a/src/lib/config/tests/module_spec_unittests.cc b/src/lib/config/tests/module_spec_unittests.cc
index d6b9a76..b2ca7b4 100644
--- a/src/lib/config/tests/module_spec_unittests.cc
+++ b/src/lib/config/tests/module_spec_unittests.cc
@@ -110,7 +110,6 @@ TEST(ModuleSpec, SpecfileItems) {
                    "item_default not of type map");
     moduleSpecError("spec15.spec",
                    "badname is not a valid type name");
-    EXPECT_NO_THROW(moduleSpecFromFile(specfile("spec40.spec")));
 }
 
 TEST(ModuleSpec, SpecfileConfigData) {
diff --git a/src/lib/config/tests/testdata/Makefile.am b/src/lib/config/tests/testdata/Makefile.am
index 6b66005..1bf9496 100644
--- a/src/lib/config/tests/testdata/Makefile.am
+++ b/src/lib/config/tests/testdata/Makefile.am
@@ -66,4 +66,3 @@ EXTRA_DIST += spec36.spec
 EXTRA_DIST += spec37.spec
 EXTRA_DIST += spec38.spec
 EXTRA_DIST += spec39.spec
-EXTRA_DIST += spec40.spec
diff --git a/src/lib/config/tests/testdata/spec40.spec b/src/lib/config/tests/testdata/spec40.spec
deleted file mode 100644
index 8e64fa9..0000000
--- a/src/lib/config/tests/testdata/spec40.spec
+++ /dev/null
@@ -1,13 +0,0 @@
-{
-  "module_spec": {
-    "module_name": "Spec40",
-    "config_data": [
-      { "item_name": "item1",
-        "item_type": "any",
-        "item_optional": false,
-        "item_default": "asdf"
-      }
-    ]
-  }
-}
-
diff --git a/src/lib/datasrc/client_list.cc b/src/lib/datasrc/client_list.cc
index e3e2948..e9718d4 100644
--- a/src/lib/datasrc/client_list.cc
+++ b/src/lib/datasrc/client_list.cc
@@ -16,6 +16,7 @@
 #include "client.h"
 #include "factory.h"
 #include "memory_datasrc.h"
+#include "logger.h"
 
 #include <memory>
 #include <boost/foreach.hpp>
@@ -48,19 +49,14 @@ ConfigurableClientList::DataSourceInfo::DataSourceInfo(bool has_cache) :
 }
 
 void
-ConfigurableClientList::configure(const ConstElementPtr& config,
-                                  bool allow_cache)
-{
-    if (!config) {
-        isc_throw(isc::BadValue, "NULL configuration passed");
-    }
+ConfigurableClientList::configure(const Element& config, bool allow_cache) {
     // TODO: Implement recycling from the old configuration.
     size_t i(0); // Outside of the try to be able to access it in the catch
     try {
         vector<DataSourceInfo> new_data_sources;
-        for (; i < config->size(); ++i) {
+        for (; i < config.size(); ++i) {
             // Extract the parameters
-            const ConstElementPtr dconf(config->get(i));
+            const ConstElementPtr dconf(config.get(i));
             const ConstElementPtr typeElem(dconf->get("type"));
             if (typeElem == ConstElementPtr()) {
                 isc_throw(ConfigurationError, "Missing the type option in "
@@ -79,6 +75,15 @@ ConfigurableClientList::configure(const ConstElementPtr& config,
                 // In case the cache is not allowed, we just skip the master
                 // files (at least for now)
                 if (!allow_cache) {
+                    // We're not going to load these zones. Issue warnings about it.
+                    const map<string, ConstElementPtr>
+                        zones_files(paramConf->mapValue());
+                    for (map<string, ConstElementPtr>::const_iterator
+                         it(zones_files.begin()); it != zones_files.end();
+                         ++it) {
+                        LOG_WARN(logger, DATASRC_LIST_NOT_CACHED).
+                            arg(it->first).arg(rrclass_);
+                    }
                     continue;
                 }
                 if (!want_cache) {
@@ -156,49 +161,37 @@ ConfigurableClientList::configure(const ConstElementPtr& config,
         // ready. So just put it there and let the old one die when we exit
         // the scope.
         data_sources_.swap(new_data_sources);
-        configuration_ = config;
     } catch (const TypeError& te) {
         isc_throw(ConfigurationError, "Malformed configuration at data source "
                   "no. " << i << ": " << te.what());
     }
 }
 
-// We have this class as a temporary storage, as the FindResult can't be
-// assigned.
-struct ConfigurableClientList::MutableResult {
-    MutableResult() :
-        datasrc_client(NULL),
-        matched_labels(0),
-        matched(false),
-        exact(false),
-        info(NULL)
-    {}
-    DataSourceClient* datasrc_client;
-    ZoneFinderPtr finder;
-    uint8_t matched_labels;
-    bool matched;
-    bool exact;
-    const DataSourceInfo* info;
-    operator FindResult() const {
-        // Conversion to the right result.
-        return (FindResult(datasrc_client, finder, exact));
-    }
-};
-
 ClientList::FindResult
 ConfigurableClientList::find(const dns::Name& name, bool want_exact_match,
-                             bool want_finder) const
+                            bool) const
 {
-    MutableResult result;
-    findInternal(result, name, want_exact_match, want_finder);
-    return (result);
-}
+    // Nothing found yet.
+    //
+    // We have this class as a temporary storage, as the FindResult can't be
+    // assigned.
+    struct MutableResult {
+        MutableResult() :
+            datasrc_client(NULL),
+            matched_labels(0),
+            matched(false)
+        {}
+        DataSourceClient* datasrc_client;
+        ZoneFinderPtr finder;
+        uint8_t matched_labels;
+        bool matched;
+        operator FindResult() const {
+            // Conversion to the right result. If we return this, there was
+            // a partial match at best.
+            return (FindResult(datasrc_client, finder, false));
+        }
+    } candidate;
 
-void
-ConfigurableClientList::findInternal(MutableResult& candidate,
-                                     const dns::Name& name,
-                                     bool want_exact_match, bool) const
-{
     BOOST_FOREACH(const DataSourceInfo& info, data_sources_) {
         DataSourceClient* client(info.cache_ ? info.cache_.get() :
                                  info.data_src_client_);
@@ -212,12 +205,8 @@ ConfigurableClientList::findInternal(MutableResult& candidate,
 
                 // TODO: In case we have only the datasource and not the finder
                 // and the need_updater parameter is true, get the zone there.
-                candidate.datasrc_client = client;
-                candidate.finder = result.zone_finder;
-                candidate.matched = true;
-                candidate.exact = true;
-                candidate.info = &info;
-                return;
+                return (FindResult(client, result.zone_finder,
+                                   true));
             case result::PARTIALMATCH:
                 if (!want_exact_match) {
                     // In case we have a partial match, check if it is better
@@ -241,7 +230,6 @@ ConfigurableClientList::findInternal(MutableResult& candidate,
                         candidate.finder = result.zone_finder;
                         candidate.matched_labels = labels;
                         candidate.matched = true;
-                        candidate.info = &info;
                     }
                 }
                 break;
@@ -256,6 +244,7 @@ ConfigurableClientList::findInternal(MutableResult& candidate,
 
     // Return the partial match we have. In case we didn't want a partial
     // match, this surely contains the original empty result.
+    return (candidate);
 }
 
 // NOTE: This function is not tested, it would be complicated. However, the
diff --git a/src/lib/datasrc/client_list.h b/src/lib/datasrc/client_list.h
index e4aff6e..75dae74 100644
--- a/src/lib/datasrc/client_list.h
+++ b/src/lib/datasrc/client_list.h
@@ -191,8 +191,7 @@ public:
     ///
     /// \param rrclass For which class the list should work.
     ConfigurableClientList(const isc::dns::RRClass &rrclass) :
-        rrclass_(rrclass),
-        configuration_(new isc::data::ListElement)
+        rrclass_(rrclass)
     {}
     /// \brief Exception thrown when there's an error in configuration.
     class ConfigurationError : public Exception {
@@ -221,44 +220,12 @@ public:
     ///     client.
     /// \throw ConfigurationError if the configuration is invalid in some
     ///     sense.
-    /// \throw BadValue if configuration is NULL
     /// \throw Unexpected if something misbehaves (like the data source
     ///     returning NULL iterator).
     /// \throw NotImplemented if the auto-detection of list of zones is
     ///     needed.
     /// \throw Whatever is propagated from within the data source.
-    void configure(const isc::data::ConstElementPtr& configuration,
-                   bool allow_cache);
-
-    /// \brief Returns the currently active configuration.
-    ///
-    /// In case configure was not called yet, it returns an empty
-    /// list, which corresponds to the default content.
-    const isc::data::ConstElementPtr& getConfiguration() const {
-        return (configuration_);
-    }
-
-    /// \brief Result of the reload() method.
-    enum ReloadResult {
-        CACHE_DISABLED,     ///< The cache is not enabled in this list.
-        ZONE_NOT_CACHED,    ///< Zone exists, but is not cached.
-        ZONE_NOT_FOUND,     ///< No data source in the list provides the zone.
-        ZONE_RELOADED       ///< The zone was successfully reloaded.
-    };
-
-    /// \brief Reloads a cached zone.
-    ///
-    /// This method finds a zone which is loaded into a cache and reloads it.
-    /// This may be used to renew the cache when the underlying data source
-    /// changes.
-    ///
-    /// \param zone The origin of the zone to reload.
-    /// \return A status if the command worked.
-    /// \throw DataSourceError or anything else that the data source
-    ///      containing the zone might throw is propagated.
-    /// \throw DataSourceError if something unexpected happens, like when
-    ///      the original data source no longer contains the cached zone.
-    ReloadResult reload(const dns::Name& zone);
+    void configure(const data::Element& configuration, bool allow_cache);
 
     /// \brief Implementation of the ClientList::find.
     virtual FindResult find(const dns::Name& zone,
@@ -322,19 +289,7 @@ public:
     /// hide it).
     const DataSources& getDataSources() const { return (data_sources_); }
 private:
-    struct MutableResult;
-    /// \brief Internal implementation of find.
-    ///
-    /// The class itself needs to do some internal searches in other methods,
-    /// so the implementation is shared.
-    ///
-    /// The result is returned as parameter because MutableResult is not
-    /// defined in the header file.
-    void findInternal(MutableResult& result, const dns::Name& name,
-                      bool want_exact_match, bool want_finder) const;
     const isc::dns::RRClass rrclass_;
-    /// \brief Currently active configuration.
-    isc::data::ConstElementPtr configuration_;
 };
 
 } // namespace datasrc
diff --git a/src/lib/datasrc/database.cc b/src/lib/datasrc/database.cc
index 61dab39..a8ba55e 100644
--- a/src/lib/datasrc/database.cc
+++ b/src/lib/datasrc/database.cc
@@ -179,8 +179,7 @@ private:
 
 DatabaseClient::Finder::FoundRRsets
 DatabaseClient::Finder::getRRsets(const string& name, const WantedTypes& types,
-                                  bool check_ns, const string* construct_name,
-                                  bool any,
+                                  const string* construct_name, bool any,
                                   DatabaseAccessor::IteratorContextPtr context)
 {
     RRsigStore sig_store;
@@ -204,9 +203,7 @@ DatabaseClient::Finder::getRRsets(const string& name, const WantedTypes& types,
     const Name construct_name_object(*construct_name);
 
     bool seen_cname(false);
-    bool seen_ds(false);
     bool seen_other(false);
-    bool seen_ns(false);
 
     while (context->getNext(columns)) {
         // The domain is not empty
@@ -249,16 +246,12 @@ DatabaseClient::Finder::getRRsets(const string& name, const WantedTypes& types,
 
             if (cur_type == RRType::CNAME()) {
                 seen_cname = true;
-            } else if (cur_type == RRType::NS()) {
-                seen_ns = true;
-            } else if (cur_type == RRType::DS()) {
-                seen_ds = true;
             } else if (cur_type != RRType::RRSIG() &&
                        cur_type != RRType::NSEC3() &&
                        cur_type != RRType::NSEC()) {
                 // NSEC and RRSIG can coexist with anything, otherwise
                 // we've seen something that can't live together with potential
-                // CNAME or NS
+                // CNAME.
                 //
                 // NSEC3 lives in separate namespace from everything, therefore
                 // we just ignore it here for these checks as well.
@@ -278,14 +271,10 @@ DatabaseClient::Finder::getRRsets(const string& name, const WantedTypes& types,
                       RDATA_COLUMN]);
         }
     }
-    if (seen_cname && (seen_other || seen_ns || seen_ds)) {
+    if (seen_cname && seen_other) {
         isc_throw(DataSourceError, "CNAME shares domain " << name <<
                   " with something else");
     }
-    if (check_ns && seen_ns && seen_other) {
-        isc_throw(DataSourceError, "NS shares domain " << name <<
-                  " with something else");
-    }
     // Add signatures to all found RRsets
     for (std::map<RRType, RRsetPtr>::iterator i(result.begin());
          i != result.end(); ++ i) {
@@ -455,20 +444,20 @@ DatabaseClient::Finder::findDelegationPoint(const isc::dns::Name& name,
     for (int i = remove_labels; i > 0; --i) {
         const Name superdomain(name.split(i));
 
-        // Note if this is the origin. (We don't count NS records at the origin
-        // as a delegation so this controls whether NS RRs are included in
-        // the results of some searches.)
-        const bool not_origin = (i != remove_labels);
-
         // Look if there's NS or DNAME at this point of the tree, but ignore
         // the NS RRs at the apex of the zone.
         const FoundRRsets found = getRRsets(superdomain.toText(),
-                                            DELEGATION_TYPES(), not_origin);
+                                            DELEGATION_TYPES());
         if (found.first) {
             // This node contains either NS or DNAME RRs so it does exist.
             const FoundIterator nsi(found.second.find(RRType::NS()));
             const FoundIterator dni(found.second.find(RRType::DNAME()));
 
+            // Note if this is the origin. (We don't count NS records at the
+            // origin as a delegation so this controls whether NS RRs are
+            // included in the results of some searches.)
+            const bool not_origin = (i != remove_labels);
+
             // An optimisation.  We know that there is an exact match for
             // something at this point in the tree so remember it.  If we have
             // to do a wildcard search, as we search upwards through the tree
@@ -477,7 +466,7 @@ DatabaseClient::Finder::findDelegationPoint(const isc::dns::Name& name,
             last_known = superdomain.getLabelCount();
 
             if (glue_ok && !first_ns && not_origin &&
-                    nsi != found.second.end()) {
+                nsi != found.second.end()) {
                 // If we are searching for glue ("glue OK" mode), store the
                 // highest NS record that we find that is not the apex.  This
                 // is another optimisation for later, where we need the
@@ -590,8 +579,9 @@ DatabaseClient::Finder::findWildcardMatch(
         // TODO Add a check for DNAME, as DNAME wildcards are discouraged (see
         // RFC 4592 section 4.4).
         // Search for a match.  The types are the same as with original query.
-        FoundRRsets found = getRRsets(wildcard, final_types, true,
-                                      &construct_name, type == RRType::ANY());
+        const FoundRRsets found = getRRsets(wildcard, final_types,
+                                            &construct_name,
+                                            type == RRType::ANY());
         if (found.first) {
             // Found something - but what?
 
@@ -694,7 +684,7 @@ DatabaseClient::Finder::FindDNSSECContext::probe() {
             // such cases).
             const string origin = finder_.getOrigin().toText();
             const FoundRRsets nsec3_found =
-                finder_.getRRsets(origin, NSEC3PARAM_TYPES(), false);
+                finder_.getRRsets(origin, NSEC3PARAM_TYPES());
             const FoundIterator nfi=
                 nsec3_found.second.find(RRType::NSEC3PARAM());
             is_nsec3_ = (nfi != nsec3_found.second.end());
@@ -705,7 +695,7 @@ DatabaseClient::Finder::FindDNSSECContext::probe() {
             // described in Section 10.4 of RFC 5155.
             if (!is_nsec3_) {
                 const FoundRRsets nsec_found =
-                    finder_.getRRsets(origin, NSEC_TYPES(), false);
+                    finder_.getRRsets(origin, NSEC_TYPES());
                 const FoundIterator nfi =
                     nsec_found.second.find(RRType::NSEC());
                 is_nsec_ = (nfi != nsec_found.second.end());
@@ -757,10 +747,8 @@ DatabaseClient::Finder::FindDNSSECContext::getDNSSECRRset(const Name &name,
     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);
+                                                    NSEC_TYPES());
         const FoundIterator nci = found.second.find(RRType::NSEC());
         if (nci != found.second.end()) {
             return (nci->second);
@@ -984,16 +972,15 @@ DatabaseClient::Finder::findInternal(const Name& name, const RRType& type,
     // - Requested name is a delegation point (NS only but not at the zone
     //   apex - DNAME is ignored here as it redirects DNS names subordinate to
     //   the owner name - the owner name itself is not redirected.)
-    const bool is_origin = (name == getOrigin());
     WantedTypes final_types(FINAL_TYPES());
     final_types.insert(type);
     const FoundRRsets found = getRRsets(name.toText(), final_types,
-                                        !is_origin, NULL,
-                                        type == RRType::ANY());
+                                        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.
+        const bool is_origin = (name == getOrigin());
         return (findOnNameResult(name, type, options, is_origin, found, NULL,
                                  target, dnssec_ctx));
     } else {
@@ -1021,7 +1008,7 @@ DatabaseClient::Finder::findNSEC3(const Name& name, bool recursive) {
     // 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));
+                                           NSEC3PARAM_TYPES()));
     const FoundIterator param(nsec3param.second.find(RRType::NSEC3PARAM()));
     if (!nsec3param.first || param == nsec3param.second.end()) {
         // No NSEC3 params? :-(
@@ -1061,7 +1048,7 @@ DatabaseClient::Finder::findNSEC3(const Name& name, bool recursive) {
         }
 
         const FoundRRsets nsec3(getRRsets(hash + "." + otext, NSEC3_TYPES(),
-                                          false, NULL, false, context));
+                                          NULL, false, context));
 
         if (nsec3.first) {
             // We found an exact match against the current label.
@@ -1086,8 +1073,8 @@ DatabaseClient::Finder::findNSEC3(const Name& name, bool recursive) {
                 arg(labels).arg(prevHash);
             context = accessor_->getNSEC3Records(prevHash, zone_id_);
             const FoundRRsets prev_nsec3(getRRsets(prevHash + "." + otext,
-                                                   NSEC3_TYPES(), false, NULL,
-                                                   false, context));
+                                                   NSEC3_TYPES(), NULL, false,
+                                                   context));
 
             if (!prev_nsec3.first) {
                 isc_throw(DataSourceError, "Hash " + prevHash + " returned "
diff --git a/src/lib/datasrc/database.h b/src/lib/datasrc/database.h
index 8ad1c5b..65ddfcc 100644
--- a/src/lib/datasrc/database.h
+++ b/src/lib/datasrc/database.h
@@ -963,17 +963,14 @@ public:
         ///
         /// \param name Which domain name should be scanned.
         /// \param types List of types the caller is interested in.
-        /// \param check_ns If this is set to true, it checks nothing lives
-        ///     together with NS record (with few little exceptions, like RRSIG
-        ///     or NSEC). This check is meant for non-apex NS records.
         /// \param construct_name If this is NULL, the resulting RRsets have
-        ///     their name set to name. If it is not NULL, it overrides the name
-        ///     and uses this one (this can be used for wildcard synthesized
-        ///     records).
+        ///     their name set to name. If it is not NULL, it overrides the
+        ///     name and uses this one (this can be used for wildcard
+        ///     synthesized records).
         /// \param any If this is true, it records all the types, not only the
         ///     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.
+        ///     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.
@@ -986,7 +983,7 @@ public:
         /// \throw DataSourceError If there's a low-level error with the
         ///     database or the database contains bad data.
         FoundRRsets getRRsets(const std::string& name,
-                              const WantedTypes& types, bool check_ns,
+                              const WantedTypes& types,
                               const std::string* construct_name = NULL,
                               bool any = false,
                               DatabaseAccessor::IteratorContextPtr srcContext =
diff --git a/src/lib/datasrc/datasrc_messages.mes b/src/lib/datasrc/datasrc_messages.mes
index 7e3d5c2..6ae744e 100644
--- a/src/lib/datasrc/datasrc_messages.mes
+++ b/src/lib/datasrc/datasrc_messages.mes
@@ -298,6 +298,13 @@ not contain RRs the requested type.  AN NXRRSET indication is returned.
 A debug message indicating that a query for the given name and RR type is being
 processed.
 
+% DATASRC_LIST_NOT_CACHED zone %1/%2 not cached, cache disabled globally. Will not be available.
+The process disabled caching of RR data completely. However, the given zone
+is provided as a master file and it can be served from memory cache only.
+Therefore, the zone will not be available for this process. If this is
+a problem, you should move the zone to some database backend (sqlite3, for
+example) and use it from there.
+
 % DATASRC_MEM_ADD_RRSET adding RRset '%1/%2' into zone '%3'
 Debug information. An RRset is being added to the in-memory data source.
 
diff --git a/src/lib/datasrc/rbtree.h b/src/lib/datasrc/rbtree.h
index 39646ac..106aaa8 100644
--- a/src/lib/datasrc/rbtree.h
+++ b/src/lib/datasrc/rbtree.h
@@ -1260,6 +1260,9 @@ RBTree<T>::previousNode(RBTreeNodeChain<T>& node_path) const {
             // already, which located the exact node. The rest of the function
             // goes one domain left and returns it for us.
             break;
+        default:
+            // This must not happen as Name::compare() never returns NONE.
+            isc_throw(isc::Unexpected, "Name::compare() returned unexpected result");
     }
 
     // So, the node_path now contains the path to a node we want previous for.
diff --git a/src/lib/datasrc/static.zone.pre b/src/lib/datasrc/static.zone.pre
index 13c0c9d..16a7379 100644
--- a/src/lib/datasrc/static.zone.pre
+++ b/src/lib/datasrc/static.zone.pre
@@ -6,9 +6,7 @@
 ;;
 ;; in the bindctl.
 
-;; This is here mostly for technical reasons.
 BIND.           0   CH  SOA bind. authors.bind. 0 28800 7200 604800 86400
-BIND.           0   CH  NS  BIND.
 
 VERSION.BIND.   0   CH  TXT "@@VERSION_STRING@@"
 ;; HOSTNAME.BIND    0   CH  TXT "localhost"
diff --git a/src/lib/datasrc/tests/client_list_unittest.cc b/src/lib/datasrc/tests/client_list_unittest.cc
index 93d9f67..6036aca 100644
--- a/src/lib/datasrc/tests/client_list_unittest.cc
+++ b/src/lib/datasrc/tests/client_list_unittest.cc
@@ -225,11 +225,6 @@ public:
             "{"
             "   \"type\": \"test_type\","
             "   \"params\": {}"
-            "}]")),
-        config_elem_zones_(Element::fromJSON("["
-            "{"
-            "   \"type\": \"test_type\","
-            "   \"params\": [\"example.org\", \"example.com\", \"noiter.org\"]"
             "}]"))
     {
         for (size_t i(0); i < ds_count; ++ i) {
@@ -240,14 +235,6 @@ public:
                 DataSourceClientContainerPtr(), false));
         }
     }
-    void prepareCache(size_t index, const Name& zone) {
-        const shared_ptr<InMemoryClient> cache(new InMemoryClient());
-        const shared_ptr<InMemoryZoneFinder>
-            finder(new InMemoryZoneFinder(RRClass::IN(), zone));
-        // We leave the zone empty, so we can check it was reloaded.
-        cache->addZone(finder);
-        list_->getDataSources()[index].cache_ = cache;
-    }
     // Check the positive result is as we expect it.
     void positiveResult(const ClientList::FindResult& result,
                         const shared_ptr<MockDataSourceClient>& dsrc,
@@ -316,7 +303,7 @@ public:
     const ClientList::FindResult negativeResult_;
     vector<shared_ptr<MockDataSourceClient> > ds_;
     vector<ConfigurableClientList::DataSourceInfo> ds_info_;
-    const ConstElementPtr config_elem_, config_elem_zones_;
+    const ConstElementPtr config_elem_;
 };
 
 // Test the test itself
@@ -431,10 +418,8 @@ TEST_F(ListTest, multiBestMatch) {
 // Check the configuration is empty when the list is empty
 TEST_F(ListTest, configureEmpty) {
     const ConstElementPtr elem(new ListElement);
-    list_->configure(elem, true);
+    list_->configure(*elem, true);
     EXPECT_TRUE(list_->getDataSources().empty());
-    // Check the exact configuration is preserved
-    EXPECT_EQ(elem, list_->getConfiguration());
 }
 
 // Check we can get multiple data sources and they are in the right order.
@@ -451,12 +436,10 @@ TEST_F(ListTest, configureMulti) {
         "   \"params\": {}"
         "}]"
     ));
-    list_->configure(elem, true);
+    list_->configure(*elem, true);
     EXPECT_EQ(2, list_->getDataSources().size());
     checkDS(0, "type1", "{}", false);
     checkDS(1, "type2", "{}", false);
-    // Check the exact configuration is preserved
-    EXPECT_EQ(elem, list_->getConfiguration());
 }
 
 // Check we can pass whatever we want to the params
@@ -479,7 +462,7 @@ TEST_F(ListTest, configureParams) {
             "   \"cache\": \"off\","
             "   \"params\": ") + *param +
             "}]"));
-        list_->configure(elem, true);
+        list_->configure(*elem, true);
         EXPECT_EQ(1, list_->getDataSources().size());
         checkDS(0, "t", *param, false);
     }
@@ -569,12 +552,12 @@ TEST_F(ListTest, wrongConfig) {
         NULL
     };
     // Put something inside to see it survives the exception
-    list_->configure(config_elem_, true);
+    list_->configure(*config_elem_, true);
     checkDS(0, "test_type", "{}", false);
     for (const char** config(configs); *config; ++config) {
         SCOPED_TRACE(*config);
         ConstElementPtr elem(Element::fromJSON(*config));
-        EXPECT_THROW(list_->configure(elem, true),
+        EXPECT_THROW(list_->configure(*elem, true),
                      ConfigurableClientList::ConfigurationError);
         // Still untouched
         checkDS(0, "test_type", "{}", false);
@@ -588,7 +571,7 @@ TEST_F(ListTest, defaults) {
         "{"
         "   \"type\": \"type1\""
         "}]"));
-    list_->configure(elem, true);
+    list_->configure(*elem, true);
     EXPECT_EQ(1, list_->getDataSources().size());
     checkDS(0, "type1", "null", false);
 }
@@ -596,11 +579,11 @@ TEST_F(ListTest, defaults) {
 // Check we can call the configure multiple times, to change the configuration
 TEST_F(ListTest, reconfigure) {
     const ConstElementPtr empty(new ListElement);
-    list_->configure(config_elem_, true);
+    list_->configure(*config_elem_, true);
     checkDS(0, "test_type", "{}", false);
-    list_->configure(empty, true);
+    list_->configure(*empty, true);
     EXPECT_TRUE(list_->getDataSources().empty());
-    list_->configure(config_elem_, true);
+    list_->configure(*config_elem_, true);
     checkDS(0, "test_type", "{}", false);
 }
 
@@ -610,9 +593,9 @@ TEST_F(ListTest, dataSrcError) {
         "{"
         "   \"type\": \"error\""
         "}]"));
-    list_->configure(config_elem_, true);
+    list_->configure(*config_elem_, true);
     checkDS(0, "test_type", "{}", false);
-    EXPECT_THROW(list_->configure(elem, true), DataSourceError);
+    EXPECT_THROW(list_->configure(*elem, true), DataSourceError);
     checkDS(0, "test_type", "{}", false);
 }
 
@@ -632,7 +615,7 @@ TEST_F(ListTest, configureCacheEmpty) {
         "   \"params\": {}"
         "}]"
     ));
-    list_->configure(elem, true);
+    list_->configure(*elem, true);
     EXPECT_EQ(2, list_->getDataSources().size());
     checkDS(0, "type1", "{}", true);
     checkDS(1, "type2", "{}", false);
@@ -654,7 +637,7 @@ TEST_F(ListTest, configureCacheDisabled) {
         "   \"params\": {}"
         "}]"
     ));
-    list_->configure(elem, false);
+    list_->configure(*elem, false);
     EXPECT_EQ(2, list_->getDataSources().size());
     checkDS(0, "type1", "{}", false);
     checkDS(1, "type2", "{}", false);
@@ -669,7 +652,7 @@ TEST_F(ListTest, cacheZones) {
         "   \"cache-zones\": [\"example.org\", \"example.com\"],"
         "   \"params\": [\"example.org\", \"example.com\", \"exmaple.cz\"]"
         "}]"));
-    list_->configure(elem, true);
+    list_->configure(*elem, true);
     checkDS(0, "type1", "[\"example.org\", \"example.com\", \"exmaple.cz\"]",
             true);
 
@@ -696,7 +679,7 @@ TEST_F(ListTest, cacheZones) {
 // Check the caching handles misbehaviour from the data source and
 // misconfiguration gracefully
 TEST_F(ListTest, badCache) {
-    list_->configure(config_elem_, true);
+    list_->configure(*config_elem_, true);
     checkDS(0, "test_type", "{}", false);
     // First, the zone is not in the data source
     const ConstElementPtr elem1(Element::fromJSON("["
@@ -706,7 +689,7 @@ TEST_F(ListTest, badCache) {
         "   \"cache-zones\": [\"example.org\"],"
         "   \"params\": []"
         "}]"));
-    EXPECT_THROW(list_->configure(elem1, true),
+    EXPECT_THROW(list_->configure(*elem1, true),
                  ConfigurableClientList::ConfigurationError);
     checkDS(0, "test_type", "{}", false);
     // Now, the zone doesn't give an iterator
@@ -717,7 +700,7 @@ TEST_F(ListTest, badCache) {
         "   \"cache-zones\": [\"noiter.org\"],"
         "   \"params\": [\"noiter.org\"]"
         "}]"));
-    EXPECT_THROW(list_->configure(elem2, true), isc::NotImplemented);
+    EXPECT_THROW(list_->configure(*elem2, true), isc::NotImplemented);
     checkDS(0, "test_type", "{}", false);
     // Now, the zone returns NULL iterator
     const ConstElementPtr elem3(Element::fromJSON("["
@@ -727,7 +710,7 @@ TEST_F(ListTest, badCache) {
         "   \"cache-zones\": [\"null.org\"],"
         "   \"params\": [\"null.org\"]"
         "}]"));
-    EXPECT_THROW(list_->configure(elem3, true), isc::Unexpected);
+    EXPECT_THROW(list_->configure(*elem3, true), isc::Unexpected);
     checkDS(0, "test_type", "{}", false);
     // The autodetection of zones is not enabled
     const ConstElementPtr elem4(Element::fromJSON("["
@@ -736,7 +719,7 @@ TEST_F(ListTest, badCache) {
         "   \"cache-enable\": true,"
         "   \"params\": [\"example.org\"]"
         "}]"));
-    EXPECT_THROW(list_->configure(elem4, true), isc::NotImplemented);
+    EXPECT_THROW(list_->configure(*elem4, true), isc::NotImplemented);
     checkDS(0, "test_type", "{}", false);
 }
 
@@ -749,33 +732,19 @@ TEST_F(ListTest, masterFiles) {
         "       \".\": \"" TEST_DATA_DIR "/root.zone\""
         "   }"
         "}]"));
-    list_->configure(elem, true);
+    list_->configure(*elem, true);
 
     // It has only the cache
-    EXPECT_EQ(NULL, list_->getDataSources()[0].data_src_client_);
+    EXPECT_EQ(static_cast<const DataSourceClient*>(NULL),
+              list_->getDataSources()[0].data_src_client_);
 
     // And it can search
     positiveResult(list_->find(Name(".")), ds_[0], Name("."), true, "com",
                    true);
 
     // If cache is not enabled, nothing is loaded
-    list_->configure(elem, false);
+    list_->configure(*elem, false);
     EXPECT_EQ(0, list_->getDataSources().size());
 }
 
-// Test we can reload a zone
-TEST_F(ListTest, reloadSuccess) {
-    list_->configure(config_elem_zones_, true);
-    Name name("example.org");
-    prepareCache(0, name);
-    // Not there yet. It would be NXDOMAIN, but it is in apex and
-    // it returns NXRRSET instead.
-    EXPECT_EQ(ZoneFinder::NXRRSET,
-              list_->find(name).finder_->find(name, RRType::SOA())->code);
-    // Now reload. It should be there now.
-    EXPECT_EQ(ConfigurableClientList::ZONE_RELOADED, list_->reload(name));
-    EXPECT_EQ(ZoneFinder::SUCCESS,
-              list_->find(name).finder_->find(name, RRType::SOA())->code);
-}
-
 }
diff --git a/src/lib/datasrc/tests/database_unittest.cc b/src/lib/datasrc/tests/database_unittest.cc
index c96a1d2..5f18283 100644
--- a/src/lib/datasrc/tests/database_unittest.cc
+++ b/src/lib/datasrc/tests/database_unittest.cc
@@ -168,13 +168,16 @@ const char* const TEST_RECORDS[][5] = {
     {"child.insecdelegation.example.org.", "DS", "3600", "", "DS 5 3 3600 "
      "20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
 
-    // Broken NS
+    // Delegation NS and other ordinary type of RR coexist at the same
+    // name.  This is deviant (except for some special cases like the other
+    // RR could be used for addressing the NS name), but as long as the
+    // other records are hidden behind the delegation for normal queries
+    // it's not necessarily harmful. (so "broken" may be too strong, but we
+    // keep the name since it could be in a chain of sorted names for DNSSEC
+    // processing and renaming them may have other bad effects for tests).
     {"brokenns1.example.org.", "A", "3600", "", "192.0.2.1"},
     {"brokenns1.example.org.", "NS", "3600", "", "ns.example.com."},
 
-    {"brokenns2.example.org.", "NS", "3600", "", "ns.example.com."},
-    {"brokenns2.example.org.", "A", "3600", "", "192.0.2.1"},
-
     // Now double DNAME, to test failure mode
     {"baddname.example.org.", "DNAME", "3600", "", "dname1.example.com."},
     {"baddname.example.org.", "DNAME", "3600", "", "dname2.example.com."},
@@ -2202,15 +2205,23 @@ TYPED_TEST(DatabaseClientTest, findDelegation) {
                               ZoneFinder::FIND_DEFAULT),
                  DataSourceError);
 
-    // Broken NS - it lives together with something else
-    EXPECT_THROW(finder->find(isc::dns::Name("brokenns1.example.org."),
-                              this->qtype_,
-                              ZoneFinder::FIND_DEFAULT),
-                 DataSourceError);
-    EXPECT_THROW(finder->find(isc::dns::Name("brokenns2.example.org."),
-                              this->qtype_,
-                              ZoneFinder::FIND_DEFAULT),
-                 DataSourceError);
+    // NS and other type coexist: deviant and not necessarily harmful.
+    // It should normally just result in DELEGATION; if GLUE_OK is specified,
+    // the other RR should be visible.
+    this->expected_rdatas_.clear();
+    this->expected_rdatas_.push_back("ns.example.com");
+    doFindTest(*finder, Name("brokenns1.example.org"), this->qtype_,
+               RRType::NS(), this->rrttl_, ZoneFinder::DELEGATION,
+               this->expected_rdatas_, this->empty_rdatas_,
+               ZoneFinder::RESULT_DEFAULT);
+
+    this->expected_rdatas_.clear();
+    this->expected_rdatas_.push_back("192.0.2.1");
+    doFindTest(*finder, Name("brokenns1.example.org"), this->qtype_,
+               this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
+               this->expected_rdatas_, this->empty_rdatas_,
+               ZoneFinder::RESULT_DEFAULT, Name("brokenns1.example.org"),
+               ZoneFinder::FIND_GLUE_OK);
 }
 
 TYPED_TEST(DatabaseClientTest, findDS) {
diff --git a/src/lib/datasrc/tests/zone_finder_context_unittest.cc b/src/lib/datasrc/tests/zone_finder_context_unittest.cc
index 50d409e..b3c9b2d 100644
--- a/src/lib/datasrc/tests/zone_finder_context_unittest.cc
+++ b/src/lib/datasrc/tests/zone_finder_context_unittest.cc
@@ -208,13 +208,6 @@ TEST_P(ZoneFinderContextTest, getAdditionalDelegation) {
 TEST_P(ZoneFinderContextTest, getAdditionalDelegationAtZoneCut) {
     // Similar to the previous case, but one of the NS addresses is at the
     // zone cut.
-
-    // XXX: the current database-based data source incorrectly rejects this
-    // setup (see #1771)
-    if (GetParam() == createSQLite3Client) {
-        return;
-    }
-
     ZoneFinderContextPtr ctx = finder_->find(Name("www.b.example.org"),
                                              RRType::SOA());
     EXPECT_EQ(ZoneFinder::DELEGATION, ctx->code);
@@ -316,12 +309,6 @@ TEST_P(ZoneFinderContextTest, getAdditionalMX) {
 }
 
 TEST_P(ZoneFinderContextTest, getAdditionalMXAtZoneCut) {
-    // XXX: the current database-based data source incorrectly rejects this
-    // setup (see #1771)
-    if (GetParam() == createSQLite3Client) {
-        return;
-    }
-
     ZoneFinderContextPtr ctx = finder_->find(Name("mxatcut.example.org."),
                                              RRType::MX());
     EXPECT_EQ(ZoneFinder::SUCCESS, ctx->code);
diff --git a/src/lib/datasrc/zone.h b/src/lib/datasrc/zone.h
index bf4b1ea..c41a2c2 100644
--- a/src/lib/datasrc/zone.h
+++ b/src/lib/datasrc/zone.h
@@ -376,6 +376,16 @@ public:
     ///   RRsets for that name are searched just like the normal case;
     ///   otherwise, if the search has encountered a zone cut, \c DELEGATION
     ///   with the information of the highest zone cut will be returned.
+    ///   Note: the term "glue" in the DNS protocol standard may sometimes
+    ///   cause confusion: some people use this term strictly for an address
+    ///   record (type AAAA or A) for the name used in the RDATA of an NS RR;
+    ///   some others seem to give it broader flexibility.  Nevertheless,
+    ///   in this API the "GLUE OK" simply means the search by find() can
+    ///   continue beyond a zone cut; the derived class implementation does
+    ///   not have to, and should not, check whether the type is an address
+    ///   record or whether the query name is pointed by some NS RR.
+    ///   It's up to the caller with which definition of "glue" the search
+    ///   result with this option should be used.
     /// - \c FIND_DNSSEC Request that DNSSEC data (like NSEC, RRSIGs) are
     ///   returned with the answer. It is allowed for the data source to
     ///   include them even when not requested.
diff --git a/src/lib/dhcp/iface_mgr.cc b/src/lib/dhcp/iface_mgr.cc
index 508413d..ae975d0 100644
--- a/src/lib/dhcp/iface_mgr.cc
+++ b/src/lib/dhcp/iface_mgr.cc
@@ -19,11 +19,14 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <sys/select.h>
+#include <asio.hpp>
 
 #include <dhcp/dhcp4.h>
 #include <dhcp/dhcp6.h>
 #include <dhcp/iface_mgr.h>
 #include <exceptions/exceptions.h>
+#include <asiolink/udp_endpoint.h>
+#include <asiolink/io_error.h>
 #include <util/io/pktinfo_utilities.h>
 
 using namespace std;
@@ -197,7 +200,7 @@ void IfaceMgr::stubDetectIfaces() {
         iface.flag_up_ = true;
         iface.flag_running_ = true;
 
-        // note that we claim that this is not a loopback. iface_mgr tries to open a
+        // Note that we claim that this is not a loopback. iface_mgr tries to open a
         // socket on all interaces that are up, running and not loopback. As this is
         // the only interface we were able to detect, let's pretend this is a normal
         // interface.
@@ -228,8 +231,8 @@ bool IfaceMgr::openSockets4(const uint16_t port) {
     int sock;
     int count = 0;
 
-    for (IfaceCollection::iterator iface=ifaces_.begin();
-         iface!=ifaces_.end();
+    for (IfaceCollection::iterator iface = ifaces_.begin();
+         iface != ifaces_.end();
          ++iface) {
 
         cout << "Trying opening socket on interface " << iface->getFullName() << endl;
@@ -243,18 +246,17 @@ bool IfaceMgr::openSockets4(const uint16_t port) {
         }
 
         AddressCollection addrs = iface->getAddresses();
-
-        for (AddressCollection::iterator addr= addrs.begin();
+        for (AddressCollection::iterator addr = addrs.begin();
              addr != addrs.end();
              ++addr) {
 
-            // skip IPv6 addresses
+            // Skip IPv6 addresses
             if (addr->getFamily() != AF_INET) {
                 continue;
             }
 
             sock = openSocket(iface->getName(), *addr, port);
-            if (sock<0) {
+            if (sock < 0) {
                 cout << "Failed to open unicast socket." << endl;
                 return (false);
             }
@@ -270,8 +272,8 @@ bool IfaceMgr::openSockets6(const uint16_t port) {
     int sock;
     int count = 0;
 
-    for (IfaceCollection::iterator iface=ifaces_.begin();
-         iface!=ifaces_.end();
+    for (IfaceCollection::iterator iface = ifaces_.begin();
+         iface != ifaces_.end();
          ++iface) {
 
         if (iface->flag_loopback_ ||
@@ -281,8 +283,7 @@ bool IfaceMgr::openSockets6(const uint16_t port) {
         }
 
         AddressCollection addrs = iface->getAddresses();
-
-        for (AddressCollection::iterator addr= addrs.begin();
+        for (AddressCollection::iterator addr = addrs.begin();
              addr != addrs.end();
              ++addr) {
 
@@ -292,7 +293,7 @@ bool IfaceMgr::openSockets6(const uint16_t port) {
             }
 
             sock = openSocket(iface->getName(), *addr, port);
-            if (sock<0) {
+            if (sock < 0) {
                 cout << "Failed to open unicast socket." << endl;
                 return (false);
             }
@@ -301,7 +302,7 @@ bool IfaceMgr::openSockets6(const uint16_t port) {
             // works well on Mac OS (and possibly other BSDs), but does not work
             // on Linux.
             if ( !joinMulticast(sock, iface->getName(),
-                                string(ALL_DHCP_RELAY_AGENTS_AND_SERVERS) ) ) {
+                                string(ALL_DHCP_RELAY_AGENTS_AND_SERVERS))) {
                 close(sock);
                 isc_throw(Unexpected, "Failed to join " << ALL_DHCP_RELAY_AGENTS_AND_SERVERS
                           << " multicast group.");
@@ -317,7 +318,7 @@ bool IfaceMgr::openSockets6(const uint16_t port) {
             int sock2 = openSocket(iface->getName(),
                                    IOAddress(ALL_DHCP_RELAY_AGENTS_AND_SERVERS),
                                    port);
-            if (sock2<0) {
+            if (sock2 < 0) {
                 isc_throw(Unexpected, "Failed to open multicast socket on "
                           << " interface " << iface->getFullName());
                 iface->delSocket(sock); // delete previously opened socket
@@ -397,6 +398,117 @@ int IfaceMgr::openSocket(const std::string& ifname, const IOAddress& addr,
     }
 }
 
+int IfaceMgr::openSocketFromIface(const std::string& ifname,
+                                  const uint16_t port,
+                                  const uint8_t family) {
+    // Search for specified interface among detected interfaces.
+    for (IfaceCollection::iterator iface = ifaces_.begin();
+         iface != ifaces_.end();
+         ++iface) {
+
+        if ((iface->getFullName() != ifname) &&
+            (iface->getName() != ifname)) {
+            continue;
+        }
+
+        // Interface is now detected. Search for address on interface
+        // that matches address family (v6 or v4).
+        AddressCollection addrs = iface->getAddresses();
+        AddressCollection::iterator addr_it = addrs.begin();
+        while (addr_it != addrs.end()) {
+            if (addr_it->getFamily() == family) {
+                // We have interface and address so let's open socket.
+                // This may cause isc::Unexpected exception.
+                return (openSocket(iface->getName(), *addr_it, port));
+            }
+            ++addr_it;
+        }
+        // If we are at the end of address collection it means that we found
+        // interface but there is no address for family specified.
+        if (addr_it == addrs.end()) {
+            // Stringify the family value to append it to exception string.
+            std::string family_name("AF_INET");
+            if (family == AF_INET6) {
+                family_name = "AF_INET6";
+            }
+            // We did not find address on the interface.
+            isc_throw(BadValue, "There is no address for interface: "
+                      << ifname << ", port: " << port << ", address "
+                      " family: " << family_name);
+        }
+    }
+    // If we got here it means that we had not found the specified interface.
+    // Otherwise we would have returned from previous exist points.
+    isc_throw(BadValue, "There is no " << ifname << " interface present.");
+}
+
+int IfaceMgr::openSocketFromAddress(const IOAddress& addr,
+                                    const uint16_t port) {
+    // Search through detected interfaces and addresses to match
+    // local address we got.
+    for (IfaceCollection::iterator iface = ifaces_.begin();
+         iface != ifaces_.end();
+         ++iface) {
+
+        AddressCollection addrs = iface->getAddresses();
+
+        for (AddressCollection::iterator addr_it = addrs.begin();
+             addr_it != addrs.end();
+             ++addr_it) {
+
+            // Local address must match one of the addresses
+            // on detected interfaces. If it does, we have
+            // address and interface detected so we can open
+            // socket.
+            if (*addr_it == addr) {
+                // Open socket using local interface, address and port.
+                // This may cause isc::Unexpected exception.
+                return (openSocket(iface->getName(), *addr_it, port));
+            }
+        }
+    }
+    // If we got here it means that we did not find specified address
+    // on any available interface.
+    isc_throw(BadValue, "There is no such address " << addr.toText());
+}
+
+int IfaceMgr::openSocketFromRemoteAddress(const IOAddress& remote_addr,
+                                          const uint16_t port) {
+    // Get local address to be used to connect to remote location.
+    IOAddress local_address(getLocalAddress(remote_addr, port).getAddress());
+    return openSocketFromAddress(local_address, port);
+}
+
+isc::asiolink::IOAddress
+IfaceMgr::getLocalAddress(const IOAddress& remote_addr, const uint16_t port) {
+    // Create remote endpoint, we will be connecting to it.
+    boost::scoped_ptr<const UDPEndpoint>
+        remote_endpoint(static_cast<const UDPEndpoint*>
+                        (UDPEndpoint::create(IPPROTO_UDP, remote_addr, port)));
+    if (!remote_endpoint) {
+        isc_throw(Unexpected, "Unable to create remote endpoint");
+    }
+
+    // Create socket that will be used to connect to remote endpoint.
+    asio::io_service io_service;
+    asio::ip::udp::socket sock(io_service);
+
+    // Try to connect to remote endpoint and check if attempt is successful.
+    asio::error_code err_code;
+    sock.connect(remote_endpoint->getASIOEndpoint(), err_code);
+    if (err_code) {
+        isc_throw(Unexpected,"Failed to connect to remote endpoint.");
+    }
+
+    // Once we are connected socket object holds local endpoint.
+    asio::ip::udp::socket::endpoint_type local_endpoint =
+        sock.local_endpoint();
+    asio::ip::address local_address(local_endpoint.address());
+
+    // Return address of local endpoint.
+    return IOAddress(local_address);
+}
+
 int IfaceMgr::openSocket4(Iface& iface, const IOAddress& addr, uint16_t port) {
 
     cout << "Creating UDP4 socket on " << iface.getFullName()
diff --git a/src/lib/dhcp/iface_mgr.h b/src/lib/dhcp/iface_mgr.h
index 7fa2e85..a40f95c 100644
--- a/src/lib/dhcp/iface_mgr.h
+++ b/src/lib/dhcp/iface_mgr.h
@@ -374,7 +374,58 @@ public:
     /// @return socket descriptor, if socket creation, binding and multicast
     /// group join were all successful.
     int openSocket(const std::string& ifname,
-                   const isc::asiolink::IOAddress& addr, const uint16_t port);
+                   const isc::asiolink::IOAddress& addr,
+                   const uint16_t port);
+
+    /// @brief Opens UDP/IP socket and binds it to interface specified.
+    ///
+    /// This method differs from \ref openSocket in that it does not require
+    /// the specification of a local address to which socket will be bound.
+    /// Instead, the method searches through the addresses on the specified
+    /// interface and selects one that matches the address family.
+    ///
+    /// @param ifname name of the interface
+    /// @param port UDP port
+    /// @param family address family (AF_INET or AF_INET6)
+    /// @return socket descriptor, if socket creation, binding and multicast
+    /// group join were all successful.
+    /// @throw isc::Unexpected if failed to create and bind socket.
+    /// @throw isc::BadValue if there is no address on specified interface
+    /// that belongs to given family.
+    int openSocketFromIface(const std::string& ifname,
+                            const uint16_t port,
+                            const uint8_t family);
+
+    /// @brief Opens UDP/IP socket and binds to address specified
+    ///
+    /// This methods differs from \ref openSocket in that it does not require
+    /// the specification of the interface to which the socket will be bound.
+    ///
+    /// @param addr address to be bound
+    /// @param port UDP port
+    /// @return socket descriptor, if socket creation, binding and multicast
+    /// group join were all successful.
+    /// @throw isc::Unexpected if failed to create and bind socket
+    /// @throw isc::BadValue if specified address is not available on
+    /// any interface
+    int openSocketFromAddress(const isc::asiolink::IOAddress& addr,
+                              const uint16_t port);
+
+    /// @brief Opens UDP/IP socket to be used to connect to remote address
+    ///
+    /// This method identifies the local address to be used to connect to the
+    /// remote address specified as argument.  Once the local address is
+    /// identified, \ref openSocket is called to open a socket and bind it to
+    /// the interface, address and port.
+    ///
+    /// @param remote_addr remote address to connect to
+    /// @param port UDP port
+    /// @return socket descriptor, if socket creation, binding and multicast
+    /// group join were all successful.
+    /// @throw isc::Unexpected if failed to create and bind socket
+    int openSocketFromRemoteAddress(const isc::asiolink::IOAddress& remote_addr,
+                                    const uint16_t port);
+
 
     /// Opens IPv6 sockets on detected interfaces.
     ///
@@ -548,6 +599,23 @@ private:
     joinMulticast(int sock, const std::string& ifname,
                   const std::string& mcast);
 
+    /// @brief Identifies local network address to be used to
+    /// connect to remote address.
+    ///
+    /// This method identifies local network address that can be used
+    /// to connect to remote address specified.
+    /// It first creates socket and makes attempt to connect
+    /// to remote location via this socket. If connection
+    /// is established successfully, the local address to which
+    /// socket is bound is returned.
+    ///
+    /// @param remote_addr remote address to connect to
+    /// @param port port to be used
+    /// @return local address to be used to connect to remote address
+    /// @throw isc::Unexpected if unable to indentify local address
+    isc::asiolink::IOAddress
+    getLocalAddress(const isc::asiolink::IOAddress& remote_addr,
+                    const uint16_t port);
 };
 
 }; // namespace isc::dhcp
diff --git a/src/lib/dhcp/tests/iface_mgr_unittest.cc b/src/lib/dhcp/tests/iface_mgr_unittest.cc
index e7ccb68..df818d8 100644
--- a/src/lib/dhcp/tests/iface_mgr_unittest.cc
+++ b/src/lib/dhcp/tests/iface_mgr_unittest.cc
@@ -19,6 +19,7 @@
 
 #include <unistd.h>
 #include <arpa/inet.h>
+#include <boost/scoped_ptr.hpp>
 #include <gtest/gtest.h>
 
 #include <asiolink/io_address.h>
@@ -31,12 +32,17 @@ using namespace isc;
 using namespace isc::asiolink;
 using namespace isc::dhcp;
 
-// name of loopback interface detection
-const size_t buf_size = 32;
-char LOOPBACK[buf_size] = "lo";
-
 namespace {
 
+// Name of loopback interface detection
+const size_t BUF_SIZE = 32;
+char LOOPBACK[BUF_SIZE] = "lo";
+
+// Ports used during testing
+const uint16_t PORT1 = 10547;   // V6 socket
+const uint16_t PORT2 = 10548;   // V4 socket
+
+
 class NakedIfaceMgr: public IfaceMgr {
     // "naked" Interface Manager, exposes internal fields
 public:
@@ -69,10 +75,10 @@ TEST_F(IfaceMgrTest, loDetect) {
     // is implemented
     if (if_nametoindex("lo") > 0) {
         cout << "This is Linux, using lo as loopback." << endl;
-        snprintf(LOOPBACK, buf_size - 1, "lo");
+        snprintf(LOOPBACK, BUF_SIZE - 1, "lo");
     } else if (if_nametoindex("lo0") > 0) {
         cout << "This is BSD, using lo0 as loopback." << endl;
-        snprintf(LOOPBACK, buf_size - 1, "lo0");
+        snprintf(LOOPBACK, BUF_SIZE - 1, "lo0");
     } else {
         cout << "Failed to detect loopback interface. Neither "
              << "lo nor lo0 worked. I give up." << endl;
@@ -80,7 +86,7 @@ TEST_F(IfaceMgrTest, loDetect) {
     }
 }
 
-// uncomment this test to create packet writer. It will
+// Uncomment this test to create packet writer. It will
 // write incoming DHCPv6 packets as C arrays. That is useful
 // for generating test sequences based on actual traffic
 //
@@ -241,6 +247,78 @@ TEST_F(IfaceMgrTest, sockets6) {
     delete ifacemgr;
 }
 
+TEST_F(IfaceMgrTest, socketsFromIface) {
+    boost::scoped_ptr<NakedIfaceMgr> ifacemgr(new NakedIfaceMgr());
+
+    // Open v6 socket on loopback interface and bind to port
+    int socket1 = 0;
+    EXPECT_NO_THROW(
+        socket1 = ifacemgr->openSocketFromIface(LOOPBACK, PORT1, AF_INET6);
+    );
+    // Socket descriptor must be positive integer
+    EXPECT_GT(socket1, 0);
+    close(socket1);
+
+    // Open v4 socket on loopback interface and bind to different port
+    int socket2 = 0;
+    EXPECT_NO_THROW(
+        socket2 = ifacemgr->openSocketFromIface(LOOPBACK, PORT2, AF_INET);
+    );
+    // socket descriptor must be positive integer
+    EXPECT_GT(socket2, 0);
+    close(socket2);
+
+}
+
+
+TEST_F(IfaceMgrTest, socketsFromAddress) {
+    boost::scoped_ptr<NakedIfaceMgr> ifacemgr(new NakedIfaceMgr());
+
+    // Open v6 socket on loopback interface and bind to port
+    int socket1 = 0;
+    IOAddress loAddr6("::1");
+    EXPECT_NO_THROW(
+        socket1 = ifacemgr->openSocketFromAddress(loAddr6, PORT1);
+    );
+    // socket descriptor must be positive integer
+    EXPECT_GT(socket1, 0);
+    close(socket1);
+
+    // Open v4 socket on loopback interface and bind to different port
+    int socket2 = 0;
+    IOAddress loAddr("127.0.0.1");
+    EXPECT_NO_THROW(
+        socket2 = ifacemgr->openSocketFromAddress(loAddr, PORT2);
+    );
+    // socket descriptor must be positive integer
+    EXPECT_GT(socket2, 0);
+    close(socket2);
+}
+
+TEST_F(IfaceMgrTest, socketsFromRemoteAddress) {
+    boost::scoped_ptr<NakedIfaceMgr> ifacemgr(new NakedIfaceMgr());
+
+    // Open v6 socket to connect to remote address.
+    // Loopback address is the only one that we know
+    // so let's treat it as remote address.
+    int socket1 = 0;
+    IOAddress loAddr6("::1");
+    EXPECT_NO_THROW(
+        socket1 = ifacemgr->openSocketFromRemoteAddress(loAddr6, PORT1);
+    );
+    EXPECT_GT(socket1, 0);
+    close(socket1);
+
+    // Open v4 socket to connect to remote address.
+    int socket2 = 0;
+    IOAddress loAddr("127.0.0.1");
+    EXPECT_NO_THROW(
+        socket2 = ifacemgr->openSocketFromRemoteAddress(loAddr, PORT2);
+    );
+    EXPECT_GT(socket2, 0);
+    close(socket2);
+}
+
 // TODO: disabled due to other naming on various systems
 // (lo in Linux, lo0 in BSD systems)
 TEST_F(IfaceMgrTest, DISABLED_sockets6Mcast) {
diff --git a/src/lib/dns/labelsequence.cc b/src/lib/dns/labelsequence.cc
index 71e0f82..98b13f0 100644
--- a/src/lib/dns/labelsequence.cc
+++ b/src/lib/dns/labelsequence.cc
@@ -23,10 +23,38 @@
 namespace isc {
 namespace dns {
 
-const char*
+LabelSequence::LabelSequence(const uint8_t* data,
+                             const uint8_t* offsets,
+                             size_t offsets_size) : data_(data),
+                                                    offsets_(offsets),
+                                                    offsets_size_(offsets_size),
+                                                    first_label_(0),
+                                                    last_label_(offsets_size_)
+{
+    if (data == NULL || offsets == NULL) {
+        isc_throw(BadValue, "Null pointer passed to LabelSequence constructor");
+    }
+    if (offsets_size == 0) {
+        isc_throw(BadValue, "Zero offsets to LabelSequence constructor");
+    }
+    if (offsets_size > Name::MAX_LABELS) {
+        isc_throw(BadValue, "MAX_LABELS exceeded");
+    }
+    for (size_t cur_offset = 0; cur_offset < offsets_size; ++cur_offset) {
+        if (offsets[cur_offset] > Name::MAX_LABELLEN) {
+            isc_throw(BadValue, "MAX_LABEL_LEN exceeded");
+        }
+        if (cur_offset > 0 && offsets[cur_offset] <= offsets[cur_offset - 1]) {
+            isc_throw(BadValue, "Offset smaller than previous offset");
+        }
+    }
+}
+
+
+const uint8_t*
 LabelSequence::getData(size_t *len) const {
     *len = getDataLength();
-    return (&name_.ndata_[name_.offsets_[first_label_]]);
+    return (&data_[offsets_[first_label_]]);
 }
 
 size_t
@@ -37,32 +65,32 @@ LabelSequence::getDataLength() const {
     // the length for the 'previous' label (the root label) plus
     // one (for the root label zero octet)
     if (isAbsolute()) {
-        return (name_.offsets_[last_label_ - 1] -
-                name_.offsets_[first_label_] + 1);
+        return (offsets_[last_label_ - 1] -
+                offsets_[first_label_] + 1);
     } else {
-        return (name_.offsets_[last_label_] - name_.offsets_[first_label_]);
+        return (offsets_[last_label_] - offsets_[first_label_]);
     }
 }
 
 bool
 LabelSequence::equals(const LabelSequence& other, bool case_sensitive) const {
     size_t len, other_len;
-    const char* data = getData(&len);
-    const char* other_data = other.getData(&other_len);
+    const uint8_t* data = getData(&len);
+    const uint8_t* other_data = other.getData(&other_len);
 
     if (len != other_len) {
         return (false);
     }
     if (case_sensitive) {
-        return (std::strncmp(data, other_data, len) == 0);
+        return (std::memcmp(data, other_data, len) == 0);
     }
 
     // As long as the data was originally validated as (part of) a name,
     // label length must never be a capital ascii character, so we can
     // simply compare them after converting to lower characters.
     for (size_t i = 0; i < len; ++i) {
-        const unsigned char ch = data[i];
-        const unsigned char other_ch = other_data[i];
+        const uint8_t ch = data[i];
+        const uint8_t other_ch = other_data[i];
         if (isc::dns::name::internal::maptolower[ch] !=
             isc::dns::name::internal::maptolower[other_ch]) {
             return (false);
@@ -71,6 +99,92 @@ LabelSequence::equals(const LabelSequence& other, bool case_sensitive) const {
     return (true);
 }
 
+NameComparisonResult
+LabelSequence::compare(const LabelSequence& other,
+                       bool case_sensitive) const {
+    if (isAbsolute() ^ other.isAbsolute()) {
+        return (NameComparisonResult(0, 0, NameComparisonResult::NONE));
+    }
+
+    // Determine the relative ordering under the DNSSEC order relation of
+    // 'this' and 'other', and also determine the hierarchical relationship
+    // of the names.
+
+    unsigned int nlabels = 0;
+    int l1 = last_label_ - first_label_;
+    int l2 = other.last_label_ - other.first_label_;
+    int ldiff = (int)l1 - (int)l2;
+    unsigned int l = (ldiff < 0) ? l1 : l2;
+
+    while (l > 0) {
+        --l;
+        --l1;
+        --l2;
+        size_t pos1 = offsets_[l1 + first_label_];
+        size_t pos2 = other.offsets_[l2 + other.first_label_];
+        unsigned int count1 = data_[pos1++];
+        unsigned int count2 = other.data_[pos2++];
+
+        // We don't support any extended label types including now-obsolete
+        // bitstring labels.
+        assert(count1 <= Name::MAX_LABELLEN && count2 <= Name::MAX_LABELLEN);
+
+        int cdiff = (int)count1 - (int)count2;
+        unsigned int count = (cdiff < 0) ? count1 : count2;
+
+        while (count > 0) {
+            uint8_t label1 = data_[pos1];
+            uint8_t label2 = other.data_[pos2];
+            int chdiff;
+
+            if (case_sensitive) {
+                chdiff = (int)label1 - (int)label2;
+            } else {
+                chdiff = (int)isc::dns::name::internal::maptolower[label1] -
+                         (int)isc::dns::name::internal::maptolower[label2];
+            }
+
+            if (chdiff != 0) {
+                if ((nlabels == 0) &&
+                     (!isAbsolute() ||
+                     ((last_label_ < getLabelCount()) ||
+                      (other.last_label_ < other.getLabelCount())))) {
+                    return (NameComparisonResult(0, 0,
+                                                 NameComparisonResult::NONE));
+                } else {
+                    return (NameComparisonResult(chdiff, nlabels,
+                                                 NameComparisonResult::COMMONANCESTOR));
+                }
+            }
+            --count;
+            ++pos1;
+            ++pos2;
+        }
+        if (cdiff != 0) {
+            if ((nlabels == 0) &&
+                ((last_label_ < getLabelCount()) ||
+                 (other.last_label_ < other.getLabelCount()))) {
+                return (NameComparisonResult(0, 0,
+                                             NameComparisonResult::NONE));
+            } else {
+                return (NameComparisonResult(cdiff, nlabels,
+                                             NameComparisonResult::COMMONANCESTOR));
+            }
+        }
+        ++nlabels;
+    }
+
+    if (ldiff < 0) {
+        return (NameComparisonResult(ldiff, nlabels,
+                                     NameComparisonResult::SUPERDOMAIN));
+    } else if (ldiff > 0) {
+        return (NameComparisonResult(ldiff, nlabels,
+                                     NameComparisonResult::SUBDOMAIN));
+    }
+
+    return (NameComparisonResult(ldiff, nlabels, NameComparisonResult::EQUAL));
+}
+
 void
 LabelSequence::stripLeft(size_t i) {
     if (i >= getLabelCount()) {
@@ -91,20 +205,20 @@ LabelSequence::stripRight(size_t i) {
 
 bool
 LabelSequence::isAbsolute() const {
-    return (last_label_ == name_.offsets_.size());
+    return (last_label_ == offsets_size_);
 }
 
 size_t
 LabelSequence::getHash(bool case_sensitive) const {
     size_t length;
-    const char* s = getData(&length);
+    const uint8_t* s = getData(&length);
     if (length > 16) {
         length = 16;
     }
 
     size_t hash_val = 0;
     while (length > 0) {
-        const unsigned char c = *s++;
+        const uint8_t c = *s++;
         boost::hash_combine(hash_val, case_sensitive ? c :
                             isc::dns::name::internal::maptolower[c]);
         --length;
@@ -112,5 +226,93 @@ LabelSequence::getHash(bool case_sensitive) const {
     return (hash_val);
 }
 
+std::string
+LabelSequence::toText(bool omit_final_dot) const {
+    const uint8_t* np = &data_[offsets_[first_label_]];
+    const uint8_t* np_end = np + getDataLength();
+
+    // use for integrity check
+    unsigned int labels = last_label_ - first_label_;
+    // init with an impossible value to catch error cases in the end:
+    unsigned int count = Name::MAX_LABELLEN + 1;
+
+    // result string: it will roughly have the same length as the wire format
+    // label sequence data.  reserve that length to minimize reallocation.
+    std::string result;
+    result.reserve(getDataLength());
+
+    while (np != np_end) {
+        labels--;
+        count = *np++;
+
+        if (count == 0) {
+            // We've reached the "final dot".  If we've not dumped any
+            // character, the entire label sequence is the root name.
+            // In that case we don't omit the final dot.
+            if (!omit_final_dot || result.empty()) {
+                result.push_back('.');
+            }
+            break;
+        }
+
+        if (count <= Name::MAX_LABELLEN) {
+            assert(np_end - np >= count);
+
+            if (!result.empty()) {
+                // just after a non-empty label.  add a separating dot.
+                result.push_back('.');
+            }
+
+            while (count-- > 0) {
+                const uint8_t c = *np++;
+                switch (c) {
+                case 0x22: // '"'
+                case 0x28: // '('
+                case 0x29: // ')'
+                case 0x2E: // '.'
+                case 0x3B: // ';'
+                case 0x5C: // '\\'
+                    // Special modifiers in zone files.
+                case 0x40: // '@'
+                case 0x24: // '$'
+                    result.push_back('\\');
+                    result.push_back(c);
+                    break;
+                default:
+                    if (c > 0x20 && c < 0x7f) {
+                        // append printable characters intact
+                        result.push_back(c);
+                    } else {
+                        // encode non-printable characters in the form of \DDD
+                        result.push_back(0x5c);
+                        result.push_back(0x30 + ((c / 100) % 10));
+                        result.push_back(0x30 + ((c / 10) % 10));
+                        result.push_back(0x30 + (c % 10));
+                    }
+                }
+            }
+        } else {
+            isc_throw(BadLabelType, "unknown label type in name data");
+        }
+    }
+
+    // We should be at the end of the data and have consumed all labels.
+    assert(np == np_end);
+    assert(labels == 0);
+
+    return (result);
+}
+
+std::string
+LabelSequence::toText() const {
+    return (toText(!isAbsolute()));
+}
+
+std::ostream&
+operator<<(std::ostream& os, const LabelSequence& label_sequence) {
+    os << label_sequence.toText();
+    return (os);
+}
+
 } // end namespace dns
 } // end namespace isc
diff --git a/src/lib/dns/labelsequence.h b/src/lib/dns/labelsequence.h
index b17eeb4..65344e1 100644
--- a/src/lib/dns/labelsequence.h
+++ b/src/lib/dns/labelsequence.h
@@ -21,26 +21,30 @@
 namespace isc {
 namespace dns {
 
-/// \brief Light-weight Accessor to Name object
+/// \brief Light-weight Accessor to data of Name object
 ///
 /// The purpose of this class is to easily match Names and parts of Names,
 /// without needing to copy the underlying data on each label strip.
 ///
-/// It can only work on existing Name objects, and the Name object MUST
+/// It can only work on existing Name objects, or data as provided by the
+/// Name object or another LabelSequence, and the data or Name MUST
 /// remain in scope during the entire lifetime of its associated
 /// LabelSequence(s).
 ///
 /// Upon creation of a LabelSequence, it records the offsets of the
 /// labels in the wireformat data of the Name. When stripLeft() or
 /// stripRight() is called on the LabelSequence, no changes in the
-/// Name's data occur, but the internal pointers of the
+/// original data occur, but the internal pointers of the
 /// LabelSequence are modified.
 ///
 /// LabelSequences can be compared to other LabelSequences, and their
 /// data can be requested (which then points to part of the original
-/// data of the associated Name object).
+/// data of the original Name object).
 ///
 class LabelSequence {
+    // Name calls the private toText(bool) method of LabelSequence.
+    friend std::string Name::toText(bool) const;
+
 public:
     /// \brief Constructs a LabelSequence for the given name
     ///
@@ -50,24 +54,47 @@ public:
     /// to the labels in the Name object).
     ///
     /// \param name The Name to construct a LabelSequence for
-    LabelSequence(const Name& name): name_(name),
+    explicit LabelSequence(const Name& name):
+                                     data_(&name.ndata_[0]),
+                                     offsets_(&name.offsets_[0]),
+                                     offsets_size_(name.offsets_.size()),
                                      first_label_(0),
                                      last_label_(name.getLabelCount())
     {}
 
+    /// \brief Constructs a LabelSequence for the given data
+    ///
+    /// \note The associated data MUST remain in scope during the lifetime
+    /// of this LabelSequence, since only the pointers are copied.
+    ///
+    /// \note No validation is done on the given data upon construction;
+    ///       use with care.
+    ///
+    /// \exception isc::BadValue if basic checks for the input data, or
+    ///            offsets fails.
+    ///
+    /// \param data The raw data for the domain name, in wire format
+    /// \param offsets The offsets of the labels in the domain name data,
+    ///        as given by a Name object or another LabelSequence
+    /// \param offsets_size The size of the offsets data
+    LabelSequence(const uint8_t* data,
+                  const uint8_t* offsets,
+                  size_t offsets_size);
+
     /// \brief Return the wire-format data for this LabelSequence
     ///
-    /// The data, is returned as a pointer to the original wireformat
-    /// data of the original Name object, and the given len value is
+    /// The data is returned as a pointer to (the part of) the original
+    /// wireformat data, from either the original Name object, or the
+    /// raw data given in the constructor, and the given len value is
     /// set to the number of octets that match this labelsequence.
     ///
     /// \note The data pointed to is only valid if the original Name
-    /// object is still in scope
+    /// object or data is still in scope
     ///
     /// \param len Pointer to a size_t where the length of the data
     ///        will be stored (in number of octets)
     /// \return Pointer to the wire-format data of this label sequence
-    const char* getData(size_t* len) const;
+    const uint8_t* getData(size_t* len) const;
 
     /// \brief Return the length of the wire-format data of this LabelSequence
     ///
@@ -80,15 +107,15 @@ public:
     /// versa.
     ///
     /// \note The data pointed to is only valid if the original Name
-    /// object is still in scope
+    /// object or data is still in scope
     ///
     /// \return The length of the data of the label sequence in octets.
     size_t getDataLength() const;
 
-    /// \brief Compares two label sequences.
+    /// \brief Compares two label sequences for equality.
     ///
     /// Performs a (optionally case-insensitive) comparison between this
-    /// LabelSequence and another LabelSequence.
+    /// LabelSequence and another LabelSequence for equality.
     ///
     /// \param other The LabelSequence to compare with
     /// \param case_sensitive If true, comparison is case-insensitive
@@ -96,6 +123,18 @@ public:
     ///         and contain the same data.
     bool equals(const LabelSequence& other, bool case_sensitive = false) const;
 
+    /// \brief Compares two label sequences.
+    ///
+    /// Performs a (optionally case-insensitive) comparison between this
+    /// LabelSequence and another LabelSequence.
+    ///
+    /// \param other The LabelSequence to compare with
+    /// \param case_sensitive If true, comparison is case-insensitive
+    /// \return a <code>NameComparisonResult</code> object representing the
+    /// comparison result.
+    NameComparisonResult compare(const LabelSequence& other,
+                                 bool case_sensitive = false) const;
+
     /// \brief Remove labels from the front of this LabelSequence
     ///
     /// \note No actual memory is changed, this operation merely updates the
@@ -110,7 +149,7 @@ public:
     /// \brief Remove labels from the end of this LabelSequence
     ///
     /// \note No actual memory is changed, this operation merely updates the
-    /// internal pointers based on the offsets in the Name object.
+    /// internal pointers based on the offsets originally provided.
     ///
     /// \exception OutOfRange if i is greater than or equal to the number
     ///           of labels currently pointed to by this LabelSequence
@@ -123,17 +162,38 @@ public:
     /// \return The number of labels
     size_t getLabelCount() const { return (last_label_ - first_label_); }
 
-    /// \brief Returns the original Name object associated with this
-    ///        LabelSequence
+    /// \brief Convert the LabelSequence to a string.
+    ///
+    /// This method returns a <code>std::string</code> object representing the
+    /// LabelSequence as a string.  The returned string ends with a dot
+    /// '.' if the label sequence is absolute.
+    ///
+    /// This function assumes the underlying data is in proper
+    /// uncompressed wire format.  If it finds an unexpected label
+    /// character including compression pointer, an exception of class
+    /// \c BadLabelType will be thrown.  In addition, if resource
+    /// allocation for the result string fails, a corresponding standard
+    /// exception will be thrown.
+    ///
+    /// \return a string representation of the <code>LabelSequence</code>.
+    std::string toText() const;
+
+private:
+    /// \brief Convert the LabelSequence to a string.
     ///
-    /// While the Name should still be in scope during the lifetime of
-    /// the LabelSequence, it can still be useful to have access to it,
-    /// for instance in helper functions that are only passed the
-    /// LabelSequence itself.
+    /// This method is a version of the zero-argument toText() method,
+    /// that accepts a <code>omit_final_dot</code> argument. The
+    /// returned string ends with a dot '.' if
+    /// <code>omit_final_dot</code> is <code>false</code>.
     ///
-    /// \return Reference to the original Name object
-    const Name& getName() const { return (name_); }
+    /// This method is used as a helper for <code>Name::toText()</code>
+    /// only.
+    ///
+    /// \param omit_final_dot whether to omit the trailing dot in the output.
+    /// \return a string representation of the <code>LabelSequence</code>.
+    std::string toText(bool omit_final_dot) const;
 
+public:
     /// \brief Calculate a simple hash for the label sequence.
     ///
     /// This method calculates a hash value for the label sequence as binary
@@ -165,12 +225,31 @@ public:
     bool isAbsolute() const;
 
 private:
-    const Name& name_;
+    const uint8_t* data_;
+    const uint8_t* offsets_;
+    size_t offsets_size_;
     size_t first_label_;
     size_t last_label_;
 };
 
 
+///
+/// \brief Insert the label sequence as a string into stream.
+///
+/// This method convert the \c label_sequence into a string and inserts
+/// it into the output stream \c os.
+///
+/// This function overloads the global operator<< to behave as described in
+/// ostream::operator<< but applied to \c LabelSequence objects.
+///
+/// \param os A \c std::ostream object on which the insertion operation is
+/// performed.
+/// \param label_sequence The \c LabelSequence object output by the operation.
+/// \return A reference to the same \c std::ostream object referenced by
+/// parameter \c os after the insertion operation.
+std::ostream&
+operator<<(std::ostream& os, const LabelSequence& label_sequence);
+
 } // end namespace dns
 } // end namespace isc
 
diff --git a/src/lib/dns/messagerenderer.cc b/src/lib/dns/messagerenderer.cc
index d5c7c69..ca4ea54 100644
--- a/src/lib/dns/messagerenderer.cc
+++ b/src/lib/dns/messagerenderer.cc
@@ -100,8 +100,8 @@ struct NameCompare {
         uint16_t item_label_len = 0;
         for (size_t i = 0; i < item.len_; ++i, ++item_pos) {
             item_pos = nextPosition(*buffer_, item_pos, item_label_len);
-            const unsigned char ch1 = (*buffer_)[item_pos];
-            const unsigned char ch2 = name_buf_->readUint8();
+            const uint8_t ch1 = (*buffer_)[item_pos];
+            const uint8_t ch2 = name_buf_->readUint8();
             if (CASE_SENSITIVE) {
                 if (ch1 != ch2) {
                     return (false);
@@ -293,7 +293,7 @@ MessageRenderer::writeName(const Name& name, const bool compress) {
     LabelSequence sequence(name);
     const size_t nlabels = sequence.getLabelCount();
     size_t data_len;
-    const char* data;
+    const uint8_t* data;
 
     // Find the offset in the offset table whose name gives the longest
     // match against the name to be rendered.
diff --git a/src/lib/dns/name.cc b/src/lib/dns/name.cc
index d642e97..c6f0c23 100644
--- a/src/lib/dns/name.cc
+++ b/src/lib/dns/name.cc
@@ -25,6 +25,7 @@
 #include <dns/name.h>
 #include <dns/name_internal.h>
 #include <dns/messagerenderer.h>
+#include <dns/labelsequence.h>
 
 using namespace std;
 using namespace isc::util;
@@ -75,7 +76,7 @@ const char digitvalue[256] = {
 
 namespace name {
 namespace internal {
-const unsigned char maptolower[] = {
+const uint8_t maptolower[] = {
     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
@@ -126,7 +127,7 @@ typedef enum {
 
     // Unused at this moment.  We'll revisit this when we support master file
     // parser where @ is used to mean an origin name.
-    ft_at                  
+    ft_at
 } ft_state;
 }
 
@@ -147,11 +148,11 @@ Name::Name(const std::string &namestring, bool downcase) {
     bool is_root = false;
     ft_state state = ft_init;
 
-    std::vector<unsigned char> offsets;
+    NameOffsets offsets;
     offsets.reserve(Name::MAX_LABELS);
     offsets.push_back(0);
 
-    std::string ndata;
+    NameString ndata;
     ndata.reserve(Name::MAX_WIRE);
 
     // should we refactor this code using, e.g, the state pattern?  Probably
@@ -310,7 +311,7 @@ typedef enum {
 }
 
 Name::Name(InputBuffer& buffer, bool downcase) {
-    std::vector<unsigned char> offsets;
+    NameOffsets offsets;
     offsets.reserve(Name::MAX_LABELS);
 
     /*
@@ -428,140 +429,13 @@ Name::toWire(AbstractMessageRenderer& renderer) const {
 
 std::string
 Name::toText(bool omit_final_dot) const {
-    if (length_ == 1) {
-        //
-        // Special handling for the root label.  We ignore omit_final_dot.
-        //
-        assert(labelcount_ == 1 && ndata_[0] == '\0');
-        return (".");
-    }
-
-    std::string::const_iterator np = ndata_.begin();
-    std::string::const_iterator np_end = ndata_.end();
-    unsigned int labels = labelcount_; // use for integrity check
-    // init with an impossible value to catch error cases in the end:
-    unsigned int count = MAX_LABELLEN + 1;
-
-    // result string: it will roughly have the same length as the wire format
-    // name data.  reserve that length to minimize reallocation.
-    std::string result;
-    result.reserve(length_);
-
-    while (np != np_end) {
-        labels--;
-        count = *np++;
-
-        if (count == 0) {
-            if (!omit_final_dot) {
-                result.push_back('.');
-            }
-            break;
-        }
-            
-        if (count <= MAX_LABELLEN) {
-            assert(np_end - np >= count);
-
-            if (!result.empty()) {
-                // just after a non-empty label.  add a separating dot.
-                result.push_back('.');
-            }
-
-            while (count-- > 0) {
-                unsigned char c = *np++;
-                switch (c) {
-                case 0x22: // '"'
-                case 0x28: // '('
-                case 0x29: // ')'
-                case 0x2E: // '.'
-                case 0x3B: // ';'
-                case 0x5C: // '\\'
-                    // Special modifiers in zone files.
-                case 0x40: // '@'
-                case 0x24: // '$'
-                    result.push_back('\\');
-                    result.push_back(c);
-                    break;
-                default:
-                    if (c > 0x20 && c < 0x7f) {
-                        // append printable characters intact
-                        result.push_back(c);
-                    } else {
-                        // encode non-printable characters in the form of \DDD
-                        result.push_back(0x5c);
-                        result.push_back(0x30 + ((c / 100) % 10));
-                        result.push_back(0x30 + ((c / 10) % 10));
-                        result.push_back(0x30 + (c % 10));
-                    }
-                }
-            }
-        } else {
-            isc_throw(BadLabelType, "unknown label type in name data");
-        }
-    }
-
-    assert(labels == 0);
-    assert(count == 0);         // a valid name must end with a 'dot'.
-
-    return (result);
+    LabelSequence ls(*this);
+    return (ls.toText(omit_final_dot));
 }
 
 NameComparisonResult
 Name::compare(const Name& other) const {
-    // Determine the relative ordering under the DNSSEC order relation of
-    // 'this' and 'other', and also determine the hierarchical relationship
-    // of the names.
-
-    unsigned int nlabels = 0;
-    unsigned int l1 = labelcount_;
-    unsigned int l2 = other.labelcount_;
-    int ldiff = (int)l1 - (int)l2;
-    unsigned int l = (ldiff < 0) ? l1 : l2;
-
-    while (l > 0) {
-        --l;
-        --l1;
-        --l2;
-        size_t pos1 = offsets_[l1];
-        size_t pos2 = other.offsets_[l2];
-        unsigned int count1 = ndata_[pos1++];
-        unsigned int count2 = other.ndata_[pos2++];
-
-        // We don't support any extended label types including now-obsolete
-        // bitstring labels.
-        assert(count1 <= MAX_LABELLEN && count2 <= MAX_LABELLEN);
-
-        int cdiff = (int)count1 - (int)count2;
-        unsigned int count = (cdiff < 0) ? count1 : count2;
-
-        while (count > 0) {
-            unsigned char label1 = ndata_[pos1];
-            unsigned char label2 = other.ndata_[pos2];
-
-            int chdiff = (int)maptolower[label1] - (int)maptolower[label2];
-            if (chdiff != 0) {
-                return (NameComparisonResult(chdiff, nlabels,
-                                         NameComparisonResult::COMMONANCESTOR));
-            }
-            --count;
-            ++pos1;
-            ++pos2;
-        }
-        if (cdiff != 0) {
-                return (NameComparisonResult(cdiff, nlabels,
-                                         NameComparisonResult::COMMONANCESTOR));
-        }
-        ++nlabels;
-    }
-
-    if (ldiff < 0) {
-        return (NameComparisonResult(ldiff, nlabels,
-                                     NameComparisonResult::SUPERDOMAIN));
-    } else if (ldiff > 0) {
-        return (NameComparisonResult(ldiff, nlabels,
-                                     NameComparisonResult::SUBDOMAIN));
-    }
-
-    return (NameComparisonResult(ldiff, nlabels, NameComparisonResult::EQUAL));
+    return LabelSequence(*this).compare(LabelSequence(other));
 }
 
 bool
@@ -571,15 +445,15 @@ Name::equals(const Name& other) const {
     }
 
     for (unsigned int l = labelcount_, pos = 0; l > 0; --l) {
-        unsigned char count = ndata_[pos];
+        uint8_t count = ndata_[pos];
         if (count != other.ndata_[pos]) {
             return (false);
         }
         ++pos;
 
         while (count-- > 0) {
-            unsigned char label1 = ndata_[pos];
-            unsigned char label2 = other.ndata_[pos];
+            uint8_t label1 = ndata_[pos];
+            uint8_t label2 = other.ndata_[pos];
 
             if (maptolower[label1] != maptolower[label2]) {
                 return (false);
@@ -613,7 +487,7 @@ Name::gthan(const Name& other) const {
 
 bool
 Name::isWildcard() const {
-    return (length_ >= 2 && ndata_[0] == 1 && ndata_[1] == '*'); 
+    return (length_ >= 2 && ndata_[0] == 1 && ndata_[1] == '*');
 }
 
 Name
@@ -663,9 +537,9 @@ Name::reverse() const {
     retname.ndata_.reserve(length_);
 
     // Copy the original name, label by label, from tail to head.
-    vector<unsigned char>::const_reverse_iterator rit0 = offsets_.rbegin();
-    vector<unsigned char>::const_reverse_iterator rit1 = rit0 + 1;
-    string::const_iterator n0 = ndata_.begin();
+    NameOffsets::const_reverse_iterator rit0 = offsets_.rbegin();
+    NameOffsets::const_reverse_iterator rit1 = rit0 + 1;
+    NameString::const_iterator n0 = ndata_.begin();
     retname.offsets_.push_back(0);
     while (rit1 != offsets_.rend()) {
         retname.ndata_.append(n0 + *rit1, n0 + *rit0);
@@ -746,7 +620,7 @@ Name::downcase() {
 
         while (count > 0) {
             ndata_.at(pos) =
-                maptolower[static_cast<unsigned char>(ndata_.at(pos))];
+                maptolower[ndata_.at(pos)];
             ++pos;
             --nlen;
             --count;
@@ -761,5 +635,6 @@ operator<<(std::ostream& os, const Name& name) {
     os << name.toText();
     return (os);
 }
+
 }
 }
diff --git a/src/lib/dns/name.h b/src/lib/dns/name.h
index ef32f90..27186d7 100644
--- a/src/lib/dns/name.h
+++ b/src/lib/dns/name.h
@@ -137,12 +137,13 @@ public:
     /// want to distinguish "com" and "com.", and the current definition would
     /// be more compatible for that purpose.
     /// If, on the other hand, we finally decide we really don't need that
-    /// notion, we'll probably reconsider the design here, too. 
+    /// notion, we'll probably reconsider the design here, too.
     enum NameRelation {
         SUPERDOMAIN = 0,
         SUBDOMAIN = 1,
         EQUAL = 2,
-        COMMONANCESTOR = 3
+        COMMONANCESTOR = 3,
+        NONE = 4
     };
 
     ///
@@ -229,6 +230,11 @@ class Name {
     ///
     //@{
 private:
+    /// \brief Name data string
+    typedef std::basic_string<uint8_t> NameString;
+    /// \brief Name offsets type
+    typedef std::vector<uint8_t> NameOffsets;
+
     /// The default constructor
     ///
     /// This is used internally in the class implementation, but at least at
@@ -399,6 +405,7 @@ public:
     /// comparison result.
     NameComparisonResult compare(const Name& other) const;
 
+public:
     /// \brief Return true iff two names are equal.
     ///
     /// Semantically this could be implemented based on the result of the
@@ -515,7 +522,7 @@ public:
     /// \param first The start position (in labels) of the extracted name
     /// \param n Number of labels of the extracted name
     /// \return A new Name object based on the Name containing <code>n</code>
-    /// labels including and following the <code>first</code> label.  
+    /// labels including and following the <code>first</code> label.
     Name split(unsigned int first, unsigned int n) const;
 
     /// \brief Extract a specified super domain name of Name.
@@ -587,7 +594,7 @@ public:
     /// \brief Reverse the labels of a name
     ///
     /// This method reverses the labels of a name.  For example, if
-    /// \c this is "www.example.com.", this method will return 
+    /// \c this is "www.example.com.", this method will return
     /// "com.example.www."  (This is useful because DNSSEC sort order
     /// is equivalent to a lexical sort of label-reversed names.)
     Name reverse() const;
@@ -679,8 +686,8 @@ public:
     //@}
 
 private:
-    std::string ndata_;
-    std::vector<unsigned char> offsets_;
+    NameString ndata_;
+    NameOffsets offsets_;
     unsigned int length_;
     unsigned int labelcount_;
 };
@@ -707,10 +714,11 @@ Name::ROOT_NAME() {
 /// parameter \c os after the insertion operation.
 std::ostream&
 operator<<(std::ostream& os, const Name& name);
+
 }
 }
 #endif // __NAME_H
 
-// Local Variables: 
+// Local Variables:
 // mode: c++
-// End: 
+// End:
diff --git a/src/lib/dns/name_internal.h b/src/lib/dns/name_internal.h
index e1eab8c..8595df1 100644
--- a/src/lib/dns/name_internal.h
+++ b/src/lib/dns/name_internal.h
@@ -31,7 +31,7 @@ namespace isc {
 namespace dns {
 namespace name {
 namespace internal {
-extern const unsigned char maptolower[];
+extern const uint8_t maptolower[];
 } // end of internal
 } // end of name
 } // end of dns
diff --git a/src/lib/dns/python/name_python.cc b/src/lib/dns/python/name_python.cc
index c24d24d..277595a 100644
--- a/src/lib/dns/python/name_python.cc
+++ b/src/lib/dns/python/name_python.cc
@@ -522,8 +522,9 @@ Name_isWildCard(s_Name* self) {
 
 Py_hash_t
 Name_hash(PyObject* pyself) {
-    s_Name* const self = static_cast<s_Name*>(pyself);
-    return (LabelSequence(*self->cppobj).getHash(false));
+    const s_Name* const self = static_cast<s_Name*>(pyself);
+    return (convertToPyHash<size_t>(
+                LabelSequence(*self->cppobj).getHash(false)));
 }
 
 } // end of unnamed namespace
diff --git a/src/lib/dns/python/pydnspp_common.h b/src/lib/dns/python/pydnspp_common.h
index e9e9359..3cc69c4 100644
--- a/src/lib/dns/python/pydnspp_common.h
+++ b/src/lib/dns/python/pydnspp_common.h
@@ -17,6 +17,9 @@
 
 #include <Python.h>
 
+#include <boost/static_assert.hpp>
+
+#include <climits>  // for CHAR_BIT
 #include <stdexcept>
 #include <string>
 
@@ -48,6 +51,58 @@ int addClassVariable(PyTypeObject& c, const char* name, PyObject* obj);
 #if PY_MINOR_VERSION < 2
 typedef long Py_hash_t;
 #endif
+
+/// \brief Convert a hash value of arbitrary type to a Python hash value.
+///
+/// This templated function is a convenient wrapper to produce a valid hash
+/// value of type Py_hash_t, which is expected to be used as the return value
+/// of a PyTypeObject.tp_hash implementation.  Py_hash_t is a signed integer
+/// the same size as Py_ssize_t.
+///
+/// The major concern is that -1 means an error in tp_hash and so we need to
+/// ensure that this value is never returned.
+///
+/// If the size of the original hash type is small enough, we convert
+/// the original hash value to a value of Py_hash_t, resetting all higher bits
+/// to 0.  Due to the assumption on the sizes, the conversion to HashvalType
+/// is safe, and (after clearing the higher bits) results in a valid positive
+/// value.
+///
+/// If the size of the input and return types is the same, we clear the
+/// highest bit of the original hash so the resulting value will be in a valid
+/// positive range of Py_hash_t.  If the original type is unsigned, there's
+/// probably no better conversion than this because otherwise the conversion
+/// to Py_hash_t could result in an undefined behavior.  If the original type
+/// is signed, this conversion reduces the effective value range of the
+/// original hash.  If this is not desired, the caller should convert it
+/// by itself (note that -1 should be still avoided).
+///
+/// This function does not support the case where the size of the original
+/// hash type is larger than that of Py_hash_t.
+template <typename HashvalType>
+Py_hash_t
+convertToPyHash(HashvalType val) {
+    BOOST_STATIC_ASSERT(sizeof(HashvalType) <= sizeof(Py_hash_t));
+
+    // Some versions of g++ doesn't ignore the impossible case of if/else
+    // below (depending on the size of HashvalType) and triggers a false
+    // warning.
+    // To work around it we use an intermediate mutable variable.
+    // See Trac #1883 for details.
+    size_t hash_val_bits = CHAR_BIT * sizeof(HashvalType);
+
+    if (sizeof(HashvalType) < sizeof(Py_hash_t)) {
+        // The original hash type is small enough.  Do trivial conversion.
+        const Py_hash_t mask = ~(static_cast<Py_hash_t>(-1) << hash_val_bits);
+        return (static_cast<Py_hash_t>(val) & mask);
+    } else {
+        // Clear the highest bit of the original hash so the conversion is
+        // safe and avoids -1.
+        HashvalType mask = ~(static_cast<HashvalType>(1) <<
+                             (hash_val_bits - 1));
+        return (val & mask);
+    }
+}
 } // namespace python
 } // namespace dns
 } // namespace isc
diff --git a/src/lib/dns/python/rrclass_python.cc b/src/lib/dns/python/rrclass_python.cc
index b94dc02..a566f47 100644
--- a/src/lib/dns/python/rrclass_python.cc
+++ b/src/lib/dns/python/rrclass_python.cc
@@ -267,8 +267,8 @@ PyObject* RRClass_ANY(s_RRClass*) {
 
 Py_hash_t
 RRClass_hash(PyObject* pyself) {
-    s_RRClass* const self = static_cast<s_RRClass*>(pyself);
-    return (self->cppobj->getCode());
+    const s_RRClass* const self = static_cast<s_RRClass*>(pyself);
+    return (convertToPyHash<uint16_t>(self->cppobj->getCode()));
 }
 
 } // end anonymous namespace
diff --git a/src/lib/dns/python/rrtype_python.cc b/src/lib/dns/python/rrtype_python.cc
index bf20b7c..97b66d4 100644
--- a/src/lib/dns/python/rrtype_python.cc
+++ b/src/lib/dns/python/rrtype_python.cc
@@ -49,6 +49,7 @@ PyObject* RRType_str(PyObject* self);
 PyObject* RRType_toWire(s_RRType* self, PyObject* args);
 PyObject* RRType_getCode(s_RRType* self);
 PyObject* RRType_richcmp(s_RRType* self, s_RRType* other, int op);
+Py_hash_t RRType_hash(PyObject* pyself);
 PyObject* RRType_NSEC3PARAM(s_RRType *self);
 PyObject* RRType_DNAME(s_RRType *self);
 PyObject* RRType_PTR(s_RRType *self);
@@ -368,6 +369,11 @@ RRType_ANY(s_RRType*) {
     return (RRType_createStatic(RRType::ANY()));
 }
 
+Py_hash_t
+RRType_hash(PyObject* pyself) {
+    const s_RRType* const self = static_cast<s_RRType*>(pyself);
+    return (convertToPyHash<uint16_t>(self->cppobj->getCode()));
+}
 } // end anonymous namespace
 
 namespace isc {
@@ -394,7 +400,7 @@ PyTypeObject rrtype_type = {
     NULL,                               // tp_as_number
     NULL,                               // tp_as_sequence
     NULL,                               // tp_as_mapping
-    NULL,                               // tp_hash
+    RRType_hash,                        // tp_hash
     NULL,                               // tp_call
     RRType_str,                         // tp_str
     NULL,                               // tp_getattro
diff --git a/src/lib/dns/python/tests/rrtype_python_test.py b/src/lib/dns/python/tests/rrtype_python_test.py
index 7135426..4548b50 100644
--- a/src/lib/dns/python/tests/rrtype_python_test.py
+++ b/src/lib/dns/python/tests/rrtype_python_test.py
@@ -116,6 +116,15 @@ class TestModuleSpec(unittest.TestCase):
 
         self.assertFalse(self.rrtype_1 == 1)
 
+    def test_hash(self):
+        # Exploiting the knowledge that the hash value is the numeric class
+        # value, we can predict the comparison result.
+        self.assertEqual(hash(RRType.AAAA()), hash(RRType("AAAA")))
+        self.assertEqual(hash(RRType("aaaa")), hash(RRType("AAAA")))
+        self.assertEqual(hash(RRType(28)), hash(RRType("AAAA")))
+        self.assertNotEqual(hash(RRType.A()), hash(RRType.NS()))
+        self.assertNotEqual(hash(RRType.AAAA()), hash(RRType("Type65535")))
+
     def test_statics(self):
         self.assertEqual(RRType("NSEC3PARAM"), RRType.NSEC3PARAM())
         self.assertEqual(RRType("DNAME"), RRType.DNAME())
diff --git a/src/lib/dns/tests/labelsequence_unittest.cc b/src/lib/dns/tests/labelsequence_unittest.cc
index 98bb99c..bbd52c9 100644
--- a/src/lib/dns/tests/labelsequence_unittest.cc
+++ b/src/lib/dns/tests/labelsequence_unittest.cc
@@ -34,14 +34,21 @@ public:
                           n3("example.org"), n4("foo.bar.test.example"),
                           n5("example.ORG"), n6("ExAmPlE.org"),
                           n7("."), n8("foo.example.org.bar"),
+                          n9("\\000xample.org"),
+                          n10("\\000xample.org"),
+                          n11("\\000xample.com"),
+                          n12("\\000xamplE.com"),
                           ls1(n1), ls2(n2), ls3(n3), ls4(n4), ls5(n5),
-                          ls6(n6), ls7(n7), ls8(n8)
+                          ls6(n6), ls7(n7), ls8(n8),
+                          ls9(n9), ls10(n10), ls11(n11), ls12(n12)
     {};
     // Need to keep names in scope for at least the lifetime of
     // the labelsequences
     Name n1, n2, n3, n4, n5, n6, n7, n8;
+    Name n9, n10, n11, n12;
 
     LabelSequence ls1, ls2, ls3, ls4, ls5, ls6, ls7, ls8;
+    LabelSequence ls9, ls10, ls11, ls12;
 };
 
 // Basic equality tests
@@ -81,6 +88,11 @@ TEST_F(LabelSequenceTest, equals_sensitive) {
     EXPECT_FALSE(ls5.equals(ls6, true));
     EXPECT_FALSE(ls5.equals(ls7, true));
     EXPECT_FALSE(ls5.equals(ls8, true));
+
+    EXPECT_TRUE(ls9.equals(ls10, true));
+    EXPECT_FALSE(ls9.equals(ls11, true));
+    EXPECT_FALSE(ls9.equals(ls12, true));
+    EXPECT_FALSE(ls11.equals(ls12, true));
 }
 
 TEST_F(LabelSequenceTest, equals_insensitive) {
@@ -123,28 +135,261 @@ TEST_F(LabelSequenceTest, equals_insensitive) {
     EXPECT_TRUE(ls5.equals(ls5));
     EXPECT_TRUE(ls5.equals(ls6));
     EXPECT_FALSE(ls5.equals(ls7));
+
+    EXPECT_TRUE(ls9.equals(ls10));
+    EXPECT_FALSE(ls9.equals(ls11));
+    EXPECT_FALSE(ls9.equals(ls12));
+    EXPECT_TRUE(ls11.equals(ls12));
+}
+
+// Compare tests
+TEST_F(LabelSequenceTest, compare) {
+    // "example.org." and "example.org.", case sensitive
+    NameComparisonResult result = ls1.compare(ls3, true);
+    EXPECT_EQ(isc::dns::NameComparisonResult::EQUAL,
+              result.getRelation());
+    EXPECT_EQ(0, result.getOrder());
+    EXPECT_EQ(3, result.getCommonLabels());
+
+    // "example.org." and "example.ORG.", case sensitive
+    result = ls3.compare(ls5, true);
+    EXPECT_EQ(isc::dns::NameComparisonResult::COMMONANCESTOR,
+              result.getRelation());
+    EXPECT_LT(0, result.getOrder());
+    EXPECT_EQ(1, result.getCommonLabels());
+
+    // "example.org." and "example.ORG.", case in-sensitive
+    result = ls3.compare(ls5);
+    EXPECT_EQ(isc::dns::NameComparisonResult::EQUAL,
+              result.getRelation());
+    EXPECT_EQ(0, result.getOrder());
+    EXPECT_EQ(3, result.getCommonLabels());
+
+    Name na("a.example.org");
+    Name nb("b.example.org");
+    LabelSequence lsa(na);
+    LabelSequence lsb(nb);
+
+    // "a.example.org." and "b.example.org.", case in-sensitive
+    result = lsa.compare(lsb);
+    EXPECT_EQ(isc::dns::NameComparisonResult::COMMONANCESTOR,
+              result.getRelation());
+    EXPECT_GT(0, result.getOrder());
+    EXPECT_EQ(3, result.getCommonLabels());
+
+    // "example.org." and "b.example.org.", case in-sensitive
+    lsa.stripLeft(1);
+    result = lsa.compare(lsb);
+    EXPECT_EQ(isc::dns::NameComparisonResult::SUPERDOMAIN,
+              result.getRelation());
+    EXPECT_GT(0, result.getOrder());
+    EXPECT_EQ(3, result.getCommonLabels());
+
+    Name nc("g.f.e.d.c.example.org");
+    LabelSequence lsc(nc);
+
+    // "g.f.e.d.c.example.org." and "b.example.org" (not absolute), case
+    // in-sensitive
+    lsb.stripRight(1);
+    result = lsc.compare(lsb);
+    EXPECT_EQ(isc::dns::NameComparisonResult::NONE,
+              result.getRelation());
+    EXPECT_EQ(0, result.getOrder());
+    EXPECT_EQ(0, result.getCommonLabels());
+
+    // "g.f.e.d.c.example.org." and "example.org.", case in-sensitive
+    result = lsc.compare(ls1);
+    EXPECT_EQ(isc::dns::NameComparisonResult::SUBDOMAIN,
+              result.getRelation());
+    EXPECT_LT(0, result.getOrder());
+    EXPECT_EQ(3, result.getCommonLabels());
+
+    // "e.d.c.example.org." and "example.org.", case in-sensitive
+    lsc.stripLeft(2);
+    result = lsc.compare(ls1);
+    EXPECT_EQ(isc::dns::NameComparisonResult::SUBDOMAIN,
+              result.getRelation());
+    EXPECT_LT(0, result.getOrder());
+    EXPECT_EQ(3, result.getCommonLabels());
+
+    // "example.org." and "example.org.", case in-sensitive
+    lsc.stripLeft(3);
+    result = lsc.compare(ls1);
+    EXPECT_EQ(isc::dns::NameComparisonResult::EQUAL,
+              result.getRelation());
+    EXPECT_EQ(0, result.getOrder());
+    EXPECT_EQ(3, result.getCommonLabels());
+
+    // "." and "example.org.", case in-sensitive
+    lsc.stripLeft(2);
+    result = lsc.compare(ls1);
+    EXPECT_EQ(isc::dns::NameComparisonResult::SUPERDOMAIN,
+              result.getRelation());
+    EXPECT_GT(0, result.getOrder());
+    EXPECT_EQ(1, result.getCommonLabels());
+
+    Name nd("a.b.c.isc.example.org");
+    LabelSequence lsd(nd);
+    Name ne("w.x.y.isc.EXAMPLE.org");
+    LabelSequence lse(ne);
+
+    // "a.b.c.isc.example.org." and "w.x.y.isc.EXAMPLE.org.",
+    // case sensitive
+    result = lsd.compare(lse, true);
+    EXPECT_EQ(isc::dns::NameComparisonResult::COMMONANCESTOR,
+              result.getRelation());
+    EXPECT_LT(0, result.getOrder());
+    EXPECT_EQ(2, result.getCommonLabels());
+
+    // "a.b.c.isc.example.org." and "w.x.y.isc.EXAMPLE.org.",
+    // case in-sensitive
+    result = lsd.compare(lse);
+    EXPECT_EQ(isc::dns::NameComparisonResult::COMMONANCESTOR,
+              result.getRelation());
+    EXPECT_GT(0, result.getOrder());
+    EXPECT_EQ(4, result.getCommonLabels());
+
+    // "isc.example.org." and "isc.EXAMPLE.org.", case sensitive
+    lsd.stripLeft(3);
+    lse.stripLeft(3);
+    result = lsd.compare(lse, true);
+    EXPECT_EQ(isc::dns::NameComparisonResult::COMMONANCESTOR,
+              result.getRelation());
+    EXPECT_LT(0, result.getOrder());
+    EXPECT_EQ(2, result.getCommonLabels());
+
+    // "isc.example.org." and "isc.EXAMPLE.org.", case in-sensitive
+    result = lsd.compare(lse);
+    EXPECT_EQ(isc::dns::NameComparisonResult::EQUAL,
+              result.getRelation());
+    EXPECT_EQ(0, result.getOrder());
+    EXPECT_EQ(4, result.getCommonLabels());
+
+    Name nf("a.b.c.isc.example.org");
+    LabelSequence lsf(nf);
+    Name ng("w.x.y.isc.EXAMPLE.org");
+    LabelSequence lsg(ng);
+
+    // "a.b.c.isc.example.org." and "w.x.y.isc.EXAMPLE.org" (not
+    // absolute), case in-sensitive
+    lsg.stripRight(1);
+    result = lsg.compare(lsf);
+    EXPECT_EQ(isc::dns::NameComparisonResult::NONE,
+              result.getRelation());
+    EXPECT_EQ(0, result.getOrder());
+    EXPECT_EQ(0, result.getCommonLabels());
+
+    // "a.b.c.isc.example.org" (not absolute) and
+    // "w.x.y.isc.EXAMPLE.org" (not absolute), case in-sensitive
+    lsf.stripRight(1);
+    result = lsg.compare(lsf);
+    EXPECT_EQ(isc::dns::NameComparisonResult::COMMONANCESTOR,
+              result.getRelation());
+    EXPECT_LT(0, result.getOrder());
+    EXPECT_EQ(3, result.getCommonLabels());
+
+    // "a.b.c.isc.example" (not absolute) and
+    // "w.x.y.isc.EXAMPLE" (not absolute), case in-sensitive
+    lsf.stripRight(1);
+    lsg.stripRight(1);
+    result = lsg.compare(lsf);
+    EXPECT_EQ(isc::dns::NameComparisonResult::COMMONANCESTOR,
+              result.getRelation());
+    EXPECT_LT(0, result.getOrder());
+    EXPECT_EQ(2, result.getCommonLabels());
+
+    // "a.b.c" (not absolute) and
+    // "w.x.y" (not absolute), case in-sensitive
+    lsf.stripRight(2);
+    lsg.stripRight(2);
+    result = lsg.compare(lsf);
+    EXPECT_EQ(isc::dns::NameComparisonResult::NONE,
+              result.getRelation());
+    EXPECT_EQ(0, result.getOrder());
+    EXPECT_EQ(0, result.getCommonLabels());
+
+    Name nh("aexample.org");
+    LabelSequence lsh(nh);
+    Name ni("bexample.org");
+    LabelSequence lsi(ni);
+
+    // "aexample.org" (not absolute) and
+    // "bexample.org" (not absolute), case in-sensitive
+    lsh.stripRight(1);
+    lsi.stripRight(1);
+    result = lsh.compare(lsi);
+    EXPECT_EQ(isc::dns::NameComparisonResult::COMMONANCESTOR,
+              result.getRelation());
+    EXPECT_GT(0, result.getOrder());
+    EXPECT_EQ(1, result.getCommonLabels());
+
+    // "aexample" (not absolute) and
+    // "bexample" (not absolute), case in-sensitive
+    lsh.stripRight(1);
+    lsi.stripRight(1);
+    result = lsh.compare(lsi);
+    EXPECT_EQ(isc::dns::NameComparisonResult::NONE,
+              result.getRelation());
+    EXPECT_EQ(0, result.getOrder());
+    EXPECT_EQ(0, result.getCommonLabels());
+
+    Name nj("example.org");
+    LabelSequence lsj(nj);
+    Name nk("example.org");
+    LabelSequence lsk(nk);
+
+    // "example.org" (not absolute) and
+    // "example.org" (not absolute), case in-sensitive
+    lsj.stripRight(1);
+    lsk.stripRight(1);
+    result = lsj.compare(lsk);
+    EXPECT_EQ(isc::dns::NameComparisonResult::EQUAL,
+              result.getRelation());
+    EXPECT_EQ(0, result.getOrder());
+    EXPECT_EQ(2, result.getCommonLabels());
+
+    // "example" (not absolute) and
+    // "example" (not absolute), case in-sensitive
+    lsj.stripRight(1);
+    lsk.stripRight(1);
+    result = lsj.compare(lsk);
+    EXPECT_EQ(isc::dns::NameComparisonResult::EQUAL,
+              result.getRelation());
+    EXPECT_EQ(0, result.getOrder());
+    EXPECT_EQ(1, result.getCommonLabels());
 }
 
 void
-getDataCheck(const char* expected_data, size_t expected_len,
+getDataCheck(const uint8_t* expected_data, size_t expected_len,
              const LabelSequence& ls)
 {
     size_t len;
-    const char* data = ls.getData(&len);
+    const uint8_t* data = ls.getData(&len);
     ASSERT_EQ(expected_len, len) << "Expected data: " << expected_data <<
-                                    " name: " << ls.getName().toText();
+                                    ", label sequence: " << ls;
     EXPECT_EQ(expected_len, ls.getDataLength()) <<
         "Expected data: " << expected_data <<
-        " name: " << ls.getName().toText();
+        ", label sequence: " << ls;
     for (size_t i = 0; i < len; ++i) {
-        EXPECT_EQ(expected_data[i], data[i]) << "Difference at pos " << i <<
-                                                ": Expected data: " <<
-                                                expected_data <<
-                                                " name: " <<
-                                                ls.getName().toText();;
+        EXPECT_EQ(expected_data[i], data[i]) <<
+          "Difference at pos " << i << ": Expected data: " << expected_data <<
+          ", label sequence: " << ls;
     }
 }
 
+// Convenient data converter for expected data.  Label data must be of
+// uint8_t*, while it's convenient if we can specify some test data in
+// plain string (which is of char*).  This wrapper converts the latter to
+// the former in a safer way.
+void
+getDataCheck(const char* expected_char_data, size_t expected_len,
+             const LabelSequence& ls)
+{
+    const vector<uint8_t> expected_data(expected_char_data,
+                                        expected_char_data + expected_len);
+    getDataCheck(&expected_data[0], expected_len, ls);
+}
+
 TEST_F(LabelSequenceTest, getData) {
     getDataCheck("\007example\003org\000", 13, ls1);
     getDataCheck("\007example\003com\000", 13, ls2);
@@ -243,7 +488,7 @@ TEST_F(LabelSequenceTest, comparePart) {
 
     // Data comparison
     size_t len;
-    const char* data = ls1.getData(&len);
+    const uint8_t* data = ls1.getData(&len);
     getDataCheck(data, len, ls8);
 }
 
@@ -264,6 +509,84 @@ TEST_F(LabelSequenceTest, isAbsolute) {
     ASSERT_TRUE(ls3.isAbsolute());
 }
 
+TEST_F(LabelSequenceTest, toText) {
+    EXPECT_EQ(".", ls7.toText());
+
+    EXPECT_EQ("example.org.", ls1.toText());
+    ls1.stripLeft(1);
+    EXPECT_EQ("org.", ls1.toText());
+    ls1.stripLeft(1);
+    EXPECT_EQ(".", ls1.toText());
+
+    EXPECT_EQ("example.com.", ls2.toText());
+    ls2.stripRight(1);
+    EXPECT_EQ("example.com", ls2.toText());
+    ls2.stripRight(1);
+    EXPECT_EQ("example", ls2.toText());
+
+    EXPECT_EQ("foo.example.org.bar.", ls8.toText());
+    ls8.stripRight(2);
+    EXPECT_EQ("foo.example.org", ls8.toText());
+
+    EXPECT_EQ(".", ls7.toText());
+    EXPECT_THROW(ls7.stripLeft(1), isc::OutOfRange);
+
+    Name n_long1("012345678901234567890123456789"
+                 "012345678901234567890123456789012."
+                 "012345678901234567890123456789"
+                 "012345678901234567890123456789012."
+                 "012345678901234567890123456789"
+                 "012345678901234567890123456789012."
+                 "012345678901234567890123456789"
+                 "0123456789012345678901234567890");
+    LabelSequence ls_long1(n_long1);
+
+    EXPECT_EQ("012345678901234567890123456789"
+              "012345678901234567890123456789012."
+              "012345678901234567890123456789"
+              "012345678901234567890123456789012."
+              "012345678901234567890123456789"
+              "012345678901234567890123456789012."
+              "012345678901234567890123456789"
+              "0123456789012345678901234567890.", ls_long1.toText());
+    ls_long1.stripRight(1);
+    EXPECT_EQ("012345678901234567890123456789"
+              "012345678901234567890123456789012."
+              "012345678901234567890123456789"
+              "012345678901234567890123456789012."
+              "012345678901234567890123456789"
+              "012345678901234567890123456789012."
+              "012345678901234567890123456789"
+              "0123456789012345678901234567890", ls_long1.toText());
+
+    Name n_long2("0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
+                 "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
+                 "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
+                 "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
+                 "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
+                 "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
+                 "0.1.2.3.4.5.6");
+    LabelSequence ls_long2(n_long2);
+
+    EXPECT_EQ("0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
+              "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
+              "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
+              "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
+              "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
+              "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
+              "0.1.2.3.4.5.6.", ls_long2.toText());
+    ls_long2.stripRight(1);
+    EXPECT_EQ("0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
+              "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
+              "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
+              "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
+              "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
+              "0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9."
+              "0.1.2.3.4.5.6", ls_long2.toText());
+    ls_long2.stripRight(125);
+    EXPECT_EQ("0.1", ls_long2.toText());
+}
+
 // The following are test data used in the getHash test below.  Normally
 // we use example/documentation domain names for testing, but in this case
 // we'd specifically like to use more realistic data, and are intentionally
@@ -345,4 +668,85 @@ TEST_F(LabelSequenceTest, getHash) {
     hashDistributionCheck(ca_servers);
 }
 
+// test operator<<.  We simply confirm it appends the result of toText().
+TEST_F(LabelSequenceTest, LeftShiftOperator) {
+    ostringstream oss;
+    oss << ls1;
+    EXPECT_EQ(ls1.toText(), oss.str());
+}
+
+// Test different ways of construction, and see if they compare
+TEST(LabelSequence, rawConstruction) {
+    Name n("example.org");
+
+    uint8_t data[] = { 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e',
+                       0x03, 'o', 'r', 'g',
+                       0x00 };
+    uint8_t offsets[] = { 0, 8, 12 };
+    size_t offsets_size = 3;
+
+    LabelSequence s1(n);
+    LabelSequence s2(s1);
+    LabelSequence s3(data, offsets, offsets_size);
+
+    // Assuming equality is transitive, so only comparing 1 to 2 and 1 to 3
+    NameComparisonResult result = s1.compare(s2);
+    EXPECT_EQ(isc::dns::NameComparisonResult::EQUAL,
+              result.getRelation());
+    EXPECT_EQ(0, result.getOrder());
+    EXPECT_EQ(3, result.getCommonLabels());
+
+    result = s1.compare(s3);
+    EXPECT_EQ(isc::dns::NameComparisonResult::EQUAL,
+              result.getRelation());
+    EXPECT_EQ(0, result.getOrder());
+    EXPECT_EQ(3, result.getCommonLabels());
+
+    // Modify the data and make sure it's not equal anymore
+    data[2] = 'f';
+    result = s1.compare(s3);
+    EXPECT_EQ(isc::dns::NameComparisonResult::COMMONANCESTOR,
+              result.getRelation());
+    EXPECT_EQ(2, result.getCommonLabels());
+
+    s1.stripRight(1);
+    s3.stripRight(1);
+
+    result = s1.compare(s3);
+    EXPECT_EQ(isc::dns::NameComparisonResult::COMMONANCESTOR,
+              result.getRelation());
+    EXPECT_EQ(1, result.getCommonLabels());
+
+    data[9] = 'f';
+    result = s1.compare(s3);
+    EXPECT_EQ(isc::dns::NameComparisonResult::NONE,
+              result.getRelation());
+    EXPECT_EQ(0, result.getCommonLabels());
+}
+
+// Test with some data that exceeds limits (MAX_LABELS and MAX_LABEL_LEN)
+TEST(LabelSequence, badRawConstruction) {
+    uint8_t data[1] = { 0 };
+    uint8_t offsets[1] = { 0 };
+
+    EXPECT_THROW(LabelSequence(NULL, offsets, 1), isc::BadValue);
+    EXPECT_THROW(LabelSequence(data, NULL, 1), isc::BadValue);
+    EXPECT_THROW(LabelSequence(data, offsets, 0), isc::BadValue);
+
+    // exceed MAX_LABELS
+    EXPECT_THROW(LabelSequence(data, offsets, 127), isc::BadValue);
+
+    // exceed MAX_LABEL_LEN
+    uint8_t offsets_toolonglabel[1] = { 64 };
+    EXPECT_THROW(LabelSequence(data, offsets_toolonglabel, 1), isc::BadValue);
+
+    // Add an offset that is lower than the previous offset
+    uint8_t offsets_lower[3] = { 0, 8, 4 };
+    EXPECT_THROW(LabelSequence(data, offsets_lower, 3), isc::BadValue);
+
+    // Add an offset that is equal to the previous offset
+    uint8_t offsets_noincrease[3] = { 0, 8, 8 };
+    EXPECT_THROW(LabelSequence(data, offsets_noincrease, 3), isc::BadValue);
+}
+
 }
diff --git a/src/lib/python/isc/Makefile.am b/src/lib/python/isc/Makefile.am
index 80fd222..e072de8 100644
--- a/src/lib/python/isc/Makefile.am
+++ b/src/lib/python/isc/Makefile.am
@@ -1,5 +1,5 @@
 SUBDIRS = datasrc cc config dns log net notify util testutils acl bind10
-SUBDIRS += xfrin log_messages server_common ddns
+SUBDIRS += xfrin log_messages server_common ddns sysinfo
 
 python_PYTHON = __init__.py
 
diff --git a/src/lib/python/isc/datasrc/configurableclientlist_python.cc b/src/lib/python/isc/datasrc/configurableclientlist_python.cc
new file mode 100644
index 0000000..ada7276
--- /dev/null
+++ b/src/lib/python/isc/datasrc/configurableclientlist_python.cc
@@ -0,0 +1,191 @@
+// 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.
+
+// Enable this if you use s# variants with PyArg_ParseTuple(), see
+// http://docs.python.org/py3k/c-api/arg.html#strings-and-buffers
+//#define PY_SSIZE_T_CLEAN
+
+// Python.h needs to be placed at the head of the program file, see:
+// http://docs.python.org/py3k/extending/extending.html#a-simple-example
+#include <Python.h>
+
+#include <string>
+#include <stdexcept>
+
+#include <util/python/pycppwrapper_util.h>
+
+#include <dns/python/rrclass_python.h>
+
+#include <datasrc/client_list.h>
+
+#include "configurableclientlist_python.h"
+
+using namespace std;
+using namespace isc::util::python;
+using namespace isc::datasrc;
+using namespace isc::datasrc::python;
+
+//
+// ConfigurableClientList
+//
+
+// Trivial constructor.
+s_ConfigurableClientList::s_ConfigurableClientList() : cppobj(NULL) {
+}
+
+namespace {
+// Shortcut type which would be convenient for adding class variables safely.
+typedef CPPPyObjectContainer<s_ConfigurableClientList, ConfigurableClientList>
+    ConfigurableClientListContainer;
+
+int
+ConfigurableClientList_init(PyObject* po_self, PyObject* args, PyObject*) {
+    s_ConfigurableClientList* self =
+        static_cast<s_ConfigurableClientList*>(po_self);
+    try {
+        isc::dns::RRClass rrclass;
+        if (PyArg_ParseTuple(args, "O!", &rrclass_type, &rrclass)) {
+            self->cppobj = new ConfigurableClientList(rrclass);
+            return (0);
+        }
+    } catch (const exception& ex) {
+        const string ex_what = "Failed to construct ConfigurableClientList object: " +
+            string(ex.what());
+        PyErr_SetString(po_IscException, ex_what.c_str());
+        return (-1);
+    } catch (...) {
+        PyErr_SetString(PyExc_SystemError, "Unexpected C++ exception");
+        return (-1);
+    }
+
+    return (-1);
+}
+
+void
+ConfigurableClientList_destroy(PyObject* po_self) {
+    s_ConfigurableClientList* self =
+        static_cast<s_ConfigurableClientList*>(po_self);
+    delete self->cppobj;
+    self->cppobj = NULL;
+    Py_TYPE(self)->tp_free(self);
+}
+
+// This list contains the actual set of functions we have in
+// python. Each entry has
+// 1. Python method name
+// 2. Our static function here
+// 3. Argument type
+// 4. Documentation
+PyMethodDef ConfigurableClientList_methods[] = {
+    { NULL, NULL, 0, NULL }
+};
+} // end of unnamed namespace
+
+namespace isc {
+namespace datasrc {
+namespace python {
+// This defines the complete type for reflection in python and
+// parsing of PyObject* to s_ConfigurableClientList
+// Most of the functions are not actually implemented and NULL here.
+PyTypeObject configurableclientlist_type = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "datasrc.ConfigurableClientList",
+    sizeof(s_ConfigurableClientList),                 // tp_basicsize
+    0,                                  // tp_itemsize
+    ConfigurableClientList_destroy,                 // tp_dealloc
+    NULL,                               // tp_print
+    NULL,                               // tp_getattr
+    NULL,                               // tp_setattr
+    NULL,                               // tp_reserved
+    NULL,                               // tp_repr
+    NULL,                               // tp_as_number
+    NULL,                               // tp_as_sequence
+    NULL,                               // tp_as_mapping
+    NULL,                               // tp_hash
+    NULL,                               // tp_call
+    NULL,                               // tp_str
+    NULL,                               // tp_getattro
+    NULL,                               // tp_setattro
+    NULL,                               // tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                 // tp_flags
+    ConfigurableClientList_doc,
+    NULL,                               // tp_traverse
+    NULL,                               // tp_clear
+    NULL,                               // tp_richcompare
+    0,                                  // tp_weaklistoffset
+    NULL,                               // tp_iter
+    NULL,                               // tp_iternext
+    ConfigurableClientList_methods,                   // tp_methods
+    NULL,                               // tp_members
+    NULL,                               // tp_getset
+    NULL,                               // tp_base
+    NULL,                               // tp_dict
+    NULL,                               // tp_descr_get
+    NULL,                               // tp_descr_set
+    0,                                  // tp_dictoffset
+    ConfigurableClientList_init,                    // tp_init
+    NULL,                               // tp_alloc
+    PyType_GenericNew,                  // tp_new
+    NULL,                               // tp_free
+    NULL,                               // tp_is_gc
+    NULL,                               // tp_bases
+    NULL,                               // tp_mro
+    NULL,                               // tp_cache
+    NULL,                               // tp_subclasses
+    NULL,                               // tp_weaklist
+    NULL,                               // tp_del
+    0                                   // tp_version_tag
+};
+
+// Module Initialization, all statics are initialized here
+bool
+initModulePart_ConfigurableClientList(PyObject* mod) {
+    // We initialize the static description object with PyType_Ready(),
+    // then add it to the module. This is not just a check! (leaving
+    // this out results in segmentation faults)
+    if (PyType_Ready(&configurableclientlist_type) < 0) {
+        return (false);
+    }
+    void* p = &configurableclientlist_type;
+    if (PyModule_AddObject(mod, "ConfigurableClientList", static_cast<PyObject*>(p)) < 0) {
+        return (false);
+    }
+    Py_INCREF(&configurableclientlist_type);
+
+    @REMOVE_THIS_ON_RELEASE@
+    // The following template is the typical procedure for installing class
+    // variables.  If the class doesn't have a class variable, remove the
+    // entire try-catch clauses.
+    try {
+        // Constant class variables
+        installClassVariable(configurableclientlist_type, "REPLACE_ME",
+                             Py_BuildValue("REPLACE ME"));
+    } catch (const exception& ex) {
+        const string ex_what =
+            "Unexpected failure in ConfigurableClientList initialization: " +
+            string(ex.what());
+        PyErr_SetString(po_IscException, ex_what.c_str());
+        return (false);
+    } catch (...) {
+        PyErr_SetString(PyExc_SystemError,
+                        "Unexpected failure in ConfigurableClientList initialization");
+        return (false);
+    }
+
+    return (true);
+}
+
+} // namespace python
+} // namespace datasrc
+} // namespace isc
diff --git a/src/lib/python/isc/datasrc/configurableclientlist_python.h b/src/lib/python/isc/datasrc/configurableclientlist_python.h
new file mode 100644
index 0000000..155d262
--- /dev/null
+++ b/src/lib/python/isc/datasrc/configurableclientlist_python.h
@@ -0,0 +1,44 @@
+// 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 __PYTHON_CONFIGURABLECLIENTLIST_H
+#define __PYTHON_CONFIGURABLECLIENTLIST_H 1
+
+#include <Python.h>
+
+namespace isc {
+namespace datasrc {
+class ConfigurableClientList;
+
+namespace python {
+
+// The s_* Class simply covers one instantiation of the object
+class s_ConfigurableClientList : public PyObject {
+public:
+    s_ConfigurableClientList();
+    ConfigurableClientList* cppobj;
+};
+
+extern PyTypeObject configurableclientlist_type;
+
+bool initModulePart_ConfigurableClientList(PyObject* mod);
+
+} // namespace python
+} // namespace datasrc
+} // namespace isc
+#endif // __PYTHON_CONFIGURABLECLIENTLIST_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/python/isc/ddns/tests/.gitignore b/src/lib/python/isc/ddns/tests/.gitignore
new file mode 100644
index 0000000..3445775
--- /dev/null
+++ b/src/lib/python/isc/ddns/tests/.gitignore
@@ -0,0 +1 @@
+/rwtest.sqlite3.copied
diff --git a/src/lib/python/isc/notify/notify_out.py b/src/lib/python/isc/notify/notify_out.py
index 83ac1d0..34db14c 100644
--- a/src/lib/python/isc/notify/notify_out.py
+++ b/src/lib/python/isc/notify/notify_out.py
@@ -161,6 +161,12 @@ class NotifyOut:
             for item in slaves:
                 self._notify_infos[zone_id].notify_slaves.append((item, 53))
 
+    def add_slave(self, address, port):
+        for zone_name, zone_class in sqlite3_ds.get_zones_info(self._db_file):
+            zone_id = (zone_name, zone_class)
+            if zone_id in self._notify_infos:
+                self._notify_infos[zone_id].notify_slaves.append((address, port))
+
     def send_notify(self, zone_name, zone_class='IN'):
         '''Send notify to one zone's slaves, this function is
         the only interface for class NotifyOut which can be called
diff --git a/src/lib/python/isc/sysinfo/Makefile.am b/src/lib/python/isc/sysinfo/Makefile.am
new file mode 100644
index 0000000..aebbc2e
--- /dev/null
+++ b/src/lib/python/isc/sysinfo/Makefile.am
@@ -0,0 +1,11 @@
+SUBDIRS = . tests
+
+python_PYTHON = __init__.py
+python_PYTHON += sysinfo.py
+
+pythondir = $(pyexecdir)/isc/sysinfo
+
+CLEANDIRS = __pycache__
+
+clean-local:
+	rm -rf $(CLEANDIRS)
diff --git a/src/lib/python/isc/sysinfo/__init__.py b/src/lib/python/isc/sysinfo/__init__.py
new file mode 100644
index 0000000..c632b30
--- /dev/null
+++ b/src/lib/python/isc/sysinfo/__init__.py
@@ -0,0 +1 @@
+from isc.sysinfo.sysinfo import *
diff --git a/src/lib/python/isc/sysinfo/sysinfo.py b/src/lib/python/isc/sysinfo/sysinfo.py
new file mode 100644
index 0000000..efba0f6
--- /dev/null
+++ b/src/lib/python/isc/sysinfo/sysinfo.py
@@ -0,0 +1,286 @@
+# Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+'''This module returns system information.'''
+
+import os
+import sys
+import re
+import subprocess
+import os.path
+import platform
+
+class SysInfo:
+    def __init__(self):
+        self._num_processors = -1
+        self._endianness = 'Unknown'
+        self._hostname = ''
+        self._platform_name = 'Unknown'
+        self._platform_version = 'Unknown'
+        self._platform_machine = 'Unknown'
+        self._platform_is_smp = False
+        self._uptime = -1
+        self._loadavg = [-1.0, -1.0, -1.0]
+        self._mem_total = -1
+        self._mem_free = -1
+        self._mem_cached = -1
+        self._mem_buffers = -1
+        self._mem_swap_total = -1
+        self._mem_swap_free = -1
+        self._platform_distro = 'Unknown'
+        self._net_interfaces = 'Unknown'
+        self._net_routing_table = 'Unknown'
+        self._net_stats = 'Unknown'
+        self._net_connections = 'Unknown'
+
+    def get_num_processors(self):
+        """Returns the number of processors. This is the number of
+        hyperthreads when hyper-threading is enabled.
+        """
+        return self._num_processors
+
+    def get_endianness(self):
+        """Returns 'big' or 'little'."""
+        return self._endianness
+
+    def get_platform_hostname(self):
+        """Returns the hostname of the system."""
+        return self._hostname
+
+    def get_platform_name(self):
+        """Returns the platform name (uname -s)."""
+        return self._platform_name
+
+    def get_platform_version(self):
+        """Returns the platform version (uname -v)."""
+        return self._platform_version
+
+    def get_platform_machine(self):
+        """Returns the platform machine architecture."""
+        return self._platform_machine
+
+    def get_platform_is_smp(self):
+        """Returns True if an SMP kernel is being used, False otherwise."""
+        return self._platform_is_smp
+
+    def get_platform_distro(self):
+        """Returns the name of the OS distribution in use."""
+        return self._platform_distro
+
+    def get_uptime(self):
+        """Returns the uptime in seconds."""
+        return self._uptime
+
+    def get_loadavg(self):
+        """Returns the load average as 3 floating point values in an array."""
+        return self._loadavg
+
+    def get_mem_total(self):
+        """Returns the total amount of memory in bytes."""
+        return self._mem_total
+
+    def get_mem_free(self):
+        """Returns the amount of free memory in bytes."""
+        return self._mem_free
+
+    def get_mem_cached(self):
+        """Returns the amount of cached memory in bytes."""
+        return self._mem_cached
+
+    def get_mem_buffers(self):
+        """Returns the amount of buffer in bytes."""
+        return self._mem_buffers
+
+    def get_mem_swap_total(self):
+        """Returns the total amount of swap in bytes."""
+        return self._mem_swap_total
+
+    def get_mem_swap_free(self):
+        """Returns the amount of free swap in bytes."""
+        return self._mem_swap_free
+
+    def get_net_interfaces(self):
+        """Returns information about network interfaces (as a multi-line string)."""
+        return self._net_interfaces
+
+    def get_net_routing_table(self):
+        """Returns information about network routing table (as a multi-line string)."""
+        return self._net_routing_table
+
+    def get_net_stats(self):
+        """Returns network statistics (as a multi-line string)."""
+        return self._net_stats
+
+    def get_net_connections(self):
+        """Returns network connection information (as a multi-line string)."""
+        return self._net_connections
+
+class SysInfoLinux(SysInfo):
+    """Linux implementation of the SysInfo class.
+    See the base class documentation for more information.
+    """
+    def __init__(self):
+        super().__init__()
+
+        self._num_processors = os.sysconf('SC_NPROCESSORS_CONF')
+        self._endianness = sys.byteorder
+
+        with open('/proc/sys/kernel/hostname') as f:
+            self._hostname = f.read().strip()
+
+        u = os.uname()
+        self._platform_name = u[0]
+        self._platform_version = u[2]
+        self._platform_machine = u[4]
+
+        with open('/proc/version') as f:
+            self._platform_is_smp = ' SMP ' in f.read().strip()
+
+        with open('/proc/uptime') as f:
+            u = f.read().strip().split(' ')
+            if len(u) > 1:
+                self._uptime = int(round(float(u[0])))
+
+        with open('/proc/loadavg') as f:
+            l = f.read().strip().split(' ')
+            if len(l) >= 3:
+                self._loadavg = [float(l[0]), float(l[1]), float(l[2])]
+
+        with open('/proc/meminfo') as f:
+            m = f.readlines()
+            for line in m:
+                r = re.match('^MemTotal:\s+(.*)\s*kB', line)
+                if r:
+                    self._mem_total = int(r.group(1).strip()) * 1024
+                    continue
+                r = re.match('^MemFree:\s+(.*)\s*kB', line)
+                if r:
+                    self._mem_free = int(r.group(1).strip()) * 1024
+                    continue
+                r = re.match('^Cached:\s+(.*)\s*kB', line)
+                if r:
+                    self._mem_cached = int(r.group(1).strip()) * 1024
+                    continue
+                r = re.match('^Buffers:\s+(.*)\s*kB', line)
+                if r:
+                    self._mem_buffers = int(r.group(1).strip()) * 1024
+                    continue
+                r = re.match('^SwapTotal:\s+(.*)\s*kB', line)
+                if r:
+                    self._mem_swap_total = int(r.group(1).strip()) * 1024
+                    continue
+                r = re.match('^SwapFree:\s+(.*)\s*kB', line)
+                if r:
+                    self._mem_swap_free = int(r.group(1).strip()) * 1024
+                    continue
+
+        self._platform_distro = None
+
+        try:
+            s = subprocess.check_output(['lsb_release', '-a'])
+            for line in s.decode('utf-8').split('\n'):
+                r = re.match('^Description:(.*)', line)
+                if r:
+                    self._platform_distro = r.group(1).strip()
+                    break
+        except (subprocess.CalledProcessError, OSError):
+            pass
+
+        if self._platform_distro is None:
+            files = ['/etc/debian_release',
+                     '/etc/debian_version',
+                     '/etc/SuSE-release',
+                     '/etc/UnitedLinux-release',
+                     '/etc/mandrake-release',
+                     '/etc/gentoo-release',
+                     '/etc/fedora-release',
+                     '/etc/redhat-release',
+                     '/etc/redhat_version',
+                     '/etc/slackware-release',
+                     '/etc/slackware-version',
+                     '/etc/arch-release',
+                     '/etc/lsb-release',
+                     '/etc/mageia-release']
+            for fn in files:
+                if os.path.exists(fn):
+                    with open(fn) as f:
+                        self._platform_distro = f.read().strip()
+                    break
+
+        if self._platform_distro is None:
+            self._platform_distro = 'Unknown'
+
+        self._net_interfaces = None
+
+        try:
+            s = subprocess.check_output(['ip', 'addr'])
+            self._net_interfaces = s.decode('utf-8')
+        except (subprocess.CalledProcessError, OSError):
+            pass
+
+        if self._net_interfaces is None:
+            self._net_interfaces = 'Unknown'
+
+        self._net_routing_table = None
+
+        try:
+            s = subprocess.check_output(['ip', 'route'])
+            self._net_routing_table = s.decode('utf-8')
+            self._net_routing_table += '\n'
+            s = subprocess.check_output(['ip', '-f', 'inet6', 'route'])
+            self._net_routing_table += s.decode('utf-8')
+        except (subprocess.CalledProcessError, OSError):
+            pass
+
+        if self._net_routing_table is None:
+            self._net_routing_table = 'Unknown'
+
+        self._net_stats = None
+
+        try:
+            s = subprocess.check_output(['netstat', '-s'])
+            self._net_stats = s.decode('utf-8')
+        except (subprocess.CalledProcessError, OSError):
+            pass
+
+        if self._net_stats is None:
+            self._net_stats = 'Unknown'
+
+        self._net_connections = None
+
+        try:
+            s = subprocess.check_output(['netstat', '-apn'])
+            self._net_connections = s.decode('utf-8')
+        except (subprocess.CalledProcessError, OSError):
+            pass
+
+        if self._net_connections is None:
+            self._net_connections = 'Unknown'
+
+class SysInfoTestcase(SysInfo):
+    def __init__(self):
+        super().__init__()
+        self._endianness = 'bigrastafarian'
+        self._platform_name = 'b10test'
+        self._uptime = 131072
+
+def SysInfoFromFactory():
+    osname = platform.system()
+    if osname == 'Linux':
+        return SysInfoLinux()
+    elif osname == 'BIND10Testcase':
+        return SysInfoTestcase()
+    else:
+        return SysInfo()
diff --git a/src/lib/python/isc/sysinfo/tests/Makefile.am b/src/lib/python/isc/sysinfo/tests/Makefile.am
new file mode 100644
index 0000000..9759c77
--- /dev/null
+++ b/src/lib/python/isc/sysinfo/tests/Makefile.am
@@ -0,0 +1,23 @@
+PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
+PYTESTS = sysinfo_test.py
+EXTRA_DIST = $(PYTESTS)
+
+# If necessary (rare cases), explicitly specify paths to dynamic libraries
+# required by loadable python modules.
+if SET_ENV_LIBRARY_PATH
+LIBRARY_PATH_PLACEHOLDER = $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/cryptolink/.libs:$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/dns/python/.libs:$(abs_top_builddir)/src/lib/cc/.libs:$(abs_top_builddir)/src/lib/config/.libs:$(abs_top_builddir)/src/lib/log/.libs:$(abs_top_builddir)/src/lib/util/.libs:$(abs_top_builddir)/src/lib/acl/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$(abs_top_builddir)/src/lib/datasrc/.libs:$$$(ENV_LIBRARY_PATH)
+endif
+
+# test using command-line arguments, so use check-local target instead of TESTS
+check-local:
+if ENABLE_PYTHON_COVERAGE
+	touch $(abs_top_srcdir)/.coverage
+	rm -f .coverage
+	${LN_S} $(abs_top_srcdir)/.coverage .coverage
+endif
+	for pytest in $(PYTESTS) ; do \
+	echo Running test: $$pytest ; \
+	$(LIBRARY_PATH_PLACEHOLDER) \
+	PYTHONPATH=$(COMMON_PYTHON_PATH) \
+	$(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
+	done
diff --git a/src/lib/python/isc/sysinfo/tests/sysinfo_test.py b/src/lib/python/isc/sysinfo/tests/sysinfo_test.py
new file mode 100644
index 0000000..93985c7
--- /dev/null
+++ b/src/lib/python/isc/sysinfo/tests/sysinfo_test.py
@@ -0,0 +1,197 @@
+# Copyright (C) 2012  Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+from isc.sysinfo import *
+import os
+import unittest
+import platform
+import subprocess
+
+def _my_testcase_platform_system():
+    return 'BIND10Testcase'
+
+def _my_linux_platform_system():
+    return 'Linux'
+
+def _my_linux_os_sysconf(key):
+    if key == 'SC_NPROCESSORS_CONF':
+        return 42
+    assert False, 'Unhandled key'
+
+class MyFile:
+    def __init__(self, filename):
+        self._filename = filename
+
+    def read(self):
+        if self._filename == '/proc/sys/kernel/hostname':
+            return 'myhostname'
+        elif self._filename == '/proc/version':
+            return 'An SMP version string'
+        elif self._filename == '/proc/uptime':
+            return '86400.75 139993.71'
+        elif self._filename == '/proc/loadavg':
+            return '0.1 0.2 0.3 0.4'
+        else:
+            assert False, 'Unhandled filename'
+
+    def readlines(self):
+        if self._filename == '/proc/meminfo':
+            return ['MemTotal:        3083872 kB',
+                    'MemFree:          870492 kB',
+                    'Buffers:           27412 kB',
+                    'Cached:          1303860 kB',
+                    'SwapTotal:       4194300 kB',
+                    'SwapFree:        3999464 kB']
+        else:
+            assert False, 'Unhandled filename'
+
+    def close(self):
+        return
+
+    def __enter__(self):
+        return self
+
+    def __exit__(self, type, value, traceback):
+        return
+
+def _my_linux_open(filename):
+    return MyFile(filename)
+
+def _my_linux_subprocess_check_output(command):
+    assert type(command) == list, 'command argument is not a list'
+    if command == ['lsb_release', '-a']:
+        return b'Description: My Distribution\n'
+    elif command == ['ip', 'addr']:
+        return b'qB2osV6vUOjqm3P/+tQ4d92xoYz8/U8P9v3KWRpNwlI=\n'
+    elif command == ['ip', 'route']:
+        return b'VGWAS92AlS14Pl2xqENJs5P2Ihe6Nv9g181Mu6Zz+aQ=\n'
+    elif command == ['ip', '-f', 'inet6', 'route']:
+        return b'XfizswwNA9NkXz6K36ZExpjV08Y5IXkHI8jjDSV+5Nc=\n'
+    elif command == ['netstat', '-s']:
+        return b'osuxbrcc1g9VgaF4yf3FrtfodrfATrbSnjhqhuQSAs8=\n'
+    elif command == ['netstat', '-apn']:
+        return b'Z+w0lwa02/T+5+EIio84rrst/Dtizoz/aL9Im7J7ESA=\n'
+    else:
+        assert False, 'Unhandled command'
+
+class SysInfoTest(unittest.TestCase):
+    def test_sysinfo(self):
+        """Test that the various methods on SysInfo exist and return data."""
+
+        s = SysInfo()
+        self.assertEqual(-1, s.get_num_processors())
+        self.assertEqual('Unknown', s.get_endianness())
+        self.assertEqual('', s.get_platform_hostname())
+        self.assertEqual('Unknown', s.get_platform_name())
+        self.assertEqual('Unknown', s.get_platform_version())
+        self.assertEqual('Unknown', s.get_platform_machine())
+        self.assertFalse(s.get_platform_is_smp())
+        self.assertEqual(-1, s.get_uptime())
+        self.assertEqual([-1.0, -1.0, -1.0], s.get_loadavg())
+        self.assertEqual(-1, s.get_mem_total())
+        self.assertEqual(-1, s.get_mem_free())
+        self.assertEqual(-1, s.get_mem_cached())
+        self.assertEqual(-1, s.get_mem_buffers())
+        self.assertEqual(-1, s.get_mem_swap_total())
+        self.assertEqual(-1, s.get_mem_swap_free())
+        self.assertEqual('Unknown', s.get_platform_distro())
+        self.assertEqual('Unknown', s.get_net_interfaces())
+        self.assertEqual('Unknown', s.get_net_routing_table())
+        self.assertEqual('Unknown', s.get_net_stats())
+        self.assertEqual('Unknown', s.get_net_connections())
+
+    def test_sysinfo_factory(self):
+        """Test that SysInfoFromFactory returns a valid system-specific
+        SysInfo implementation."""
+
+        old_platform_system = platform.system
+        platform.system = _my_testcase_platform_system
+
+        s = SysInfoFromFactory()
+        self.assertEqual(-1, s.get_num_processors())
+        self.assertEqual('bigrastafarian', s.get_endianness())
+        self.assertEqual('', s.get_platform_hostname())
+        self.assertEqual('b10test', s.get_platform_name())
+        self.assertEqual('Unknown', s.get_platform_version())
+        self.assertEqual('Unknown', s.get_platform_machine())
+        self.assertFalse(s.get_platform_is_smp())
+        self.assertEqual(131072, s.get_uptime())
+        self.assertEqual([-1.0, -1.0, -1.0], s.get_loadavg())
+        self.assertEqual(-1, s.get_mem_total())
+        self.assertEqual(-1, s.get_mem_free())
+        self.assertEqual(-1, s.get_mem_cached())
+        self.assertEqual(-1, s.get_mem_buffers())
+        self.assertEqual(-1, s.get_mem_swap_total())
+        self.assertEqual(-1, s.get_mem_swap_free())
+        self.assertEqual('Unknown', s.get_platform_distro())
+        self.assertEqual('Unknown', s.get_net_interfaces())
+        self.assertEqual('Unknown', s.get_net_routing_table())
+        self.assertEqual('Unknown', s.get_net_stats())
+        self.assertEqual('Unknown', s.get_net_connections())
+
+        platform.system = old_platform_system
+
+    def test_sysinfo_linux(self):
+        """Tests the Linux implementation of SysInfo. Note that this
+        tests deep into the implementation, and not just the
+        interfaces."""
+
+        # Don't run this test on platform other than Linux as some
+        # system calls may not even be available.
+        osname = platform.system()
+        if osname != 'Linux':
+            return
+
+        # Save and replace existing implementations of library functions
+        # with mock ones for testing.
+        old_platform_system = platform.system
+        platform.system = _my_linux_platform_system
+        old_os_sysconf = os.sysconf
+        os.sysconf = _my_linux_os_sysconf
+        old_open = __builtins__.open
+        __builtins__.open = _my_linux_open
+        old_subprocess_check_output = subprocess.check_output
+        subprocess.check_output = _my_linux_subprocess_check_output
+
+        s = SysInfoFromFactory()
+        self.assertEqual(42, s.get_num_processors())
+        self.assertEqual('myhostname', s.get_platform_hostname())
+        self.assertTrue(s.get_platform_is_smp())
+        self.assertEqual(86401, s.get_uptime())
+        self.assertEqual([0.1, 0.2, 0.3], s.get_loadavg())
+        self.assertEqual(3157884928, s.get_mem_total())
+        self.assertEqual(891383808, s.get_mem_free())
+        self.assertEqual(1335152640, s.get_mem_cached())
+        self.assertEqual(28069888, s.get_mem_buffers())
+        self.assertEqual(4294963200, s.get_mem_swap_total())
+        self.assertEqual(4095451136, s.get_mem_swap_free())
+        self.assertEqual('My Distribution', s.get_platform_distro())
+
+        # These test that the corresponding tools are being called (and
+        # no further processing is done on this data). Please see the
+        # implementation functions at the top of this file.
+        self.assertEqual('qB2osV6vUOjqm3P/+tQ4d92xoYz8/U8P9v3KWRpNwlI=\n', s.get_net_interfaces())
+        self.assertEqual('VGWAS92AlS14Pl2xqENJs5P2Ihe6Nv9g181Mu6Zz+aQ=\n\nXfizswwNA9NkXz6K36ZExpjV08Y5IXkHI8jjDSV+5Nc=\n', s.get_net_routing_table())
+        self.assertEqual('osuxbrcc1g9VgaF4yf3FrtfodrfATrbSnjhqhuQSAs8=\n', s.get_net_stats())
+        self.assertEqual('Z+w0lwa02/T+5+EIio84rrst/Dtizoz/aL9Im7J7ESA=\n', s.get_net_connections())
+
+        # Restore original implementations.
+        platform.system = old_platform_system
+        os.sysconf = old_os_sysconf
+        __builtins__.open = old_open
+        subprocess.check_output = old_subprocess_check_output
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/tests/lettuce/configurations/xfrin/inmem_slave.conf b/tests/lettuce/configurations/xfrin/inmem_slave.conf
index a6d88ee..9b69300 100644
--- a/tests/lettuce/configurations/xfrin/inmem_slave.conf
+++ b/tests/lettuce/configurations/xfrin/inmem_slave.conf
@@ -19,8 +19,8 @@
             } ]
         } ],
         "listen_on": [ {
-            "port": 47806,
-            "address": "127.0.0.1"
+            "address": "::1",
+            "port": 47806
         } ]
     },
     "Boss": {
diff --git a/tests/lettuce/configurations/xfrin/retransfer_master.conf b/tests/lettuce/configurations/xfrin/retransfer_master.conf
index eae47a6..378cff9 100644
--- a/tests/lettuce/configurations/xfrin/retransfer_master.conf
+++ b/tests/lettuce/configurations/xfrin/retransfer_master.conf
@@ -10,13 +10,17 @@
     "Auth": {
         "database_file": "data/example.org.sqlite3",
         "listen_on": [ {
-            "port": 47807,
-            "address": "::1"
+            "address": "::1",
+            "port": 47807
         } ]
     },
     "Xfrout": {
         "zone_config": [ {
             "origin": "example.org"
+        } ],
+        "also_notify": [ {
+            "address": "::1",
+            "port": 47806
         } ]
     },
     "Boss": {
diff --git a/tests/lettuce/configurations/xfrin/retransfer_slave.conf b/tests/lettuce/configurations/xfrin/retransfer_slave.conf
index 2296b8f..260147d 100644
--- a/tests/lettuce/configurations/xfrin/retransfer_slave.conf
+++ b/tests/lettuce/configurations/xfrin/retransfer_slave.conf
@@ -10,8 +10,8 @@
     "Auth": {
         "database_file": "data/test_nonexistent_db.sqlite3",
         "listen_on": [ {
-            "port": 47806,
-            "address": "127.0.0.1"
+            "address": "::1",
+            "port": 47806
         } ]
     },
     "Boss": {
diff --git a/tests/lettuce/configurations/xfrin/retransfer_slave_notify.conf b/tests/lettuce/configurations/xfrin/retransfer_slave_notify.conf
new file mode 100644
index 0000000..57244a4
--- /dev/null
+++ b/tests/lettuce/configurations/xfrin/retransfer_slave_notify.conf
@@ -0,0 +1,38 @@
+{
+    "version": 2,
+    "Logging": {
+        "loggers": [ {
+            "debuglevel": 99,
+            "severity": "DEBUG",
+            "name": "*"
+        } ]
+    },
+    "Auth": {
+        "database_file": "data/xfrin-notify.sqlite3",
+        "listen_on": [ {
+            "address": "::1",
+            "port": 47806
+        } ]
+    },
+    "Xfrin": {
+        "zones": [ {
+            "name": "example.org",
+            "master_addr": "::1",
+            "master_port": 47807
+        } ]
+    },
+    "Zonemgr": {
+        "secondary_zones": [ {
+            "name": "example.org",
+            "class": "IN"
+        } ]
+    },
+    "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
index 8c54200..888175e 100644
--- a/tests/lettuce/data/.gitignore
+++ b/tests/lettuce/data/.gitignore
@@ -1,2 +1,3 @@
 /inmem-xfrin.sqlite3
 /test_nonexistent_db.sqlite3
+/xfrin-notify.sqlite3
diff --git a/tests/lettuce/data/xfrin-notify.sqlite3.orig b/tests/lettuce/data/xfrin-notify.sqlite3.orig
new file mode 100644
index 0000000..3c38322
Binary files /dev/null and b/tests/lettuce/data/xfrin-notify.sqlite3.orig differ
diff --git a/tests/lettuce/features/inmemory_over_sqlite3.feature b/tests/lettuce/features/inmemory_over_sqlite3.feature
index 2e48689..851caca 100644
--- a/tests/lettuce/features/inmemory_over_sqlite3.feature
+++ b/tests/lettuce/features/inmemory_over_sqlite3.feature
@@ -26,18 +26,18 @@ Feature: In-memory zone using SQLite3 backend
         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 NOERROR
+        A query for www.example.org to [::1]:47806 should have rcode NOERROR
         """
         www.example.org.        3600    IN      A       192.0.2.63
         """
-        A query for mail.example.org should have rcode NXDOMAIN
+        A query for mail.example.org to [::1]:47806 should have rcode NXDOMAIN
         When I send bind10 the command Xfrin retransfer example.org IN ::1 47807
         Then wait for new bind10 stderr message XFRIN_TRANSFER_SUCCESS not XFRIN_XFR_PROCESS_FAILURE
         Then wait for new bind10 stderr message AUTH_LOAD_ZONE
 
-        A query for www.example.org should have rcode NOERROR
+        A query for www.example.org to [::1]:47807 should have rcode NOERROR
         The answer section of the last query response should be
         """
         www.example.org.        3600    IN      A       192.0.2.1
         """
-        A query for mail.example.org should have rcode NOERROR
+        A query for mail.example.org to [::1]:47806 should have rcode NOERROR
diff --git a/tests/lettuce/features/queries.feature b/tests/lettuce/features/queries.feature
index 8ca9467..7ae2284 100644
--- a/tests/lettuce/features/queries.feature
+++ b/tests/lettuce/features/queries.feature
@@ -103,6 +103,7 @@ Feature: Querying feature
         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
         And wait for bind10 stderr message BIND10_STARTED_CC
@@ -122,7 +123,9 @@ Feature: Querying feature
         """
         ns.sub.example.org.	3600	IN	A	192.0.2.101
         """
+
     Scenario: SSHFP query
+        # We are testing one more RR type for a normal successful case
         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
diff --git a/tests/lettuce/features/terrain/bind10_control.py b/tests/lettuce/features/terrain/bind10_control.py
index a08a887..248c6ec 100644
--- a/tests/lettuce/features/terrain/bind10_control.py
+++ b/tests/lettuce/features/terrain/bind10_control.py
@@ -306,8 +306,8 @@ def config_remove_command(step, name, value, cmdctl_port):
                 "quit"]
     run_bindctl(commands, cmdctl_port)
 
- at step('send bind10 the command (.+)(?: with cmdctl port (\d+))?')
-def send_command(step, command, cmdctl_port):
+ at step('send bind10(?: with cmdctl port (\d+))? the command (.+)')
+def send_command(step, cmdctl_port, command):
     """
     Run bindctl, send the given command, and exit bindctl.
     Parameters:
diff --git a/tests/lettuce/features/terrain/terrain.py b/tests/lettuce/features/terrain/terrain.py
index a35d0de..876e7cf 100644
--- a/tests/lettuce/features/terrain/terrain.py
+++ b/tests/lettuce/features/terrain/terrain.py
@@ -59,6 +59,8 @@ copylist = [
      "configurations/ddns/noddns.config"],
     ["data/inmem-xfrin.sqlite3.orig",
      "data/inmem-xfrin.sqlite3"],
+    ["data/xfrin-notify.sqlite3.orig",
+     "data/xfrin-notify.sqlite3"],
     ["data/ddns/example.org.sqlite3.orig",
      "data/ddns/example.org.sqlite3"]
 ]
diff --git a/tests/lettuce/features/terrain/transfer.py b/tests/lettuce/features/terrain/transfer.py
index 4ba45b8..eb4ddc0 100644
--- a/tests/lettuce/features/terrain/transfer.py
+++ b/tests/lettuce/features/terrain/transfer.py
@@ -67,11 +67,11 @@ def perform_axfr(step, zone_name, address, port):
     Step definition:
     An AXFR transfer of <zone_name> [from <address>:<port>]
 
-    Address defaults to 127.0.0.1
+    Address defaults to ::1
     Port defaults to 47806
     """
     if address is None:
-        address = "127.0.0.1"
+        address = "::1"
     # convert [IPv6_addr] to IPv6_addr:
     address = re.sub(r"\[(.+)\]", r"\1", address)
     if port is None:
diff --git a/tests/lettuce/features/xfrin_bind10.feature b/tests/lettuce/features/xfrin_bind10.feature
index 27dfb83..7a45ddd 100644
--- a/tests/lettuce/features/xfrin_bind10.feature
+++ b/tests/lettuce/features/xfrin_bind10.feature
@@ -23,11 +23,11 @@ Feature: Xfrin
     # Now we use the first step again to see if the file has been created
     The file data/test_nonexistent_db.sqlite3 should exist
 
-    A query for www.example.org should have rcode REFUSED
+    A query for www.example.org to [::1]:47806 should have rcode REFUSED
     When I send bind10 the command Xfrin retransfer example.org IN ::1 47807
     Then wait for new bind10 stderr message XFRIN_TRANSFER_SUCCESS not XFRIN_XFR_PROCESS_FAILURE
     Then wait for new bind10 stderr message ZONEMGR_RECEIVE_XFRIN_SUCCESS
-    A query for www.example.org should have rcode NOERROR
+    A query for www.example.org to [::1]:47806 should have rcode NOERROR
 
     # The transferred zone should have 11 non-NSEC3 RRs and 1 NSEC3 RR.
     # The following check will get these by AXFR, so the total # of RRs
diff --git a/tests/lettuce/features/xfrin_notify_handling.feature b/tests/lettuce/features/xfrin_notify_handling.feature
new file mode 100644
index 0000000..e514b83
--- /dev/null
+++ b/tests/lettuce/features/xfrin_notify_handling.feature
@@ -0,0 +1,29 @@
+Feature: Xfrin incoming notify handling
+    Tests for Xfrin incoming notify handling.
+
+    Scenario: Handle incoming notify
+    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_notify.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 to [::1]:47806 should have rcode NXDOMAIN
+
+    When I send bind10 with cmdctl port 47804 the command Xfrout notify example.org IN
+    Then wait for new master stderr message XFROUT_NOTIFY_COMMAND
+    Then wait for new bind10 stderr message AUTH_RECEIVED_NOTIFY
+    Then wait for new bind10 stderr message ZONEMGR_RECEIVE_NOTIFY
+    Then wait for new bind10 stderr message XFRIN_XFR_TRANSFER_STARTED
+    Then wait for new bind10 stderr message XFRIN_TRANSFER_SUCCESS not XFRIN_XFR_PROCESS_FAILURE
+    Then wait for new bind10 stderr message ZONEMGR_RECEIVE_XFRIN_SUCCESS
+
+    A query for www.example.org to [::1]:47806 should have rcode NOERROR



More information about the bind10-changes mailing list