Browse Source

Merge branch 'master' into trac2052

Conflicts:
	src/lib/dns/name.cc
Mukund Sivaraman 13 years ago
parent
commit
1170780af0
37 changed files with 515 additions and 321 deletions
  1. 8 0
      ChangeLog
  2. 202 182
      doc/guide/bind10-guide.xml
  3. 3 0
      src/bin/auth/auth_messages.mes
  4. 3 0
      src/bin/auth/auth_srv.cc
  5. 1 1
      src/bin/cmdctl/cmdctl.py.in
  6. 1 7
      src/bin/msgq/msgq.xml
  7. 4 0
      src/bin/xfrin/xfrin.py.in
  8. 3 0
      src/bin/xfrout/xfrout.py.in
  9. 27 0
      src/bin/xfrout/xfrout.spec.pre.in
  10. 6 5
      src/lib/config/tests/ccsession_unittests.cc
  11. 22 35
      src/lib/datasrc/database.cc
  12. 6 9
      src/lib/datasrc/database.h
  13. 24 13
      src/lib/datasrc/tests/database_unittest.cc
  14. 0 13
      src/lib/datasrc/tests/zone_finder_context_unittest.cc
  15. 10 0
      src/lib/datasrc/zone.h
  16. 8 8
      src/lib/dns/labelsequence.cc
  17. 1 1
      src/lib/dns/labelsequence.h
  18. 3 3
      src/lib/dns/messagerenderer.cc
  19. 16 16
      src/lib/dns/name.cc
  20. 7 2
      src/lib/dns/name.h
  21. 1 1
      src/lib/dns/name_internal.h
  22. 37 9
      src/lib/dns/tests/labelsequence_unittest.cc
  23. 6 0
      src/lib/python/isc/notify/notify_out.py
  24. 2 2
      tests/lettuce/configurations/xfrin/inmem_slave.conf
  25. 6 2
      tests/lettuce/configurations/xfrin/retransfer_master.conf
  26. 2 2
      tests/lettuce/configurations/xfrin/retransfer_slave.conf
  27. 38 0
      tests/lettuce/configurations/xfrin/retransfer_slave_notify.conf
  28. 1 0
      tests/lettuce/data/.gitignore
  29. 1 0
      tests/lettuce/data/example.org
  30. BIN
      tests/lettuce/data/xfrin-notify.sqlite3.orig
  31. 4 4
      tests/lettuce/features/inmemory_over_sqlite3.feature
  32. 25 0
      tests/lettuce/features/queries.feature
  33. 2 2
      tests/lettuce/features/terrain/bind10_control.py
  34. 2 0
      tests/lettuce/features/terrain/terrain.py
  35. 2 2
      tests/lettuce/features/terrain/transfer.py
  36. 2 2
      tests/lettuce/features/xfrin_bind10.feature
  37. 29 0
      tests/lettuce/features/xfrin_notify_handling.feature

+ 8 - 0
ChangeLog

@@ -1,3 +1,11 @@
+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
 450.	[func]*		tomek
 	b10-dhcp4: DHCPv4 server component is now integrated into
 	b10-dhcp4: DHCPv4 server component is now integrated into
 	BIND10 framework. It can be started from BIND10 (using bindctl)
 	BIND10 framework. It can be started from BIND10 (using bindctl)

+ 202 - 182
doc/guide/bind10-guide.xml

@@ -36,8 +36,8 @@
     <abstract>
     <abstract>
       <para>BIND 10 is a framework that features Domain Name System
       <para>BIND 10 is a framework that features Domain Name System
       (DNS) suite and Dynamic Host Configuration Protocol (DHCP)
       (DNS) suite and Dynamic Host Configuration Protocol (DHCP)
-      servers managed by Internet Systems Consortium (ISC). It
+      servers with development managed by Internet Systems Consortium (ISC).
-      includes DNS libraries, modular components for controlling
+      It includes DNS libraries, modular components for controlling
       authoritative and recursive DNS servers, and experimental DHCPv4
       authoritative and recursive DNS servers, and experimental DHCPv4
       and DHCPv6 servers.
       and DHCPv6 servers.
       </para>
       </para>
@@ -59,6 +59,8 @@
     <section id="acknowledgements">
     <section id="acknowledgements">
       <title>Acknowledgements</title>
       <title>Acknowledgements</title>
 
 
+<!-- TODO: acknowledge all sponsors and CNNIC and CZNIC too -->
+
       <para>ISC would like to acknowledge generous support for
       <para>ISC would like to acknowledge generous support for
       BIND 10 development of DHCPv4 and DHCPv6 components provided
       BIND 10 development of DHCPv4 and DHCPv6 components provided
       by <ulink url="http://www.comcast.com/">Comcast</ulink>.</para>
       by <ulink url="http://www.comcast.com/">Comcast</ulink>.</para>
@@ -72,11 +74,13 @@
     <para>
     <para>
       BIND is the popular implementation of a DNS server, developer
       BIND is the popular implementation of a DNS server, developer
       interfaces, and DNS tools.
       interfaces, and DNS tools.
-      BIND 10 is a rewrite of BIND 9.  BIND 10 is written in C++ and Python
+      BIND 10 is a rewrite of BIND 9 and ISC DHCP.
-      and provides a modular environment for serving and maintaining DNS.
+      BIND 10 is written in C++ and Python and provides a modular
+      environment for serving, maintaining, and developing DNS and DHCP.
       BIND 10 provides a EDNS0- and DNSSEC-capable authoritative
       BIND 10 provides a EDNS0- and DNSSEC-capable authoritative
       DNS server and a caching recursive name server which also
       DNS server and a caching recursive name server which also
       provides forwarding.
       provides forwarding.
+      It also provides experimental DHCPv4 and DHCPv6 servers.
     </para>
     </para>
 
 
     <para>
     <para>
@@ -88,7 +92,7 @@
       <title>Supported Platforms</title>
       <title>Supported Platforms</title>
       <para>
       <para>
   BIND 10 builds have been tested on (in no particular order)
   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,
   Solaris 10 and 11, FreeBSD 7 and 8, CentOS Linux 5.3,
   MacOS 10.6 and 10.7, and OpenBSD 5.1.
   MacOS 10.6 and 10.7, and OpenBSD 5.1.
 
 
@@ -101,11 +105,21 @@
     </section>
     </section>
 
 
     <section id="required-software">
     <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>
       <para>
         BIND 10 requires at least Python 3.1
         BIND 10 requires at least Python 3.1
         (<ulink url="http://www.python.org/"/>).
         (<ulink url="http://www.python.org/"/>).
-        It has also been tested with Python 3.2.
+        It also works with Python 3.2.
       </para>
       </para>
 
 
       <para>
       <para>
@@ -118,6 +132,7 @@
         BIND 10 uses the log4cplus C++ logging library
         BIND 10 uses the log4cplus C++ logging library
         (<ulink url="http://log4cplus.sourceforge.net/"/>).
         (<ulink url="http://log4cplus.sourceforge.net/"/>).
         It requires at least log4cplus version 1.0.3.
         It requires at least log4cplus version 1.0.3.
+<!-- TODO: It is recommended to use at least version .... -->
       </para>
       </para>
 
 
       <para>
       <para>
@@ -132,20 +147,9 @@
         <command>b10-xfrout</command>, and <command>b10-zonemgr</command>
         <command>b10-xfrout</command>, and <command>b10-zonemgr</command>
         components require the libpython3 library and the Python
         components require the libpython3 library and the Python
         _sqlite3.so module (which is included with Python).
         _sqlite3.so module (which is included with Python).
-        The <command>b10-stats-httpd</command> component uses the
+        Python modules need to be built for the corresponding Python 3.
-        Python pyexpat.so module.
-        The Python modules need to be built for the corresponding Python 3.
       </para>
       </para>
 <!-- TODO: this will change ... -->
 <!-- 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>
 
 
     <section id="starting_stopping">
     <section id="starting_stopping">
@@ -220,8 +224,8 @@
             <simpara>
             <simpara>
               <command>b10-resolver</command> &mdash;
               <command>b10-resolver</command> &mdash;
               Recursive name server.
               Recursive name server.
-              This process handles incoming queries.
+              This process handles incoming DNS queries and provides
-<!-- TODO: -->
+              answers from its cache or by recursively doing remote lookups.
             </simpara>
             </simpara>
           </listitem>
           </listitem>
 
 
@@ -264,15 +268,14 @@
               <command>b10-xfrout</command> &mdash;
               <command>b10-xfrout</command> &mdash;
               Outgoing zone transfer service.
               Outgoing zone transfer service.
               This process is used to handle transfer requests to
               This process is used to handle transfer requests to
-              send a local zone to a remote secondary server,
+              send a local zone to a remote secondary server.
-              when acting as a master server.
             </simpara>
             </simpara>
           </listitem>
           </listitem>
 
 
           <listitem>
           <listitem>
             <simpara>
             <simpara>
               <command>b10-zonemgr</command> &mdash;
               <command>b10-zonemgr</command> &mdash;
-              Secondary manager.
+              Secondary zone manager.
               This process keeps track of timers and other
               This process keeps track of timers and other
               necessary information for BIND 10 to act as a slave server.
               necessary information for BIND 10 to act as a slave server.
             </simpara>
             </simpara>
@@ -282,8 +285,8 @@
       </para>
       </para>
 
 
       <para>
       <para>
-        These are ran automatically by <command>bind10</command>
+        These are ran by <command>bind10</command>
-        and do not need to be run manually.
+        and do not need to be manually started independently.
       </para>
       </para>
 
 
     </section>
     </section>
