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])
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])
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
},
{ // 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":
// 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
.. 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
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
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
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
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:
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
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:
...
directory "/var/cache/bind";
dnssec-validation auto;
+ listen-on-v6 { any; };
tkey-gssapi-keytab "/etc/bind/dns.keytab";
};
zone "example.org" {
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
.. code-block:: javascript
:linenos:
- :emphasize-lines: 57-97
+ :emphasize-lines: 57-107
+
{
"DhcpDdns": {
},
{ // 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
}
]
}
// 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
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
``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
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).
- ``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.
- ``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:
"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.
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
#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>
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
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
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
-// 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
/// @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 {
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
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
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
-// 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 nc_remove.h This file defines the class NameRemoveTransaction.
-#include <d2/nc_trans.h>
+#include <d2srv/nc_trans.h>
namespace isc {
namespace d2 {
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
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
-// 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
/// @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 {
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
}
}
-
void
SimpleRemoveTransaction::selectingRevServerHandler() {
switch(getNextEvent()) {
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
-// 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
/// @file nc_remove.h This file defines the class SimpleRemoveTransaction.
-#include <d2/nc_trans.h>
+#include <d2srv/nc_trans.h>
namespace isc {
namespace d2 {
# 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)
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
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)
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
# 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)
#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>
#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>
-// 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
#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>
using namespace isc;
using namespace isc::dhcp_ddns;
using namespace isc::d2;
+using namespace isc::d2::test;
namespace {
/// @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_;
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++) {
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());
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));
#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>
// 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;
}
}
}
#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>
// 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);
// 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);
// 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);
// 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);
// 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);
#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>
// 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);
// 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);
// 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);
// 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);
// 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);
#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>
// 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);
// 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);
// 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);
// 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);
#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>
// 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);
// 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);
// 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);
// 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);
+++ /dev/null
-// 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
};
+/// \brief Defines a pointer to an IOFetch.
+typedef boost::shared_ptr<IOFetch> IOFetchPtr;
+
} // namespace asiodns
} // namespace isc
-SUBDIRS = . tests
+SUBDIRS = . testutils tests
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
AM_CPPFLAGS += $(BOOST_INCLUDES)
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)
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
-// 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
#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>
-// 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
#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>
-// 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
#include <config.h>
-#include <d2/d2_zone.h>
+#include <d2srv/d2_zone.h>
namespace isc {
namespace d2 {
-// 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
// 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>
// 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,
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);
};
}
DNSClient::~DNSClient() {
- delete (impl_);
}
unsigned int
#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 {
const D2TsigKeyPtr& tsig_key = D2TsigKeyPtr());
private:
- DNSClientImpl* impl_; ///< Pointer to DNSClient implementation.
+ /// @brief Pointer to DNSClient implementation.
+ std::unique_ptr<DNSClientImpl> impl_;
};
} // namespace d2
#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>
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;
/// @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>
/// @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.
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
#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>
-// 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>
#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>
// 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));
}
/// @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();
}
}
/// @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
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,
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));
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;
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;
// 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.
}
- // 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.
// 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
// 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
// "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
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.
// 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
// 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
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
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
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
// 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
#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>
// 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
using NameChangeTransaction::setNcrStatus;
using NameChangeTransaction::setDnsUpdateRequest;
using NameChangeTransaction::clearDnsUpdateRequest;
+ using NameChangeTransaction::clearUpdateAttempts;
using NameChangeTransaction::setDnsUpdateStatus;
using NameChangeTransaction::getDnsUpdateResponse;
using NameChangeTransaction::setDnsUpdateResponse;
// 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();
// 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
--- /dev/null
+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
#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>
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());
(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()) {
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;
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()) {
}
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);
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);
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);
ASSERT_NO_THROW(request->toWire(renderer));
}
-void checkRemoveFwdAddressRequest(NameChangeTransaction& tran) {
+void
+checkRemoveFwdAddressRequest(NameChangeTransaction& tran) {
const D2UpdateMessagePtr& request = tran.getDnsUpdateRequest();
ASSERT_TRUE(request);
ASSERT_NO_THROW(request->toWire(renderer));
}
-void checkRemoveFwdRRsRequest(NameChangeTransaction& tran) {
+void
+checkRemoveFwdRRsRequest(NameChangeTransaction& tran) {
const D2UpdateMessagePtr& request = tran.getDnsUpdateRequest();
ASSERT_TRUE(request);
ASSERT_NO_THROW(request->toWire(renderer));
}
-void checkRemoveRevPtrsRequest(NameChangeTransaction& tran) {
+void
+checkRemoveRevPtrsRequest(NameChangeTransaction& tran) {
const D2UpdateMessagePtr& request = tran.getDnsUpdateRequest();
ASSERT_TRUE(request);
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) {
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);
ASSERT_NO_THROW(request->toWire(renderer));
}
-void checkSimpleRemoveFwdRRsRequest(NameChangeTransaction& tran) {
+void
+checkSimpleRemoveFwdRRsRequest(NameChangeTransaction& tran) {
const D2UpdateMessagePtr& request = tran.getDnsUpdateRequest();
ASSERT_TRUE(request);
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);
}
// 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)
#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>
/// 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
asiolink::IntervalTimer timer_;
int run_time_;
- // Constructor
+ /// @brief Constructor
TimedIO();
- // Destructor
+ /// @brief Destructor
virtual ~TimedIO();
/// @brief IO Timer expiration handler
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.
/// be used.
void setupForIPv6Transaction(dhcp_ddns::NameChangeType change_type,
int change_mask, const std::string& key_name);
-
};
/// @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
#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;
}
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 =
--- /dev/null
+// 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
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
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;
}
}
-SUBDIRS = . tests
+SUBDIRS = . tests testutils
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
AM_CPPFLAGS += $(BOOST_INCLUDES)
--- /dev/null
+EXTRA_DIST = stats_test_utils.h
--- /dev/null
+// 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