]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#2228] backport gss-tsig hook library to Kea 2.0
authorRazvan Becheriu <razvan@isc.org>
Tue, 7 Dec 2021 11:44:56 +0000 (13:44 +0200)
committerRazvan Becheriu <razvan@isc.org>
Tue, 7 Dec 2021 15:22:39 +0000 (17:22 +0200)
48 files changed:
configure.ac
doc/devel/unit-tests.dox
doc/examples/ddns/gss-tsig.json
doc/sphinx/arm/ext-gss-tsig.rst
src/bin/d2/Makefile.am
src/bin/d2/d2_update_mgr.h
src/bin/d2/nc_add.cc
src/bin/d2/nc_add.h
src/bin/d2/nc_remove.cc
src/bin/d2/nc_remove.h
src/bin/d2/simple_add.cc
src/bin/d2/simple_add.h
src/bin/d2/simple_remove.cc
src/bin/d2/simple_remove.h
src/bin/d2/tests/Makefile.am
src/bin/d2/tests/d2_controller_unittests.cc
src/bin/d2/tests/d2_process_unittests.cc
src/bin/d2/tests/d2_queue_mgr_unittests.cc
src/bin/d2/tests/d2_update_mgr_unittests.cc
src/bin/d2/tests/nc_add_unittests.cc
src/bin/d2/tests/nc_remove_unittests.cc
src/bin/d2/tests/simple_add_unittests.cc
src/bin/d2/tests/simple_remove_unittests.cc
src/bin/d2/tests/stats_test_utils.h [deleted file]
src/lib/asiodns/io_fetch.h
src/lib/d2srv/Makefile.am
src/lib/d2srv/d2_update_message.cc [moved from src/bin/d2/d2_update_message.cc with 98% similarity]
src/lib/d2srv/d2_update_message.h [moved from src/bin/d2/d2_update_message.h with 99% similarity]
src/lib/d2srv/d2_zone.cc [moved from src/bin/d2/d2_zone.cc with 87% similarity]
src/lib/d2srv/d2_zone.h [moved from src/bin/d2/d2_zone.h with 98% similarity]
src/lib/d2srv/dns_client.cc [moved from src/bin/d2/dns_client.cc with 75% similarity]
src/lib/d2srv/dns_client.h [moved from src/bin/d2/dns_client.h with 97% similarity]
src/lib/d2srv/nc_trans.cc [moved from src/bin/d2/nc_trans.cc with 99% similarity]
src/lib/d2srv/nc_trans.h [moved from src/bin/d2/nc_trans.h with 99% similarity]
src/lib/d2srv/tests/Makefile.am
src/lib/d2srv/tests/d2_update_message_unittests.cc [moved from src/bin/d2/tests/d2_update_message_unittests.cc with 99% similarity]
src/lib/d2srv/tests/d2_zone_unittests.cc [moved from src/bin/d2/tests/d2_zone_unittests.cc with 96% similarity]
src/lib/d2srv/tests/dns_client_unittests.cc [moved from src/bin/d2/tests/dns_client_unittests.cc with 69% similarity]
src/lib/d2srv/tests/nc_trans_unittests.cc [moved from src/bin/d2/tests/nc_trans_unittests.cc with 99% similarity]
src/lib/d2srv/testutils/Makefile.am [new file with mode: 0644]
src/lib/d2srv/testutils/nc_test_utils.cc [moved from src/bin/d2/tests/nc_test_utils.cc with 94% similarity]
src/lib/d2srv/testutils/nc_test_utils.h [moved from src/bin/d2/tests/nc_test_utils.h with 95% similarity]
src/lib/d2srv/testutils/stats_test_utils.cc [moved from src/bin/d2/tests/stats_test_utils.cc with 59% similarity]
src/lib/d2srv/testutils/stats_test_utils.h [new file with mode: 0644]
src/lib/dhcp_ddns/ncr_udp.cc
src/lib/stats/Makefile.am
src/lib/stats/testutils/Makefile.am [new file with mode: 0644]
src/lib/stats/testutils/stats_test_utils.h [new file with mode: 0644]

index 7feae351807182b949f1ce92af471c3eeae7a3dc..a576580b07b19c0a1ea147a0550d0221d1b4c1ba 100644 (file)
@@ -1660,6 +1660,7 @@ AC_CONFIG_FILES([src/lib/config_backend/tests/Makefile])
 AC_CONFIG_FILES([src/lib/cryptolink/Makefile])
 AC_CONFIG_FILES([src/lib/cryptolink/tests/Makefile])
 AC_CONFIG_FILES([src/lib/d2srv/Makefile])
+AC_CONFIG_FILES([src/lib/d2srv/testutils/Makefile])
 AC_CONFIG_FILES([src/lib/d2srv/tests/Makefile])
 AC_CONFIG_FILES([src/lib/database/Makefile])
 AC_CONFIG_FILES([src/lib/database/tests/Makefile])
@@ -1722,6 +1723,7 @@ AC_CONFIG_FILES([src/lib/process/tests/Makefile])
 AC_CONFIG_FILES([src/lib/process/testutils/Makefile])
 AC_CONFIG_FILES([src/lib/stats/Makefile])
 AC_CONFIG_FILES([src/lib/stats/tests/Makefile])
+AC_CONFIG_FILES([src/lib/stats/testutils/Makefile])
 AC_CONFIG_FILES([src/lib/testutils/Makefile])
 AC_CONFIG_FILES([src/lib/testutils/dhcp_test_lib.sh],
                 [chmod +x src/lib/testutils/dhcp_test_lib.sh])
index f49bb49934f676addbfb8db074963f878b934b95..942164a90297f2f95abde5a60931ebd623877db9 100644 (file)
@@ -354,6 +354,17 @@ local   all             postgres                                trust
  Use HELP for help.
  cqlsh> @endverbatim\n
 
+@section unitTestsKerberos Kerberos Configuration for Unit Tests
+
+The GSS-TSIG hook library uses the GSS-API with Kerberos. While there are
+no doubts that the hook can be safely used with a valid Kerberos configuration
+in production, unit tests reported problems on some systems.
+
+GSS-TSIG hook unit tests use a setup inherited from bind9 with old crypto
+settings which are not allowed by default Kerberos system configuration.
+A simple workaround is to set the KRB5_CONFIG environment variable to
+a random value that doesn't match a file (e.g. KRB5_CONFIG=).
+
 @section writingShellScriptsAndTests Writing shell scripts and tests
 
 Shell tests are `shellcheck`ed. But there are other writing practices that are
index cad5024f58a51865797ed02eddde6b7eb8b47fd7..0cc324df74f216356c8f906ae4daccce9fa553b2 100644 (file)
                     },
                     { // This server also has an entry there, so will
                       // use GSS-TSIG, too.
-                        "ip-address": "192.0.2.2"
+                        "ip-address": "192.0.2.2",
+                        "port": 5300
                     }
                 ]
             }
         ]
     },
 