@@ -298,7 +301,7 @@
           <listitem>
           <listitem>
             <simpara>
             <simpara>
               <command>bindctl</command> &mdash;
               <command>bindctl</command> &mdash;
-              interactive administration interface.
+              Interactive administration interface.
               This is a low-level command-line tool which allows
               This is a low-level command-line tool which allows
               a developer or an experienced administrator to control
               a developer or an experienced administrator to control
               BIND 10.
               BIND 10.
@@ -307,7 +310,7 @@
           <listitem>
           <listitem>
             <simpara>
             <simpara>
               <command>b10-loadzone</command> &mdash;
               <command>b10-loadzone</command> &mdash;
-              zone file loader.
+              Zone file loader.
               This tool will load standard masterfile-format zone files into
               This tool will load standard masterfile-format zone files into
               BIND 10.
               BIND 10.
             </simpara>
             </simpara>
@@ -315,7 +318,7 @@
           <listitem>
           <listitem>
             <simpara>
             <simpara>
               <command>b10-cmdctl-usermgr</command> &mdash;
               <command>b10-cmdctl-usermgr</command> &mdash;
-              user access control.
+              User access control.
               This tool allows an administrator to authorize additional users
               This tool allows an administrator to authorize additional users
               to manage BIND 10.
               to manage BIND 10.
             </simpara>
             </simpara>
@@ -358,6 +361,7 @@ var/
       for C++ and Python for the message bus, configuration backend,
       for C++ and Python for the message bus, configuration backend,
       and, of course, DNS. These include detailed developer
       and, of course, DNS. These include detailed developer
       documentation and code examples.
       documentation and code examples.
+<!-- TODO: DHCP also but no Python yet. -->
 <!-- TODO point to this -->
 <!-- TODO point to this -->
     </para>
     </para>
 
 
@@ -366,12 +370,100 @@ var/
   <chapter id="installation">
   <chapter id="installation">
     <title>Installation</title>
     <title>Installation</title>
 
 
+    <section id="packages">
+      <title>Packages</title>
+
+      <para>
+        Some operating systems or softare package vendors may
+        provide ready-to-use, pre-built software packages for
+        the BIND 10 suite.
+        Installing a pre-built package means you do not need to
+        install build-only prerequisites and do not need to
+        <emphasis>make</emphasis> the software.
+      </para>
+
+      <para>
+        FreeBSD ports, NetBSD pkgsrc, and Debian
+        <emphasis>testing</emphasis> package collections provide
+        all the prerequisite packages.
+      </para>
+    </section>
+
+    <section id="install-hierarchy">
+      <title>Install Hierarchy</title>
+      <para>
+        The following is the standard, common layout of the
+        complete BIND 10 installation:
+        <itemizedlist>
+          <listitem>
+           <simpara>
+              <filename>bin/</filename> &mdash;
+              general tools and diagnostic clients.
+            </simpara>
+          </listitem>
+          <listitem>
+          <simpara>
+            <filename>etc/bind10-devel/</filename> &mdash;
+            configuration files.
+          </simpara>
+          </listitem>
+          <listitem>
+            <simpara>
+              <filename>lib/</filename> &mdash;
+              libraries and python modules.
+            </simpara>
+          </listitem>
+          <listitem>
+            <simpara>
+              <filename>libexec/bind10-devel/</filename> &mdash;
+              executables that a user wouldn't normally run directly and
+              are not run independently.
+              These are the BIND 10 modules which are daemons started by
+              the <command>bind10</command> tool.
+            </simpara>
+          </listitem>
+          <listitem>
+            <simpara>
+              <filename>sbin/</filename> &mdash;
+              commands used by the system administrator.
+            </simpara>
+          </listitem>
+          <listitem>
+            <simpara>
+              <filename>share/bind10-devel/</filename> &mdash;
+              configuration specifications.
+            </simpara>
+          </listitem>
+          <listitem>
+            <simpara>
+              <filename>share/doc/bind10-devel/</filename> &mdash;
+              this guide and other supplementary documentation.
+            </simpara>
+          </listitem>
+          <listitem>
+            <simpara>
+              <filename>share/man/</filename> &mdash;
+              manual pages (online documentation).
+            </simpara>
+          </listitem>
+          <listitem>
+            <simpara>
+              <filename>var/bind10-devel/</filename> &mdash;
+              data source and configuration databases.
+            </simpara>
+          </listitem>
+        </itemizedlist>
+      </para>
+    </section>
+
     <section id="build-requirements">
     <section id="build-requirements">
       <title>Building Requirements</title>
       <title>Building Requirements</title>
 
 
         <para>
         <para>
-          In addition to the run-time requirements, building BIND 10
+          In addition to the run-time requirements (listed in
-          from source code requires various development include headers.
+          <xref linkend="required-software"/>), building BIND 10
+          from source code requires various development include headers and
+          program development tools.
         </para>
         </para>
 
 
         <note>
         <note>
@@ -415,7 +507,7 @@ as a dependency earlier -->
         </para>
         </para>
 
 
         <para>
         <para>
-          Visit the wiki at <ulink
+          Visit the user-contributed wiki at <ulink
           url="http://bind10.isc.org/wiki/SystemSpecificNotes" />
           url="http://bind10.isc.org/wiki/SystemSpecificNotes" />
           for system-specific installation tips.
           for system-specific installation tips.
         </para>
         </para>
@@ -484,7 +576,7 @@ as a dependency earlier -->
         </listitem>
         </listitem>
 
 
         <listitem>
         <listitem>
-
+<!-- TODO: this is wrong; b10-auth is not started by default any more -->
          <para>Test it; for example:
          <para>Test it; for example:
             <screen>$ <userinput>dig @127.0.0.1 -c CH -t TXT authors.bind</userinput></screen>
             <screen>$ <userinput>dig @127.0.0.1 -c CH -t TXT authors.bind</userinput></screen>
          </para>
          </para>
@@ -510,10 +602,10 @@ as a dependency earlier -->
       <title>Installation from source</title>
       <title>Installation from source</title>
       <para>
       <para>
         BIND 10 is open source software written in C++ and Python.
         BIND 10 is open source software written in C++ and Python.
-        It is freely available in source code form from ISC via
+        It is freely available in source code form from ISC as a
-        the Git code revision control system or as a downloadable
+        downloadable tar file or via BIND 10's Git code revision control
-        tar file. It may also be available in pre-compiled ready-to-use
+        service. (It may also be available in pre-compiled ready-to-use
-        packages from operating system vendors.
+        packages from operating system vendors.)
       </para>
       </para>
 
 
       <section>
       <section>
@@ -541,7 +633,7 @@ as a dependency earlier -->
 
 
         <note>
         <note>
           <para>
           <para>
-            When using source code retrieved via Git additional
+            When using source code retrieved via Git, additional
             software will be required:  automake (v1.11 or newer),
             software will be required:  automake (v1.11 or newer),
             libtoolize, and autoconf (2.59 or newer).
             libtoolize, and autoconf (2.59 or newer).
             These may need to be installed.
             These may need to be installed.
@@ -549,11 +641,12 @@ as a dependency earlier -->
         </note>
         </note>
 
 
         <para>
         <para>
-          The latest development code, including temporary experiments
+          The latest development code (and temporary experiments
-          and un-reviewed code, is available via the BIND 10 code revision
+          and un-reviewed code) is available via the BIND 10 code revision
           control system. This is powered by Git and all the BIND 10
           control system. This is powered by Git and all the BIND 10
           development is public.
           development is public.
-          The leading development is done in the <quote>master</quote>.
+          The leading development is done in the <quote>master</quote>
+          branch.
         </para>
         </para>
         <para>
         <para>
           The code can be checked out from
           The code can be checked out from
@@ -566,8 +659,8 @@ as a dependency earlier -->
         <para>
         <para>
           When checking out the code from
           When checking out the code from
           the code version control system, it doesn't include the
           the code version control system, it doesn't include the
-          generated configure script, Makefile.in files, nor the
+          generated configure script, Makefile.in files, nor their
-          related configure files.
+          related build files.
           They can be created by running <command>autoreconf</command>
           They can be created by running <command>autoreconf</command>
           with the <option>--install</option> switch.
           with the <option>--install</option> switch.
           This will run <command>autoconf</command>,
           This will run <command>autoconf</command>,
@@ -591,7 +684,7 @@ as a dependency earlier -->
         </para>
         </para>
         <para>
         <para>
           Run <command>./configure</command> with the <option>--help</option>
           Run <command>./configure</command> with the <option>--help</option>
-          switch to view the different options. The commonly-used options are:
+          switch to view the different options. Some commonly-used options are:
 
 
           <variablelist>
           <variablelist>
 
 
@@ -679,65 +772,6 @@ as a dependency earlier -->
 
 
   <!-- TODO: tests -->
   <!-- TODO: tests -->
 
 
