Browse Source

Merge branch 'master' into trac2052

Conflicts:
	src/lib/dns/name.cc
Mukund Sivaraman 12 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
 	b10-dhcp4: DHCPv4 server component is now integrated into
 	BIND10 framework. It can be started from BIND10 (using bindctl)

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

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

+ 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
 lower layer that detects the failure.
 
+% AUTH_RECEIVED_NOTIFY received incoming NOTIFY for zone name %1, zone class %2
+This is a debug message reporting that an incoming NOTIFY was received.
+
 % AUTH_NOTIFY_QUESTIONS invalid number of questions (%1) in incoming NOTIFY
 This debug message is logged by the authoritative server when it receives
 a NOTIFY packet that contains zero or more than one question. (A valid

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

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

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

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

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

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

+ 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'
             if check_soa:
                 self._check_soa_serial()
+                self.close()
+                self.init_socket()
+                if not self.connect_to_master():
+                    raise XfrinException('Unable to reconnect to master')
 
             logger.info(XFRIN_XFR_TRANSFER_STARTED, req_str, self.zone_str())
             self._send_query(self._request_type)

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

@@ -952,6 +952,9 @@ class XfroutServer:
     def _start_notifier(self):
         datasrc = self._unix_socket_server.get_db_file()
         self._notifier = notify_out.NotifyOut(datasrc)
+        if 'also_notify' in self._config_data:
+            for slave in self._config_data['also_notify']:
+                self._notifier.add_slave(slave['address'], slave['port'])
         self._notifier.dispatcher()
 
     def send_notify(self, zone_name, zone_class):

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

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

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

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

@@ -963,17 +963,14 @@ public:
         ///
         /// \param name Which domain name should be scanned.
         /// \param types List of types the caller is interested in.
-        /// \param check_ns If this is set to true, it checks nothing lives
-        ///     together with NS record (with few little exceptions, like RRSIG
-        ///     or NSEC). This check is meant for non-apex NS records.
         /// \param construct_name If this is NULL, the resulting RRsets have
-        ///     their name set to name. If it is not NULL, it overrides the name
-        ///     and uses this one (this can be used for wildcard synthesized
-        ///     records).
+        ///     their name set to name. If it is not NULL, it overrides the
+        ///     name and uses this one (this can be used for wildcard
+        ///     synthesized records).
         /// \param any If this is true, it records all the types, not only the
         ///     ones requested by types. It also puts a NULL pointer under the
-        ///     ANY type into the result, if it finds any RRs at all, to easy the
-        ///     identification of success.
+        ///     ANY type into the result, if it finds any RRs at all, to easy
+        ///     the identification of success.
         /// \param srcContext This can be set to non-NULL value to override the
         ///     iterator context used for obtaining the data. This can be used,
         ///     for example, to get data from the NSEC3 namespace.
@@ -986,7 +983,7 @@ public:
         /// \throw DataSourceError If there's a low-level error with the
         ///     database or the database contains bad data.
         FoundRRsets getRRsets(const std::string& name,
-                              const WantedTypes& types, bool check_ns,
+                              const WantedTypes& types,
                               const std::string* construct_name = NULL,
                               bool any = false,
                               DatabaseAccessor::IteratorContextPtr srcContext =

+ 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 "
      "20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
 
-    // Broken NS
+    // Delegation NS and other ordinary type of RR coexist at the same
+    // name.  This is deviant (except for some special cases like the other
+    // RR could be used for addressing the NS name), but as long as the
+    // other records are hidden behind the delegation for normal queries
+    // it's not necessarily harmful. (so "broken" may be too strong, but we
+    // keep the name since it could be in a chain of sorted names for DNSSEC
+    // processing and renaming them may have other bad effects for tests).
     {"brokenns1.example.org.", "A", "3600", "", "192.0.2.1"},
     {"brokenns1.example.org.", "NS", "3600", "", "ns.example.com."},
 
-    {"brokenns2.example.org.", "NS", "3600", "", "ns.example.com."},
-    {"brokenns2.example.org.", "A", "3600", "", "192.0.2.1"},
-
     // Now double DNAME, to test failure mode
     {"baddname.example.org.", "DNAME", "3600", "", "dname1.example.com."},
     {"baddname.example.org.", "DNAME", "3600", "", "dname2.example.com."},
@@ -2202,15 +2205,23 @@ TYPED_TEST(DatabaseClientTest, findDelegation) {
                               ZoneFinder::FIND_DEFAULT),
                  DataSourceError);
 
-    // Broken NS - it lives together with something else
-    EXPECT_THROW(finder->find(isc::dns::Name("brokenns1.example.org."),
-                              this->qtype_,
-                              ZoneFinder::FIND_DEFAULT),
-                 DataSourceError);
-    EXPECT_THROW(finder->find(isc::dns::Name("brokenns2.example.org."),
-                              this->qtype_,
-                              ZoneFinder::FIND_DEFAULT),
-                 DataSourceError);
+    // NS and other type coexist: deviant and not necessarily harmful.
+    // It should normally just result in DELEGATION; if GLUE_OK is specified,
+    // the other RR should be visible.
+    this->expected_rdatas_.clear();
+    this->expected_rdatas_.push_back("ns.example.com");
+    doFindTest(*finder, Name("brokenns1.example.org"), this->qtype_,
+               RRType::NS(), this->rrttl_, ZoneFinder::DELEGATION,
+               this->expected_rdatas_, this->empty_rdatas_,
+               ZoneFinder::RESULT_DEFAULT);
+
+    this->expected_rdatas_.clear();
+    this->expected_rdatas_.push_back("192.0.2.1");
+    doFindTest(*finder, Name("brokenns1.example.org"), this->qtype_,
+               this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
+               this->expected_rdatas_, this->empty_rdatas_,
+               ZoneFinder::RESULT_DEFAULT, Name("brokenns1.example.org"),
+               ZoneFinder::FIND_GLUE_OK);
 }
 
 TYPED_TEST(DatabaseClientTest, findDS) {

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

@@ -208,13 +208,6 @@ TEST_P(ZoneFinderContextTest, getAdditionalDelegation) {
 TEST_P(ZoneFinderContextTest, getAdditionalDelegationAtZoneCut) {
     // Similar to the previous case, but one of the NS addresses is at the
     // zone cut.
-
-    // XXX: the current database-based data source incorrectly rejects this
-    // setup (see #1771)
-    if (GetParam() == createSQLite3Client) {
-        return;
-    }
-
     ZoneFinderContextPtr ctx = finder_->find(Name("www.b.example.org"),
                                              RRType::SOA());
     EXPECT_EQ(ZoneFinder::DELEGATION, ctx->code);
@@ -316,12 +309,6 @@ TEST_P(ZoneFinderContextTest, getAdditionalMX) {
 }
 
 TEST_P(ZoneFinderContextTest, getAdditionalMXAtZoneCut) {
-    // XXX: the current database-based data source incorrectly rejects this
-    // setup (see #1771)
-    if (GetParam() == createSQLite3Client) {
-        return;
-    }
-
     ZoneFinderContextPtr ctx = finder_->find(Name("mxatcut.example.org."),
                                              RRType::MX());
     EXPECT_EQ(ZoneFinder::SUCCESS, ctx->code);

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

@@ -376,6 +376,16 @@ public:
     ///   RRsets for that name are searched just like the normal case;
     ///   otherwise, if the search has encountered a zone cut, \c DELEGATION
     ///   with the information of the highest zone cut will be returned.
+    ///   Note: the term "glue" in the DNS protocol standard may sometimes
+    ///   cause confusion: some people use this term strictly for an address
+    ///   record (type AAAA or A) for the name used in the RDATA of an NS RR;
+    ///   some others seem to give it broader flexibility.  Nevertheless,
+    ///   in this API the "GLUE OK" simply means the search by find() can
+    ///   continue beyond a zone cut; the derived class implementation does
+    ///   not have to, and should not, check whether the type is an address
+    ///   record or whether the query name is pointed by some NS RR.
+    ///   It's up to the caller with which definition of "glue" the search
+    ///   result with this option should be used.
     /// - \c FIND_DNSSEC Request that DNSSEC data (like NSEC, RRSIGs) are
     ///   returned with the answer. It is allowed for the data source to
     ///   include them even when not requested.

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

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

+ 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
     ///        will be stored (in number of octets)
     /// \return Pointer to the wire-format data of this label sequence
-    const char* getData(size_t* len) const;
+    const uint8_t* getData(size_t* len) const;
 
     /// \brief Return the length of the wire-format data of this LabelSequence
     ///

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

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

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

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

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

@@ -230,6 +230,11 @@ class Name {
     ///
     //@{
 private:
+    /// \brief Name data string
+    typedef std::basic_string<uint8_t> NameString;
+    /// \brief Name offsets type
+    typedef std::vector<uint8_t> NameOffsets;
+
     /// The default constructor
     ///
     /// This is used internally in the class implementation, but at least at
@@ -710,8 +715,8 @@ public:
     //@}
 
 private:
-    std::string ndata_;
-    std::vector<unsigned char> offsets_;
+    NameString ndata_;
+    NameOffsets offsets_;
     unsigned int length_;
     unsigned int labelcount_;
 };

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

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

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

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

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

@@ -161,6 +161,12 @@ class NotifyOut:
             for item in slaves:
                 self._notify_infos[zone_id].notify_slaves.append((item, 53))
 
+    def add_slave(self, address, port):
+        for zone_name, zone_class in sqlite3_ds.get_zones_info(self._db_file):
+            zone_id = (zone_name, zone_class)
+            if zone_id in self._notify_infos:
+                self._notify_infos[zone_id].notify_slaves.append((address, port))
+
     def send_notify(self, zone_name, zone_class='IN'):
         '''Send notify to one zone's slaves, this function is
         the only interface for class NotifyOut which can be called

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

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

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

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

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

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

+ 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
 /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.
 ns1.example.org.	3600	IN	A	192.0.2.3
 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 ZONEMGR_STARTED
 
-        A query for www.example.org should have rcode NOERROR
+        A query for www.example.org to [::1]:47806 should have rcode NOERROR
         """
         www.example.org.        3600    IN      A       192.0.2.63
         """
-        A query for mail.example.org should have rcode NXDOMAIN
+        A query for mail.example.org to [::1]:47806 should have rcode NXDOMAIN
         When I send bind10 the command Xfrin retransfer example.org IN ::1 47807
         Then wait for new bind10 stderr message XFRIN_TRANSFER_SUCCESS not XFRIN_XFR_PROCESS_FAILURE
         Then wait for new bind10 stderr message AUTH_LOAD_ZONE
 
-        A query for www.example.org should have rcode NOERROR
+        A query for www.example.org to [::1]:47807 should have rcode NOERROR
         The answer section of the last query response should be
         """
         www.example.org.        3600    IN      A       192.0.2.1
         """
-        A query for mail.example.org should have rcode NOERROR
+        A query for mail.example.org to [::1]:47806 should have rcode NOERROR

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

@@ -103,6 +103,7 @@ Feature: Querying feature
         ns2.example.org.        3600    IN      A       192.0.2.4
         mail.example.org.       3600    IN      A       192.0.2.10
         """
+
     Scenario: Delegation query for unsigned child zone
         Given I have bind10 running with configuration example.org.inmem.config
         And wait for bind10 stderr message BIND10_STARTED_CC
@@ -122,3 +123,27 @@ Feature: Querying feature
         """
         ns.sub.example.org.	3600	IN	A	192.0.2.101
         """
+
+    Scenario: SSHFP query
+        # We are testing one more RR type for a normal successful case
+        Given I have bind10 running with configuration example.org.inmem.config
+        And wait for bind10 stderr message BIND10_STARTED_CC
+        And wait for bind10 stderr message CMDCTL_STARTED
+        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"]
     run_bindctl(commands, cmdctl_port)
 
-@step('send bind10 the command (.+)(?: with cmdctl port (\d+))?')
-def send_command(step, command, cmdctl_port):
+@step('send bind10(?: with cmdctl port (\d+))? the command (.+)')
+def send_command(step, cmdctl_port, command):
     """
     Run bindctl, send the given command, and exit bindctl.
     Parameters:

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

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

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

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

+ 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
     The file data/test_nonexistent_db.sqlite3 should exist
 
-    A query for www.example.org should have rcode REFUSED
+    A query for www.example.org to [::1]:47806 should have rcode REFUSED
     When I send bind10 the command Xfrin retransfer example.org IN ::1 47807
     Then wait for new bind10 stderr message XFRIN_TRANSFER_SUCCESS not XFRIN_XFR_PROCESS_FAILURE
     Then wait for new bind10 stderr message ZONEMGR_RECEIVE_XFRIN_SUCCESS
-    A query for www.example.org should have rcode NOERROR
+    A query for www.example.org to [::1]:47806 should have rcode NOERROR
 
     # The transferred zone should have 11 non-NSEC3 RRs and 1 NSEC3 RR.
     # The following check will get these by AXFR, so the total # of RRs

+ 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