-    // Reverse zone: we want to update the reverse zone "2.0.192.in-addr-arpa".
+    // Reverse zone: we want to update the reverse zone "2.0.192.in-addr.arpa".
     "reverse-ddns":
     {
         "ddns-domains":
@@ -58,7 +59,7 @@
     // Need to add gss-tsig hook here
     "hooks-libraries": [
     {
-        "library": "/opt/lib/libdhcp_gss_tsig.so",
+        "library": "/opt/lib/libddns_gss_tsig.so",
         "parameters": {
             // This section governs the GSS-TSIG integration. Each server
             // mentioned in forward-ddns and/or reverse-ddns needs to have
 
             "server-principal": "DNS/server.example.org@EXAMPLE.ORG",
             "client-principal": "DHCP/admin.example.org@EXAMPLE.ORG",
-            "client-keytab": "FILE:/etc/krb5.keytab", // toplevel only
+            "client-keytab": "FILE:/etc/dhcp.keytab", // toplevel only
             "credentials-cache": "FILE:/etc/ccache", // toplevel only
-            "tkey-lifetime": 3600,
+            "tkey-lifetime": 3600, // 1 hour
+            "rekey-interval": 2700, // 45 minutes
+            "retry-interval": 120, // 2 minutes
             "tkey-protocol": "TCP",
+            "fallback": false,
 
             // The list of GSS-TSIG capable servers
             "servers": [
                     "port": 53,
                     "server-principal": "DNS/server1.example.org@EXAMPLE.ORG",
                     "client-principal": "DHCP/admin1.example.org@EXAMPLE.ORG",
-                    "tkey-lifetime": 86400, // 24h
-                    "tkey-protocol": "TCP"
+                    "tkey-lifetime": 7200, // 2 hours
+                    "rekey-interval": 5400, // 90 minutes
+                    "retry-interval": 240, // 4 minutes
+                    "tkey-protocol": "TCP",
+                    "fallback": true // if no key is available fallback to the
+                                     // standard behavior (vs skip this server)
                 },
                 {
                     // The second server (it has most of the parameters missing
index af769694f1353e23609b15d9e452fa660b220040..cf718a55897ddd12379eeed2a3529d0742436752 100644 (file)
@@ -10,7 +10,7 @@ GSS-TSIG
 .. note::
 
    The GSS-TSIG feature is considered experimental. It is possible to perform
-   the key exchanges and sign the DNS updates using GSS-TSIG, but some error
+   the TKEY exchanges and sign the DNS updates using GSS-TSIG, but some error
    handling and fallback scenarios are not covered yet. Use with caution.
 
 GSS-TSIG Overview
@@ -19,7 +19,7 @@ GSS-TSIG Overview
 Kea provides a support for DNS updates, which can be protected using
 Transaction Signatures (or TSIG). This protection is often adequate.
 However some systems, in particular Active Directory (AD) on Microsoft
-Windows systems, chose to adopt more complex GSS-TSIG approach that offers
+Windows servers, chose to adopt more complex GSS-TSIG approach that offers
 additional capabilities as using negotiated dynamic keys.
 
 Kea provides the support of GSS-TSIG to protect DNS updates sent by
@@ -131,7 +131,7 @@ detection, similar to this:
 
 7.  After compilation, the gss_tsig hook is available in the
     ``premium/src/hooks/d2/gss_tsig`` directory. It can be loaded by
-    the DHCP-DDNS (D2) daemon.
+    the Kea DHCP-DDNS (D2) daemon.
 
 
 The gss_tsig was developed using the MIT Kerberos 5 implementation but
@@ -250,7 +250,7 @@ You will be required to retype the password:
 
     Re-enter KDC database master key to verify:
 
-If succesfully applied, the following message will be displayed:
+If successfully applied, the following message will be displayed:
 
 .. code-block:: console
 
@@ -269,7 +269,7 @@ If succesfully applied, the following message will be displayed:
 
 Next step consists in creating the principals for the Bind9 DNS server
 (the service protected by the GSS-TSIG TKEY) and for the DNS client
-(the Kea DDNS server).
+(the Kea DHCP-DDNS server).
 
 The Bind9 DNS server principal (used for authentication) is created the
 following way:
@@ -278,7 +278,7 @@ following way:
 
     kadmin.local -q "addprinc -randkey DNS/server.example.org"
 
-If succesfully created, the following message will be displayed:
+If successfully created, the following message will be displayed:
 
 .. code-block:: console
 
@@ -286,36 +286,44 @@ If succesfully created, the following message will be displayed:
     Authenticating as principal root/admin@EXAMPLE.ORG with password.
     Principal "DNS/server.example.org@EXAMPLE.ORG" created.
 
-The DNS client principal (used by the Kea DDNS server) is created the
-following way (please choose your own password here):
+The DNS server principal must be exported so that it can be used by the Bind 9
+DNS server. Only this principal is required and is is exported to the keytab
+file with the name ``dns.keytab``.
 
 .. code-block:: console
 
-    kadmin.local -q "addprinc -pw <password> DHCP/admin.example.org"
+    kadmin.local -q "ktadd -k /tmp/dns.keytab DNS/server.example.org"
 
-If succesfully created, the following message will be displayed:
+If successfully exported, the following message will be displayed:
 
 .. code-block:: console
 
-    No policy specified for DHCP/admin.example.org@EXAMPLE.ORG; defaulting to no policy
     Authenticating as principal root/admin@EXAMPLE.ORG with password.
-    Principal "DHCP/admin.example.org@EXAMPLE.ORG" created.
+    Entry for principal DNS/server.example.org with kvno 2, encryption type aes256-cts-hmac-sha1-96 added to keytab WRFILE:/tmp/dns.keytab.
+    Entry for principal DNS/server.example.org with kvno 2, encryption type aes128-cts-hmac-sha1-96 added to keytab WRFILE:/tmp/dns.keytab.
 
-The DNS server principal must be exported so that it can be used by the Bind 9
-DNS server. Only this principal is required and is is exported to the keytab
-file with the name ``dns.keytab``.
+The DHCP client principal (used by the Kea DHCP-DDNS server) is created the
+following way:
 
 .. code-block:: console
 
-    kadmin.local -q "ktadd -k /tmp/dns.keytab DNS/server.example.org"
+    kadmin.local -q "addprinc -randkey DHCP/admin.example.org"
 
-If succesfully exported, the following message will be displayed:
+If successfully created, the following message will be displayed:
 
 .. code-block:: console
 
+    No policy specified for DHCP/admin.example.org@EXAMPLE.ORG; defaulting to no policy
     Authenticating as principal root/admin@EXAMPLE.ORG with password.
-    Entry for principal DNS/server.example.org with kvno 2, encryption type aes256-cts-hmac-sha1-96 added to keytab WRFILE:/tmp/dns.keytab.
-    Entry for principal DNS/server.example.org with kvno 2, encryption type aes128-cts-hmac-sha1-96 added to keytab WRFILE:/tmp/dns.keytab.
+    Principal "DHCP/admin.example.org@EXAMPLE.ORG" created.
+
+The DHCP client principal must be exported so that it can be used by the
+Kea DHCP-DDNS server and GSS-TSIG hook library. It is exported to the client
+keytab file with the name ```dhcp.keytab```.
+
+.. code-block:: console
+
+    kadmin.local -q "ktadd -k /tmp/dhcp.keytab DHCP/admin.example.org"
 
 Finally, the krb5-admin-server must be restarted:
 
@@ -336,6 +344,7 @@ Updating the ``named.conf`` file is required:
         ...
         directory "/var/cache/bind";
         dnssec-validation auto;
+        listen-on-v6 { any; };
         tkey-gssapi-keytab "/etc/bind/dns.keytab";
     };
     zone "example.org" {
@@ -392,6 +401,74 @@ The ``/var/lib/bind/db.example.org`` file needs to be created or updated:
     kdc                 A       ${KDC_IP_ADDR}
     server              A       ${BIND9_IP_ADDR}
 
+After any configuration change the server must be reloaded or
+restarted:
+
+.. code-block:: console
+
+    systemctl restart named.service
+
+It is possible to get status or restart logs:
+
+.. code-block:: console
+
+    systemctl status named.service
+    journalctl -u named | tail -n 30
+
+Windows Active Directory Configuration
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This sub-section is based on an Amazon AWS provided Microsoft Windows Server
+2016 with Active Directory pre-installed so describes only the steps used
+for GSS-TSIG deployment (for complete configuration process please refer to
+Microsoft documentation or other external resources. We found `this <https://www.tenforums.com/tutorials/51456-windows-server-2016-setup-local-domain-controller.html>`__ tutorial very
+useful during configuration of our internal QA testing systems.
+
+Two Active Directory (AD) user accounts are needed:
+ - the first account is used to download AD information, for instance
+   the client key table of Kea
+ - the second account will be mapped to the Kea DHCP client principal
+
+Kea needs to know:
+ - the server IP address
+ - the domain/realm name: the domain is in lower case, the realm in upper
+   case, both without a final dot
+ - the server name
+
+The second account (named ``kea`` below) is used to create a Service
+Principal Name (SPN):
+
+.. code-block:: console
+
+    setspn -S DHCP/kea.<domain> kea
+
+After a shared secret key is generated and put in a key table file:
+
+.. code-block:: console
+
+    ktpass -princ DHCP/kea.<domain>@<REALM> -mapuser kea +rndpass -mapop set -ptype KRB5_NT_PRINCIPAL -out dhcp.keytab
+
+The ``dhcp.keytab`` takes the same usage as for Unix Kerberos.
+
+
+GSS-TSIG Troubleshooting
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+While testing GSS-TSIG integration with Active Directory we came across
+one very cryptic error:
+
+.. code-block:: console
+
+   INFO  [kea-dhcp-ddns.gss-tsig-hooks/4678.139690935890624] GSS_TSIG_VERIFY_FAILED GSS-TSIG verify failed: gss_verify_mic failed with GSSAPI error:
+   Major = 'A token had an invalid Message Integrity Check (MIC)' (393216), Minor = 'Packet was replayed in wrong direction' (100002).
+
+In our case problem was that Kea DDNS was trying to perform update of reverse
+DNS zone while it was not configured. Easy solution was to add reverse DNS
+zone similar to the one configured in Kea. To do it open `DNS Manager` choose
+DNS from the list, from drop down list choose `Reverse Lookup Zones`
+click `Action` and `New Zone` then follow New Zone Wizard to add new zone.
+
+
 .. _gss-tsig-using:
 
 Using GSS-TSIG
@@ -407,7 +484,8 @@ An excerpt from D2 server is provided below. More examples are available in the
 
 .. code-block:: javascript
    :linenos:
-   :emphasize-lines: 57-97
+   :emphasize-lines: 57-107
+
 
     {
     "DhcpDdns": {
@@ -437,7 +515,8 @@ An excerpt from D2 server is provided below. More examples are available in the
                         },
                         { // This server also has an entry there, so will
                           // use GSS-TSIG, too.
-                            "ip-address": "192.0.2.2"
+                            "ip-address": "192.0.2.2",
+                            "port": 5300
                         }
                     ]
                 }
@@ -467,7 +546,7 @@ An excerpt from D2 server is provided below. More examples are available in the
         // Need to add gss-tsig hook here
         "hooks-libraries": [
         {
-            "library": "/opt/lib/libdhcp_gss_tsig.so",
+            "library": "/opt/lib/libddns_gss_tsig.so",
             "parameters": {
                 // This section governs the GSS-TSIG integration. Each server
                 // mentioned in forward-ddns and/or reverse-ddns needs to have
@@ -477,10 +556,13 @@ An excerpt from D2 server is provided below. More examples are available in the
 
                 "server-principal": "DNS/server.example.org@EXAMPLE.ORG",
                 "client-principal": "DHCP/admin.example.org@EXAMPLE.ORG",
-                "client-keytab": "FILE:/etc/krb5.keytab", // toplevel only
+                "client-keytab": "FILE:/etc/dhcp.keytab", // toplevel only
                 "credentials-cache": "FILE:/etc/ccache", // toplevel only
-                "tkey-lifetime": 3600,
+                "tkey-lifetime": 3600, // 1 hour
+                "rekey-interval": 2700, // 45 minutes
+                "retry-interval": 120, // 2 minutes
                 "tkey-protocol": "TCP",
+                "fallback": false,
 
                 // The list of GSS-TSIG capable servers
                 "servers": [
@@ -494,8 +576,12 @@ An excerpt from D2 server is provided below. More examples are available in the
                         "port": 53,
                         "server-principal": "DNS/server1.example.org@EXAMPLE.ORG",
                         "client-principal": "DHCP/admin1.example.org@EXAMPLE.ORG",
-                        "tkey-lifetime": 86400, // 24h
-                        "tkey-protocol": "TCP"
+                        "tkey-lifetime": 7200, // 2 hours
+                        "rekey-interval": 5400, // 90 minutes
+                        "retry-interval": 240, // 4 minutes
+                        "tkey-protocol": "TCP",
+                        "fallback": true // if no key is available fallback to the
+                                         // standard behavior (vs skip this server)
                     },
                     {
                         // The second server (it has most of the parameters missing
@@ -523,23 +609,89 @@ specified, the default of 53 is assumed. This is similar to basic mode with no
 authentication or authentication done using TSIG keys, with the
 exception that static TSIG keys are not referenced by name.
 
-Second, the ``libdhcp_gss_tsig.so`` library has to be specified on the
-``hooks-libraries`` list. This hook takes many parameters. The most
-important one is `servers`, which is a list of GSS-TSIG capable
-servers.  If there are several servers and they share some
-characteristics, the values can be specified in `parameters` scope as
-defaults. In the example above, the defaults that apply to all servers
-unless otherwise specified on per server scope, are defined in lines
-63 through 68. The defaults can be skipped if there is only one server
+Second, the ``libddns_gss_tsig.so`` library has to be specified on the
+``hooks-libraries`` list. This hook takes many parameters. The most important
+one is ``servers``, which is a list of GSS-TSIG capable servers.  If there are
+several servers and they share some characteristics, the values can be specified
+in ``parameters`` scope as defaults. In the example above, the defaults that apply
+to all servers unless otherwise specified on per server scope, are defined in
+lines 63 through 68. The defaults can be skipped if there is only one server
 defined or all servers have different values.
 
-The parameters have the following meaning:
+.. table:: List of available parameters
+
+   +-------------------+----------+---------+---------------------+--------------------------------+
+   | Name              | Scope    | Type    | Default value       | Description                    |
+   |                   |          |         |                     |                                |
+   +===================+==========+=========+=====================+================================+
+   | client-keytab     | global / | string  | empty               | the Kerberos **client** key    |
+   |                   | server   |         |                     | table                          |
+   +-------------------+----------+---------+---------------------+--------------------------------+
+   | credentials-cache | global / | string  | empty               | the Kerberos credentials cache |
+   |                   | server   |         |                     |                                |
+   +-------------------+----------+---------+---------------------+--------------------------------+
+   | server-principal  | global / | string  | empty               | the Kerberos principal name of |
+   |                   | server   |         |                     | the DNS server that will       |
+   |                   |          |         |                     | receive updates                |
+   +-------------------+----------+---------+---------------------+--------------------------------+
+   | client-principal  | global / | string  | empty               | the Kerberos principal name of |
+   |                   | server   |         |                     | the Kea D2 service             |
+   +-------------------+----------+---------+---------------------+--------------------------------+
+   | tkey-protocol     | global / | string  | "TCP"               | the protocol used to establish |
+   |                   | server   | "TCP" / |                     | the security context with the  |
+   |                   |          | "UDP"   |                     | DNS servers                    |
+   +-------------------+----------+---------+---------------------+--------------------------------+
+   | tkey-lifetime     | global / | uint32  | | 3600 seconds      | the lifetime of GSS-TSIG keys  |
+   |                   | server   |         | | ( 1 hour )        |                                |
+   +-------------------+----------+---------+---------------------+--------------------------------+
+   | rekey-interval    | global / | uint32  | | 2700 seconds      | the time interval the keys are |
+   |                   | server   |         | | ( 45 minutes )    | checked for rekeying           |
+   +-------------------+----------+---------+---------------------+--------------------------------+
+   | retry-interval    | global / | uint32  | | 120 seconds       | the time interval to retry to  |
+   |                   | server   |         | | ( 2 minutes )     | create a key if any error      |
+   |                   |          |         |                     | occurred previously            |
+   +-------------------+----------+---------+---------------------+--------------------------------+
+   | fallback          | global / | true /  | false               | the behavior to fallback to    |
+   |                   | server   | false   |                     | non GSS-TSIG when GSS-TSIG     |
+   |                   |          |         |                     | should be used but no GSS-TSIG |
+   |                   |          |         |                     | key is available.              |
+   +-------------------+----------+---------+---------------------+--------------------------------+
+   | exchange-timeout  | global / | uint32  | | 3000 milliseconds | the time used to wait for the  |
+   |                   | server   |         | | ( 3 seconds )     | GSS-TSIG TKEY exchange to      |
+   |                   |          |         |                     | finish before it timeouts      |
+   +-------------------+----------+---------+---------------------+--------------------------------+
+   | user-context      | global / | string  | empty               | the user provided data in JSON |
+   |                   | server   |         |                     | format (will not be used by    |
+   |                   |          |         |                     | the GSS-TSIG hook)             |
+   +-------------------+----------+---------+---------------------+--------------------------------+
+   | comment           | global / | string  | empty               | ignored                        |
+   |                   | server   |         |                     |                                |
+   +-------------------+----------+---------+---------------------+--------------------------------+
+   | id                | server   | string  | empty               | identifier to a DNS server     |
+   |                   |          |         |                     | (required)                     |
+   +-------------------+----------+---------+---------------------+--------------------------------+
+   | domain-names      | server   | list of | empty               | the many to one relationship   |
+   |                   |          | strings |                     | between D2 DNS servers and     |
+   |                   |          |         |                     | GSS-TSIG DNS servers           |
+   +-------------------+----------+---------+---------------------+--------------------------------+
+   | ip-address        | server   | IPv4 /  | empty               | the IP address at which the    |
+   |                   |          | IPv6    |                     | GSS-TSIG DNS server listens    |
+   |                   |          | address |                     | for DDNS and TKEY requests     |
+   |                   |          |         |                     | (required)                     |
+   +-------------------+----------+---------+---------------------+--------------------------------+
+   | port              | server   | uint16  | 53                  | the DNS transport port at      |
+   |                   |          |         |                     | which the GSS-TSIG DNS server  |
+   |                   |          |         |                     | listens for DDNS and TKEY      |
+   |                   |          |         |                     | requests                       |
+   +-------------------+----------+---------+---------------------+--------------------------------+
+
+The global parameters are described below:
 
 - ``client-keytab`` specifies the Kerberos **client** key table.
   For instance, ``FILE:<filename>`` can be used to point to a specific file.
   This parameter can be specified only once, in the parameters scope,
   and is the equivalent of setting the ``KRB5_CLIENT_KTNAME`` environment
-  variable.
+  variable. The empty value is silently ignored.
 
 - ``credentials-cache`` specifies the Kerberos credentials cache.
   For instance ``FILE:<filename>`` can be used to point to a file or
@@ -547,7 +699,7 @@ The parameters have the following meaning:
   ``DIR:<directory-path>``.
   This parameter can be specified only once, in the parameters scope,
   and is the equivalent of setting the ``KRB5CCNAME`` environment
-  variable.
+  variable. The empty value is silently ignored.
 
 - ``server-principal`` is the Kerberos principal name of the DNS
   server that will receive updates.  In plain words, this is the
@@ -564,7 +716,34 @@ The parameters have the following meaning:
   values are TCP (the default) and UDP.
 
 - ``tkey-lifetime`` determines the lifetime of GSS-TSIG keys in the
-  TKEY protocol, expressed in seconds. Default value is 3600 (one hour).
+  TKEY protocol. The value must be greater than the ``rekey-interval``
+  value. It is expressed in seconds and it default to 3600 seconds
+  (one hour) if not specified.
+
+- ``rekey-interval`` governs the time interval the keys for each configured
+  server are checked for rekeying, i.e. a new key is created to replace the
+  current usable one when its age is greater than the ``rekey-interval`` value.
+  The value must be smaller than the ``tkey-lifetime`` value (it is recommend
+  between 50% and 80% of the ``tkey-lifetime`` value). It is expressed in
+  seconds and it defaults to 2700 seconds (45 minutes, 75% of one hour) if not
+  specified.
+
+- ``retry-interval`` governs the time interval to retry to create a key if any
+  error occurred previously for any configured server. The value must be smaller
+  than the ``rekey-interval`` value, and should be at most 1/3 of the difference
+  between ``tkey-lifetime`` and ``rekey-interval``. It is expressed in seconds
+  and it defaults to 120 seconds (2 minutes) if not specified.
+
+- ``fallback`` governs the behavior when GSS-TSIG should be used (a
+  matching DNS server is configured) but no GSS-TSIG key is available.
+  If configured to false (the default) this server is skipped, if
+  configured to true the DNS server is ignored and the DNS update
+  is sent with the configured DHCP-DDNS protection e.g. TSIG key or
+  without any protection when none was configured.
+
+- ``exchange-timeout`` governs the time used to wait for the GSS-TSIG TKEY
+  exchange to finish before it timeouts. It is expressed in milliseconds and it
+  defaults to 3000 milliseconds (3 seconds) if not specified.
 
 - ``user-context`` is an optional parameter (see :ref:`user-context`
   for a general description of user contexts in Kea).
@@ -573,7 +752,7 @@ The parameters have the following meaning:
 
 - ``servers`` specifies the list of DNS servers where GSS-TSIG is enabled.
 
-The server map parameters are:
+The server map parameters are described below:
 
 - ``id`` assigns an identifier to a DNS server. It is used for statistics
   and commands. It is required, must be not empty and unique.
@@ -607,20 +786,139 @@ The server map parameters are:
 
 - ``tkey-lifetime`` determines the lifetime of GSS-TSIG keys in the
   TKEY protocol for the DNS server. The TKEY lifetime parameter per server
-  takes precedence. Default and supported values are the same as for
-  the global level parameter.
+  takes precedence. Default and supported values are the same as for the
+  global level parameter.
+
+- ``rekey-interval`` governs the time interval the keys for this particular
+  server are checked for rekeying, i.e. a new key is created to replace the
+  current usable one when its age is greater than the ``rekey-interval`` value.
+  The value must be smaller than the ``tkey-lifetime`` value (it is recommend
+  between 50% and 80% of the ``tkey-lifetime`` value). The rekey interval
+  parameter per server takes precedence. Default and supported values are the
+  same as for the global level parameter.
+
+- ``retry-interval`` governs the time interval to retry to create a key if any
+  error occurred previously for this particular server. The value must be
+  smaller than the ``rekey-interval`` value, and should be at most 1/3 of the
+  difference between ``tkey-lifetime`` and ``rekey-interval``. The retry
+  interval parameter per server takes precedence. Default and supported values
+  are the same as for the global level parameter.
+
+- ``fallback`` governs the behavior when GSS-TSIG should be used (a
+  matching DNS server is configured) but no GSS-TSIG key is available.
+  The fallback parameter per server takes precedence. Default and
+  supported values are the same as for the global level parameter.
+
+- ``exchange-timeout`` governs the time used to wait for the GSS-TSIG TKEY
+  exchange to finish before it timeouts. The exchange timeout parameter per
+  server takes precedence. Default and supported values are the same as for the
+  global level parameter.
 
 - ``user-context`` is an optional parameter (see :ref:`user-context`
   for a general description of user contexts in Kea).
 
 - ``comment`` is allowed but currently ignored.
 
-.. _command-gss-tsig:
+
+GSS-TSIG Automatic Key Removal
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The server will periodically delete keys which expired more than 3 times the
+maximum key lifetime (``tkey-lifetime`` parameter).
+The user has the option to purge keys on demand by using ``gss-tsig-purge-all``
+command (see :ref:`command-gss-tsig-purge-all`) or ``gss-tsig-purge`` command
+(see :ref:`command-gss-tsig-purge`).
+
+
+GSS-TSIG Configuration for Deployment
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When using the Kerberos 5 and Bind9 setup of :ref:`gss-tsig-deployment`
+the local resolver must point to the Bind9 named server address and
+local Kerberos be configured by putting in the ``krb5.conf`` file:
+
+.. code-block:: ini
+
+    [libdefaults]
+        default_realm = EXAMPLE.ORG
+        kdc_timesync = 1
+        ccache_type = 4
+        forwardable = true
+        proxiable = true
+    [realms]
+        EXAMPLE.ORG = {
+                kdc = kdc.example.org
+                admin_server = kdc.example.org
+        }
+
+With Windows AD the DNS service is provided by AD. AD also provides
+the Kerberos service and the ``krb5.conf`` file becomes:
+
+.. code-block:: ini
+
+    [libdefaults]
+        default_realm = <REALM>
+        kdc_timesync = 1
+        ccache_type = 4
+        forwardable = true
+        proxiable = true
+    [realms]
+        ${REALM} = {
+                kdc = <AD_IP_ADDR>
+                admin_server = <AD_IP_ADDR>
+        }
+
+Even when the GSS-API library can use the secret from the client key
+table it is far better to get and cache credentials.
+
+This can be done manually by:
+
+.. code-block:: console
+
+    kinit -k -t /tmp/dhcp.keytab DHCP/admin.example.org
+
+or when using AD:
+
+.. code-block:: console
+
+    kinit -k -t /tmp/dhcp.keytab DHCP/kea.<domain>
+
+The credential cache can be displayed using ``klist``.
+
+In production it is better to rely on a Kerberos Credential Manager as
+the System Security Services Daemon (``sssd``).
+
+The server principal will be "DNS/server.example.org@EXAMPLE.ORG¨ or
+for AD "DNS/<server>.<domain>@<REALM>".
+
+.. _stats-gss-tsig:
+
+GSS-TSIG Statistics
+-------------------
+
+The GSS-TSIG hook library introduces new statistics at global and
+per DNS server levels:
+
+-  ``gss-tsig-key-created`` - number of created GSS-TSIG keys
+-  ``tkey-sent`` - sent TKEY exchange initial requests
+-  ``tkey-success`` - TKEY exchanges which completed with a success
+-  ``tkey-timeout`` - TKEY exchanges which completed on timeout
+-  ``tkey-error`` - TKEY exchanges which completed with an error other than
+   timeout
+
+The relationship between keys and DNS servers are very different between
+the D2 code and static TSIG keys, and GSS-TSIG keys and DNS servers:
+
+ - a static TSIG key can be shared between many DNS servers
+ - a GSS-TSIG key is used only by one DNS server inside a dedicated
+   set of keys.
+
+.. _commands-gss-tsig:
 
 GSS-TSIG Commands
 -----------------
 
-The GSS-TSIG hook library supports some commands.
+The GSS-TSIG hook library supports some commands which are described below.
 
 .. _command-gss-tsig-get-all:
 
@@ -899,3 +1197,62 @@ An example response informing about 2 GSS-TSIG keys for server 'foo' being purge
         "result": 0,
         "text": "2 purged keys for GSS-TSIG server[foo]"
     }
+
+.. _command-gss-tsig-rekey-all:
+
+The gss-tsig-rekey-all Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The command rekeys i.e. unconditionally creates new GSS-TSIG keys for
+all DNS servers.
+
+An example command invocation looks like this:
+
+.. code-block:: json
+
+    {
+        "command": "gss-tsig-rekey-all"
+    }
+
+An example response informing that a rekey was scheduled:
+
+.. code-block:: json
+
+    {
+        "result": 0,
+        "text": "rekeyed"
+    }
+
+This command should be use for instance when the DHCP-DDNS server is
+reconnected to the network.
+
+.. _command-gss-tsig-rekey:
+
+The gss-tsig-rekey Command
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The command rekeys i.e. unconditionally creates new GSS-TSIG keys for
+a specified DNS server.
+
+An example command invocation looks like this:
+
+.. code-block:: json
+
+    {
+        "command": "gss-tsig-purge",
+        "arguments": {
+            "server-id": "foo"
+        }
+    }
+
+An example response informing that a rekey was scheduled:
+
+.. code-block:: json
+
+    {
+        "result": 0,
+        "text": "GSS-TSIG server[foo] rekeyed"
+    }
+
+A typical usage of this command is when a DNS server was rebooted so
+existing GSS-TSIG keys shared with this server can no longer be used.
index 9a716e42e483398b203d0b534689741285b2673f..53282977f71c8aea2ddb086d3b1609dfb3d7c1a1 100644 (file)
@@ -33,13 +33,9 @@ libd2_la_SOURCES += d2_process.cc d2_process.h
 libd2_la_SOURCES += d2_lexer.ll location.hh
 libd2_la_SOURCES += d2_parser.cc d2_parser.h
 libd2_la_SOURCES += d2_queue_mgr.cc d2_queue_mgr.h
-libd2_la_SOURCES += d2_update_message.cc d2_update_message.h
 libd2_la_SOURCES += d2_update_mgr.cc d2_update_mgr.h
-libd2_la_SOURCES += d2_zone.cc d2_zone.h
-libd2_la_SOURCES += dns_client.cc dns_client.h
 libd2_la_SOURCES += nc_add.cc nc_add.h
 libd2_la_SOURCES += nc_remove.cc nc_remove.h
-libd2_la_SOURCES += nc_trans.cc nc_trans.h
 libd2_la_SOURCES += d2_controller.cc d2_controller.h
 libd2_la_SOURCES += parser_context.cc parser_context.h parser_context_decl.h
 libd2_la_SOURCES += simple_add.cc simple_add.h
index 2ff8765bcd339cde76b2ff42a20e6d3ca54d8f1d..593cfd1167a0600bf75a408ee9a2df67e3169b10 100644 (file)
@@ -11,7 +11,7 @@
 
 #include <asiolink/io_service.h>
 #include <d2/d2_queue_mgr.h>
-#include <d2/nc_trans.h>
+#include <d2srv/nc_trans.h>
 #include <d2srv/d2_cfg_mgr.h>
 #include <d2srv/d2_log.h>
 #include <exceptions/exceptions.h>
index 4a1661ac77b6dfd1f384336052e06b2a89b972f4..0d517cb4d52ffe549d4f72aef45fbc521e2b3b60 100644 (file)
@@ -172,28 +172,25 @@ NameAddTransaction::selectingFwdServerHandler() {
 void
 NameAddTransaction::addingFwdAddrsHandler() {
     if (doOnEntry()) {
-        // Clear the request on initial transition. This allows us to reuse
-        // the request on retries if necessary.
-        clearDnsUpdateRequest();
+        // Clear the update attempts count on initial transition.
+        clearUpdateAttempts();
     }
 
     switch(getNextEvent()) {
     case SERVER_SELECTED_EVT:
-        if (!getDnsUpdateRequest()) {
-            // Request hasn't been constructed yet, so build it.
-            try {
-                buildAddFwdAddressRequest();
-            } catch (const std::exception& ex) {
-                // While unlikely, the build might fail if we have invalid
-                // data.  Should that be the case, we need to fail the
-                // transaction.
-                LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_FORWARD_ADD_BUILD_FAILURE)
-                          .arg(getRequestId())
-                          .arg(getNcr()->toText())
-                          .arg(ex.what());
-                transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
-                break;
-            }
+        try {
+            clearDnsUpdateRequest();
+            buildAddFwdAddressRequest();
+        } catch (const std::exception& ex) {
+            // While unlikely, the build might fail if we have invalid
+            // data.  Should that be the case, we need to fail the
+            // transaction.
+            LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_FORWARD_ADD_BUILD_FAILURE)
+                .arg(getRequestId())
+                .arg(getNcr()->toText())
+                .arg(ex.what());
+            transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
+            break;
         }
 
         // Call sendUpdate() to initiate the async send. Note it also sets
@@ -287,29 +284,26 @@ NameAddTransaction::addingFwdAddrsHandler() {
 void
 NameAddTransaction::replacingFwdAddrsHandler() {
     if (doOnEntry()) {
-        // Clear the request on initial transition. This allows us to reuse
-        // the request on retries if necessary.
-        clearDnsUpdateRequest();
+        // Clear the update attempts count on initial transition.
+        clearUpdateAttempts();
     }
 
     switch(getNextEvent()) {
     case FQDN_IN_USE_EVT:
     case SERVER_SELECTED_EVT:
-        if (!getDnsUpdateRequest()) {
-            // Request hasn't been constructed yet, so build it.
-            try {
-                buildReplaceFwdAddressRequest();
-            } catch (const std::exception& ex) {
-                // While unlikely, the build might fail if we have invalid
-                // data.  Should that be the case, we need to fail the
-                // transaction.
-                LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_FORWARD_REPLACE_BUILD_FAILURE)
-                          .arg(getRequestId())
-                          .arg(getNcr()->toText())
-                          .arg(ex.what());
-                transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
-                break;
-            }
+        try {
+            clearDnsUpdateRequest();
+            buildReplaceFwdAddressRequest();
+        } catch (const std::exception& ex) {
+            // While unlikely, the build might fail if we have invalid
+            // data.  Should that be the case, we need to fail the
+            // transaction.
+            LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_FORWARD_REPLACE_BUILD_FAILURE)
+                .arg(getRequestId())
+                .arg(getNcr()->toText())
+                .arg(ex.what());
+            transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
+            break;
         }
 
         // Call sendUpdate() to initiate the async send. Note it also sets
@@ -439,28 +433,25 @@ NameAddTransaction::selectingRevServerHandler() {
 void
 NameAddTransaction::replacingRevPtrsHandler() {
     if (doOnEntry()) {
-        // Clear the request on initial transition. This allows us to reuse
-        // the request on retries if necessary.
-        clearDnsUpdateRequest();
+        // Clear the update attempts count on initial transition.
+        clearUpdateAttempts();
     }
 
     switch(getNextEvent()) {
     case SERVER_SELECTED_EVT:
-        if (!getDnsUpdateRequest()) {
-            // Request hasn't been constructed yet, so build it.
-            try {
-                buildReplaceRevPtrsRequest();
-            } catch (const std::exception& ex) {
-                // While unlikely, the build might fail if we have invalid
-                // data.  Should that be the case, we need to fail the
-                // transaction.
-                LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_REVERSE_REPLACE_BUILD_FAILURE)
-                          .arg(getRequestId())
-                          .arg(getNcr()->toText())
-                          .arg(ex.what());
-                transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
-                break;
-            }
+        try {
+            clearDnsUpdateRequest();
+            buildReplaceRevPtrsRequest();
+        } catch (const std::exception& ex) {
+            // While unlikely, the build might fail if we have invalid
+            // data.  Should that be the case, we need to fail the
+            // transaction.
+            LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_REVERSE_REPLACE_BUILD_FAILURE)
+                .arg(getRequestId())
+                .arg(getNcr()->toText())
+                .arg(ex.what());
+            transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
+            break;
         }
 
         // Call sendUpdate() to initiate the async send. Note it also sets
index 0f9929abd12c9e0c3ec5eccb8e04b305f84a9a6e..6bb8ce311f5c1854384f2465b98bedd946217162 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2021 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -9,7 +9,7 @@
 
 /// @file nc_add.h This file defines the class NameAddTransaction.
 
-#include <d2/nc_trans.h>
+#include <d2srv/nc_trans.h>
 #include <dns/rdata.h>
 
 namespace isc {
index 8c158598d32e15ebb5ac59909c31633929bfd8bc..cd9c6794bf67664a5c611e91448947a93bf15cbc 100644 (file)
@@ -176,29 +176,26 @@ NameRemoveTransaction::selectingFwdServerHandler() {
 void
 NameRemoveTransaction::removingFwdAddrsHandler() {
     if (doOnEntry()) {
-        // Clear the request on initial transition. This allows us to reuse
-        // the request on retries if necessary.
-        clearDnsUpdateRequest();
+        // Clear the update attempts count on initial transition.
+        clearUpdateAttempts();
     }
 
     switch(getNextEvent()) {
     case SERVER_SELECTED_EVT:
-        if (!getDnsUpdateRequest()) {
-            // Request hasn't been constructed yet, so build it.
-            try {
-                buildRemoveFwdAddressRequest();
-            } catch (const std::exception& ex) {
-                // While unlikely, the build might fail if we have invalid
-                // data.  Should that be the case, we need to fail the
-                // transaction.
-                LOG_ERROR(d2_to_dns_logger,
-                          DHCP_DDNS_FORWARD_REMOVE_ADDRS_BUILD_FAILURE)
-                          .arg(getRequestId())
-                          .arg(getNcr()->toText())
-                          .arg(ex.what());
-                transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
-                break;
-            }
+        try {
+            clearDnsUpdateRequest();
+            buildRemoveFwdAddressRequest();
+        } catch (const std::exception& ex) {
+            // While unlikely, the build might fail if we have invalid
+            // data.  Should that be the case, we need to fail the
+            // transaction.
+            LOG_ERROR(d2_to_dns_logger,
+                      DHCP_DDNS_FORWARD_REMOVE_ADDRS_BUILD_FAILURE)
+                .arg(getRequestId())
+                .arg(getNcr()->toText())
+                .arg(ex.what());
+            transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
+            break;
         }
 
         // Call sendUpdate() to initiate the async send. Note it also sets
@@ -286,30 +283,27 @@ NameRemoveTransaction::removingFwdAddrsHandler() {
 void
 NameRemoveTransaction::removingFwdRRsHandler() {
     if (doOnEntry()) {
-        // Clear the request on initial transition. This allows us to reuse
-        // the request on retries if necessary.
-        clearDnsUpdateRequest();
+        // Clear the update attempts count on initial transition.
+        clearUpdateAttempts();
     }
 
     switch(getNextEvent()) {
     case UPDATE_OK_EVT:
     case SERVER_SELECTED_EVT:
-        if (!getDnsUpdateRequest()) {
-            // Request hasn't been constructed yet, so build it.
-            try {
-                buildRemoveFwdRRsRequest();
-            } catch (const std::exception& ex) {
-                // While unlikely, the build might fail if we have invalid
-                // data.  Should that be the case, we need to fail the
-                // transaction.
-                LOG_ERROR(d2_to_dns_logger,
-                          DHCP_DDNS_FORWARD_REMOVE_RRS_BUILD_FAILURE)
-                          .arg(getRequestId())
-                          .arg(getNcr()->toText())
-                          .arg(ex.what());
-                transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
-                break;
-            }
+        try {
+            clearDnsUpdateRequest();
+            buildRemoveFwdRRsRequest();
+        } catch (const std::exception& ex) {
+            // While unlikely, the build might fail if we have invalid
+            // data.  Should that be the case, we need to fail the
+            // transaction.
+            LOG_ERROR(d2_to_dns_logger,
+                      DHCP_DDNS_FORWARD_REMOVE_RRS_BUILD_FAILURE)
+                .arg(getRequestId())
+                .arg(getNcr()->toText())
+                .arg(ex.what());
+            transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
+            break;
         }
 
         // Call sendUpdate() to initiate the async send. Note it also sets
@@ -446,28 +440,25 @@ NameRemoveTransaction::selectingRevServerHandler() {
 void
 NameRemoveTransaction::removingRevPtrsHandler() {
     if (doOnEntry()) {
-        // Clear the request on initial transition. This allows us to reuse
-        // the request on retries if necessary.
-        clearDnsUpdateRequest();
+        // Clear the update attempts count on initial transition.
+        clearUpdateAttempts();
     }
 
     switch(getNextEvent()) {
     case SERVER_SELECTED_EVT:
-        if (!getDnsUpdateRequest()) {
-            // Request hasn't been constructed yet, so build it.
-            try {
-                buildRemoveRevPtrsRequest();
-            } catch (const std::exception& ex) {
-                // While unlikely, the build might fail if we have invalid
-                // data.  Should that be the case, we need to fail the
-                // transaction.
-                LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_REVERSE_REMOVE_BUILD_FAILURE)
-                          .arg(getRequestId())
-                          .arg(getNcr()->toText())
-                          .arg(ex.what());
-                transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
-                break;
-            }
+        try {
+            clearDnsUpdateRequest();
+            buildRemoveRevPtrsRequest();
+        } catch (const std::exception& ex) {
+            // While unlikely, the build might fail if we have invalid
+            // data.  Should that be the case, we need to fail the
+            // transaction.
+            LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_REVERSE_REMOVE_BUILD_FAILURE)
+                .arg(getRequestId())
+                .arg(getNcr()->toText())
+                .arg(ex.what());
+            transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
+            break;
         }
 
         // Call sendUpdate() to initiate the async send. Note it also sets
index 1584cb0025d6131100ad26ec3b62c0aa19129251..672a3d9841a8668af9a5529141c4bd4693fa0945 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2015,2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2021 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -9,7 +9,7 @@
 
 /// @file nc_remove.h This file defines the class NameRemoveTransaction.
 
-#include <d2/nc_trans.h>
+#include <d2srv/nc_trans.h>
 
 namespace isc {
 namespace d2 {
index 7c7b0cf2c426a28953e180f118a05eb86cf6f50c..c1814c77b4d10df9bb9ae453ce0b66e67e70a216 100644 (file)
@@ -167,28 +167,25 @@ SimpleAddTransaction::selectingFwdServerHandler() {
 void
 SimpleAddTransaction::replacingFwdAddrsHandler() {
     if (doOnEntry()) {
-        // Clear the request on initial transition. This allows us to reuse
-        // the request on retries if necessary.
-        clearDnsUpdateRequest();
+        // Clear the update attempts count on initial transition.
+        clearUpdateAttempts();
     }
 
     switch(getNextEvent()) {
     case SERVER_SELECTED_EVT:
-        if (!getDnsUpdateRequest()) {
-            // Request hasn't been constructed yet, so build it.
-            try {
-                buildReplaceFwdAddressRequest();
-            } catch (const std::exception& ex) {
-                // While unlikely, the build might fail if we have invalid
-                // data.  Should that be the case, we need to fail the
-                // transaction.
-                LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_FORWARD_ADD_BUILD_FAILURE)
-                          .arg(getRequestId())
-                          .arg(getNcr()->toText())
-                          .arg(ex.what());
-                transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
-                break;
-            }
+        try {
+            clearDnsUpdateRequest();
+            buildReplaceFwdAddressRequest();
+        } catch (const std::exception& ex) {
+            // While unlikely, the build might fail if we have invalid
+            // data.  Should that be the case, we need to fail the
+            // transaction.
+            LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_FORWARD_ADD_BUILD_FAILURE)
+                .arg(getRequestId())
+                .arg(getNcr()->toText())
+                .arg(ex.what());
+            transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
+            break;
         }
 
         // Call sendUpdate() to initiate the async send. Note it also sets
@@ -306,28 +303,25 @@ SimpleAddTransaction::selectingRevServerHandler() {
 void
 SimpleAddTransaction::replacingRevPtrsHandler() {
     if (doOnEntry()) {
-        // Clear the request on initial transition. This allows us to reuse
-        // the request on retries if necessary.
-        clearDnsUpdateRequest();
+        // Clear the update attempts count on initial transition.
+        clearUpdateAttempts();
     }
 
     switch(getNextEvent()) {
     case SERVER_SELECTED_EVT:
-        if (!getDnsUpdateRequest()) {
-            // Request hasn't been constructed yet, so build it.
-            try {
-                buildReplaceRevPtrsRequest();
-            } catch (const std::exception& ex) {
-                // While unlikely, the build might fail if we have invalid
-                // data.  Should that be the case, we need to fail the
-                // transaction.
-                LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_REVERSE_REPLACE_BUILD_FAILURE)
-                          .arg(getRequestId())
-                          .arg(getNcr()->toText())
-                          .arg(ex.what());
-                transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
-                break;
-            }
+        try {
+            clearDnsUpdateRequest();
+            buildReplaceRevPtrsRequest();
+        } catch (const std::exception& ex) {
+            // While unlikely, the build might fail if we have invalid
+            // data.  Should that be the case, we need to fail the
+            // transaction.
+            LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_REVERSE_REPLACE_BUILD_FAILURE)
+                .arg(getRequestId())
+                .arg(getNcr()->toText())
+                .arg(ex.what());
+            transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
+            break;
         }
 
         // Call sendUpdate() to initiate the async send. Note it also sets
index 7bf7b6c605472d73c43f4df004f74b2adec58960..bf617a50a77ccd90294f3d84d739a056dbcb96d1 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2020 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2020-2021 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -9,7 +9,7 @@
 
 /// @file nc_add.h This file defines the class SimpleAddTransaction.
 
-#include <d2/nc_trans.h>
+#include <d2srv/nc_trans.h>
 #include <dns/rdata.h>
 
 namespace isc {
index e780080d71b478c2910646c0925e5184782c507c..457afe712527c1868f1cfb35faa191e6b1d3dc41 100644 (file)
@@ -170,30 +170,27 @@ SimpleRemoveTransaction::selectingFwdServerHandler() {
 void
 SimpleRemoveTransaction::removingFwdRRsHandler() {
     if (doOnEntry()) {
-        // Clear the request on initial transition. This allows us to reuse
-        // the request on retries if necessary.
-        clearDnsUpdateRequest();
+        // Clear the update attempts count on initial transition.
+        clearUpdateAttempts();
     }
 
     switch(getNextEvent()) {
     case UPDATE_OK_EVT:
     case SERVER_SELECTED_EVT:
-        if (!getDnsUpdateRequest()) {
-            // Request hasn't been constructed yet, so build it.
-            try {
-                buildRemoveFwdRRsRequest();
-            } catch (const std::exception& ex) {
-                // While unlikely, the build might fail if we have invalid
-                // data.  Should that be the case, we need to fail the
-                // transaction.
-                LOG_ERROR(d2_to_dns_logger,
-                          DHCP_DDNS_FORWARD_REMOVE_RRS_BUILD_FAILURE)
-                          .arg(getRequestId())
-                          .arg(getNcr()->toText())
-                          .arg(ex.what());
-                transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
-                break;
-            }
+        try {
+            clearDnsUpdateRequest();
+            buildRemoveFwdRRsRequest();
+        } catch (const std::exception& ex) {
+            // While unlikely, the build might fail if we have invalid
+            // data.  Should that be the case, we need to fail the
+            // transaction.
+            LOG_ERROR(d2_to_dns_logger,
+                      DHCP_DDNS_FORWARD_REMOVE_RRS_BUILD_FAILURE)
+                .arg(getRequestId())
+                .arg(getNcr()->toText())
+                .arg(ex.what());
+            transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
+            break;
         }
 
         // Call sendUpdate() to initiate the async send. Note it also sets
@@ -286,7 +283,6 @@ SimpleRemoveTransaction::removingFwdRRsHandler() {
     }
 }
 
-
 void
 SimpleRemoveTransaction::selectingRevServerHandler() {
     switch(getNextEvent()) {
@@ -320,28 +316,25 @@ SimpleRemoveTransaction::selectingRevServerHandler() {
 void
 SimpleRemoveTransaction::removingRevPtrsHandler() {
     if (doOnEntry()) {
-        // Clear the request on initial transition. This allows us to reuse
-        // the request on retries if necessary.
-        clearDnsUpdateRequest();
+        // Clear the update attempts count on initial transition.
+        clearUpdateAttempts();
     }
 
     switch(getNextEvent()) {
     case SERVER_SELECTED_EVT:
-        if (!getDnsUpdateRequest()) {
-            // Request hasn't been constructed yet, so build it.
-            try {
-                buildRemoveRevPtrsRequest();
-            } catch (const std::exception& ex) {
-                // While unlikely, the build might fail if we have invalid
-                // data.  Should that be the case, we need to fail the
-                // transaction.
-                LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_REVERSE_REMOVE_BUILD_FAILURE)
-                          .arg(getRequestId())
-                          .arg(getNcr()->toText())
-                          .arg(ex.what());
-                transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
-                break;
-            }
+        try {
+            clearDnsUpdateRequest();
+            buildRemoveRevPtrsRequest();
+        } catch (const std::exception& ex) {
+            // While unlikely, the build might fail if we have invalid
+            // data.  Should that be the case, we need to fail the
+            // transaction.
+            LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_REVERSE_REMOVE_BUILD_FAILURE)
+                .arg(getRequestId())
+                .arg(getNcr()->toText())
+                .arg(ex.what());
+            transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
+            break;
         }
 
         // Call sendUpdate() to initiate the async send. Note it also sets
index ce6d52514556a96878e4bded96e06b16201644b6..957cb138a7ce11501b56a68cebbf3b40773cee2e 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2020 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2020-2021 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -9,7 +9,7 @@
 
 /// @file nc_remove.h This file defines the class SimpleRemoveTransaction.
 
-#include <d2/nc_trans.h>
+#include <d2srv/nc_trans.h>
 
 namespace isc {
 namespace d2 {
index 820c4900c470ba783817d7604d53e4be7a5b5146..fe9d60f0f018f29e1fa517e9fefd845ec97ce32e 100644 (file)
@@ -17,7 +17,11 @@ TESTS = $(SHTESTS)
 
 # As with every file generated by ./configure, clean them up when running
 # "make distclean", but not on "make clean".
-DISTCLEANFILES = $(SHTESTS)
+DISTCLEANFILES  = $(SHTESTS)
+DISTCLEANFILES += d2_process_tests.sh
+DISTCLEANFILES += test_data_files_config.h
+DISTCLEANFILES += test_callout_libraries.h
+DISTCLEANFILES += test_configured_libraries.h
 
 # Don't install shell tests.
 noinst_SCRIPTS = $(SHTESTS)
@@ -45,14 +49,9 @@ d2_unittests_SOURCES  = d2_unittests.cc
 d2_unittests_SOURCES += d2_process_unittests.cc
 d2_unittests_SOURCES += d2_cfg_mgr_unittests.cc
 d2_unittests_SOURCES += d2_queue_mgr_unittests.cc
-d2_unittests_SOURCES += d2_update_message_unittests.cc
 d2_unittests_SOURCES += d2_update_mgr_unittests.cc
-d2_unittests_SOURCES += d2_zone_unittests.cc
-d2_unittests_SOURCES += dns_client_unittests.cc
 d2_unittests_SOURCES += nc_add_unittests.cc
 d2_unittests_SOURCES += nc_remove_unittests.cc
-d2_unittests_SOURCES += nc_test_utils.cc nc_test_utils.h
-d2_unittests_SOURCES += nc_trans_unittests.cc
 d2_unittests_SOURCES += d2_controller_unittests.cc
 d2_unittests_SOURCES += d2_simple_parser_unittest.cc
 d2_unittests_SOURCES += parser_unittest.cc parser_unittest.h
@@ -60,7 +59,6 @@ d2_unittests_SOURCES += get_config_unittest.cc
 d2_unittests_SOURCES += d2_command_unittest.cc
 d2_unittests_SOURCES += simple_add_unittests.cc
 d2_unittests_SOURCES += simple_remove_unittests.cc
-d2_unittests_SOURCES += stats_test_utils.cc stats_test_utils.h
 
 d2_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 d2_unittests_LDFLAGS = $(AM_LDFLAGS) $(CRYPTO_LDFLAGS)
@@ -75,7 +73,8 @@ d2_unittests_LDFLAGS += $(CQL_LIBS)
 endif
 d2_unittests_LDFLAGS += $(GTEST_LDFLAGS)
 
-d2_unittests_LDADD = $(top_builddir)/src/bin/d2/libd2.la
+d2_unittests_LDADD  = $(top_builddir)/src/bin/d2/libd2.la
+d2_unittests_LDADD += $(top_builddir)/src/lib/d2srv/testutils/libd2srvtest.la
 d2_unittests_LDADD += $(top_builddir)/src/lib/d2srv/libkea-d2srv.la
 d2_unittests_LDADD += $(top_builddir)/src/lib/process/testutils/libprocesstest.la
 d2_unittests_LDADD += $(top_builddir)/src/lib/cfgrpt/libcfgrpt.la
@@ -132,13 +131,6 @@ nodist_d2_unittests_SOURCES += test_configured_libraries.h
 # Run C++ tests on "make check".
 TESTS += $(PROGRAM_TESTS)
 
-# As with every file generated by ./configure, clean them up when running
-# "make distclean", but not on "make clean".
-DISTCLEANFILES += d2_process_tests.sh
-DISTCLEANFILES += test_data_files_config.h
-DISTCLEANFILES += test_callout_libraries.h
-DISTCLEANFILES += test_configured_libraries.h
-
 # Don't install C++ tests.
 noinst_PROGRAMS = $(PROGRAM_TESTS)
 
index 2a4a7dd73822dc913fa2c160199f379ba2e02474..0c6e5ecf90aab1002d2388fcfc07d1f9d72d9abc 100644 (file)
@@ -8,9 +8,9 @@
 
 #include <asiolink/testutils/timed_signal.h>
 #include <cc/command_interpreter.h>
+#include <d2srv/testutils/nc_test_utils.h>
 #include <d2/d2_controller.h>
 #include <d2/d2_process.h>
-#include <d2/tests/nc_test_utils.h>
 #include <process/testutils/d_test_stubs.h>
 
 #include <boost/pointer_cast.hpp>
index 992c533fb669e91ff8f6aba4ecca14f29c69d432..4dda27551d0e02e71c10ca24a7764bc980d4ef0d 100644 (file)
@@ -8,11 +8,11 @@
 
 #include <asiolink/io_service.h>
 #include <cc/command_interpreter.h>
+#include <d2srv/testutils/nc_test_utils.h>
 #include <d2/d2_process.h>
+#include <d2/tests/test_configured_libraries.h>
 #include <dhcp_ddns/ncr_io.h>
 #include <process/testutils/d_test_stubs.h>
-#include <d2/tests/nc_test_utils.h>
-#include <d2/tests/test_configured_libraries.h>
 
 #include <boost/date_time/posix_time/posix_time.hpp>
 #include <gtest/gtest.h>
index a00de29f4bd7013a23efebd3596798740a91627d..42177e6f6a67909b0a56cc9772877b09a68acb1b 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2020 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2021 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -9,6 +9,7 @@
 #include <asiolink/io_service.h>
 #include <asiolink/interval_timer.h>
 #include <d2/d2_queue_mgr.h>
+#include <d2srv/testutils/stats_test_utils.h>
 #include <dhcp_ddns/ncr_udp.h>
 #include <util/time_utilities.h>
 
@@ -21,6 +22,7 @@ using namespace std;
 using namespace isc;
 using namespace isc::dhcp_ddns;
 using namespace isc::d2;
+using namespace isc::d2::test;
 
 namespace {
 
@@ -203,7 +205,7 @@ bool checkSendVsReceived(NameChangeRequestPtr sent_ncr,
 /// @brief Text fixture that allows testing a listener and sender together
 /// It derives from both the receive and send handler classes and contains
 /// and instance of UDP listener and UDP sender.
-class QueueMgrUDPTest : public virtual ::testing::Test,
+class QueueMgrUDPTest : public virtual ::testing::Test, public D2StatTest,
                         NameChangeSender::RequestSendHandler {
 public:
     asiolink::IOServicePtr io_service_;
@@ -384,6 +386,13 @@ TEST_F (QueueMgrUDPTest, liveFeed) {
         EXPECT_EQ(0, queue_mgr_->getQueueSize());
     }
 
+    StatMap stats_ncr = {
+        { "ncr-received", 3},
+        { "ncr-invalid", 0},
+        { "ncr-error", 0}
+    };
+    checkStats(stats_ncr);
+
     // Iterate over the list of requests, sending and receiving
     // each one. Allow them to accumulate in the queue.
     for (int i = 0; i < VALID_MSG_CNT; i++) {
@@ -397,6 +406,13 @@ TEST_F (QueueMgrUDPTest, liveFeed) {
         EXPECT_EQ(i+1, queue_mgr_->getQueueSize());
     }
 
+    StatMap stats_ncr_new = {
+        { "ncr-received", 6},
+        { "ncr-invalid", 0},
+        { "ncr-error", 0}
+    };
+    checkStats(stats_ncr_new);
+
     // Verify that the queue is at max capacity.
     EXPECT_EQ(queue_mgr_->getMaxQueueSize(), queue_mgr_->getQueueSize());
 
@@ -428,7 +444,6 @@ TEST_F (QueueMgrUDPTest, liveFeed) {
     EXPECT_NO_THROW(queue_mgr_->clearQueue());
     EXPECT_EQ(0, queue_mgr_->getQueueSize());
 
-
     // Verify that we can again receive requests.
     // Send should be fine.
     ASSERT_NO_THROW(sender_->sendRequest(send_ncr));
index a89de3e27369c5f0d95336e27dc385848634e366..d79b4538f0b6fadbda9182a6da98356c8408747e 100644 (file)
@@ -7,8 +7,8 @@
 #include <config.h>
 
 #include <asiolink/io_service.h>
+#include <d2srv/testutils/nc_test_utils.h>
 #include <d2/d2_update_mgr.h>
-#include <nc_test_utils.h>
 #include <d2/nc_add.h>
 #include <d2/nc_remove.h>
 #include <d2/simple_add.h>
@@ -232,8 +232,8 @@ public:
             // value).  This is roughly ten times the number for the longest
             // test (currently, multiTransactionTimeout).
             if (passes > max_passes) {
-                ADD_FAILURE() << "processALL failed, too many passes: "
-                    << passes <<  ", total handlers executed: " << handlers;
+                FAIL() << "processALL failed, too many passes: "
+                       << passes <<  ", total handlers executed: " << handlers;
             }
         }
     }
index 0ef94ddf6b6786672a58280ff15bb9472823dd91..3f36b46737f1595688a8cdf89bf4679769cb0a5c 100644 (file)
@@ -9,8 +9,8 @@
 #include <asiolink/io_service.h>
 #include <d2/nc_add.h>
 #include <d2srv/d2_cfg_mgr.h>
+#include <d2srv/testutils/nc_test_utils.h>
 #include <dns/messagerenderer.h>
-#include <nc_test_utils.h>
 
 #include <gtest/gtest.h>
 
@@ -714,24 +714,9 @@ TEST_F(NameAddTransactionTest, addingFwdAddrsHandler_Timeout) {
     // and then transition to selecting a new server.
     int max_tries = NameChangeTransaction::MAX_UPDATE_TRIES_PER_SERVER;
     for (int i = 1; i <= max_tries; ++i) {
-        const D2UpdateMessagePtr prev_msg = name_add->getDnsUpdateRequest();
-
         // Run addingFwdAddrsHandler to send the request.
         EXPECT_NO_THROW(name_add->addingFwdAddrsHandler());
 
-        const D2UpdateMessagePtr curr_msg = name_add->getDnsUpdateRequest();
-        if (i == 1) {
-            // First time out we should build the message.
-            EXPECT_FALSE(prev_msg);
-            EXPECT_TRUE(curr_msg);
-        } else {
-            // Subsequent passes should reuse the request. We are only
-            // looking to check that we have not replaced the pointer value
-            // with a new pointer.  This tests the on_entry() logic which
-            // clears the request ONLY upon initial entry into the state.
-            EXPECT_TRUE(prev_msg == curr_msg);
-        }
-
         // Simulate a server IO timeout.
         name_add->setDnsUpdateStatus(DNSClient::TIMEOUT);
         name_add->postNextEvent(NameChangeTransaction::IO_COMPLETED_EVT);
@@ -1059,24 +1044,9 @@ TEST_F(NameAddTransactionTest, replacingFwdAddrsHandler_Timeout) {
     // and then transition to selecting a new server.
     int max_tries = NameChangeTransaction::MAX_UPDATE_TRIES_PER_SERVER;
     for (int i = 1; i <= max_tries; ++i) {
-        const D2UpdateMessagePtr prev_msg = name_add->getDnsUpdateRequest();
-
         // Run replacingFwdAddrsHandler to send the request.
         EXPECT_NO_THROW(name_add->replacingFwdAddrsHandler());
 
-        const D2UpdateMessagePtr curr_msg = name_add->getDnsUpdateRequest();
-        if (i == 1) {
-            // First time out we should build the message.
-            EXPECT_FALSE(prev_msg);
-            EXPECT_TRUE(curr_msg);
-        } else {
-            // Subsequent passes should reuse the request. We are only
-            // looking to check that we have not replaced the pointer value
-            // with a new pointer.  This tests the on_entry() logic which
-            // clears the request ONLY upon initial entry into the state.
-            EXPECT_TRUE(prev_msg == curr_msg);
-        }
-
         // Simulate a server IO timeout.
         name_add->setDnsUpdateStatus(DNSClient::TIMEOUT);
         name_add->postNextEvent(NameChangeTransaction::IO_COMPLETED_EVT);
@@ -1127,24 +1097,9 @@ TEST_F(NameAddTransactionTest, replacingFwdAddrsHandler_CorruptResponse) {
     // and then transition to selecting a new server.
     int max_tries = NameChangeTransaction::MAX_UPDATE_TRIES_PER_SERVER;
     for (int i = 1; i <= max_tries; ++i) {
-        const D2UpdateMessagePtr prev_msg = name_add->getDnsUpdateRequest();
-
         // Run replacingFwdAddrsHandler to send the request.
         EXPECT_NO_THROW(name_add->replacingFwdAddrsHandler());
 
-        const D2UpdateMessagePtr curr_msg = name_add->getDnsUpdateRequest();
-        if (i == 1) {
-            // First time out we should build the message.
-            EXPECT_FALSE(prev_msg);
-            EXPECT_TRUE(curr_msg);
-        } else {
-            // Subsequent passes should reuse the request. We are only
-            // looking to check that we have not replaced the pointer value
-            // with a new pointer.  This tests the on_entry() logic which
-            // clears the request ONLY upon initial entry into the state.
-            EXPECT_TRUE(prev_msg == curr_msg);
-        }
-
         // Simulate a corrupt server response.
         name_add->setDnsUpdateStatus(DNSClient::INVALID_RESPONSE);
         name_add->postNextEvent(NameChangeTransaction::IO_COMPLETED_EVT);
@@ -1371,24 +1326,9 @@ TEST_F(NameAddTransactionTest, replacingRevPtrsHandler_Timeout) {
     // and then transition to selecting a new server.
     int max_tries = NameChangeTransaction::MAX_UPDATE_TRIES_PER_SERVER;
     for (int i = 1; i <= max_tries; ++i) {
-        const D2UpdateMessagePtr prev_msg = name_add->getDnsUpdateRequest();
-
         // Run replacingRevPtrsHandler to send the request.
         EXPECT_NO_THROW(name_add->replacingRevPtrsHandler());
 
-        const D2UpdateMessagePtr curr_msg = name_add->getDnsUpdateRequest();
-        if (i == 1) {
-            // First time out we should build the message.
-            EXPECT_FALSE(prev_msg);
-            EXPECT_TRUE(curr_msg);
-        } else {
-            // Subsequent passes should reuse the request. We are only
-            // looking to check that we have not replaced the pointer value
-            // with a new pointer.  This tests the on_entry() logic which
-            // clears the request ONLY upon initial entry into the state.
-            EXPECT_TRUE(prev_msg == curr_msg);
-        }
-
         // Simulate a server IO timeout.
         name_add->setDnsUpdateStatus(DNSClient::TIMEOUT);
         name_add->postNextEvent(NameChangeTransaction::IO_COMPLETED_EVT);
@@ -1438,24 +1378,9 @@ TEST_F(NameAddTransactionTest, replacingRevPtrsHandler_CorruptResponse) {
     // and then transition to selecting a new server.
     int max_tries = NameChangeTransaction::MAX_UPDATE_TRIES_PER_SERVER;
     for (int i = 1; i <= max_tries; ++i) {
-        const D2UpdateMessagePtr prev_msg = name_add->getDnsUpdateRequest();
-
         // Run replacingRevPtrsHandler to send the request.
         EXPECT_NO_THROW(name_add->replacingRevPtrsHandler());
 
-        const D2UpdateMessagePtr curr_msg = name_add->getDnsUpdateRequest();
-        if (i == 1) {
-            // First time out we should build the message.
-            EXPECT_FALSE(prev_msg);
-            EXPECT_TRUE(curr_msg);
-        } else {
-            // Subsequent passes should reuse the request. We are only
-            // looking to check that we have not replaced the pointer value
-            // with a new pointer.  This tests the on_entry() logic which
-            // clears the request ONLY upon initial entry into the state.
-            EXPECT_TRUE(prev_msg == curr_msg);
-        }
-
         // Simulate a server corrupt response.
         name_add->setDnsUpdateStatus(DNSClient::INVALID_RESPONSE);
         name_add->postNextEvent(NameChangeTransaction::IO_COMPLETED_EVT);
index d335e101a5ba72caf65c4587967734a812507214..4373811f17cd8cf97f39a7c48d33c12e8498df83 100644 (file)
@@ -9,8 +9,8 @@
 #include <asiolink/io_service.h>
 #include <d2/nc_remove.h>
 #include <d2srv/d2_cfg_mgr.h>
+#include <d2srv/testutils/nc_test_utils.h>
 #include <dns/messagerenderer.h>
-#include <nc_test_utils.h>
 
 #include <gtest/gtest.h>
 
@@ -692,24 +692,9 @@ TEST_F(NameRemoveTransactionTest, removingFwdAddrsHandler_Timeout) {
     // and then transition to selecting a new server.
     int max_tries = NameChangeTransaction::MAX_UPDATE_TRIES_PER_SERVER;
     for (int i = 1; i <= max_tries; ++i) {
-        const D2UpdateMessagePtr prev_msg = name_remove->getDnsUpdateRequest();
-
         // Run removingFwdAddrsHandler to send the request.
         EXPECT_NO_THROW(name_remove->removingFwdAddrsHandler());
 
-        const D2UpdateMessagePtr curr_msg = name_remove->getDnsUpdateRequest();
-        if (i == 1) {
-            // First time around we should build the message.
-            EXPECT_FALSE(prev_msg);
-            EXPECT_TRUE(curr_msg);
-        } else {
-            // Subsequent passes should reuse the request. We are only
-            // looking to check that we have not replaced the pointer value
-            // with a new pointer.  This tests the on_entry() logic which
-            // clears the request ONLY upon initial entry into the state.
-            EXPECT_TRUE(prev_msg == curr_msg);
-        }
-
         // Simulate a server IO timeout.
         name_remove->setDnsUpdateStatus(DNSClient::TIMEOUT);
         name_remove->postNextEvent(NameChangeTransaction::IO_COMPLETED_EVT);
@@ -1045,24 +1030,9 @@ TEST_F(NameRemoveTransactionTest, removingFwdRRsHandler_Timeout) {
     // and then transition to selecting a new server.
     int max_tries = NameChangeTransaction::MAX_UPDATE_TRIES_PER_SERVER;
     for (int i = 1; i <= max_tries; ++i) {
-        const D2UpdateMessagePtr prev_msg = name_remove->getDnsUpdateRequest();
-
         // Run removingFwdRRsHandler to send the request.
         EXPECT_NO_THROW(name_remove->removingFwdRRsHandler());
 
-        const D2UpdateMessagePtr curr_msg = name_remove->getDnsUpdateRequest();
-        if (i == 1) {
-            // First time around we should build the message.
-            EXPECT_FALSE(prev_msg);
-            EXPECT_TRUE(curr_msg);
-        } else {
-            // Subsequent passes should reuse the request. We are only
-            // looking to check that we have not replaced the pointer value
-            // with a new pointer.  This tests the on_entry() logic which
-            // clears the request ONLY upon initial entry into the state.
-            EXPECT_TRUE(prev_msg == curr_msg);
-        }
-
         // Simulate a server IO timeout.
         name_remove->setDnsUpdateStatus(DNSClient::TIMEOUT);
         name_remove->postNextEvent(NameChangeTransaction::IO_COMPLETED_EVT);
@@ -1115,24 +1085,9 @@ TEST_F(NameRemoveTransactionTest, removingFwdRRsHandler_InvalidResponse) {
     // and then transition to selecting a new server.
     int max_tries = NameChangeTransaction::MAX_UPDATE_TRIES_PER_SERVER;
     for (int i = 1; i <= max_tries; ++i) {
-        const D2UpdateMessagePtr prev_msg = name_remove->getDnsUpdateRequest();
-
         // Run removingFwdRRsHandler to send the request.
         EXPECT_NO_THROW(name_remove->removingFwdRRsHandler());
 
-        const D2UpdateMessagePtr curr_msg = name_remove->getDnsUpdateRequest();
-        if (i == 1) {
-            // First time around we should build the message.
-            EXPECT_FALSE(prev_msg);
-            EXPECT_TRUE(curr_msg);
-        } else {
-            // Subsequent passes should reuse the request. We are only
-            // looking to check that we have not replaced the pointer value
-            // with a new pointer.  This tests the on_entry() logic which
-            // clears the request ONLY upon initial entry into the state.
-            EXPECT_TRUE(prev_msg == curr_msg);
-        }
-
         // Simulate a corrupt server response.
         name_remove->setDnsUpdateStatus(DNSClient::INVALID_RESPONSE);
         name_remove->postNextEvent(NameChangeTransaction::IO_COMPLETED_EVT);
@@ -1419,24 +1374,9 @@ TEST_F(NameRemoveTransactionTest, removingRevPtrsHandler_Timeout) {
     // and then transition to selecting a new server.
     int max_tries = NameChangeTransaction::MAX_UPDATE_TRIES_PER_SERVER;
     for (int i = 1; i <= max_tries; ++i) {
-        const D2UpdateMessagePtr prev_msg = name_remove->getDnsUpdateRequest();
-
         // Run removingRevPtrsHandler to send the request.
         EXPECT_NO_THROW(name_remove->removingRevPtrsHandler());
 
-        const D2UpdateMessagePtr curr_msg = name_remove->getDnsUpdateRequest();
-        if (i == 1) {
-            // First time around we should build the message.
-            EXPECT_FALSE(prev_msg);
-            EXPECT_TRUE(curr_msg);
-        } else {
-            // Subsequent passes should reuse the request. We are only
-            // looking to check that we have not replaced the pointer value
-            // with a new pointer.  This tests the on_entry() logic which
-            // clears the request ONLY upon initial entry into the state.
-            EXPECT_TRUE(prev_msg == curr_msg);
-        }
-
         // Simulate a server IO timeout.
         name_remove->setDnsUpdateStatus(DNSClient::TIMEOUT);
         name_remove->postNextEvent(NameChangeTransaction::IO_COMPLETED_EVT);
@@ -1488,24 +1428,9 @@ TEST_F(NameRemoveTransactionTest, removingRevPtrsHandler_CorruptResponse) {
     // and then transition to selecting a new server.
     int max_tries = NameChangeTransaction::MAX_UPDATE_TRIES_PER_SERVER;
     for (int i = 1; i <= max_tries; ++i) {
-        const D2UpdateMessagePtr prev_msg = name_remove->getDnsUpdateRequest();
-
         // Run removingRevPtrsHandler to send the request.
         EXPECT_NO_THROW(name_remove->removingRevPtrsHandler());
 
-        const D2UpdateMessagePtr curr_msg = name_remove->getDnsUpdateRequest();
-        if (i == 1) {
-            // First time around we should build the message.
-            EXPECT_FALSE(prev_msg);
-            EXPECT_TRUE(curr_msg);
-        } else {
-            // Subsequent passes should reuse the request. We are only
-            // looking to check that we have not replaced the pointer value
-            // with a new pointer.  This tests the on_entry() logic which
-            // clears the request ONLY upon initial entry into the state.
-            EXPECT_TRUE(prev_msg == curr_msg);
-        }
-
         // Simulate a server corrupt response.
         name_remove->setDnsUpdateStatus(DNSClient::INVALID_RESPONSE);
         name_remove->postNextEvent(NameChangeTransaction::IO_COMPLETED_EVT);
index 5d8f4d56530cbeefe79b021ff2481c2cf72ca92e..c47a2b6f4b3464002d7bc08e9316cf6f851637b1 100644 (file)
@@ -9,8 +9,8 @@
 #include <asiolink/io_service.h>
 #include <d2/simple_add.h>
 #include <d2srv/d2_cfg_mgr.h>
+#include <d2srv/testutils/nc_test_utils.h>
 #include <dns/messagerenderer.h>
-#include <nc_test_utils.h>
 
 #include <gtest/gtest.h>
 
@@ -598,24 +598,9 @@ TEST_F(SimpleAddTransactionTest, replacingFwdAddrsHandler_Timeout) {
     // and then transition to selecting a new server.
     int max_tries = NameChangeTransaction::MAX_UPDATE_TRIES_PER_SERVER;
     for (int i = 1; i <= max_tries; ++i) {
-        const D2UpdateMessagePtr prev_msg = name_add->getDnsUpdateRequest();
-
         // Run replacingFwdAddrsHandler to send the request.
         EXPECT_NO_THROW(name_add->replacingFwdAddrsHandler());
 
-        const D2UpdateMessagePtr curr_msg = name_add->getDnsUpdateRequest();
-        if (i == 1) {
-            // First time out we should build the message.
-            EXPECT_FALSE(prev_msg);
-            EXPECT_TRUE(curr_msg);
-        } else {
-            // Subsequent passes should reuse the request. We are only
-            // looking to check that we have not replaced the pointer value
-            // with a new pointer.  This tests the on_entry() logic which
-            // clears the request ONLY upon initial entry into the state.
-            EXPECT_TRUE(prev_msg == curr_msg);
-        }
-
         // Simulate a server IO timeout.
         name_add->setDnsUpdateStatus(DNSClient::TIMEOUT);
         name_add->postNextEvent(NameChangeTransaction::IO_COMPLETED_EVT);
@@ -662,24 +647,9 @@ TEST_F(SimpleAddTransactionTest, replacingFwdAddrsHandler_CorruptResponse) {
     // and then transition to selecting a new server.
     int max_tries = NameChangeTransaction::MAX_UPDATE_TRIES_PER_SERVER;
     for (int i = 1; i <= max_tries; ++i) {
-        const D2UpdateMessagePtr prev_msg = name_add->getDnsUpdateRequest();
-
         // Run replacingFwdAddrsHandler to send the request.
         EXPECT_NO_THROW(name_add->replacingFwdAddrsHandler());
 
-        const D2UpdateMessagePtr curr_msg = name_add->getDnsUpdateRequest();
-        if (i == 1) {
-            // First time out we should build the message.
-            EXPECT_FALSE(prev_msg);
-            EXPECT_TRUE(curr_msg);
-        } else {
-            // Subsequent passes should reuse the request. We are only
-            // looking to check that we have not replaced the pointer value
-            // with a new pointer.  This tests the on_entry() logic which
-            // clears the request ONLY upon initial entry into the state.
-            EXPECT_TRUE(prev_msg == curr_msg);
-        }
-
         // Simulate a corrupt server response.
         name_add->setDnsUpdateStatus(DNSClient::INVALID_RESPONSE);
         name_add->postNextEvent(NameChangeTransaction::IO_COMPLETED_EVT);
@@ -886,24 +856,9 @@ TEST_F(SimpleAddTransactionTest, replacingRevPtrsHandler_Timeout) {
     // and then transition to selecting a new server.
     int max_tries = NameChangeTransaction::MAX_UPDATE_TRIES_PER_SERVER;
     for (int i = 1; i <= max_tries; ++i) {
-        const D2UpdateMessagePtr prev_msg = name_add->getDnsUpdateRequest();
-
         // Run replacingRevPtrsHandler to send the request.
         EXPECT_NO_THROW(name_add->replacingRevPtrsHandler());
 
-        const D2UpdateMessagePtr curr_msg = name_add->getDnsUpdateRequest();
-        if (i == 1) {
-            // First time out we should build the message.
-            EXPECT_FALSE(prev_msg);
-            EXPECT_TRUE(curr_msg);
-        } else {
-            // Subsequent passes should reuse the request. We are only
-            // looking to check that we have not replaced the pointer value
-            // with a new pointer.  This tests the on_entry() logic which
-            // clears the request ONLY upon initial entry into the state.
-            EXPECT_TRUE(prev_msg == curr_msg);
-        }
-
         // Simulate a server IO timeout.
         name_add->setDnsUpdateStatus(DNSClient::TIMEOUT);
         name_add->postNextEvent(NameChangeTransaction::IO_COMPLETED_EVT);
@@ -949,24 +904,9 @@ TEST_F(SimpleAddTransactionTest, replacingRevPtrsHandler_CorruptResponse) {
     // and then transition to selecting a new server.
     int max_tries = NameChangeTransaction::MAX_UPDATE_TRIES_PER_SERVER;
     for (int i = 1; i <= max_tries; ++i) {
-        const D2UpdateMessagePtr prev_msg = name_add->getDnsUpdateRequest();
-
         // Run replacingRevPtrsHandler to send the request.
         EXPECT_NO_THROW(name_add->replacingRevPtrsHandler());
 
-        const D2UpdateMessagePtr curr_msg = name_add->getDnsUpdateRequest();
-        if (i == 1) {
-            // First time out we should build the message.
-            EXPECT_FALSE(prev_msg);
-            EXPECT_TRUE(curr_msg);
-        } else {
-            // Subsequent passes should reuse the request. We are only
-            // looking to check that we have not replaced the pointer value
-            // with a new pointer.  This tests the on_entry() logic which
-            // clears the request ONLY upon initial entry into the state.
-            EXPECT_TRUE(prev_msg == curr_msg);
-        }
-
         // Simulate a server corrupt response.
         name_add->setDnsUpdateStatus(DNSClient::INVALID_RESPONSE);
         name_add->postNextEvent(NameChangeTransaction::IO_COMPLETED_EVT);
index 64ce75834a7fa7079a11f5ff4841c2c333b3bae8..1d53400fc9d138a80d74082460f1b2228f6a447c 100644 (file)
@@ -9,8 +9,8 @@
 #include <asiolink/io_service.h>
 #include <d2/simple_remove.h>
 #include <d2srv/d2_cfg_mgr.h>
+#include <d2srv/testutils/nc_test_utils.h>
 #include <dns/messagerenderer.h>
-#include <nc_test_utils.h>
 
 #include <gtest/gtest.h>
 
@@ -605,24 +605,9 @@ TEST_F(SimpleRemoveTransactionTest, removingFwdRRsHandler_Timeout) {
     // and then transition to selecting a new server.
     int max_tries = NameChangeTransaction::MAX_UPDATE_TRIES_PER_SERVER;
     for (int i = 1; i <= max_tries; ++i) {
-        const D2UpdateMessagePtr prev_msg = name_remove->getDnsUpdateRequest();
-
         // Run removingFwdRRsHandler to send the request.
         EXPECT_NO_THROW(name_remove->removingFwdRRsHandler());
 
-        const D2UpdateMessagePtr curr_msg = name_remove->getDnsUpdateRequest();
-        if (i == 1) {
-            // First time around we should build the message.
-            EXPECT_FALSE(prev_msg);
-            EXPECT_TRUE(curr_msg);
-        } else {
-            // Subsequent passes should reuse the request. We are only
-            // looking to check that we have not replaced the pointer value
-            // with a new pointer.  This tests the on_entry() logic which
-            // clears the request ONLY upon initial entry into the state.
-            EXPECT_TRUE(prev_msg == curr_msg);
-        }
-
         // Simulate a server IO timeout.
         name_remove->setDnsUpdateStatus(DNSClient::TIMEOUT);
         name_remove->postNextEvent(NameChangeTransaction::IO_COMPLETED_EVT);
@@ -669,24 +654,9 @@ TEST_F(SimpleRemoveTransactionTest, removingFwdRRsHandler_InvalidResponse) {
     // and then transition to selecting a new server.
     int max_tries = NameChangeTransaction::MAX_UPDATE_TRIES_PER_SERVER;
     for (int i = 1; i <= max_tries; ++i) {
-        const D2UpdateMessagePtr prev_msg = name_remove->getDnsUpdateRequest();
-
         // Run removingFwdRRsHandler to send the request.
         EXPECT_NO_THROW(name_remove->removingFwdRRsHandler());
 
-        const D2UpdateMessagePtr curr_msg = name_remove->getDnsUpdateRequest();
-        if (i == 1) {
-            // First time around we should build the message.
-            EXPECT_FALSE(prev_msg);
-            EXPECT_TRUE(curr_msg);
-        } else {
-            // Subsequent passes should reuse the request. We are only
-            // looking to check that we have not replaced the pointer value
-            // with a new pointer.  This tests the on_entry() logic which
-            // clears the request ONLY upon initial entry into the state.
-            EXPECT_TRUE(prev_msg == curr_msg);
-        }
-
         // Simulate a corrupt server response.
         name_remove->setDnsUpdateStatus(DNSClient::INVALID_RESPONSE);
         name_remove->postNextEvent(NameChangeTransaction::IO_COMPLETED_EVT);
@@ -945,24 +915,9 @@ TEST_F(SimpleRemoveTransactionTest, removingRevPtrsHandler_Timeout) {
     // and then transition to selecting a new server.
     int max_tries = NameChangeTransaction::MAX_UPDATE_TRIES_PER_SERVER;
     for (int i = 1; i <= max_tries; ++i) {
-        const D2UpdateMessagePtr prev_msg = name_remove->getDnsUpdateRequest();
-
         // Run removingRevPtrsHandler to send the request.
         EXPECT_NO_THROW(name_remove->removingRevPtrsHandler());
 
-        const D2UpdateMessagePtr curr_msg = name_remove->getDnsUpdateRequest();
-        if (i == 1) {
-            // First time around we should build the message.
-            EXPECT_FALSE(prev_msg);
-            EXPECT_TRUE(curr_msg);
-        } else {
-            // Subsequent passes should reuse the request. We are only
-            // looking to check that we have not replaced the pointer value
-            // with a new pointer.  This tests the on_entry() logic which
-            // clears the request ONLY upon initial entry into the state.
-            EXPECT_TRUE(prev_msg == curr_msg);
-        }
-
         // Simulate a server IO timeout.
         name_remove->setDnsUpdateStatus(DNSClient::TIMEOUT);
         name_remove->postNextEvent(NameChangeTransaction::IO_COMPLETED_EVT);
@@ -1009,24 +964,9 @@ TEST_F(SimpleRemoveTransactionTest, removingRevPtrsHandler_CorruptResponse) {
     // and then transition to selecting a new server.
     int max_tries = NameChangeTransaction::MAX_UPDATE_TRIES_PER_SERVER;
     for (int i = 1; i <= max_tries; ++i) {
-        const D2UpdateMessagePtr prev_msg = name_remove->getDnsUpdateRequest();
-
         // Run removingRevPtrsHandler to send the request.
         EXPECT_NO_THROW(name_remove->removingRevPtrsHandler());
 
-        const D2UpdateMessagePtr curr_msg = name_remove->getDnsUpdateRequest();
-        if (i == 1) {
-            // First time around we should build the message.
-            EXPECT_FALSE(prev_msg);
-            EXPECT_TRUE(curr_msg);
-        } else {
-            // Subsequent passes should reuse the request. We are only
-            // looking to check that we have not replaced the pointer value
-            // with a new pointer.  This tests the on_entry() logic which
-            // clears the request ONLY upon initial entry into the state.
-            EXPECT_TRUE(prev_msg == curr_msg);
-        }
-
         // Simulate a server corrupt response.
         name_remove->setDnsUpdateStatus(DNSClient::INVALID_RESPONSE);
         name_remove->postNextEvent(NameChangeTransaction::IO_COMPLETED_EVT);
diff --git a/src/bin/d2/tests/stats_test_utils.h b/src/bin/d2/tests/stats_test_utils.h
deleted file mode 100644 (file)
index d7e4ae1..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright (C) 2020-2021 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#ifndef STATS_TEST_UTILS_H
-#define STATS_TEST_UTILS_H
-
-#include <cc/data.h>
-#include <d2srv/d2_stats.h>
-#include <d2srv/d2_tsig_key.h>
-#include <stats/stats_mgr.h>
-
-#include <gtest/gtest.h>
-
-namespace isc {
-namespace d2 {
-namespace test {
-
-/// @brief Type of name x value for statistics.
-typedef std::map<std::string, int64_t> StatMap;
-
-/// @brief Test fixture class with utility functions to test statistics.
-class D2StatTest : public ::testing::Test {
-public:
-    /// @brief Constructor.
-    D2StatTest();
-
-    /// @brief Destructor.
-    virtual ~D2StatTest();
-
-    /// @brief Compares a statistic to an expected value.
-    ///
-    /// Attempt to fetch the named statistic from the StatsMgr and if
-    /// found, compare its observed value to the given value.
-    /// Fails if the stat is not found or if the values do not match.
-    ///
-    /// @param name StatsMgr name for the statistic to check.
-    /// @param expected_value expected value of the statistic.
-    void checkStat(const std::string& name, const int64_t expected_value);
-
-    /// @brief Compares StatsMgr statistics against expected values.
-    ///
-    /// Iterates over a list of statistic names and expected values, attempting
-    /// to fetch each from the StatsMgr and if found, compare its observed
-    /// value to the expected value. Fails if any of the expected stats are not
-    /// found or if the values do not match.
-    ///
-    /// @param expected_stats Map of expected static names and values.
-    void checkStats(const StatMap& expected_stats);
-
-    /// @brief Compares StatsMgr key statistics against expected values.
-    ///
-    /// Prepend key part of names before calling checkStats simpler variant.
-    ///
-    /// @param key_name Name of the key.
-    /// @param expected_stats Map of expected static names and values.
-    void checkStats(const std::string& key_name, const StatMap& expected_stats);
-};
-
-}
-}
-}
-
-#endif // STATS_TEST_UTILS_H
index c6e909f286593093b78f80ca49e72ee2f6b3ccd3..0b67e74d5ddeaf2d5ebe7f42d10a2ae8509aa8fc 100644 (file)
@@ -237,6 +237,9 @@ private:
 
 };
 
+/// \brief Defines a pointer to an IOFetch.
+typedef boost::shared_ptr<IOFetch> IOFetchPtr;
+
 } // namespace asiodns
 } // namespace isc
 
index 5b79604203823898ab2103a715288d52132ccbf7..6ece84cbc7f0d3cb0c6edcd3678a1da1c4279cd4 100644 (file)
@@ -1,4 +1,4 @@
-SUBDIRS = . tests
+SUBDIRS = . testutils tests
 
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS += $(BOOST_INCLUDES)
@@ -15,9 +15,13 @@ libkea_d2srv_la_SOURCES += d2_cfg_mgr.cc d2_cfg_mgr.h
 libkea_d2srv_la_SOURCES += d2_config.cc d2_config.h
 libkea_d2srv_la_SOURCES += d2_log.cc d2_log.h
 libkea_d2srv_la_SOURCES += d2_messages.cc d2_messages.h
+libkea_d2srv_la_SOURCES += d2_update_message.cc d2_update_message.h
 libkea_d2srv_la_SOURCES += d2_simple_parser.cc d2_simple_parser.h
 libkea_d2srv_la_SOURCES += d2_stats.cc d2_stats.h
 libkea_d2srv_la_SOURCES += d2_tsig_key.cc d2_tsig_key.h
+libkea_d2srv_la_SOURCES += d2_zone.cc d2_zone.h
+libkea_d2srv_la_SOURCES += dns_client.cc dns_client.h
+libkea_d2srv_la_SOURCES += nc_trans.cc nc_trans.h
 EXTRA_DIST += d2_messages.mes
 
 libkea_d2srv_la_CXXFLAGS = $(AM_CXXFLAGS)
@@ -27,6 +31,7 @@ libkea_d2srv_la_LIBADD  =
 libkea_d2srv_la_LIBADD += $(top_builddir)/src/lib/process/libkea-process.la
 libkea_d2srv_la_LIBADD += $(top_builddir)/src/lib/cfgrpt/libcfgrpt.la
 libkea_d2srv_la_LIBADD += $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la
+libkea_d2srv_la_LIBADD += $(top_builddir)/src/lib/asiodns/libkea-asiodns.la
 libkea_d2srv_la_LIBADD += $(top_builddir)/src/lib/stats/libkea-stats.la
 libkea_d2srv_la_LIBADD += $(top_builddir)/src/lib/config/libkea-cfgclient.la
 libkea_d2srv_la_LIBADD += $(top_builddir)/src/lib/http/libkea-http.la
similarity index 98%
rename from src/bin/d2/d2_update_message.cc
rename to src/lib/d2srv/d2_update_message.cc
index 115663fa80d3efbe79e9f43e32f93a751365a05e..1917d6e33959287626713aee8fea444e31e6bd06 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2020 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2021 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -6,7 +6,7 @@
 
 #include <config.h>
 
-#include <d2/d2_update_message.h>
+#include <d2srv/d2_update_message.h>
 #include <dns/messagerenderer.h>
 #include <dns/name.h>
 #include <dns/opcode.h>
similarity index 99%
rename from src/bin/d2/d2_update_message.h
rename to src/lib/d2srv/d2_update_message.h
index ad01a9ce6907ed4c40dc49911e992d68260eb223..8365128d0516d4aee877a232c466510fc62e4ca4 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2015,2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2021 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -7,7 +7,7 @@
 #ifndef D2_UPDATE_MESSAGE_H
 #define D2_UPDATE_MESSAGE_H
 
-#include <d2/d2_zone.h>
+#include <d2srv/d2_zone.h>
 #include <dns/message.h>
 #include <dns/name.h>
 #include <dns/rcode.h>
similarity index 87%
rename from src/bin/d2/d2_zone.cc
rename to src/lib/d2srv/d2_zone.cc
index e029d17d018480f31eaec5415114b789a94faab2..c48b2c5fac1a51936e3275bcb05dc0d92e0ee02c 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2021 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -6,7 +6,7 @@
 
 #include <config.h>
 
-#include <d2/d2_zone.h>
+#include <d2srv/d2_zone.h>
 
 namespace isc {
 namespace d2 {
similarity index 98%
rename from src/bin/d2/d2_zone.h
rename to src/lib/d2srv/d2_zone.h
index ec13871094a4bb45663553cac8b32aa3a3e1efa1..077ad16b8be839acc0a1bf2419d3a2ff94f210cb 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2021 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
similarity index 75%
rename from src/bin/d2/dns_client.cc
rename to src/lib/d2srv/dns_client.cc
index de929bc549abe505fac8a168fe041a5062a57f62..57982076705f00d2922d5dfade7348d495d6e94c 100644 (file)
@@ -5,8 +5,9 @@
 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 #include <config.h>
-#include <d2/dns_client.h>
+
 #include <d2srv/d2_log.h>
+#include <d2srv/dns_client.h>
 #include <dns/messagerenderer.h>
 #include <stats/stats_mgr.h>
 #include <limits>
@@ -37,42 +38,68 @@ using namespace isc::stats;
 // to this separation.
 class DNSClientImpl : public asiodns::IOFetch::Callback {
 public:
-    // A buffer holding response from a DNS.
+    /// @brief A buffer holding response from a DNS.
     util::OutputBufferPtr in_buf_;
-    // A caller-supplied object which will hold the parsed response from DNS.
-    // The response object is (or descends from) isc::dns::Message and is
-    // populated using Message::fromWire().  This method may only be called
-    // once in the lifetime of a Message instance.  Therefore, response_ is a
-    // pointer reference thus allowing this class to replace the object
-    // pointed to with a new Message instance each time a message is
-    // received. This allows a single DNSClientImpl instance to be used for
-    // multiple, sequential IOFetch calls. (@todo Trac# 3286 has been opened
-    // against dns::Message::fromWire.  Should the behavior of fromWire change
-    // the behavior here with could be reexamined).
+
+    /// A caller-supplied object which will hold the parsed response from DNS.
+    /// The response object is (or descends from) isc::dns::Message and is
+    /// populated using Message::fromWire().  This method may only be called
+    /// once in the lifetime of a Message instance.  Therefore, response_ is a
+    /// pointer reference thus allowing this class to replace the object
+    /// pointed to with a new Message instance each time a message is
+    /// received. This allows a single DNSClientImpl instance to be used for
+    /// multiple, sequential IOFetch calls. (@todo Trac# 3286 has been opened
+    /// against dns::Message::fromWire.  Should the behavior of fromWire change
+    /// the behavior here with could be reexamined).
     D2UpdateMessagePtr& response_;
-    // A caller-supplied external callback which is invoked when DNS message
-    // exchange is complete or interrupted.
+
+    /// @brief A caller-supplied external callback which is invoked when DNS
+    /// message exchange is complete or interrupted.
     DNSClient::Callback* callback_;
-    // A Transport Layer protocol used to communicate with a DNS.
+
+    /// @brief A Transport Layer protocol used to communicate with a DNS.
     DNSClient::Protocol proto_;
-    // TSIG context used to sign outbound and verify inbound messages.
+
+    /// @brief TSIG context used to sign outbound and verify inbound messages.
     dns::TSIGContextPtr tsig_context_;
-    // TSIG key name for stats.
+
+    /// @brief TSIG key name for stats.
     std::string tsig_key_name_;
 
-    // Constructor and Destructor
+    /// @brief Constructor.
+    ///
+    /// @param response_placeholder Message object pointer which will be updated
+    /// with dynamically allocated object holding the DNS server's response.
+    /// @param callback Pointer to an object implementing @c DNSClient::Callback
+    /// class. This object will be called when DNS message exchange completes or
+    /// if an error occurs. NULL value disables callback invocation.
+    /// @param proto caller's preference regarding Transport layer protocol to
+    /// be used by DNS Client to communicate with a server.
     DNSClientImpl(D2UpdateMessagePtr& response_placeholder,
                   DNSClient::Callback* callback,
                   const DNSClient::Protocol proto);
+
+    /// @brief Destructor.
     virtual ~DNSClientImpl();
 
-    // This internal callback is called when the DNS update message exchange is
-    // complete. It further invokes the external callback provided by a caller.
-    // Before external callback is invoked, an object of the D2UpdateMessage
-    // type, representing a response from the server is set.
+    /// @brief This internal callback is called when the DNS update message
+    /// exchange is complete. It further invokes the external callback provided
+    /// by a caller. Before external callback is invoked, an object of the
+    /// D2UpdateMessage type, representing a response from the server is set.
     virtual void operator()(asiodns::IOFetch::Result result);
 
-    // Starts asynchronous DNS Update using TSIG.
+    /// @brief Starts asynchronous DNS Update using TSIG.
+    ///
+    /// @param io_service IO service to be used to run the message exchange.
+    /// @param ns_addr DNS server address.
+    /// @param ns_port DNS server port.
+    /// @param update A DNS Update message to be sent to the server.
+    /// @param wait A timeout (in milliseconds) for the response. If a response
+    /// is not received within the timeout, exchange is interrupted. This value
+    /// must not exceed maximal value for 'int' data type.
+    /// @param tsig_key A pointer to an @c D2TsigKeyPtr object that will
+    /// (if not null) be used to sign the DNS Update message and verify the
+    /// response.
     void doUpdate(asiolink::IOService& io_service,
                   const asiolink::IOAddress& ns_addr,
                   const uint16_t ns_port,
@@ -80,10 +107,17 @@ public:
                   const unsigned int wait,
                   const D2TsigKeyPtr& tsig_key);
 
-    // This function maps the IO error to the DNSClient error.
-    DNSClient::Status getStatus(const asiodns::IOFetch::Result);
-
-    // This function updates statistics.
+    /// @brief This function maps the IO error to the DNSClient error.
+    ///
+    /// @param result The IOFetch result to be converted to DNSClient status.
+    /// @return The DNSClient status corresponding to the IOFetch result.
+    DNSClient::Status getStatus(const asiodns::IOFetch::Result result);
+
+    /// @brief This function updates statistics.
+    ///
+    /// @param stat The statistic name to be incremented.
+    /// @param update_key The flag indicating if the key statistics should also
+    /// be updated.
     void incrStats(const std::string& stat, bool update_key = true);
 };
 
@@ -268,7 +302,6 @@ DNSClient::DNSClient(D2UpdateMessagePtr& response_placeholder,
 }
 
 DNSClient::~DNSClient() {
-    delete (impl_);
 }
 
 unsigned int
similarity index 97%
rename from src/bin/d2/dns_client.h
rename to src/lib/d2srv/dns_client.h
index fb2412523d78eb8705b62fec08e80c815d2b56cd..c63a7a0c0a07000cd940051f357faf7e904647cd 100644 (file)
@@ -7,13 +7,11 @@
 #ifndef DNS_CLIENT_H
 #define DNS_CLIENT_H
 
-#include <d2/d2_update_message.h>
-
 #include <asiolink/io_service.h>
-#include <util/buffer.h>
-
 #include <asiodns/io_fetch.h>
 #include <d2srv/d2_tsig_key.h>
+#include <d2srv/d2_update_message.h>
+#include <util/buffer.h>
 
 namespace isc {
 namespace d2 {
@@ -149,7 +147,8 @@ public:
                   const D2TsigKeyPtr& tsig_key = D2TsigKeyPtr());
 
 private:
-    DNSClientImpl* impl_;  ///< Pointer to DNSClient implementation.
+    /// @brief Pointer to DNSClient implementation.
+    std::unique_ptr<DNSClientImpl> impl_;
 };
 
 } // namespace d2
similarity index 99%
rename from src/bin/d2/nc_trans.cc
rename to src/lib/d2srv/nc_trans.cc
index 6f5c8ebb9f0bdc667e2beaa6b1c37f9c63d5f491..e9534c256c85647bc063c8eb5795742439c0a63d 100644 (file)
@@ -6,8 +6,8 @@
 
 #include <config.h>
 
-#include <d2/nc_trans.h>
 #include <d2srv/d2_log.h>
+#include <d2srv/nc_trans.h>
 #include <dns/qid_gen.h>
 #include <dns/rdata.h>
 #include <hooks/hooks.h>
@@ -301,10 +301,14 @@ NameChangeTransaction::setDnsUpdateRequest(D2UpdateMessagePtr& request) {
 
 void
 NameChangeTransaction::clearDnsUpdateRequest() {
-    update_attempts_ = 0;
     dns_update_request_.reset();
 }
 
+void
+NameChangeTransaction::clearUpdateAttempts() {
+    update_attempts_ = 0;
+}
+
 void
 NameChangeTransaction::setDnsUpdateStatus(const DNSClient::Status& status) {
     dns_update_status_ = status;
similarity index 99%
rename from src/bin/d2/nc_trans.h
rename to src/lib/d2srv/nc_trans.h
index 503d9a0f83a870f1aeeec47fe784fb8ebe927417..2aee7eccfbe391f639082a34e53030a466681fe1 100644 (file)
@@ -10,7 +10,7 @@
 /// @file nc_trans.h This file defines the class NameChangeTransaction.
 
 #include <asiolink/io_service.h>
-#include <d2/dns_client.h>
+#include <d2srv/dns_client.h>
 #include <d2srv/d2_cfg_mgr.h>
 #include <d2srv/d2_tsig_key.h>
 #include <dhcp_ddns/ncr_msg.h>
@@ -288,10 +288,12 @@ protected:
     /// @param request is the new request packet to assign.
     void setDnsUpdateRequest(D2UpdateMessagePtr& request);
 
-    /// @brief Destroys the current update request packet and resets
-    /// update attempts count.
+    /// @brief Destroys the current update request packet.
     void clearDnsUpdateRequest();
 
+    /// @brief Resets the update attempts count.
+    void clearUpdateAttempts();
+
     /// @brief Sets the update status to the given status value.
     ///
     /// @param status is the new value for the update status.
index caede036f9ecb048c501cb163ffcb711b33d15c1..436cb21ee1479f6dddff3121ccc3ea7731620bd3 100644 (file)
@@ -20,13 +20,19 @@ TESTS += libd2srv_unittests
 
 libd2srv_unittests_SOURCES  = run_unittests.cc
 libd2srv_unittests_SOURCES += d2_tsig_key_unittest.cc
+libd2srv_unittests_SOURCES += d2_update_message_unittests.cc
+libd2srv_unittests_SOURCES += d2_zone_unittests.cc
+libd2srv_unittests_SOURCES += dns_client_unittests.cc
+libd2srv_unittests_SOURCES += nc_trans_unittests.cc
 
 libd2srv_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 libd2srv_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 
 libd2srv_unittests_LDADD  = $(top_builddir)/src/lib/d2srv/libkea-d2srv.la
+libd2srv_unittests_LDADD += $(top_builddir)/src/lib/d2srv/testutils/libd2srvtest.la
 libd2srv_unittests_LDADD += $(top_builddir)/src/lib/process/libkea-process.la
 libd2srv_unittests_LDADD += $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la
+libd2srv_unittests_LDADD += $(top_builddir)/src/lib/asiodns/libkea-asiodns.la
 libd2srv_unittests_LDADD += $(top_builddir)/src/lib/stats/libkea-stats.la
 libd2srv_unittests_LDADD += $(top_builddir)/src/lib/config/libkea-cfgclient.la
 libd2srv_unittests_LDADD += $(top_builddir)/src/lib/http/libkea-http.la
similarity index 99%
rename from src/bin/d2/tests/d2_update_message_unittests.cc
rename to src/lib/d2srv/tests/d2_update_message_unittests.cc
index 092b23f9e60b2cce060e76b4781678d27b3408b3..6f0cfca7cf9d52fbfb540f520ab514fce444b37f 100644 (file)
@@ -6,9 +6,9 @@
 
 #include <config.h>
 
-#include <d2/d2_update_message.h>
-#include <d2/d2_zone.h>
 #include <d2srv/d2_config.h>
+#include <d2srv/d2_update_message.h>
+#include <d2srv/d2_zone.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
similarity index 96%
rename from src/bin/d2/tests/d2_zone_unittests.cc
rename to src/lib/d2srv/tests/d2_zone_unittests.cc
index 486bed4798532b70550d3ffe8af8ffb0d8b52831..f252d07aa10da43146e61c6c35bdf09f0f49d7bd 100644 (file)
@@ -1,11 +1,11 @@
-// Copyright (C) 2013-2015,2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2021 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 #include <config.h>
-#include <d2/d2_zone.h>
+#include <d2srv/d2_zone.h>
 #include <gtest/gtest.h>
 #include <sstream>
 
similarity index 69%
rename from src/bin/d2/tests/dns_client_unittests.cc
rename to src/lib/d2srv/tests/dns_client_unittests.cc
index 6d38cc3fac9ebc96037aafb1c02c0ced8b400f06..a560546b0fc6fd523172e83dad353f5fe0ebf1c6 100644 (file)
@@ -6,14 +6,14 @@
 
 #include <config.h>
 
-#include <d2/dns_client.h>
+#include <d2srv/dns_client.h>
 #include <dns/opcode.h>
 #include <asiodns/io_fetch.h>
 #include <asiodns/logger.h>
 #include <asiolink/interval_timer.h>
+#include <d2srv/testutils/nc_test_utils.h>
+#include <d2srv/testutils/stats_test_utils.h>
 #include <dns/messagerenderer.h>
-#include <nc_test_utils.h>
-#include <stats_test_utils.h>
 
 #include <boost/asio/ip/udp.hpp>
 #include <boost/asio/socket_base.hpp>
@@ -56,34 +56,61 @@ const long TEST_TIMEOUT = 5 * 1000;
 // properly handled a task may be hanging for a long time. In order to prevent
 // it, the asiolink::IntervalTimer is used to break a running test if test
 // timeout is hit. This will result in test failure.
-class DNSClientTest : public virtual D2StatTest, DNSClient::Callback {
+class DNSClientTest : public ::testing::Test, DNSClient::Callback,
+                      public D2StatTest {
 public:
+    /// @brief The IOService which handles IO operations.
     IOService service_;
+
+    /// @brief The UDP socket.
+    std::unique_ptr<udp::socket> socket_;
+
+    /// @brief The UDP socket endpoint.
+    std::unique_ptr<udp::endpoint> endpoint_;
+
+    /// @brief DNS client response.
     D2UpdateMessagePtr response_;
+
+    /// @brief The status of the DNS client update callback.
     DNSClient::Status status_;
+
+    /// @brief The receive buffer.
     uint8_t receive_buffer_[MAX_SIZE];
+
+    /// @brief The DNS client performing DNS update.
     DNSClientPtr dns_client_;
+
+    /// @brief The flag which specifies if the response should be corrupted.
     bool corrupt_response_;
+
+    /// @brief The flag which specifies if a response is expected.
     bool expect_response_;
+
+    /// @brief The timeout timer.
     asiolink::IntervalTimer test_timer_;
+
+    /// @brief The number of received DNS updates.
     int received_;
+
+    /// @brief The number of expected DNS updates.
     int expected_;
 
+    /// @brief The flag which specifies if the server should continue with
+    /// receiving DNS updates.
+    bool go_on_;
+
     /// @brief Constructor
-    //
-    // This constructor overrides the default logging level of asiodns logger to
-    // prevent it from emitting debug messages from IOFetch class. Such an error
-    // message can be emitted if timeout occurs when DNSClient class is
-    // waiting for a response. Some of the tests are checking DNSClient behavior
-    // in case when response from the server is not received. Tests output would
-    // become messy if such errors were logged.
-    DNSClientTest()
-        : service_(),
-          status_(DNSClient::SUCCESS),
-          corrupt_response_(false),
-          expect_response_(true),
-          test_timer_(service_),
-          received_(0), expected_(0) {
+    ///
+    /// This constructor overrides the default logging level of asiodns logger to
+    /// prevent it from emitting debug messages from IOFetch class. Such an error
+    /// message can be emitted if timeout occurs when DNSClient class is
+    /// waiting for a response. Some of the tests are checking DNSClient behavior
+    /// in case when response from the server is not received. Tests output would
+    /// become messy if such errors were logged.
+    DNSClientTest() : service_(), socket_(), endpoint_(),
+                      status_(DNSClient::SUCCESS), corrupt_response_(false),
+                      expect_response_(true), test_timer_(service_),
+                      received_(0), expected_(0), go_on_(false) {
         asiodns::logger.setSeverity(isc::log::INFO);
         response_.reset();
         dns_client_.reset(new DNSClient(response_, this));
@@ -94,22 +121,21 @@ public:
     }
 
     /// @brief Destructor
-    //
-    // Sets the asiodns logging level back to DEBUG.
+    ///
+    /// Sets the asiodns logging level back to DEBUG.
     virtual ~DNSClientTest() {
         asiodns::logger.setSeverity(isc::log::DEBUG);
     };
 
     /// @brief Exchange completion callback
-    //
-    // This callback is called when the exchange with the DNS server is
-    // complete or an error occurred. This includes the occurrence of a timeout.
-    //
-    // @param status A status code returned by DNSClient.
+    ///
+    /// This callback is called when the exchange with the DNS server is
+    /// complete or an error occurred. This includes the occurrence of a timeout.
+    ///
+    /// @param status A status code returned by DNSClient.
     virtual void operator()(DNSClient::Status status) {
         status_ = status;
-        if (!expected_ || (expected_ == ++received_))
-        {
+        if (!expected_ || (expected_ == ++received_)) {
             service_.stop();
         }
 
@@ -139,27 +165,27 @@ public:
     }
 
     /// @brief Handler invoked when test timeout is hit
-    //
-    // This callback stops all running (hanging) tasks on IO service.
+    ///
+    /// This callback stops all running (hanging) tasks on IO service.
     void testTimeoutHandler() {
         service_.stop();
         FAIL() << "Test timeout hit.";
     }
 
     /// @brief Handler invoked when test request is received
-    //
-    // This callback handler is installed when performing async read on a
-    // socket to emulate reception of the DNS Update request by a server.
-    // As a result, this handler will send an appropriate DNS Update response
-    // message back to the address from which the request has come.
-    //
-    // @param socket A pointer to a socket used to receive a query and send a
-    // response.
-    // @param remote A pointer to an object which specifies the host (address
-    // and port) from which a request has come.
-    // @param receive_length A length (in bytes) of the received data.
-    // @param corrupt_response A bool value which indicates that the server's
-    // response should be invalid (true) or valid (false)
+    ///
+    /// This callback handler is installed when performing async read on a
+    /// socket to emulate reception of the DNS Update request by a server.
+    /// As a result, this handler will send an appropriate DNS Update response
+    /// message back to the address from which the request has come.
+    ///
+    /// @param socket A pointer to a socket used to receive a query and send a
+    /// response.
+    /// @param remote A pointer to an object which specifies the host (address
+    /// and port) from which a request has come.
+    /// @param receive_length A length (in bytes) of the received data.
+    /// @param corrupt_response A bool value which specifies if the server's
+    /// response should be invalid (true) or valid (false).
     void udpReceiveHandler(udp::socket* socket, udp::endpoint* remote,
                            size_t receive_length, const bool corrupt_response) {
         // The easiest way to create a response message is to copy the entire
@@ -183,31 +209,39 @@ public:
         socket->send_to(boost::asio::buffer(response_buf.getData(),
                                             response_buf.getLength()),
                         *remote);
+
+        if (go_on_) {
+            socket_->async_receive_from(boost::asio::buffer(receive_buffer_,
+                                                            sizeof(receive_buffer_)),
+                                        *endpoint_,
+                                        std::bind(&DNSClientTest::udpReceiveHandler,
+                                                  this, socket_.get(),
+                                                  endpoint_.get(), ph::_2,
+                                                  corrupt_response));
+        }
     }
 
     /// @brief Request handler for testing clients using TSIG
-    //
-    // This callback handler is installed when performing async read on a
-    // socket to emulate reception of the DNS Update request with TSIG by a
-    // server.  As a result, this handler will send an appropriate DNS Update
-    // response message back to the address from which the request has come.
-    //
-    // @param socket A pointer to a socket used to receive a query and send a
-    // response.
-    // @param remote A pointer to an object which specifies the host (address
-    // and port) from which a request has come.
-    // @param receive_length A length (in bytes) of the received data.
-    // @param corrupt_response A bool value which indicates that the server's
-    // response should be invalid (true) or valid (false)
-    // @param client_key TSIG key the server should use to verify the inbound
-    // request.  If the pointer is NULL, the server will not attempt to
-    // verify the request.
-    // @param server_key TSIG key the server should use to sign the outbound
-    // request. If the pointer is NULL, the server will not sign the outbound
-    // response.  If the pointer is not NULL and not the same value as the
-    // client_key, the server will use a new context to sign the response then
-    // the one used to verify it.  This allows us to simulate the server
-    // signing with the wrong key.
+    ///
+    /// This callback handler is installed when performing async read on a
+    /// socket to emulate reception of the DNS Update request with TSIG by a
+    /// server.  As a result, this handler will send an appropriate DNS Update
+    /// response message back to the address from which the request has come.
+    ///
+    /// @param socket A pointer to a socket used to receive a query and send a
+    /// response.
+    /// @param remote A pointer to an object which specifies the host (address
+    /// and port) from which a request has come.
+    /// @param receive_length A length (in bytes) of the received data.
+    /// @param client_key TSIG key the server should use to verify the inbound
+    /// request.  If the pointer is NULL, the server will not attempt to
+    /// verify the request.
+    /// @param server_key TSIG key the server should use to sign the outbound
+    /// request. If the pointer is NULL, the server will not sign the outbound
+    /// response.  If the pointer is not NULL and not the same value as the
+    /// client_key, the server will use a new context to sign the response then
+    /// the one used to verify it.  This allows us to simulate the server
+    /// signing with the wrong key.
     void TSIGReceiveHandler(udp::socket* socket, udp::endpoint* remote,
                             size_t receive_length,
                             D2TsigKeyPtr client_key,
@@ -255,14 +289,15 @@ public:
 
         response.toWire(renderer, context.get());
         // A response message is now ready to send. Send it!
-        socket->send_to(boost::asio::buffer(renderer.getData(), renderer.getLength()),
+        socket->send_to(boost::asio::buffer(renderer.getData(),
+                        renderer.getLength()),
                         *remote);
     }
 
-    // This test verifies that when invalid response placeholder object is
-    // passed to a constructor, constructor throws the appropriate exception.
-    // It also verifies that the constructor will not throw if the supplied
-    // callback object is NULL.
+    /// @brief This test verifies that when invalid response placeholder object
+    /// is passed to a constructor which throws the appropriate exception.
+    /// It also verifies that the constructor will not throw if the supplied
+    /// callback object is NULL.
     void runConstructorTest() {
         EXPECT_NO_THROW(DNSClient(response_, NULL, DNSClient::UDP));
 
@@ -273,8 +308,8 @@ public:
                      isc::NotImplemented);
     }
 
-    // This test verifies that it accepted timeout values belong to the range of
-    // <0, DNSClient::getMaxTimeout()>.
+    /// @brief This test verifies that it accepted timeout values belong to the
+    /// range of <0, DNSClient::getMaxTimeout()>.
     void runInvalidTimeoutTest() {
 
         expect_response_ = false;
@@ -299,9 +334,9 @@ public:
                      isc::BadValue);
     }
 
-    // This test verifies the DNSClient behavior when a server does not respond
-    // do the DNS Update message. In such case, the callback function is
-    // expected to be called and the TIME_OUT error code should be returned.
+    /// @brief This test verifies the DNSClient behavior when a server does not
+    /// respond do the DNS Update message. In such case, the callback function
+    /// is expected to be called and the TIME_OUT error code should be returned.
     void runSendNoReceiveTest() {
         // We expect no response from a server.
         expect_response_ = false;
@@ -329,7 +364,7 @@ public:
         // completion callback will be triggered. The doUpdate function returns
         // immediately.
         EXPECT_NO_THROW(dns_client_->doUpdate(service_, IOAddress(TEST_ADDRESS),
-                                             TEST_PORT, message, timeout));
+                                              TEST_PORT, message, timeout));
 
         // This starts the execution of tasks posted to IOService. run() blocks
         // until stop() is called in the completion callback function.
@@ -337,10 +372,11 @@ public:
 
     }
 
-    // This test verifies that DNSClient can send DNS Update and receive a
-    // corresponding response from a server.
+    /// @brief This test verifies that DNSClient can send DNS Update and receive
+    /// a corresponding response from a server.
     void runSendReceiveTest(const bool corrupt_response,
                             const bool two_sends) {
+        go_on_ = two_sends;
         corrupt_response_ = corrupt_response;
 
         // Create a request DNS Update message.
@@ -352,15 +388,16 @@ public:
         // and receives a response from the server, we have to emulate the
         // server's response in the test. A request will be sent via loopback
         // interface to 127.0.0.1 and known test port. Response must be sent
-        // to 127.0.0.1 and a source port which has been used to send the
+        // to 127.0.0.1 and the source port which has been used to send the
         // request. A new socket is created, specifically to handle sending
         // responses. The reuse address option is set so as both sockets can
         // use the same address. This new socket is bound to the test address
         // and port, where requests will be sent.
-        udp::socket udp_socket(service_.get_io_service(), boost::asio::ip::udp::v4());
-        udp_socket.set_option(socket_base::reuse_address(true));
-        udp_socket.bind(udp::endpoint(address::from_string(TEST_ADDRESS),
-                                      TEST_PORT));
+        socket_.reset(new udp::socket(service_.get_io_service(),
+                                      boost::asio::ip::udp::v4()));
+        socket_->set_option(socket_base::reuse_address(true));
+        socket_->bind(udp::endpoint(address::from_string(TEST_ADDRESS),
+                                    TEST_PORT));
         // Once socket is created, we can post an IO request to receive some
         // packet from this socket. This is asynchronous operation and
         // nothing is received until another IO request to send a query is
@@ -373,13 +410,14 @@ public:
         // Callback function will send a response to this address and port.
         // The last parameter holds a length of the received request. It is
         // required to construct a response.
-        udp::endpoint remote;
-        udp_socket.async_receive_from(boost::asio::buffer(receive_buffer_,
-                                                   sizeof(receive_buffer_)),
-                                      remote,
-                                      std::bind(&DNSClientTest::udpReceiveHandler,
-                                                this, &udp_socket, &remote, ph::_2,
-                                                corrupt_response));
+        endpoint_.reset(new udp::endpoint());
+        socket_->async_receive_from(boost::asio::buffer(receive_buffer_,
+                                                        sizeof(receive_buffer_)),
+                                    *endpoint_,
+                                    std::bind(&DNSClientTest::udpReceiveHandler,
+                                              this, socket_.get(),
+                                              endpoint_.get(), ph::_2,
+                                              corrupt_response));
 
         // The socket is now ready to receive the data. Let's post some request
         // message then. Set timeout to some reasonable value to make sure that
@@ -402,7 +440,7 @@ public:
         // "send" and "receive" operations.
         service_.run();
 
-        udp_socket.close();
+        socket_->close();
 
         // Since the callback, operator(), calls stop() on the io_service,
         // we must reset it in order for subsequent calls to run() or
@@ -410,14 +448,13 @@ public:
         service_.get_io_service().reset();
     }
 
-    // Performs a single request-response exchange with or without TSIG
-    //
-    // @param client_key TSIG passed to dns_client and also used by the
-    // "server" to verify the request.
-    // request.
-    // @param server_key TSIG key the "server" should use to sign the response.
-    // If this is NULL, then client_key is used.
-    // @param should_pass indicates if the test should pass.
+    /// @brief Performs a single request-response exchange with or without TSIG.
+    ///
+    /// @param client_key TSIG passed to dns_client and also used by the
+    /// "server" to verify the request.
+    /// @param server_key TSIG key the "server" should use to sign the response.
+    /// If this is NULL, then client_key is used.
+    /// @param should_pass indicates if the test should pass.
     void runTSIGTest(D2TsigKeyPtr client_key, D2TsigKeyPtr server_key,
                      bool should_pass = true) {
         // Tell operator() method if we expect an invalid response.
@@ -468,6 +505,15 @@ public:
 // valid. Constructor should throw exceptions when parameters are invalid.
 TEST_F(DNSClientTest, constructor) {
     runConstructorTest();
+    StatMap stats_upd = {
+        { "update-sent", 0},
+        { "update-signed", 0},
+        { "update-unsigned", 0},
+        { "update-success", 0},
+        { "update-timeout", 0},
+        { "update-error", 0}
+    };
+    checkStats(stats_upd);
 }
 
 // This test verifies that the maximal allowed timeout value is maximal int
@@ -479,6 +525,15 @@ TEST_F(DNSClientTest, getMaxTimeout) {
 // Verify that timeout is reported when no response is received from DNS.
 TEST_F(DNSClientTest, timeout) {
     runSendNoReceiveTest();
+    StatMap stats_upd = {
+        { "update-sent", 1},
+        { "update-signed", 0},
+        { "update-unsigned", 1},
+        { "update-success", 0},
+        { "update-timeout", 1},
+        { "update-error", 0}
+    };
+    checkStats(stats_upd);
 }
 
 // Verify that exception is thrown when invalid (too high) timeout value is
@@ -553,6 +608,15 @@ TEST_F(DNSClientTest, runTSIGTest) {
 TEST_F(DNSClientTest, sendReceive) {
     // false means that server response is not corrupted.
     runSendReceiveTest(false, false);
+    StatMap stats_upd = {
+        { "update-sent", 1},
+        { "update-signed", 0},
+        { "update-unsigned", 1},
+        { "update-success", 1},
+        { "update-timeout", 0},
+        { "update-error", 0}
+    };
+    checkStats(stats_upd);
 }
 
 // Verify that the DNSClient reports an error when the response is received from
@@ -560,6 +624,15 @@ TEST_F(DNSClientTest, sendReceive) {
 TEST_F(DNSClientTest, sendReceiveCorrupted) {
     // true means that server's response is corrupted.
     runSendReceiveTest(true, false);
+    StatMap stats_upd = {
+        { "update-sent", 1},
+        { "update-signed", 0},
+        { "update-unsigned", 1},
+        { "update-success", 0},
+        { "update-timeout", 0},
+        { "update-error", 1}
+    };
+    checkStats(stats_upd);
 }
 
 // Verify that it is possible to use the same DNSClient instance to
@@ -572,6 +645,15 @@ TEST_F(DNSClientTest, sendReceiveTwice) {
     runSendReceiveTest(false, false);
     runSendReceiveTest(false, false);
     EXPECT_EQ(2, received_);
+    StatMap stats_upd = {
+        { "update-sent", 2},
+        { "update-signed", 0},
+        { "update-unsigned", 2},
+        { "update-success", 2},
+        { "update-timeout", 0},
+        { "update-error", 0}
+    };
+    checkStats(stats_upd);
 }
 
 // Verify that it is possible to use the DNSClient instance to perform the
@@ -580,14 +662,17 @@ TEST_F(DNSClientTest, sendReceiveTwice) {
 // 2. send
 // 3. receive
 // 4. receive
-// @todo  THIS Test does not function. The method runSendReceive only
-// schedules one "server" receive.  In other words only one request is
-// listened for and then received. Once it is received, the operator()
-// method calls stop() on the io_service, which causes the second receive
-// to be cancelled.  It is also unclear, what the asio layer does with a
-// second receive on the same socket.
-TEST_F(DNSClientTest, DISABLED_concurrentSendReceive) {
+TEST_F(DNSClientTest, concurrentSendReceive) {
     runSendReceiveTest(false, true);
+    StatMap stats_upd = {
+        { "update-sent", 2},
+        { "update-signed", 0},
+        { "update-unsigned", 2},
+        { "update-success", 2},
+        { "update-timeout", 0},
+        { "update-error", 0}
+    };
+    checkStats(stats_upd);
 }
 
 } // End of anonymous namespace
similarity index 99%
rename from src/bin/d2/tests/nc_trans_unittests.cc
rename to src/lib/d2srv/tests/nc_trans_unittests.cc
index 1471006a14f15468c72d128e22673117319d89ca..89a23b78065c2f6d1bf0de8009953e212f1ef2c5 100644 (file)
@@ -8,13 +8,13 @@
 #include <asiolink/asio_wrapper.h>
 #include <asiolink/io_service.h>
 #include <asiolink/interval_timer.h>
-#include <d2/nc_trans.h>
+#include <d2srv/nc_trans.h>
+#include <d2srv/testutils/nc_test_utils.h>
 #include <dns/opcode.h>
 #include <dns/messagerenderer.h>
 #include <log/logger_support.h>
 #include <log/macros.h>
 #include <util/buffer.h>
-#include <nc_test_utils.h>
 
 #include <boost/date_time/posix_time/posix_time.hpp>
 #include <gtest/gtest.h>
@@ -44,6 +44,8 @@ public:
     // NameChangeStub events
     static const int SEND_UPDATE_EVT = NCT_DERIVED_EVENT_MIN + 2;
 
+    /// @brief Flag which specifies if the NameChangeStub's callback should be
+    /// used instead of the NameChangeTransaction's callback.
     bool use_stub_callback_;
 
     /// @brief Constructor
@@ -235,6 +237,7 @@ public:
     using NameChangeTransaction::setNcrStatus;
     using NameChangeTransaction::setDnsUpdateRequest;
     using NameChangeTransaction::clearDnsUpdateRequest;
+    using NameChangeTransaction::clearUpdateAttempts;
     using NameChangeTransaction::setDnsUpdateStatus;
     using NameChangeTransaction::getDnsUpdateResponse;
     using NameChangeTransaction::setDnsUpdateResponse;
@@ -663,7 +666,7 @@ TEST_F(NameChangeTransactionTest, serverSelectionTest) {
 
     // The server selection process determines the current server,
     // instantiates a new DNSClient, and a DNS response message buffer.
-    //  We need to save the values before each selection, so we can verify
+    // We need to save the values before each selection, so we can verify
     // they are correct after each selection.
     DnsServerInfoPtr prev_server = name_change->getCurrentServer();
     DNSClientPtr prev_client = name_change->getDNSClient();
@@ -871,6 +874,12 @@ TEST_F(NameChangeTransactionTest, updateAttempts) {
 
     // Verify that the value is as expected.
     EXPECT_EQ(5, name_change->getUpdateAttempts());
+
+    // Clear it.
+    name_change->clearUpdateAttempts();
+
+    // Verify that it was cleared as expected.
+    EXPECT_EQ(0, name_change->getUpdateAttempts());
 }
 
 /// @brief Tests retryTransition method
diff --git a/src/lib/d2srv/testutils/Makefile.am b/src/lib/d2srv/testutils/Makefile.am
new file mode 100644 (file)
index 0000000..c7ae2ad
--- /dev/null
@@ -0,0 +1,23 @@
+SUBDIRS = .
+
+AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+
+AM_CXXFLAGS = $(KEA_CXXFLAGS)
+
+CLEANFILES = *.gcno *.gcda
+
+if HAVE_GTEST
+
+noinst_LTLIBRARIES = libd2srvtest.la
+
+libd2srvtest_la_SOURCES  = nc_test_utils.cc nc_test_utils.h
+libd2srvtest_la_SOURCES += stats_test_utils.cc stats_test_utils.h
+
+libd2srvtest_la_CXXFLAGS = $(AM_CXXFLAGS)
+libd2srvtest_la_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
+
+libd2srvtest_la_LIBADD  = $(top_builddir)/src/lib/d2srv/libkea-d2srv.la
+libd2srvtest_la_LIBADD += $(top_builddir)/src/lib/log/libkea-log.la
+
+endif
similarity index 94%
rename from src/bin/d2/tests/nc_test_utils.cc
rename to src/lib/d2srv/testutils/nc_test_utils.cc
index 358387bdc7821742c76292891a77d06e944c8d29..39035352b3cace8e697bc6c61f89f7a419e369f5 100644 (file)
@@ -8,9 +8,9 @@
 #include <asiolink/asio_wrapper.h>
 #include <asiolink/udp_endpoint.h>
 #include <d2srv/d2_cfg_mgr.h>
+#include <d2srv/testutils/nc_test_utils.h>
 #include <dns/messagerenderer.h>
 #include <dns/opcode.h>
-#include <nc_test_utils.h>
 #include <util/encode/base64.h>
 
 #include <gtest/gtest.h>
@@ -394,9 +394,9 @@ checkZone(const D2UpdateMessagePtr& request, const std::string& exp_zone_name) {
 
 void
 checkRR(dns::RRsetPtr rrset, const std::string& exp_name,
-              const dns::RRClass& exp_class, const dns::RRType& exp_type,
-              unsigned int exp_ttl, dhcp_ddns::NameChangeRequestPtr ncr,
-              bool has_rdata) {
+        const dns::RRClass& exp_class, const dns::RRType& exp_type,
+        unsigned int exp_ttl, dhcp_ddns::NameChangeRequestPtr ncr,
+        bool has_rdata) {
     // Verify the FQDN/DHCID RR fields.
     EXPECT_EQ(exp_name, rrset->getName().toText());
     EXPECT_EQ(exp_class.getCode(), rrset->getClass().getCode());
@@ -417,7 +417,7 @@ checkRR(dns::RRsetPtr rrset, const std::string& exp_name,
         (exp_type == dns::RRType::AAAA())) {
         // should have lease rdata
         EXPECT_EQ(ncr->getIpAddress(), rdata_it->getCurrent().toText());
-    } else if (exp_type == dns::RRType::PTR())  {
+    } else if (exp_type == dns::RRType::PTR()) {
         // should have PTR rdata
         EXPECT_EQ(ncr->getFqdn(), rdata_it->getCurrent().toText());
     } else if (exp_type == dns::RRType::DHCID()) {
@@ -447,19 +447,20 @@ getRRFromSection(const D2UpdateMessagePtr& request,
     return (*rrset_it);
 }
 
-dhcp_ddns::NameChangeRequestPtr makeNcrFromString(const std::string& ncr_str) {
+dhcp_ddns::NameChangeRequestPtr
+makeNcrFromString(const std::string& ncr_str) {
     return (dhcp_ddns::NameChangeRequest::fromJSON(ncr_str));
 }
 
-DdnsDomainPtr makeDomain(const std::string& zone_name,
-                         const std::string& key_name) {
+DdnsDomainPtr
+makeDomain(const std::string& zone_name, const std::string& key_name) {
     DnsServerInfoStoragePtr servers(new DnsServerInfoStorage());
     DdnsDomainPtr domain(new DdnsDomain(zone_name, servers, key_name));
     return (domain);
 }
 
-DdnsDomainPtr makeDomain(const std::string& zone_name,
-                         const TSIGKeyInfoPtr &tsig_key_info) {
+DdnsDomainPtr
+makeDomain(const std::string& zone_name, const TSIGKeyInfoPtr &tsig_key_info) {
     DdnsDomainPtr domain;
     DnsServerInfoStoragePtr servers(new DnsServerInfoStorage());
     std::string key_name;
@@ -470,9 +471,9 @@ DdnsDomainPtr makeDomain(const std::string& zone_name,
     return (domain);
 }
 
-TSIGKeyInfoPtr makeTSIGKeyInfo(const std::string& key_name,
-                           const std::string& secret,
-                           const std::string& algorithm) {
+TSIGKeyInfoPtr
+makeTSIGKeyInfo(const std::string& key_name, const std::string& secret,
+                const std::string& algorithm) {
     TSIGKeyInfoPtr key_info;
     if (!key_name.empty()) {
         if (!secret.empty()) {
@@ -493,20 +494,21 @@ TSIGKeyInfoPtr makeTSIGKeyInfo(const std::string& key_name,
     }
 
     return (key_info);
-
 }
 
-void addDomainServer(DdnsDomainPtr& domain, const std::string& name,
-                     const std::string& ip, const size_t port,
-                     const TSIGKeyInfoPtr &tsig_key_info) {
+void
+addDomainServer(DdnsDomainPtr& domain, const std::string& name,
+                const std::string& ip, const size_t port,
+                const TSIGKeyInfoPtr &tsig_key_info) {
     DnsServerInfoPtr server(new DnsServerInfo(name, asiolink::IOAddress(ip),
                                               port, true, tsig_key_info));
     domain->getServers()->push_back(server);
 }
 
-// Verifies that the contents of the given transaction's  DNS update request
+// Verifies that the contents of the given transaction's DNS update request
 // is correct for adding a forward DNS entry
-void checkAddFwdAddressRequest(NameChangeTransaction& tran) {
+void
+checkAddFwdAddressRequest(NameChangeTransaction& tran) {
     const D2UpdateMessagePtr& request = tran.getDnsUpdateRequest();
     ASSERT_TRUE(request);
 
@@ -555,9 +557,10 @@ void checkAddFwdAddressRequest(NameChangeTransaction& tran) {
     ASSERT_NO_THROW(request->toWire(renderer));
 }
 
-// Verifies that the contents of the given transaction's  DNS update request
+// Verifies that the contents of the given transaction's DNS update request
 // is correct for replacing a forward DNS entry
-void checkReplaceFwdAddressRequest(NameChangeTransaction& tran) {
+void
+checkReplaceFwdAddressRequest(NameChangeTransaction& tran) {
     const D2UpdateMessagePtr& request = tran.getDnsUpdateRequest();
     ASSERT_TRUE(request);
 
@@ -614,9 +617,10 @@ void checkReplaceFwdAddressRequest(NameChangeTransaction& tran) {
     ASSERT_NO_THROW(request->toWire(renderer));
 }
 
-// Verifies that the contents of the given transaction's  DNS update request
+// Verifies that the contents of the given transaction's DNS update request
 // is correct for replacing a reverse DNS entry
-void checkReplaceRevPtrsRequest(NameChangeTransaction& tran) {
+void
+checkReplaceRevPtrsRequest(NameChangeTransaction& tran) {
     const D2UpdateMessagePtr& request = tran.getDnsUpdateRequest();
     ASSERT_TRUE(request);
 
@@ -677,7 +681,8 @@ void checkReplaceRevPtrsRequest(NameChangeTransaction& tran) {
     ASSERT_NO_THROW(request->toWire(renderer));
 }
 
-void checkRemoveFwdAddressRequest(NameChangeTransaction& tran) {
+void
+checkRemoveFwdAddressRequest(NameChangeTransaction& tran) {
     const D2UpdateMessagePtr& request = tran.getDnsUpdateRequest();
     ASSERT_TRUE(request);
 
@@ -716,7 +721,8 @@ void checkRemoveFwdAddressRequest(NameChangeTransaction& tran) {
     ASSERT_NO_THROW(request->toWire(renderer));
 }
 
-void checkRemoveFwdRRsRequest(NameChangeTransaction& tran) {
+void
+checkRemoveFwdRRsRequest(NameChangeTransaction& tran) {
     const D2UpdateMessagePtr& request = tran.getDnsUpdateRequest();
     ASSERT_TRUE(request);
 
@@ -766,7 +772,8 @@ void checkRemoveFwdRRsRequest(NameChangeTransaction& tran) {
     ASSERT_NO_THROW(request->toWire(renderer));
 }
 
-void checkRemoveRevPtrsRequest(NameChangeTransaction& tran) {
+void
+checkRemoveRevPtrsRequest(NameChangeTransaction& tran) {
     const D2UpdateMessagePtr& request = tran.getDnsUpdateRequest();
     ASSERT_TRUE(request);
 
@@ -804,7 +811,8 @@ void checkRemoveRevPtrsRequest(NameChangeTransaction& tran) {
     ASSERT_NO_THROW(request->toWire(renderer));
 }
 
-std::string toHexText(const uint8_t* data, size_t len) {
+std::string
+toHexText(const uint8_t* data, size_t len) {
     std::ostringstream stream;
     stream << "Data length is: " << len << std::endl;
     for (int i = 0; i < len; ++i) {
@@ -819,10 +827,11 @@ std::string toHexText(const uint8_t* data, size_t len) {
     return (stream.str());
 }
 
-// Verifies that the contents of the given transaction's  DNS update request
+// Verifies that the contents of the given transaction's DNS update request
 // is correct for replacing a forward DNS entry when not using conflict
 // resolution.
-void checkSimpleReplaceFwdAddressRequest(NameChangeTransaction& tran) {
+void
+checkSimpleReplaceFwdAddressRequest(NameChangeTransaction& tran) {
     const D2UpdateMessagePtr& request = tran.getDnsUpdateRequest();
     ASSERT_TRUE(request);
 
@@ -883,7 +892,8 @@ void checkSimpleReplaceFwdAddressRequest(NameChangeTransaction& tran) {
     ASSERT_NO_THROW(request->toWire(renderer));
 }
 
-void checkSimpleRemoveFwdRRsRequest(NameChangeTransaction& tran) {
+void
+checkSimpleRemoveFwdRRsRequest(NameChangeTransaction& tran) {
     const D2UpdateMessagePtr& request = tran.getDnsUpdateRequest();
     ASSERT_TRUE(request);
 
@@ -921,10 +931,11 @@ void checkSimpleRemoveFwdRRsRequest(NameChangeTransaction& tran) {
     ASSERT_NO_THROW(request->toWire(renderer));
 }
 
-// Verifies that the contents of the given transaction's  DNS update request
+// Verifies that the contents of the given transaction's DNS update request
 // is correct for removing a reverse DNS entry when not using conflict
 // resolution.
-void checkSimpleRemoveRevPtrsRequest(NameChangeTransaction& tran) {
+void
+checkSimpleRemoveRevPtrsRequest(NameChangeTransaction& tran) {
     const D2UpdateMessagePtr& request = tran.getDnsUpdateRequest();
     ASSERT_TRUE(request);
 
@@ -961,8 +972,9 @@ void checkSimpleRemoveRevPtrsRequest(NameChangeTransaction& tran) {
 }
 
 // Verifies the current state and next event in a transaction
-void checkContext(NameChangeTransactionPtr trans, const int exp_state,
-                  const int exp_evt, const std::string& file, int line) {
+void
+checkContext(NameChangeTransactionPtr trans, const int exp_state,
+             const int exp_evt, const std::string& file, int line) {
     ASSERT_TRUE(trans);
     ASSERT_TRUE(exp_state == trans->getCurrState() && exp_evt == trans->getNextEvent())
             << "expected state: " << trans->getStateLabel(exp_state)
similarity index 95%
rename from src/bin/d2/tests/nc_test_utils.h
rename to src/lib/d2srv/testutils/nc_test_utils.h
index 4cfff4cb92cacaa6f09d0784deb25292dde071e8..73b6287624c1906c16f60c264ae2d286be58d75d 100644 (file)
@@ -11,7 +11,8 @@
 
 #include <asiolink/io_service.h>
 #include <asiolink/interval_timer.h>
-#include <d2/nc_trans.h>
+#include <d2srv/d2_update_message.h>
+#include <d2srv/nc_trans.h>
 
 #include <boost/asio/ip/udp.hpp>
 #include <boost/asio/socket_base.hpp>
@@ -34,33 +35,41 @@ typedef boost::shared_ptr<boost::asio::ip::udp::socket> SocketPtr;
 /// requests in a given manner.
 class FauxServer {
 public:
-    enum  ResponseMode {
+    /// @brief The types of response generated by the server.
+    enum ResponseMode {
         USE_RCODE,    // Generate a response with a given RCODE
         CORRUPT_RESP, // Generate a corrupt response
         INVALID_TSIG  // Generate a response with the wrong TSIG key
     };
 
-    // Reference to IOService to use for IO processing.
+    /// @brief Reference to IOService to use for IO processing.
     asiolink::IOService& io_service_;
-    // IP address at which to listen for requests.
+
+    /// @brief IP address at which to listen for requests.
     const asiolink::IOAddress& address_;
-    // Port on which to listen for requests.
+
+    /// @brief Port on which to listen for requests.
     size_t port_;
-    // Socket on which listening is done.
+
+    /// @brief Socket on which listening is done.
     SocketPtr server_socket_;
-    // Stores the end point of requesting client.
+
+    /// @brief Stores the end point of requesting client.
     boost::asio::ip::udp::endpoint remote_;
-    // Buffer in which received packets are stuffed.
+
+    /// @brief Buffer in which received packets are stuffed.
     uint8_t receive_buffer_[TEST_MSG_MAX];
-    // Flag which indicates if a receive has been initiated but
-    // not yet completed.
+
+    /// @brief Flag which indicates if a receive has been initiated but not yet
+    /// completed.
     bool receive_pending_;
-    // Indicates if server is in perpetual receive mode. If true once
-    // a receive has been completed, a new one will be automatically
-    // initiated.
+    /// @brief Flag which indicates if server is in perpetual receive mode.
+    /// If true once a receive has been completed, a new one will be
+    /// automatically initiated.
     bool perpetual_receive_;
-    // TSIG Key to use to verify requests and sign responses.  If its
-    // NULL TSIG is not used.
+
+    /// @brief TSIG Key to use to verify requests and sign responses. If it is
+    /// NULL TSIG is not used.
     D2TsigKeyPtr tsig_key_;
 
     /// @brief Constructor
@@ -137,10 +146,10 @@ public:
     asiolink::IntervalTimer timer_;
     int run_time_;
 
-    // Constructor
+    /// @brief Constructor
     TimedIO();
 
-    // Destructor
+    /// @brief Destructor
     virtual ~TimedIO();
 
     /// @brief IO Timer expiration handler
@@ -177,7 +186,7 @@ public:
     DdnsDomainPtr reverse_domain_;
     D2CfgMgrPtr cfg_mgr_;
 
-    /// #brief constants used to specify change directions for a transaction.
+    /// @brief constants used to specify change directions for a transaction.
     static const unsigned int FORWARD_CHG;      // Only forward change.
     static const unsigned int REVERSE_CHG;      // Only reverse change.
     static const unsigned int FWD_AND_REV_CHG;  // Both forward and reverse.
@@ -252,7 +261,6 @@ public:
     /// be used.
     void setupForIPv6Transaction(dhcp_ddns::NameChangeType change_type,
                                  int change_mask, const std::string& key_name);
-
 };
 
 
@@ -483,7 +491,6 @@ extern void checkContext(NameChangeTransactionPtr trans, const int exp_state,
 /// @brief Macro for calling checkContext() that supplies invocation location
 #define CHECK_CONTEXT(a,b,c) checkContext(a,b,c,__FILE__,__LINE__)
 
-
 } // namespace isc::d2
 } // namespace isc
 
similarity index 59%
rename from src/bin/d2/tests/stats_test_utils.cc
rename to src/lib/d2srv/testutils/stats_test_utils.cc
index 7c8f6df6e328a997fe59e9ab35337ce3f1249628..262879b421c3dd0af4c55dea2ce8dc2a2df8af6d 100644 (file)
@@ -6,7 +6,7 @@
 #include <config.h>
 
 #include <d2srv/d2_stats.h>
-#include <stats_test_utils.h>
+#include <d2srv/testutils/stats_test_utils.h>
 
 using namespace isc::data;
 using namespace isc::stats;
@@ -26,22 +26,7 @@ D2StatTest::~D2StatTest() {
 }
 
 void
-D2StatTest::checkStat(const string& name, const int64_t expected_value) {
-    ObservationPtr obs = StatsMgr::instance().getObservation(name);
-    ASSERT_TRUE(obs) << " stat: " << name << " not found ";
-    ASSERT_EQ(expected_value, obs->getInteger().first)
-        << " stat: " << name << " value wrong";
-}
-
-void
-D2StatTest::checkStats(const StatMap& expected_stats) {
-    for (const auto& it : expected_stats) {
-        checkStat(it.first, it.second);
-    }
-}
-
-void
-D2StatTest::checkStats(const string& key_name, const StatMap& expected_stats) {
+checkStats(const string& key_name, const StatMap& expected_stats) {
     StatMap key_stats;
     for (const auto& it : expected_stats) {
         const string& stat_name =
diff --git a/src/lib/d2srv/testutils/stats_test_utils.h b/src/lib/d2srv/testutils/stats_test_utils.h
new file mode 100644 (file)
index 0000000..ccdad02
--- /dev/null
@@ -0,0 +1,48 @@
+// Copyright (C) 2020-2021 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef D2_STATS_TEST_UTILS_H
+#define D2_STATS_TEST_UTILS_H
+
+#include <cc/data.h>
+#include <d2srv/d2_stats.h>
+#include <d2srv/d2_tsig_key.h>
+#include <stats/testutils/stats_test_utils.h>
+
+#include <gtest/gtest.h>
+
+namespace isc {
+namespace d2 {
+namespace test {
+
+/// @brief Import statistic test utils.
+using isc::stats::test::StatMap;
+using isc::stats::test::checkStat;
+using isc::stats::test::checkStats;
+
+/// @brief Test class with utility functions to test statistics.
+class D2StatTest {
+public:
+    /// @brief Constructor.
+    D2StatTest();
+
+    /// @brief Destructor.
+    virtual ~D2StatTest();
+};
+
+/// @brief Compares StatsMgr key statistics against expected values.
+///
+/// Prepend key part of names before calling checkStats simpler variant.
+///
+/// @param key_name Name of the key.
+/// @param expected_stats Map of expected static names and values.
+void checkStats(const std::string& key_name, const StatMap& expected_stats);
+
+}
+}
+}
+
+#endif // D2_STATS_TEST_UTILS_H
index fc46f5b651b8dacde2c5136e1b77ae3ff24d5943..43629d18188ca274ff5703b8eaaee032236e5032 100644 (file)
@@ -163,12 +163,12 @@ NameChangeUDPListener::receiveCompletionHandler(const bool successful,
         try {
             ncr = NameChangeRequest::fromFormat(format_, input_buffer);
             isc::stats::StatsMgr::instance().addValue("ncr-received",
-                                                      static_cast<int64_t>(0));
+                                                      static_cast<int64_t>(1));
         } catch (const NcrMessageError& ex) {
             // log it and go back to listening
             LOG_ERROR(dhcp_ddns_logger, DHCP_DDNS_INVALID_NCR).arg(ex.what());
             isc::stats::StatsMgr::instance().addValue("ncr-invalid",
-                                                      static_cast<int64_t>(0));
+                                                      static_cast<int64_t>(1));
 
             // Queue up the next receive.
             // NOTE: We must call the base class, NEVER doReceive
@@ -187,7 +187,7 @@ NameChangeUDPListener::receiveCompletionHandler(const bool successful,
             LOG_ERROR(dhcp_ddns_logger, DHCP_DDNS_NCR_UDP_RECV_ERROR)
                       .arg(error_code.message());
             isc::stats::StatsMgr::instance().addValue("ncr-error",
-                                                      static_cast<int64_t>(0));
+                                                      static_cast<int64_t>(1));
             result = ERROR;
         }
     }
index aa7568a7695c4415ec713f473871ad64d3dcee61..37f3e41f15cc5fb0cda57e9777901e557df07da4 100644 (file)
@@ -1,4 +1,4 @@
-SUBDIRS = . tests
+SUBDIRS = . tests testutils
 
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS += $(BOOST_INCLUDES)
diff --git a/src/lib/stats/testutils/Makefile.am b/src/lib/stats/testutils/Makefile.am
new file mode 100644 (file)
index 0000000..009257f
--- /dev/null
@@ -0,0 +1 @@
+EXTRA_DIST = stats_test_utils.h
diff --git a/src/lib/stats/testutils/stats_test_utils.h b/src/lib/stats/testutils/stats_test_utils.h
new file mode 100644 (file)
index 0000000..808dced
--- /dev/null
@@ -0,0 +1,64 @@
+// Copyright (C) 2020-2021 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef STATS_TEST_UTILS_H
+#define STATS_TEST_UTILS_H
+
+#include <cc/data.h>
+#include <stats/stats_mgr.h>
+
+#include <gtest/gtest.h>
+
+namespace isc {
+namespace stats {
+namespace test {
+
+/// @brief Type of name x value for statistics.
+typedef std::map<std::string, int64_t> StatMap;
+
+/// @brief Compares a statistic to an expected value.
+///
+/// Attempt to fetch the named statistic from the StatsMgr and if
+/// found, compare its observed value to the given value.
+/// Fails if the stat is not found or if the values do not match.
+///
+/// @param name StatsMgr name for the statistic to check.
+/// @param expected_value expected value of the statistic.
+inline void checkStat(const std::string& name, const int64_t expected_value) {
+    using namespace isc::stats;
+    ObservationPtr obs = StatsMgr::instance().getObservation(name);
+    ASSERT_TRUE(obs) << " stat: " << name << " not found ";
+    ASSERT_EQ(expected_value, obs->getInteger().first)
+        << " stat: " << name << " value wrong";
+}
+
+/// @brief Check if a statistic does not exists.
+///
+/// @param name StatsMgr name for the statistic to check.
+inline void checkNoStat(const std::string& name) {
+    using namespace isc::stats;
+    EXPECT_FALSE(StatsMgr::instance().getObservation(name));
+}
+
+/// @brief Compares StatsMgr statistics against expected values.
+///
+/// Iterates over a list of statistic names and expected values, attempting
+/// to fetch each from the StatsMgr and if found, compare its observed
+/// value to the expected value. Fails if any of the expected stats are not
+/// found or if the values do not match.
+///
+/// @param expected_stats Map of expected static names and values.
+inline void checkStats(const StatMap& expected_stats) {
+    for (const auto& it : expected_stats) {
+        checkStat(it.first, it.second);
+    }
+}
+
+}
+}
+}
+
+#endif // STATS_TEST_UTILS_H