-      <section>
-        <title>Install Hierarchy</title>
-        <para>
-          The following is the layout of the complete BIND 10 installation:
-          <itemizedlist>
-            <listitem>
-              <simpara>
-                <filename>bin/</filename> &mdash;
-                general tools and diagnostic clients.
-              </simpara>
-            </listitem>
-            <listitem>
-            <simpara>
-              <filename>etc/bind10-devel/</filename> &mdash;
-              configuration files.
-            </simpara>
-            </listitem>
-            <listitem>
-              <simpara>
-                <filename>lib/</filename> &mdash;
-                libraries and python modules.
-              </simpara>
-            </listitem>
-            <listitem>
-              <simpara>
-                <filename>libexec/bind10-devel/</filename> &mdash;
-                executables that a user wouldn't normally run directly and
-                are not run independently.
-                These are the BIND 10 modules which are daemons started by
-                the <command>bind10</command> tool.
-              </simpara>
-            </listitem>
-            <listitem>
-              <simpara>
-                <filename>sbin/</filename> &mdash;
-                commands used by the system administrator.
-              </simpara>
-            </listitem>
-            <listitem>
-              <simpara>
-                <filename>share/bind10-devel/</filename> &mdash;
-                configuration specifications.
-              </simpara>
-            </listitem>
-            <listitem>
-              <simpara>
-                <filename>share/man/</filename> &mdash;
-                manual pages (online documentation).
-              </simpara>
-            </listitem>
-            <listitem>
-              <simpara>
-                <filename>var/bind10-devel/</filename> &mdash;
-                data source and configuration databases.
-              </simpara>
-            </listitem>
-          </itemizedlist>
-        </para>
-      </section>
     </section>
     </section>
 
 
   <!--
   <!--
@@ -775,8 +809,9 @@ as a dependency earlier -->
       The <command>b10-cfgmgr</command> daemon is always needed by every
       The <command>b10-cfgmgr</command> daemon is always needed by every
       module, if only to send information about themselves somewhere,
       module, if only to send information about themselves somewhere,
       but more importantly to ask about their own settings, and
       but more importantly to ask about their own settings, and
-      about other modules. The <command>b10-sockcreator</command> will
+      about other modules. The <command>b10-sockcreator</command> daemon
-      allocate sockets for the rest of the system.
+      helps allocate Internet addresses and ports as needed for BIND 10
+      network services.
     </para>
     </para>
 
 
     <para>
     <para>
@@ -807,23 +842,22 @@ as a dependency earlier -->
 
 
     </section>
     </section>
     <section id="bind10.config">
     <section id="bind10.config">
-      <title>Configuration of started processes</title>
+      <title>Configuration to start 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>
 
 
       <para>
       <para>
-        The configuration is in the Boss/components section. Each element
+	The processes to be used can be configured for
-        represents one component, which is an abstraction of a process
+	<command>bind10</command> to start, with the exception
-        (currently there's also one component which doesn't represent
+	of the required <command>b10-sockcreator</command>,
-        a process).
+	<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>
 
 
       <para>
       <para>
-        To add a process to the set, let's say the resolver (which not started
+	To add a process to the set, let's say the resolver (which
-        by default), you would do this:
+	is not started by default), you would do this:
         <screen>&gt; <userinput>config add Boss/components b10-resolver</userinput>
         <screen>&gt; <userinput>config add Boss/components b10-resolver</userinput>
 &gt; <userinput>config set Boss/components/b10-resolver/special resolver</userinput>
 &gt; <userinput>config set Boss/components/b10-resolver/special resolver</userinput>
 &gt; <userinput>config set Boss/components/b10-resolver/kind needed</userinput>
 &gt; <userinput>config set Boss/components/b10-resolver/kind needed</userinput>
@@ -831,27 +865,32 @@ as a dependency earlier -->
 &gt; <userinput>config commit</userinput></screen></para>
 &gt; <userinput>config commit</userinput></screen></para>
 
 
       <para>
       <para>
-        Now, what it means. We add an entry called b10-resolver. It is both a
+	Now, what it means. We add an entry called
-        name used to reference this component in the configuration and the
+	<quote>b10-resolver</quote>. It is both a name used to
-        name of the process to start. Then we set some parameters on how to
+	reference this component in the configuration and the name
-        start it.
+	of the process to start. Then we set some parameters on
+	how to start it.
       </para>
       </para>
 
 
       <para>
       <para>
-        The special one is for components that need some kind of special care
+	The <varname>special</varname> setting is for components
-        during startup or shutdown. Unless specified, the component is started
+	that need some kind of special care during startup or
-        in usual way. This is the list of components that need to be started
+	shutdown. Unless specified, the component is started in a
-        in a special way, with the value of special used for them:
+	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>
         <table>
+          <title>Special startup components</title>
           <tgroup cols='3' align='left'>
           <tgroup cols='3' align='left'>
           <colspec colname='component'/>
           <colspec colname='component'/>
           <colspec colname='special'/>
           <colspec colname='special'/>
           <colspec colname='description'/>
           <colspec colname='description'/>
           <thead><row><entry>Component</entry><entry>Special</entry><entry>Description</entry></row></thead>
           <thead><row><entry>Component</entry><entry>Special</entry><entry>Description</entry></row></thead>
           <tbody>
           <tbody>
-            <row><entry>b10-auth</entry><entry>auth</entry><entry>Authoritative server</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>The resolver</entry></row>
+            <row><entry>b10-resolver</entry><entry>resolver</entry><entry>DNS resolver</entry></row>
-            <row><entry>b10-cmdctl</entry><entry>cmdctl</entry><entry>The command control (remote control interface)</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 -->
             <!-- TODO Either add xfrin and xfrout as well or clean up the workarounds in boss before the release -->
           </tbody>
           </tbody>
           </tgroup>
           </tgroup>
@@ -859,32 +898,34 @@ as a dependency earlier -->
       </para>
       </para>
 
 
       <para>
       <para>
-        The kind specifies how a failure of the component should
+	The <varname>kind</varname> specifies how a failure of the
-        be handled.  If it is set to <quote>dispensable</quote>
+	component should be handled.  If it is set to
-        (the default unless you set something else), it will get
+	<quote>dispensable</quote> (the default unless you set
-        started again if it fails. If it is set to <quote>needed</quote>
+	something else), it will get started again if it fails. If
-        and it fails at startup, the whole <command>bind10</command>
+	it is set to <quote>needed</quote> and it fails at startup,
-        shuts down and exits with error exit code. But if it fails
+	the whole <command>bind10</command> shuts down and exits
-        some time later, it is just started again. If you set it
+	with an error exit code. But if it fails some time later, it
-        to <quote>core</quote>, you indicate that the system is
+	is just started again. If you set it to <quote>core</quote>,
-        not usable without the component and if such component
+	you indicate that the system is not usable without the
-        fails, the system shuts down no matter when the failure
+	component and if such component fails, the system shuts
-        happened.  This is the behaviour of the core components
+	down no matter when the failure happened.  This is the
-        (the ones you can't turn off), but you can declare any
+	behaviour of the core components (the ones you can't turn
-        other components as core as well if you wish (but you can
+	off), but you can declare any other components as core as
-        turn these off, they just can't fail).
+	well if you wish (but you can turn these off, they just
+	can't fail).
       </para>
       </para>
 
 
       <para>
       <para>
-        The priority defines order in which the components should start.
+	The <varname>priority</varname> defines order in which the
-        The ones with higher number are started sooner than the ones with
+	components should start.  The ones with higher numbers are
-        lower ones. If you don't set it, 0 (zero) is used as the priority.
+	started sooner than the ones with lower ones. If you don't
-        Usually, leaving it at the default is enough.
+	set it, 0 (zero) is used as the priority.  Usually, leaving
+	it at the default is enough.
       </para>
       </para>
 
 
       <para>
       <para>
         There are other parameters we didn't use in our example.
         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>
         used by the component on the <command>b10-msgq</command>
         message bus. The special components already know their
         message bus. The special components already know their
         address, but the usual ones don't. The address is by
         address, but the usual ones don't. The address is by
@@ -900,25 +941,17 @@ address, but the usual ones don't." mean? -->
 <!-- TODO: document params when is enabled -->
 <!-- TODO: document params when is enabled -->
 
 
       <para>
       <para>
-        The last one is process. It is the name of the process to be started.
+	The last one is <varname>process</varname>. It is the name
-        It defaults to the name of the component if not set, but you can use
+	of the process to be started.  It defaults to the name of
-        this to override it.
+	the component if not set, but you can use this to override
+	it. (The special components also already know their
+        executable name.)
       </para>
       </para>
 
 
       <!-- TODO Add parameters when they work, not implemented yet-->
       <!-- TODO Add parameters when they work, not implemented yet-->
 
 
       <note>
       <note>
         <para>
         <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
           The configuration is quite powerful, but that includes
           a lot of space for mistakes. You could turn off the
           a lot of space for mistakes. You could turn off the
           <command>b10-cmdctl</command>, but then you couldn't
           <command>b10-cmdctl</command>, but then you couldn't
@@ -938,7 +971,7 @@ address, but the usual ones don't." mean? -->
       </note>
       </note>
       <para>
       <para>
         It is possible to start some components multiple times (currently
         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
         You might want to do that to gain more performance (each one uses only
         single core). Just put multiple entries under different names, like
         single core). Just put multiple entries under different names, like
         this, with the same config:
         this, with the same config:
@@ -953,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
         server will keep its own copy of in-memory data and there could be
         problems with locking the sqlite database, if used. The configuration
         problems with locking the sqlite database, if used. The configuration
         might be changed to something more convenient in future.
         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>
       </para>
     </section>
     </section>
 
 
@@ -977,23 +1013,11 @@ address, but the usual ones don't." mean? -->
       <para>
       <para>
         Administrators do not communicate directly with the
         Administrators do not communicate directly with the
         <command>b10-msgq</command> daemon.
         <command>b10-msgq</command> daemon.
-        By default, BIND 10 uses port 9912 for the
+        By default, BIND 10 uses a UNIX domain socket file named
-        <command>b10-msgq</command> service.
+        <filename>/usr/local/var/bind10-devel/msg_socket</filename>
-        It listens on 127.0.0.1.
+        for this interprocess communication.
       </para>
       </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>
 
 
   <chapter id="cfgmgr">
   <chapter id="cfgmgr">
@@ -1035,9 +1059,6 @@ Unix domain sockets
         specifications and all current settings to the
         specifications and all current settings to the
         <command>bindctl</command> client (via
         <command>bindctl</command> client (via
         <command>b10-cmdctl</command>).
         <command>b10-cmdctl</command>).
-      </para>
-
-      <para>
         <command>b10-cfgmgr</command> relays configurations received
         <command>b10-cfgmgr</command> relays configurations received
         from <command>b10-cmdctl</command> to the appropriate modules.
         from <command>b10-cmdctl</command> to the appropriate modules.
       </para>
       </para>
@@ -1056,7 +1077,7 @@ config changes are actually commands to cfgmgr
       <para>
       <para>
         The stored configuration file is at
         The stored configuration file is at
         <filename>/usr/local/var/bind10-devel/b10-config.db</filename>.
         <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>.
         <option>--localstatedir</option>.
         The default is <filename>/usr/local/var/</filename>.)
         The default is <filename>/usr/local/var/</filename>.)
         The format is loosely based on JSON and is directly parseable
         The format is loosely based on JSON and is directly parseable
@@ -1174,7 +1195,7 @@ but you might wanna check with likun
 
 
 <!-- TODO
 <!-- TODO
 openssl req -new -x509 -keyout server.pem -out server.pem -days 365 -nodes
 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?
 -->
 -->
 
 
 <!--
 <!--
@@ -1241,7 +1262,6 @@ shutdown
 <!--
 <!--
 TODO
 TODO
 (12:21:30) jinmei: I'd like to have sample session using a command line www client such as wget
 (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>
   </chapter>

+ 3 - 0
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
 the client's address (and port), and the error message sent from the
 lower layer that detects the failure.
 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
 % AUTH_NOTIFY_QUESTIONS invalid number of questions (%1) in incoming NOTIFY
 This debug message is logged by the authoritative server when it receives
 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
 a NOTIFY packet that contains zero or more than one question. (A valid

+ 3 - 0
src/bin/auth/auth_srv.cc

@@ -828,6 +828,9 @@ AuthSrvImpl::processNotify(const IOMessage& io_message, Message& message,
         return (false);
         return (false);
     }
     }
 
 
+    LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_RECEIVED_NOTIFY)
+      .arg(question->getName()).arg(question->getClass());
+
     const string remote_ip_address =
     const string remote_ip_address =
         io_message.getRemoteEndpoint().getAddress().toText();
         io_message.getRemoteEndpoint().getAddress().toText();
     static const string command_template_start =
     static const string command_template_start =

+ 1 - 1
src/bin/cmdctl/cmdctl.py.in

@@ -541,7 +541,7 @@ class SecureHTTPServer(socketserver_mixin.NoPollMixIn,
                                       ssl_version = ssl.PROTOCOL_SSLv23)
                                       ssl_version = ssl.PROTOCOL_SSLv23)
             return ssl_sock
             return ssl_sock
         except (ssl.SSLError, CmdctlException) as err :
         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)
             self.close_request(sock)
             # raise socket error to finish the request
             # raise socket error to finish the request
             raise socket.error
             raise socket.error

+ 1 - 7
src/bin/msgq/msgq.xml

@@ -20,7 +20,7 @@
 <refentry>
 <refentry>
 
 
   <refentryinfo>
   <refentryinfo>
-    <date>August 4, 2010</date>
+    <date>June 25, 2012</date>
   </refentryinfo>
   </refentryinfo>
 
 
   <refmeta>
   <refmeta>
@@ -92,10 +92,6 @@
     </para>
     </para>
 
 
     <para>
     <para>
-      It listens on 127.0.0.1.
-    </para>
-
-    <para>
       The <command>b10-msgq</command> daemon may be cleanly stopped by
       The <command>b10-msgq</command> daemon may be cleanly stopped by
       sending the SIGTERM signal to the process.
       sending the SIGTERM signal to the process.
       This shutdown does not notify the subscribers.
       This shutdown does not notify the subscribers.
@@ -168,5 +164,3 @@
  - End:
  - End:
 -->
 -->
 
 
-
-

+ 4 - 0
src/bin/xfrin/xfrin.py.in

@@ -889,6 +889,10 @@ class XfrinConnection(asyncore.dispatcher):
             req_str = 'IXFR' if request_type == RRType.IXFR() else 'AXFR'
             req_str = 'IXFR' if request_type == RRType.IXFR() else 'AXFR'
             if check_soa:
             if check_soa:
                 self._check_soa_serial()
                 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())
             logger.info(XFRIN_XFR_TRANSFER_STARTED, req_str, self.zone_str())
             self._send_query(self._request_type)
             self._send_query(self._request_type)

+ 3 - 0
src/bin/xfrout/xfrout.py.in

@@ -952,6 +952,9 @@ class XfroutServer:
     def _start_notifier(self):
     def _start_notifier(self):
         datasrc = self._unix_socket_server.get_db_file()
         datasrc = self._unix_socket_server.get_db_file()
         self._notifier = notify_out.NotifyOut(datasrc)
         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()
         self._notifier.dispatcher()
 
 
     def send_notify(self, zone_name, zone_class):
     def send_notify(self, zone_name, zone_class):

+ 27 - 0
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_name": "zone_config",
          "item_type": "list",
          "item_type": "list",
          "item_optional": true,
          "item_optional": true,

+ 6 - 5
src/lib/config/tests/ccsession_unittests.cc

@@ -33,7 +33,6 @@ using namespace isc::data;
 using namespace isc::config;
 using namespace isc::config;
 using namespace isc::cc;
 using namespace isc::cc;
 using namespace std;
 using namespace std;
-using namespace boost;
 
 
 namespace {
 namespace {
 std::string
 std::string
@@ -52,6 +51,7 @@ protected:
                       root_name(isc::log::getRootLoggerName())
                       root_name(isc::log::getRootLoggerName())
     {
     {
         // upon creation of a ModuleCCSession, the class
         // upon creation of a ModuleCCSession, the class
+
         // sends its specification to the config manager.
         // sends its specification to the config manager.
         // it expects an ok answer back, so everytime we
         // it expects an ok answer back, so everytime we
         // create a ModuleCCSession, we must set an initial
         // create a ModuleCCSession, we must set an initial
@@ -740,8 +740,9 @@ protected:
         registerCommand(const string& recipient)
         registerCommand(const string& recipient)
     {
     {
         return (mccs_.groupRecvMsgAsync(
         return (mccs_.groupRecvMsgAsync(
-            bind(&AsyncReceiveCCSessionTest::callback, this, next_flag_ ++, _1,
+                    boost::bind(&AsyncReceiveCCSessionTest::callback, this,
-                 _2, _3), false, -1, recipient));
+                                next_flag_++, _1, _2, _3), false, -1,
+                    recipient));
     }
     }
     /// \brief Convenience function to queue a request to get a reply
     /// \brief Convenience function to queue a request to get a reply
     ///     message.
     ///     message.
@@ -749,8 +750,8 @@ protected:
         registerReply(int seq)
         registerReply(int seq)
     {
     {
         return (mccs_.groupRecvMsgAsync(
         return (mccs_.groupRecvMsgAsync(
-            bind(&AsyncReceiveCCSessionTest::callback, this, next_flag_ ++, _1,
+                    boost::bind(&AsyncReceiveCCSessionTest::callback, this,
-                 _2, _3), true, seq));
+                                next_flag_++, _1, _2, _3), true, seq));
     }
     }
     /// \brief Check the next called callback was with this flag
     /// \brief Check the next called callback was with this flag
     void called(int flag) {
     void called(int flag) {

+ 22 - 35
src/lib/datasrc/database.cc

@@ -179,8 +179,7 @@ private:
 
 
 DatabaseClient::Finder::FoundRRsets
 DatabaseClient::Finder::FoundRRsets
 DatabaseClient::Finder::getRRsets(const string& name, const WantedTypes& types,
 DatabaseClient::Finder::getRRsets(const string& name, const WantedTypes& types,
-                                  bool check_ns, const string* construct_name,
+                                  const string* construct_name, bool any,
-                                  bool any,
                                   DatabaseAccessor::IteratorContextPtr context)
                                   DatabaseAccessor::IteratorContextPtr context)
 {
 {
     RRsigStore sig_store;
     RRsigStore sig_store;
@@ -204,9 +203,7 @@ DatabaseClient::Finder::getRRsets(const string& name, const WantedTypes& types,
     const Name construct_name_object(*construct_name);
     const Name construct_name_object(*construct_name);
 
 
     bool seen_cname(false);
     bool seen_cname(false);
-    bool seen_ds(false);
     bool seen_other(false);
     bool seen_other(false);
-    bool seen_ns(false);
 
 
     while (context->getNext(columns)) {
     while (context->getNext(columns)) {
         // The domain is not empty
         // The domain is not empty
@@ -249,16 +246,12 @@ DatabaseClient::Finder::getRRsets(const string& name, const WantedTypes& types,
 
 
             if (cur_type == RRType::CNAME()) {
             if (cur_type == RRType::CNAME()) {
                 seen_cname = true;
                 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() &&
             } else if (cur_type != RRType::RRSIG() &&
                        cur_type != RRType::NSEC3() &&
                        cur_type != RRType::NSEC3() &&
                        cur_type != RRType::NSEC()) {
                        cur_type != RRType::NSEC()) {
                 // NSEC and RRSIG can coexist with anything, otherwise
                 // NSEC and RRSIG can coexist with anything, otherwise
                 // we've seen something that can't live together with potential
                 // we've seen something that can't live together with potential
-                // CNAME or NS
+                // CNAME.
                 //
                 //
                 // NSEC3 lives in separate namespace from everything, therefore
                 // NSEC3 lives in separate namespace from everything, therefore
                 // we just ignore it here for these checks as well.
                 // 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]);
                       RDATA_COLUMN]);
         }
         }
     }
     }
-    if (seen_cname && (seen_other || seen_ns || seen_ds)) {
+    if (seen_cname && seen_other) {
         isc_throw(DataSourceError, "CNAME shares domain " << name <<
         isc_throw(DataSourceError, "CNAME shares domain " << name <<
                   " with something else");
                   " 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
     // Add signatures to all found RRsets
     for (std::map<RRType, RRsetPtr>::iterator i(result.begin());
     for (std::map<RRType, RRsetPtr>::iterator i(result.begin());
          i != result.end(); ++ i) {
          i != result.end(); ++ i) {
@@ -455,20 +444,20 @@ DatabaseClient::Finder::findDelegationPoint(const isc::dns::Name& name,
     for (int i = remove_labels; i > 0; --i) {
     for (int i = remove_labels; i > 0; --i) {
         const Name superdomain(name.split(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
         // Look if there's NS or DNAME at this point of the tree, but ignore
         // the NS RRs at the apex of the zone.
         // the NS RRs at the apex of the zone.
         const FoundRRsets found = getRRsets(superdomain.toText(),
         const FoundRRsets found = getRRsets(superdomain.toText(),
-                                            DELEGATION_TYPES(), not_origin);
+                                            DELEGATION_TYPES());
         if (found.first) {
         if (found.first) {
             // This node contains either NS or DNAME RRs so it does exist.
             // This node contains either NS or DNAME RRs so it does exist.
             const FoundIterator nsi(found.second.find(RRType::NS()));
             const FoundIterator nsi(found.second.find(RRType::NS()));
             const FoundIterator dni(found.second.find(RRType::DNAME()));
             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
             // An optimisation.  We know that there is an exact match for
             // something at this point in the tree so remember it.  If we have
             // 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
             // 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();
             last_known = superdomain.getLabelCount();
 
 
             if (glue_ok && !first_ns && not_origin &&
             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
                 // If we are searching for glue ("glue OK" mode), store the
                 // highest NS record that we find that is not the apex.  This
                 // highest NS record that we find that is not the apex.  This
                 // is another optimisation for later, where we need the
                 // 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
         // TODO Add a check for DNAME, as DNAME wildcards are discouraged (see
         // RFC 4592 section 4.4).
         // RFC 4592 section 4.4).
         // Search for a match.  The types are the same as with original query.
         // Search for a match.  The types are the same as with original query.
-        FoundRRsets found = getRRsets(wildcard, final_types, true,
+        const FoundRRsets found = getRRsets(wildcard, final_types,
-                                      &construct_name, type == RRType::ANY());
+                                            &construct_name,
+                                            type == RRType::ANY());
         if (found.first) {
         if (found.first) {
             // Found something - but what?
             // Found something - but what?
 
 
@@ -694,7 +684,7 @@ DatabaseClient::Finder::FindDNSSECContext::probe() {
             // such cases).
             // such cases).
             const string origin = finder_.getOrigin().toText();
             const string origin = finder_.getOrigin().toText();
             const FoundRRsets nsec3_found =
             const FoundRRsets nsec3_found =
-                finder_.getRRsets(origin, NSEC3PARAM_TYPES(), false);
+                finder_.getRRsets(origin, NSEC3PARAM_TYPES());
             const FoundIterator nfi=
             const FoundIterator nfi=
                 nsec3_found.second.find(RRType::NSEC3PARAM());
                 nsec3_found.second.find(RRType::NSEC3PARAM());
             is_nsec3_ = (nfi != nsec3_found.second.end());
             is_nsec3_ = (nfi != nsec3_found.second.end());
@@ -705,7 +695,7 @@ DatabaseClient::Finder::FindDNSSECContext::probe() {
             // described in Section 10.4 of RFC 5155.
             // described in Section 10.4 of RFC 5155.
             if (!is_nsec3_) {
             if (!is_nsec3_) {
                 const FoundRRsets nsec_found =
                 const FoundRRsets nsec_found =
-                    finder_.getRRsets(origin, NSEC_TYPES(), false);
+                    finder_.getRRsets(origin, NSEC_TYPES());
                 const FoundIterator nfi =
                 const FoundIterator nfi =
                     nsec_found.second.find(RRType::NSEC());
                     nsec_found.second.find(RRType::NSEC());
                 is_nsec_ = (nfi != nsec_found.second.end());
                 is_nsec_ = (nfi != nsec_found.second.end());
@@ -757,10 +747,8 @@ DatabaseClient::Finder::FindDNSSECContext::getDNSSECRRset(const Name &name,
     try {
     try {
         const Name& nsec_name =
         const Name& nsec_name =
             covering ? finder_.findPreviousName(name) : name;
             covering ? finder_.findPreviousName(name) : name;
-        const bool need_nscheck = (nsec_name != finder_.getOrigin());
         const FoundRRsets found = finder_.getRRsets(nsec_name.toText(),
         const FoundRRsets found = finder_.getRRsets(nsec_name.toText(),
-                                                    NSEC_TYPES(),
+                                                    NSEC_TYPES());
-                                                    need_nscheck);
         const FoundIterator nci = found.second.find(RRType::NSEC());
         const FoundIterator nci = found.second.find(RRType::NSEC());
         if (nci != found.second.end()) {
         if (nci != found.second.end()) {
             return (nci->second);
             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
     // - 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
     //   apex - DNAME is ignored here as it redirects DNS names subordinate to
     //   the owner name - the owner name itself is not redirected.)
     //   the owner name - the owner name itself is not redirected.)
-    const bool is_origin = (name == getOrigin());
     WantedTypes final_types(FINAL_TYPES());
     WantedTypes final_types(FINAL_TYPES());
     final_types.insert(type);
     final_types.insert(type);
     const FoundRRsets found = getRRsets(name.toText(), final_types,
     const FoundRRsets found = getRRsets(name.toText(), final_types,
-                                        !is_origin, NULL,
+                                        NULL, type == RRType::ANY());
-                                        type == RRType::ANY());
     FindDNSSECContext dnssec_ctx(*this, options);
     FindDNSSECContext dnssec_ctx(*this, options);
     if (found.first) {
     if (found.first) {
         // Something found at the domain name.  Look into it further to get
         // Something found at the domain name.  Look into it further to get
         // the final result.
         // the final result.
+        const bool is_origin = (name == getOrigin());
         return (findOnNameResult(name, type, options, is_origin, found, NULL,
         return (findOnNameResult(name, type, options, is_origin, found, NULL,
                                  target, dnssec_ctx));
                                  target, dnssec_ctx));
     } else {
     } 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
     // Now, we need to get the NSEC3 params from the apex and create the hash
     // creator for it.
     // creator for it.
     const FoundRRsets nsec3param(getRRsets(getOrigin().toText(),
     const FoundRRsets nsec3param(getRRsets(getOrigin().toText(),
-                                 NSEC3PARAM_TYPES(), false));
+                                           NSEC3PARAM_TYPES()));
     const FoundIterator param(nsec3param.second.find(RRType::NSEC3PARAM()));
     const FoundIterator param(nsec3param.second.find(RRType::NSEC3PARAM()));
     if (!nsec3param.first || param == nsec3param.second.end()) {
     if (!nsec3param.first || param == nsec3param.second.end()) {
         // No NSEC3 params? :-(
         // No NSEC3 params? :-(
@@ -1061,7 +1048,7 @@ DatabaseClient::Finder::findNSEC3(const Name& name, bool recursive) {
         }
         }
 
 
         const FoundRRsets nsec3(getRRsets(hash + "." + otext, NSEC3_TYPES(),
         const FoundRRsets nsec3(getRRsets(hash + "." + otext, NSEC3_TYPES(),
-                                          false, NULL, false, context));
+                                          NULL, false, context));
 
 
         if (nsec3.first) {
         if (nsec3.first) {
             // We found an exact match against the current label.
             // 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);
                 arg(labels).arg(prevHash);
             context = accessor_->getNSEC3Records(prevHash, zone_id_);
             context = accessor_->getNSEC3Records(prevHash, zone_id_);
             const FoundRRsets prev_nsec3(getRRsets(prevHash + "." + otext,
             const FoundRRsets prev_nsec3(getRRsets(prevHash + "." + otext,
-                                                   NSEC3_TYPES(), false, NULL,
+                                                   NSEC3_TYPES(), NULL, false,
-                                                   false, context));
+                                                   context));
 
 
             if (!prev_nsec3.first) {
             if (!prev_nsec3.first) {
                 isc_throw(DataSourceError, "Hash " + prevHash + " returned "
                 isc_throw(DataSourceError, "Hash " + prevHash + " returned "

+ 6 - 9
src/lib/datasrc/database.h

@@ -963,17 +963,14 @@ public:
         ///
         ///
         /// \param name Which domain name should be scanned.
         /// \param name Which domain name should be scanned.
         /// \param types List of types the caller is interested in.
         /// \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
         /// \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
+        ///     their name set to name. If it is not NULL, it overrides the
-        ///     and uses this one (this can be used for wildcard synthesized
+        ///     name and uses this one (this can be used for wildcard
-        ///     records).
+        ///     synthesized records).
         /// \param any If this is true, it records all the types, not only the
         /// \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
         ///     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
+        ///     ANY type into the result, if it finds any RRs at all, to easy
-        ///     identification of success.
+        ///     the identification of success.
         /// \param srcContext This can be set to non-NULL value to override the
         /// \param srcContext This can be set to non-NULL value to override the
         ///     iterator context used for obtaining the data. This can be used,
         ///     iterator context used for obtaining the data. This can be used,
         ///     for example, to get data from the NSEC3 namespace.
         ///     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
         /// \throw DataSourceError If there's a low-level error with the
         ///     database or the database contains bad data.
         ///     database or the database contains bad data.
         FoundRRsets getRRsets(const std::string& name,
         FoundRRsets getRRsets(const std::string& name,
-                              const WantedTypes& types, bool check_ns,
+                              const WantedTypes& types,
                               const std::string* construct_name = NULL,
                               const std::string* construct_name = NULL,
                               bool any = false,
                               bool any = false,
                               DatabaseAccessor::IteratorContextPtr srcContext =
                               DatabaseAccessor::IteratorContextPtr srcContext =

+ 24 - 13
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 "
     {"child.insecdelegation.example.org.", "DS", "3600", "", "DS 5 3 3600 "
      "20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
      "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.", "A", "3600", "", "192.0.2.1"},
     {"brokenns1.example.org.", "NS", "3600", "", "ns.example.com."},
     {"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
     // Now double DNAME, to test failure mode
     {"baddname.example.org.", "DNAME", "3600", "", "dname1.example.com."},
     {"baddname.example.org.", "DNAME", "3600", "", "dname1.example.com."},
     {"baddname.example.org.", "DNAME", "3600", "", "dname2.example.com."},
     {"baddname.example.org.", "DNAME", "3600", "", "dname2.example.com."},
@@ -2202,15 +2205,23 @@ TYPED_TEST(DatabaseClientTest, findDelegation) {
                               ZoneFinder::FIND_DEFAULT),
                               ZoneFinder::FIND_DEFAULT),
                  DataSourceError);
                  DataSourceError);
 
 
-    // Broken NS - it lives together with something else
+    // NS and other type coexist: deviant and not necessarily harmful.
-    EXPECT_THROW(finder->find(isc::dns::Name("brokenns1.example.org."),
+    // It should normally just result in DELEGATION; if GLUE_OK is specified,
-                              this->qtype_,
+    // the other RR should be visible.
-                              ZoneFinder::FIND_DEFAULT),
+    this->expected_rdatas_.clear();
-                 DataSourceError);
+    this->expected_rdatas_.push_back("ns.example.com");
-    EXPECT_THROW(finder->find(isc::dns::Name("brokenns2.example.org."),
+    doFindTest(*finder, Name("brokenns1.example.org"), this->qtype_,
-                              this->qtype_,
+               RRType::NS(), this->rrttl_, ZoneFinder::DELEGATION,
-                              ZoneFinder::FIND_DEFAULT),
+               this->expected_rdatas_, this->empty_rdatas_,
-                 DataSourceError);
+               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) {
 TYPED_TEST(DatabaseClientTest, findDS) {

+ 0 - 13
src/lib/datasrc/tests/zone_finder_context_unittest.cc

@@ -208,13 +208,6 @@ TEST_P(ZoneFinderContextTest, getAdditionalDelegation) {
 TEST_P(ZoneFinderContextTest, getAdditionalDelegationAtZoneCut) {
 TEST_P(ZoneFinderContextTest, getAdditionalDelegationAtZoneCut) {
     // Similar to the previous case, but one of the NS addresses is at the
     // Similar to the previous case, but one of the NS addresses is at the
     // zone cut.
     // 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"),
     ZoneFinderContextPtr ctx = finder_->find(Name("www.b.example.org"),
                                              RRType::SOA());
                                              RRType::SOA());
     EXPECT_EQ(ZoneFinder::DELEGATION, ctx->code);
     EXPECT_EQ(ZoneFinder::DELEGATION, ctx->code);
@@ -316,12 +309,6 @@ TEST_P(ZoneFinderContextTest, getAdditionalMX) {
 }
 }
 
 
 TEST_P(ZoneFinderContextTest, getAdditionalMXAtZoneCut) {
 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."),
     ZoneFinderContextPtr ctx = finder_->find(Name("mxatcut.example.org."),
                                              RRType::MX());
                                              RRType::MX());
     EXPECT_EQ(ZoneFinder::SUCCESS, ctx->code);
     EXPECT_EQ(ZoneFinder::SUCCESS, ctx->code);

+ 10 - 0
src/lib/datasrc/zone.h

@@ -376,6 +376,16 @@ public:
     ///   RRsets for that name are searched just like the normal case;
     ///   RRsets for that name are searched just like the normal case;
     ///   otherwise, if the search has encountered a zone cut, \c DELEGATION
     ///   otherwise, if the search has encountered a zone cut, \c DELEGATION
     ///   with the information of the highest zone cut will be returned.
     ///   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
     /// - \c FIND_DNSSEC Request that DNSSEC data (like NSEC, RRSIGs) are
     ///   returned with the answer. It is allowed for the data source to
     ///   returned with the answer. It is allowed for the data source to
     ///   include them even when not requested.
     ///   include them even when not requested.

+ 8 - 8
src/lib/dns/labelsequence.cc

@@ -23,7 +23,7 @@
 namespace isc {
 namespace isc {
 namespace dns {
 namespace dns {
 
 
-const char*
+const uint8_t*
 LabelSequence::getData(size_t *len) const {
 LabelSequence::getData(size_t *len) const {
     *len = getDataLength();
     *len = getDataLength();
     return (&name_.ndata_[name_.offsets_[first_label_]]);
     return (&name_.ndata_[name_.offsets_[first_label_]]);
@@ -47,22 +47,22 @@ LabelSequence::getDataLength() const {
 bool
 bool
 LabelSequence::equals(const LabelSequence& other, bool case_sensitive) const {
 LabelSequence::equals(const LabelSequence& other, bool case_sensitive) const {
     size_t len, other_len;
     size_t len, other_len;
-    const char* data = getData(&len);
+    const uint8_t* data = getData(&len);
-    const char* other_data = other.getData(&other_len);
+    const uint8_t* other_data = other.getData(&other_len);
 
 
     if (len != other_len) {
     if (len != other_len) {
         return (false);
         return (false);
     }
     }
     if (case_sensitive) {
     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,
     // 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
     // label length must never be a capital ascii character, so we can
     // simply compare them after converting to lower characters.
     // simply compare them after converting to lower characters.
     for (size_t i = 0; i < len; ++i) {
     for (size_t i = 0; i < len; ++i) {
-        const unsigned char ch = data[i];
+        const uint8_t ch = data[i];
-        const unsigned char other_ch = other_data[i];
+        const uint8_t other_ch = other_data[i];
         if (isc::dns::name::internal::maptolower[ch] !=
         if (isc::dns::name::internal::maptolower[ch] !=
             isc::dns::name::internal::maptolower[other_ch]) {
             isc::dns::name::internal::maptolower[other_ch]) {
             return (false);
             return (false);
@@ -112,14 +112,14 @@ LabelSequence::isAbsolute() const {
 size_t
 size_t
 LabelSequence::getHash(bool case_sensitive) const {
 LabelSequence::getHash(bool case_sensitive) const {
     size_t length;
     size_t length;
-    const char* s = getData(&length);
+    const uint8_t* s = getData(&length);
     if (length > 16) {
     if (length > 16) {
         length = 16;
         length = 16;
     }
     }
 
 
     size_t hash_val = 0;
     size_t hash_val = 0;
     while (length > 0) {
     while (length > 0) {
-        const unsigned char c = *s++;
+        const uint8_t c = *s++;
         boost::hash_combine(hash_val, case_sensitive ? c :
         boost::hash_combine(hash_val, case_sensitive ? c :
                             isc::dns::name::internal::maptolower[c]);
                             isc::dns::name::internal::maptolower[c]);
         --length;
         --length;

+ 1 - 1
src/lib/dns/labelsequence.h

@@ -67,7 +67,7 @@ public:
     /// \param len Pointer to a size_t where the length of the data
     /// \param len Pointer to a size_t where the length of the data
     ///        will be stored (in number of octets)
     ///        will be stored (in number of octets)
     /// \return Pointer to the wire-format data of this label sequence
     /// \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
     /// \brief Return the length of the wire-format data of this LabelSequence
     ///
     ///

+ 3 - 3
src/lib/dns/messagerenderer.cc

@@ -100,8 +100,8 @@ struct NameCompare {
         uint16_t item_label_len = 0;
         uint16_t item_label_len = 0;
         for (size_t i = 0; i < item.len_; ++i, ++item_pos) {
         for (size_t i = 0; i < item.len_; ++i, ++item_pos) {
             item_pos = nextPosition(*buffer_, item_pos, item_label_len);
             item_pos = nextPosition(*buffer_, item_pos, item_label_len);
-            const unsigned char ch1 = (*buffer_)[item_pos];
+            const uint8_t ch1 = (*buffer_)[item_pos];
-            const unsigned char ch2 = name_buf_->readUint8();
+            const uint8_t ch2 = name_buf_->readUint8();
             if (CASE_SENSITIVE) {
             if (CASE_SENSITIVE) {
                 if (ch1 != ch2) {
                 if (ch1 != ch2) {
                     return (false);
                     return (false);
@@ -293,7 +293,7 @@ MessageRenderer::writeName(const Name& name, const bool compress) {
     LabelSequence sequence(name);
     LabelSequence sequence(name);
     const size_t nlabels = sequence.getLabelCount();
     const size_t nlabels = sequence.getLabelCount();
     size_t data_len;
     size_t data_len;
-    const char* data;
+    const uint8_t* data;
 
 
     // Find the offset in the offset table whose name gives the longest
     // Find the offset in the offset table whose name gives the longest
     // match against the name to be rendered.
     // match against the name to be rendered.

+ 16 - 16
src/lib/dns/name.cc

@@ -75,7 +75,7 @@ const char digitvalue[256] = {
 
 
 namespace name {
 namespace name {
 namespace internal {
 namespace internal {
-const unsigned char maptolower[] = {
+const uint8_t maptolower[] = {
     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
@@ -147,11 +147,11 @@ Name::Name(const std::string &namestring, bool downcase) {
     bool is_root = false;
     bool is_root = false;
     ft_state state = ft_init;
     ft_state state = ft_init;
 
 
-    std::vector<unsigned char> offsets;
+    NameOffsets offsets;
     offsets.reserve(Name::MAX_LABELS);
     offsets.reserve(Name::MAX_LABELS);
     offsets.push_back(0);
     offsets.push_back(0);
 
 
-    std::string ndata;
+    NameString ndata;
     ndata.reserve(Name::MAX_WIRE);
     ndata.reserve(Name::MAX_WIRE);
 
 
     // should we refactor this code using, e.g, the state pattern?  Probably
     // should we refactor this code using, e.g, the state pattern?  Probably
@@ -310,7 +310,7 @@ typedef enum {
 }
 }
 
 
 Name::Name(InputBuffer& buffer, bool downcase) {
 Name::Name(InputBuffer& buffer, bool downcase) {
-    std::vector<unsigned char> offsets;
+    NameOffsets offsets;
     offsets.reserve(Name::MAX_LABELS);
     offsets.reserve(Name::MAX_LABELS);
 
 
     /*
     /*
@@ -436,8 +436,8 @@ Name::toText(bool omit_final_dot) const {
         return (".");
         return (".");
     }
     }
 
 
-    std::string::const_iterator np = ndata_.begin();
+    NameString::const_iterator np = ndata_.begin();
-    std::string::const_iterator np_end = ndata_.end();
+    NameString::const_iterator np_end = ndata_.end();
     unsigned int labels = labelcount_; // use for integrity check
     unsigned int labels = labelcount_; // use for integrity check
     // init with an impossible value to catch error cases in the end:
     // init with an impossible value to catch error cases in the end:
     unsigned int count = MAX_LABELLEN + 1;
     unsigned int count = MAX_LABELLEN + 1;
@@ -467,7 +467,7 @@ Name::toText(bool omit_final_dot) const {
             }
             }
 
 
             while (count-- > 0) {
             while (count-- > 0) {
-                unsigned char c = *np++;
+                uint8_t c = *np++;
                 switch (c) {
                 switch (c) {
                 case 0x22: // '"'
                 case 0x22: // '"'
                 case 0x28: // '('
                 case 0x28: // '('
@@ -554,8 +554,8 @@ Name::compare(const Name& other,
         unsigned int count = (cdiff < 0) ? count1 : count2;
         unsigned int count = (cdiff < 0) ? count1 : count2;
 
 
         while (count > 0) {
         while (count > 0) {
-            unsigned char label1 = ndata_[pos1];
+            uint8_t label1 = ndata_[pos1];
-            unsigned char label2 = other.ndata_[pos2];
+            uint8_t label2 = other.ndata_[pos2];
             int chdiff;
             int chdiff;
 
 
             if (case_sensitive) {
             if (case_sensitive) {
@@ -611,15 +611,15 @@ Name::equals(const Name& other) const {
     }
     }
 
 
     for (unsigned int l = labelcount_, pos = 0; l > 0; --l) {
     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]) {
         if (count != other.ndata_[pos]) {
             return (false);
             return (false);
         }
         }
         ++pos;
         ++pos;
 
 
         while (count-- > 0) {
         while (count-- > 0) {
-            unsigned char label1 = ndata_[pos];
+            uint8_t label1 = ndata_[pos];
-            unsigned char label2 = other.ndata_[pos];
+            uint8_t label2 = other.ndata_[pos];
 
 
             if (maptolower[label1] != maptolower[label2]) {
             if (maptolower[label1] != maptolower[label2]) {
                 return (false);
                 return (false);
@@ -703,9 +703,9 @@ Name::reverse() const {
     retname.ndata_.reserve(length_);
     retname.ndata_.reserve(length_);
 
 
     // Copy the original name, label by label, from tail to head.
     // Copy the original name, label by label, from tail to head.
-    vector<unsigned char>::const_reverse_iterator rit0 = offsets_.rbegin();
+    NameOffsets::const_reverse_iterator rit0 = offsets_.rbegin();
-    vector<unsigned char>::const_reverse_iterator rit1 = rit0 + 1;
+    NameOffsets::const_reverse_iterator rit1 = rit0 + 1;
-    string::const_iterator n0 = ndata_.begin();
+    NameString::const_iterator n0 = ndata_.begin();
     retname.offsets_.push_back(0);
     retname.offsets_.push_back(0);
     while (rit1 != offsets_.rend()) {
     while (rit1 != offsets_.rend()) {
         retname.ndata_.append(n0 + *rit1, n0 + *rit0);
         retname.ndata_.append(n0 + *rit1, n0 + *rit0);
@@ -786,7 +786,7 @@ Name::downcase() {
 
 
         while (count > 0) {
         while (count > 0) {
             ndata_.at(pos) =
             ndata_.at(pos) =
-                maptolower[static_cast<unsigned char>(ndata_.at(pos))];
+                maptolower[ndata_.at(pos)];
             ++pos;
             ++pos;
             --nlen;
             --nlen;
             --count;
             --count;

+ 7 - 2
src/lib/dns/name.h

@@ -230,6 +230,11 @@ class Name {
     ///
     ///
     //@{
     //@{
 private:
 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
     /// The default constructor
     ///
     ///
     /// This is used internally in the class implementation, but at least at
     /// This is used internally in the class implementation, but at least at
@@ -710,8 +715,8 @@ public:
     //@}
     //@}
 
 
 private:
 private:
-    std::string ndata_;
+    NameString ndata_;
-    std::vector<unsigned char> offsets_;
+    NameOffsets offsets_;
     unsigned int length_;
     unsigned int length_;
     unsigned int labelcount_;
     unsigned int labelcount_;
 };
 };

+ 1 - 1
src/lib/dns/name_internal.h

@@ -31,7 +31,7 @@ namespace isc {
 namespace dns {
 namespace dns {
 namespace name {
 namespace name {
 namespace internal {
 namespace internal {
-extern const unsigned char maptolower[];
+extern const uint8_t maptolower[];
 } // end of internal
 } // end of internal
 } // end of name
 } // end of name
 } // end of dns
 } // end of dns

+ 37 - 9
src/lib/dns/tests/labelsequence_unittest.cc

@@ -34,14 +34,21 @@ public:
                           n3("example.org"), n4("foo.bar.test.example"),
                           n3("example.org"), n4("foo.bar.test.example"),
                           n5("example.ORG"), n6("ExAmPlE.org"),
                           n5("example.ORG"), n6("ExAmPlE.org"),
                           n7("."), n8("foo.example.org.bar"),
                           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),
                           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
     // Need to keep names in scope for at least the lifetime of
     // the labelsequences
     // the labelsequences
     Name n1, n2, n3, n4, n5, n6, n7, n8;
     Name n1, n2, n3, n4, n5, n6, n7, n8;
+    Name n9, n10, n11, n12;
 
 
     LabelSequence ls1, ls2, ls3, ls4, ls5, ls6, ls7, ls8;
     LabelSequence ls1, ls2, ls3, ls4, ls5, ls6, ls7, ls8;
+    LabelSequence ls9, ls10, ls11, ls12;
 };
 };
 
 
 // Basic equality tests
 // Basic equality tests
@@ -81,6 +88,11 @@ TEST_F(LabelSequenceTest, equals_sensitive) {
     EXPECT_FALSE(ls5.equals(ls6, true));
     EXPECT_FALSE(ls5.equals(ls6, true));
     EXPECT_FALSE(ls5.equals(ls7, true));
     EXPECT_FALSE(ls5.equals(ls7, true));
     EXPECT_FALSE(ls5.equals(ls8, 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) {
 TEST_F(LabelSequenceTest, equals_insensitive) {
@@ -123,6 +135,11 @@ TEST_F(LabelSequenceTest, equals_insensitive) {
     EXPECT_TRUE(ls5.equals(ls5));
     EXPECT_TRUE(ls5.equals(ls5));
     EXPECT_TRUE(ls5.equals(ls6));
     EXPECT_TRUE(ls5.equals(ls6));
     EXPECT_FALSE(ls5.equals(ls7));
     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
 // Compare tests
@@ -343,25 +360,36 @@ TEST_F(LabelSequenceTest, compare) {
 }
 }
 
 
 void
 void
-getDataCheck(const char* expected_data, size_t expected_len,
+getDataCheck(const uint8_t* expected_data, size_t expected_len,
              const LabelSequence& ls)
              const LabelSequence& ls)
 {
 {
     size_t len;
     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 <<
     ASSERT_EQ(expected_len, len) << "Expected data: " << expected_data <<
                                     " name: " << ls.getName().toText();
                                     " name: " << ls.getName().toText();
     EXPECT_EQ(expected_len, ls.getDataLength()) <<
     EXPECT_EQ(expected_len, ls.getDataLength()) <<
         "Expected data: " << expected_data <<
         "Expected data: " << expected_data <<
         " name: " << ls.getName().toText();
         " name: " << ls.getName().toText();
     for (size_t i = 0; i < len; ++i) {
     for (size_t i = 0; i < len; ++i) {
-        EXPECT_EQ(expected_data[i], data[i]) << "Difference at pos " << i <<
+        EXPECT_EQ(expected_data[i], data[i]) <<
-                                                ": Expected data: " <<
+          "Difference at pos " << i << ": Expected data: " << expected_data <<
-                                                expected_data <<
+          " name: " << ls.getName().toText();;
-                                                " name: " <<
-                                                ls.getName().toText();;
     }
     }
 }
 }
 
 
+// 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) {
 TEST_F(LabelSequenceTest, getData) {
     getDataCheck("\007example\003org\000", 13, ls1);
     getDataCheck("\007example\003org\000", 13, ls1);
     getDataCheck("\007example\003com\000", 13, ls2);
     getDataCheck("\007example\003com\000", 13, ls2);
@@ -460,7 +488,7 @@ TEST_F(LabelSequenceTest, comparePart) {
 
 
     // Data comparison
     // Data comparison
     size_t len;
     size_t len;
-    const char* data = ls1.getData(&len);
+    const uint8_t* data = ls1.getData(&len);
     getDataCheck(data, len, ls8);
     getDataCheck(data, len, ls8);
 }
 }
 
 

+ 6 - 0
src/lib/python/isc/notify/notify_out.py

@@ -161,6 +161,12 @@ class NotifyOut:
             for item in slaves:
             for item in slaves:
                 self._notify_infos[zone_id].notify_slaves.append((item, 53))
                 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'):
     def send_notify(self, zone_name, zone_class='IN'):
         '''Send notify to one zone's slaves, this function is
         '''Send notify to one zone's slaves, this function is
         the only interface for class NotifyOut which can be called
         the only interface for class NotifyOut which can be called

+ 2 - 2
tests/lettuce/configurations/xfrin/inmem_slave.conf

@@ -19,8 +19,8 @@
             } ]
             } ]
         } ],
         } ],
         "listen_on": [ {
         "listen_on": [ {
-            "port": 47806,
+            "address": "::1",
-            "address": "127.0.0.1"
+            "port": 47806
         } ]
         } ]
     },
     },
     "Boss": {
     "Boss": {

+ 6 - 2
tests/lettuce/configurations/xfrin/retransfer_master.conf

@@ -10,13 +10,17 @@
     "Auth": {
     "Auth": {
         "database_file": "data/example.org.sqlite3",
         "database_file": "data/example.org.sqlite3",
         "listen_on": [ {
         "listen_on": [ {
-            "port": 47807,
+            "address": "::1",
-            "address": "::1"
+            "port": 47807
         } ]
         } ]
     },
     },
     "Xfrout": {
     "Xfrout": {
         "zone_config": [ {
         "zone_config": [ {
             "origin": "example.org"
             "origin": "example.org"
+        } ],
+        "also_notify": [ {
+            "address": "::1",
+            "port": 47806
         } ]
         } ]
     },
     },
     "Boss": {
     "Boss": {

+ 2 - 2
tests/lettuce/configurations/xfrin/retransfer_slave.conf

@@ -10,8 +10,8 @@
     "Auth": {
     "Auth": {
         "database_file": "data/test_nonexistent_db.sqlite3",
         "database_file": "data/test_nonexistent_db.sqlite3",
         "listen_on": [ {
         "listen_on": [ {
-            "port": 47806,
+            "address": "::1",
-            "address": "127.0.0.1"
+            "port": 47806
         } ]
         } ]
     },
     },
     "Boss": {
     "Boss": {

+ 38 - 0
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" }
+        }
+    }
+}

+ 1 - 0
tests/lettuce/data/.gitignore

@@ -1,2 +1,3 @@
 /inmem-xfrin.sqlite3
 /inmem-xfrin.sqlite3
 /test_nonexistent_db.sqlite3
 /test_nonexistent_db.sqlite3
+/xfrin-notify.sqlite3

+ 1 - 0
tests/lettuce/data/example.org

@@ -10,3 +10,4 @@ dname.example.org.	3600	IN	DNAME	dname.example.info.
 dname2.foo.example.org.	3600	IN	DNAME	dname2.example.info.
 dname2.foo.example.org.	3600	IN	DNAME	dname2.example.info.
 ns1.example.org.	3600	IN	A	192.0.2.3
 ns1.example.org.	3600	IN	A	192.0.2.3
 ns2.example.org.	3600	IN	A	192.0.2.4
 ns2.example.org.	3600	IN	A	192.0.2.4
+shell.example.org.	3600	IN	SSHFP	2 1 123456789abcdef67890123456789abcdef67890

BIN
tests/lettuce/data/xfrin-notify.sqlite3.orig


+ 4 - 4
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 XFRIN_STARTED
         And wait for bind10 stderr message ZONEMGR_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
         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
         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 XFRIN_TRANSFER_SUCCESS not XFRIN_XFR_PROCESS_FAILURE
         Then wait for new bind10 stderr message AUTH_LOAD_ZONE
         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
         The answer section of the last query response should be
         """
         """
         www.example.org.        3600    IN      A       192.0.2.1
         www.example.org.        3600    IN      A       192.0.2.1
         """
         """
-        A query for mail.example.org should have rcode NOERROR
+        A query for mail.example.org to [::1]:47806 should have rcode NOERROR

+ 25 - 0
tests/lettuce/features/queries.feature

@@ -103,6 +103,7 @@ Feature: Querying feature
         ns2.example.org.        3600    IN      A       192.0.2.4
         ns2.example.org.        3600    IN      A       192.0.2.4
         mail.example.org.       3600    IN      A       192.0.2.10
         mail.example.org.       3600    IN      A       192.0.2.10
         """
         """
+
     Scenario: Delegation query for unsigned child zone
     Scenario: Delegation query for unsigned child zone
         Given I have bind10 running with configuration example.org.inmem.config
         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 BIND10_STARTED_CC
@@ -122,3 +123,27 @@ Feature: Querying feature
         """
         """
         ns.sub.example.org.	3600	IN	A	192.0.2.101
         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
+        And wait for bind10 stderr message AUTH_SERVER_STARTED
+
+        bind10 module Auth should be running
+        And bind10 module Resolver should not be running
+        And bind10 module Xfrout should not be running
+        And bind10 module Zonemgr should not be running
+        And bind10 module Xfrin should not be running
+        And bind10 module Stats should not be running
+        And bind10 module StatsHttpd should not be running
+
+        A query for example.org type SSHFP should have rcode NOERROR
+        The last query response should have ancount 0
+        A query for shell.example.org type SSHFP should have rcode NOERROR
+        The last query response should have ancount 1
+        The answer section of the last query response should be
+        """
+        shell.example.org.      3600    IN      SSHFP   2 1 123456789abcdef67890123456789abcdef67890
+        """

+ 2 - 2
tests/lettuce/features/terrain/bind10_control.py

@@ -306,8 +306,8 @@ def config_remove_command(step, name, value, cmdctl_port):
                 "quit"]
                 "quit"]
     run_bindctl(commands, cmdctl_port)
     run_bindctl(commands, cmdctl_port)
 
 
-@step('send bind10 the command (.+)(?: with cmdctl port (\d+))?')
+@step('send bind10(?: with cmdctl port (\d+))? the command (.+)')
-def send_command(step, command, cmdctl_port):
+def send_command(step, cmdctl_port, command):
     """
     """
     Run bindctl, send the given command, and exit bindctl.
     Run bindctl, send the given command, and exit bindctl.
     Parameters:
     Parameters:

+ 2 - 0
tests/lettuce/features/terrain/terrain.py

@@ -59,6 +59,8 @@ copylist = [
      "configurations/ddns/noddns.config"],
      "configurations/ddns/noddns.config"],
     ["data/inmem-xfrin.sqlite3.orig",
     ["data/inmem-xfrin.sqlite3.orig",
      "data/inmem-xfrin.sqlite3"],
      "data/inmem-xfrin.sqlite3"],
+    ["data/xfrin-notify.sqlite3.orig",
+     "data/xfrin-notify.sqlite3"],
     ["data/ddns/example.org.sqlite3.orig",
     ["data/ddns/example.org.sqlite3.orig",
      "data/ddns/example.org.sqlite3"]
      "data/ddns/example.org.sqlite3"]
 ]
 ]

+ 2 - 2
tests/lettuce/features/terrain/transfer.py

@@ -67,11 +67,11 @@ def perform_axfr(step, zone_name, address, port):
     Step definition:
     Step definition:
     An AXFR transfer of <zone_name> [from <address>:<port>]
     An AXFR transfer of <zone_name> [from <address>:<port>]
 
 
-    Address defaults to 127.0.0.1
+    Address defaults to ::1
     Port defaults to 47806
     Port defaults to 47806
     """
     """
     if address is None:
     if address is None:
-        address = "127.0.0.1"
+        address = "::1"
     # convert [IPv6_addr] to IPv6_addr:
     # convert [IPv6_addr] to IPv6_addr:
     address = re.sub(r"\[(.+)\]", r"\1", address)
     address = re.sub(r"\[(.+)\]", r"\1", address)
     if port is None:
     if port is None:

+ 2 - 2
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
     # Now we use the first step again to see if the file has been created
     The file data/test_nonexistent_db.sqlite3 should exist
     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
     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 XFRIN_TRANSFER_SUCCESS not XFRIN_XFR_PROCESS_FAILURE
     Then wait for new bind10 stderr message ZONEMGR_RECEIVE_XFRIN_SUCCESS
     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 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
     # The following check will get these by AXFR, so the total # of RRs

+ 29 - 0
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