diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 14:53:22 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 14:53:22 +0000 |
commit | 52c021ee0b0c6ad2128ed550c694aad0d11d4c3f (patch) | |
tree | 83cf8627b94336cf4bee7479b9749263bbfd3a06 /doc/sphinx/arm | |
parent | Initial commit. (diff) | |
download | isc-kea-52c021ee0b0c6ad2128ed550c694aad0d11d4c3f.tar.xz isc-kea-52c021ee0b0c6ad2128ed550c694aad0d11d4c3f.zip |
Adding upstream version 2.5.7.upstream/2.5.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'doc/sphinx/arm')
55 files changed, 43997 insertions, 0 deletions
diff --git a/doc/sphinx/arm/acknowledgments.rst b/doc/sphinx/arm/acknowledgments.rst new file mode 100644 index 0000000..0df58dd --- /dev/null +++ b/doc/sphinx/arm/acknowledgments.rst @@ -0,0 +1,29 @@ +Acknowledgments +=============== + +Kea is an open source project designed, developed, and maintained by +Internet Systems Consortium, Inc, a 501(c)3 non-profit organization. ISC +is primarily funded by revenues from support subscriptions for our open +source, and we encourage all professional users to consider this option. +To learn more, see \ https://www.isc.org/support/. + +We thank all the organizations and individuals who have helped to make +Kea possible. `Comcast <https://www.comcast.com/>`__ and the Comcast +Innovation Fund provided major support for the development of Kea's +DHCPv4, DHCPv6, and DDNS modules. Mozilla funded initial work on the +RESTful API via a MOSS award. + +Kea was initially implemented as a collection of applications within the +BIND 10 framework. We thank the founding sponsors of the BIND 10 +project: `Afilias <https://www.afilias.info/>`__, +`IIS.SE <https://www.iis.se/>`__, +`Nominet <https://www.nominet.uk/>`__, +`SIDN <https://www.sidn.nl/>`__, `JPRS <https://jprs.co.jp/>`__, +and `CIRA <https://cira.ca/>`__; and additional sponsors +`AFNIC <https://www.afnic.fr/>`__, +`CNNIC <https://www.cnnic.net.cn/>`__, `CZ.NIC <https://www.nic.cz/>`__, +`DENIC eG <https://www.denic.de/>`__, +`Google <https://www.google.com/>`__, `RIPE +NCC <https://www.ripe.net/>`__, `Registro.br <https://registro.br/>`__, +`.nz Registry Services <https://nzrs.net.nz/>`__, and `Technical Center +of Internet <https://www.tcinet.ru/>`__. diff --git a/doc/sphinx/arm/admin.rst b/doc/sphinx/arm/admin.rst new file mode 100644 index 0000000..aac1b81 --- /dev/null +++ b/doc/sphinx/arm/admin.rst @@ -0,0 +1,678 @@ +.. _admin: + +*************************** +Kea Database Administration +*************************** + +.. _kea-database-version: + +Databases and Schema Versions +============================= + +Kea may be configured to use a database as storage for leases or as a +source of servers' configurations and host reservations (i.e. static +assignments of addresses, prefixes, options, etc.). As Kea is +updated, new database schemas are introduced to facilitate new +features and correct discovered issues with the existing schemas. + +Each version of Kea expects a particular schema structure and checks for this by +examining the version of the database it is using. Separate version numbers are +maintained for the schemas, independent of the version of Kea itself. It is +possible that the schema version will stay the same through several Kea +revisions; similarly, it is possible that the version of the schema may go up +several revisions during a single Kea version upgrade. Versions for each backend +type are also independent, so an increment in the MySQL backend version does not +imply an increment in that of PostgreSQL. + +Schema versions are specified in a major.minor format. For the most recent +versions, the minor version is always zero and only the major version is +incremented. + +Historically, the minor version used to be incremented when backward-compatible +changes were introduced to the schema: for example - when a new index is added. +This was opposed to incrementing the major version which implied an incompatible +schema change: for example - changing the type of an existing column. If Kea +attempts to run on a schema that is too old, as indicated by a mismatched schema +version, it will fail; administrative action is required to upgrade the schema. + +.. _kea-admin: + +The :iscman:`kea-admin` Tool +============================ + +To manage the databases, Kea provides the :iscman:`kea-admin` tool. It can +initialize a new backend, check its version number, perform a backend +upgrade, and dump lease data to a text file. + +:iscman:`kea-admin` takes two mandatory parameters: ``command`` and +``backend``. Additional, non-mandatory options may be specified. The +currently supported commands are: + +- ``db-init`` — initializes a new database schema. This is useful + during a new Kea installation. The database is initialized to the + latest version supported by the version of the software being installed. + Called automatically on startup or reconfiguration of Kea DHCP servers if + required. + +- ``db-version`` — reports the database backend version number. This + is not necessarily equal to the Kea version number, as each backend + has its own versioning scheme. + +- ``db-upgrade`` — conducts a database schema upgrade. This is + useful when upgrading Kea. + +- ``lease-dump`` — dumps the contents of the lease database (for MySQL or + PostgreSQL backends) to a CSV (comma-separated values) text file. + + The first line of the file contains the column names. This can be used + as a way to switch from a database backend to a memfile backend. + Alternatively, it can be used as a diagnostic tool, so it provides a portable + form of the lease data. + +- ``lease-upload`` — uploads leases from a CSV (comma-separated values) text + file to a MySQL or a PostgreSQL lease database. The CSV file needs to be in + memfile format. + +``backend`` specifies the type of backend database. The currently +supported types are: + +- ``memfile`` — lease information is stored on disk in a text file. + +- ``mysql`` — information is stored in a MySQL relational database. + +- ``pgsql`` — information is stored in a PostgreSQL relational + database. + +Additional parameters may be needed, depending on the setup and +specific operation: username, password, and database name or the +directory where specific files are located. See the appropriate manual +page for details (``man 8 kea-admin``). + +.. _supported-databases: + +Supported Backends +================== + +The following table presents the capabilities of available backends. +Please refer to the specific sections dedicated to each backend to +better understand their capabilities and limitations. Choosing the right +backend is essential for the success of the deployment. + +.. table:: List of available backends + + +---------------+----------------+----------------+---------------+ + | Feature | Memfile | MySQL | PostgreSQL | + | | | | | + +===============+================+================+===============+ + | Status | Stable | Stable | Stable | + | | | | | + +---------------+----------------+----------------+---------------+ + | Data format | CSV file | SQL RMDB | SQL RMDB | + | | | | | + | | | | | + +---------------+----------------+----------------+---------------+ + | Leases | yes | yes | yes | + +---------------+----------------+----------------+---------------+ + | Host | no | yes | yes | + | reservations | | | | + | | | | | + +---------------+----------------+----------------+---------------+ + | Options | no | yes | yes | + | defined on | | | | + | per host | | | | + | basis | | | | + +---------------+----------------+----------------+---------------+ + | Configuration | no | yes | yes | + | backend | | | | + | | | | | + +---------------+----------------+----------------+---------------+ + +Memfile +------- + +The memfile backend is able to store lease information, but cannot +store host reservation details; these must be stored in the +configuration file. (There are no plans to add a host reservations +storage capability to this backend.) + +No special initialization steps are necessary for the memfile backend. +During the first run, both :iscman:`kea-dhcp4` and :iscman:`kea-dhcp6` create +an empty lease file if one is not present. Necessary disk-write +permission is required. + +.. _memfile-upgrade: + +Upgrading Memfile Lease Files From an Earlier Version of Kea +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +There are no special steps required to upgrade memfile lease files +between versions of Kea. During startup, the +servers check the schema version of the lease files against their +own. If there is a mismatch, the servers automatically launch the +LFC process to convert the files to the server's schema version. While +this mechanism is primarily meant to ease the process of upgrading to +newer versions of Kea, it can also be used for downgrading should the +need arise. When upgrading, any values not present in the original lease +files are assigned appropriate default values. When downgrading, any +data present in the files but not in the server's schema are +dropped. To convert the files manually prior to starting the +servers, run the lease file cleanup (LFC) process. See :ref:`kea-lfc` for more information. + +.. _mysql-database: + +MySQL +----- + +MySQL is able to store leases, host reservations, options defined on a +per-host basis, and a subset of the server configuration parameters +(serving as a configuration backend). + +.. _mysql-database-engine: + +MySQL 5.7 vs MySQL 8 vs MariaDB 10 and 11 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In our Kea performance testing, MySQL 8 shows a 60-90% drop in speed +in comparison with MySQL 5.7. +Due to the upcoming MySQL 5.7 EOL, we recommend using MariaDB instead of MySQL 8. + +MySQL 5.7, MySQL 8, MariaDB 10, and MariaDB 11 are fully compatible, +interchangeable, and tested with Kea. + +.. _mysql-database-create: + +First-Time Creation of the MySQL Database +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Before preparing any Kea-specific database and tables, the MySQL database +must be configured to use the system timezone. It is recommended to use UTC +as the timezone for both the system and the MySQL database. + +To check the system timezone: + + .. code-block:: console + + date +%Z + +To check the MySQL timezone: + + .. code-block:: mysql + + mysql> SELECT @@system_time_zone; + mysql> SELECT @@global.time_zone; + mysql> SELECT @@session.time_zone; + +To configure the MySQL timezone for a specific server, please refer to the +installed version documentation. + +Usually the setting is configured in the [mysqld] section in ``/etc/mysql/my.cnf``, +``/etc/mysql/mysql.cnf``, ``/etc/mysql/mysqld.cnf``, or +``/etc/mysql/mysql.conf.d/mysqld.cnf``. + + .. code-block:: ini + + [mysqld] + # using default-time-zone + default-time-zone='+00:00' + + # or using timezone + timezone='UTC' + +When setting up the MySQL database for the first time, the +database area must be created within MySQL, and the MySQL user ID under +which Kea will access the database must be set up. This needs to be done manually, +rather than via :iscman:`kea-admin`. + +To create the database: + +1. Log into MySQL as "root": + + .. code-block:: console + + $ mysql -u root -p + Enter password: + mysql> + +2. Create the MySQL database: + + .. code-block:: mysql + + mysql> CREATE DATABASE database_name; + + (``database_name`` is the name chosen for the database.) + +3. Create the user under which Kea will access the database (and give it + a password), then grant it access to the database tables: + + .. code-block:: mysql + + mysql> CREATE USER 'user-name'@'localhost' IDENTIFIED BY 'password'; + mysql> GRANT ALL ON database-name.* TO 'user-name'@'localhost'; + + (``user-name`` and ``password`` are the user ID and password used to + allow Kea access to the MySQL instance. All apostrophes in the + command lines above are required.) + +4. Create the database. + + Exit the MySQL client + + .. code-block:: mysql + + mysql> quit + Bye + + Then use the :iscman:`kea-admin` tool to create the database. + + .. code-block:: console + + $ kea-admin db-init mysql -u database-user -p database-password -n database-name + + While it is possible to create the database from within the MySQL client, we recommend + using the :iscman:`kea-admin` tool as it performs some necessary validations to ensure Kea can + access the database at runtime. Among those checks is verification that the schema does not contain + any pre-existing tables; any pre-existing tables must be removed + manually. An additional check examines the user's ability to create functions and + triggers. The following error indicates that the user does not have the necessary + permissions to create functions or triggers: + + .. code-block:: console + + ERROR 1419 (HY000) at line 1: You do not have the SUPER privilege and binary logging is + enabled (you *might* want to use the less safe log_bin_trust_function_creators variable) + ERROR/kea-admin: mysql_can_create cannot trigger, check user permissions, mysql status = 1 + mysql: [Warning] Using a password on the command line interface can be insecure. + ERROR/kea-admin: Create failed, the user, keatest, has insufficient privileges. + + The simplest way around this is to set the global MySQL variable, + ``log_bin_trust_function_creators``, to 1 via the MySQL client. + Note this must be done as a user with SUPER privileges: + + .. code-block:: mysql + + mysql> set @@global.log_bin_trust_function_creators = 1; + Query OK, 0 rows affected (0.00 sec) + + To create the database with MySQL directly, follow these steps: + + .. code-block:: mysql + + mysql> CONNECT database-name; + mysql> SOURCE path-to-kea/share/kea/scripts/mysql/dhcpdb_create.mysql + + (where ``path-to-kea`` is the location where Kea is installed.) + + The database may also be dropped manually as follows: + + .. code-block:: mysql + + mysql> CONNECT database-name; + mysql> SOURCE path-to-kea/share/kea/scripts/mysql/dhcpdb_drop.mysql + + (where ``path-to-kea`` is the location where Kea is installed.) + +.. warning:: + + Dropping the database results in the unrecoverable loss of any data it contains. + + +5. Exit MySQL: + + .. code-block:: mysql + + mysql> quit + Bye + +If the tables were not created in Step 4, run the :iscman:`kea-admin` tool +to create them now: + +.. code-block:: console + + $ kea-admin db-init mysql -u database-user -p database-password -n database-name + +Do not do this if the tables were created in Step 4. :iscman:`kea-admin` +implements rudimentary checks; it will refuse to initialize a database +that contains any existing tables. To start from scratch, +all data must be removed manually. (This process is a manual operation +on purpose, to avoid accidentally irretrievable mistakes by :iscman:`kea-admin`.) + +.. _mysql-upgrade: + +Upgrading a MySQL Database From an Earlier Version of Kea +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Sometimes a new Kea version uses a newer database schema, so the +existing database needs to be upgraded. This can be done using the +``kea-admin db-upgrade`` command. + +To check the current version of the database, use the following command: + +.. code-block:: console + + $ kea-admin db-version mysql -u database-user -p database-password -n database-name + +(See :ref:`kea-database-version` +for a discussion about versioning.) If the version does not match the +minimum required for the new version of Kea (as described in the release +notes), the database needs to be upgraded. + +Before upgrading, please make sure that the database is backed up. The +upgrade process does not discard any data, but depending on the nature +of the changes, it may be impossible to subsequently downgrade to an +earlier version. + +To perform an upgrade, issue the following command: + +.. code-block:: console + + $ kea-admin db-upgrade mysql -u database-user -p database-password -n database-name + +.. note:: + + To search host reservations by hostname, it is critical that the collation of + the hostname column in the host table be case-insensitive. Fortunately, that + is the default in MySQL, but it can be verified via this command: + + .. code-block:: mysql + + mysql> SELECT COLLATION(''); + +-----------------+ + | COLLATION('') | + +-----------------+ + | utf8_general_ci | + +-----------------+ + + According to mysql's naming convention, when the name ends in ``_ci``, + the collation is case-insensitive. + +.. _mysql-performance: + +Improved Performance With MySQL +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Changing the MySQL internal value ``innodb_flush_log_at_trx_commit`` from the default value +of 1 to 2 can result in a huge gain in Kea performance. In some deployments, the +gain was over 1000% (10 times faster when set to 2, compared to the default value of 1). +It can be set per-session for testing: + +.. code-block:: mysql + + mysql> SET GLOBAL innodb_flush_log_at_trx_commit=2; + mysql> SHOW SESSION VARIABLES LIKE 'innodb_flush_log%'; + +or permanently in ``/etc/mysql/my.cnf``: + +.. code-block:: ini + + [mysqld] + innodb_flush_log_at_trx_commit=2 + +Be aware that changing this value can cause problems during data recovery +after a crash, so we recommend checking the `MySQL documentation +<https://dev.mysql.com/doc/refman/8.0/en/innodb-parameters.html#sysvar_innodb_flush_log_at_trx_commit>`__. +With the default value of 1, MySQL writes changes to disk after every INSERT or UPDATE query +(in Kea terms, every time a client gets a new lease or renews an existing lease). When +``innodb_flush_log_at_trx_commit`` is set to 2, MySQL writes the changes at intervals +no longer than 1 second. Batching writes gives a substantial performance boost. The trade-off, +however, is that in the worst-case scenario, all changes in the last second before crash +could be lost. Given the fact that Kea is stable software and crashes very rarely, +most deployments find it a beneficial trade-off. + +.. _pgsql-database: + +PostgreSQL +---------- + +PostgreSQL can store leases, host reservations, and options +defined on a per-host basis. + +.. _pgsql-database-create: + +First-Time Creation of the PostgreSQL Database +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Before preparing any Kea-specific database and tables, the PostgreSQL database +must be configured to use the system timezone. It is recommended to use UTC +as the timezone for both the system and the PostgreSQL database. + +To check the system timezone: + + .. code-block:: console + + date +%Z + +To check the PostgreSQL timezone: + + .. code-block:: psql + + postgres=# show timezone; + postgres=# SELECT * FROM pg_timezone_names WHERE name = current_setting('TIMEZONE'); + +To configure the PostgreSQL timezone for a specific server, please refer to the +installed version documentation. + +Usually the setting is configured in the ``postgresql.conf`` with the varying +version path ``/etc/postgresql/<version>/main/postgresql.conf``, but on some systems +the files may be located in ``/var/lib/pgsql/data``. + + .. code-block:: ini + + timezone = 'UTC' + +The first task is to create both the database and the user under +which the servers will access it. A number of steps are required: + +1. Log into PostgreSQL as "root": + + .. code-block:: console + + $ sudo -u postgres psql postgres + Enter password: + postgres=# + +2. Create the database: + + .. code-block:: psql + + postgres=# CREATE DATABASE database-name; + CREATE DATABASE + postgres=# + + (``database-name`` is the name chosen for the database.) + +3. Create the user under which Kea will access the database (and give it + a password), then grant it access to the database: + + .. code-block:: psql + + postgres=# CREATE USER user-name WITH PASSWORD 'password'; + CREATE ROLE + postgres=# GRANT ALL PRIVILEGES ON DATABASE database-name TO user-name; + GRANT + postgres=# + +4. Exit PostgreSQL: + + .. code-block:: psql + + postgres=# \q + Bye + $ + +5. At this point, create the database tables either + using the :iscman:`kea-admin` tool, as explained in the next section + (recommended), or manually. To create the tables manually, enter the + following command. PostgreSQL will prompt the administrator to enter the + new user's password that was specified in Step 3. When the command + completes, Kea will return to the shell prompt. The + output should be similar to the following: + + .. code-block:: console + + $ psql -d database-name -U user-name -f path-to-kea/share/kea/scripts/pgsql/dhcpdb_create.pgsql + Password for user user-name: + CREATE TABLE + CREATE INDEX + CREATE INDEX + CREATE TABLE + CREATE INDEX + CREATE TABLE + START TRANSACTION + INSERT 0 1 + INSERT 0 1 + INSERT 0 1 + COMMIT + CREATE TABLE + START TRANSACTION + INSERT 0 1 + COMMIT + $ + + (``path-to-kea`` is the location where Kea is installed.) + + If instead an error is encountered, such as: + + :: + + psql: FATAL: no pg_hba.conf entry for host "[local]", user "user-name", database "database-name", SSL off + + ... the PostgreSQL configuration will need to be altered. Kea uses + password authentication when connecting to the database and must have + the appropriate entries added to PostgreSQL's pg_hba.conf file. This + file is normally located in the primary data directory for the + PostgreSQL server. The precise path may vary depending on the + operating system and version, but the default location for PostgreSQL is + ``/etc/postgresql/*/main/postgresql.conf``. However, on some systems, the + file may reside in ``/var/lib/pgsql/data``. + + Assuming Kea is running on the same host as PostgreSQL, adding lines + similar to the following should be sufficient to provide + password-authenticated access to Kea's database: + + :: + + local database-name user-name password + host database-name user-name 127.0.0.1/32 password + host database-name user-name ::1/128 password + + These edits are primarily intended as a starting point, and are not a + definitive reference on PostgreSQL administration or database + security. Please consult the PostgreSQL user manual before making + these changes, as they may expose other databases that are running. It + may be necessary to restart PostgreSQL for the changes to + take effect. + +Initialize the PostgreSQL Database Using :iscman:`kea-admin` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If the tables were not created manually, do so now by +running the :iscman:`kea-admin` tool: + +.. code-block:: console + + $ kea-admin db-init pgsql -u database-user -p database-password -n database-name + +Do not do this if the tables were already created manually. :iscman:`kea-admin` +implements rudimentary checks; it will refuse to initialize a database +that contains any existing tables. To start from scratch, +all data must be removed manually. (This process is a manual operation +on purpose, to avoid accidentally irretrievable mistakes by :iscman:`kea-admin`.) + +.. _pgsql-upgrade: + +Upgrading a PostgreSQL Database From an Earlier Version of Kea +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The PostgreSQL database schema can be upgraded using the same tool and +commands as described in :ref:`mysql-upgrade`, with the exception that the "pgsql" +database backend type must be used in the commands. + +Use the following command to check the current schema version: + +.. code-block:: console + + $ kea-admin db-version pgsql -u database-user -p database-password -n database-name + +Use the following command to perform an upgrade: + +.. code-block:: console + + $ kea-admin db-upgrade pgsql -u database-user -p database-password -n database-name + +.. _pgsl-ssl: + +PostgreSQL without OpenSSL support +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Usually the PostgreSQL database client library is built with the OpenSSL +support but Kea can be configured to handle the case where it is not +supported: + +.. code-block:: console + + $ ./configure [other-options] --disable-pgsql-ssl + +.. _pgsql-performance: + +Improved Performance With PostgreSQL +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Changing the PostgreSQL internal value ``synchronous_commit`` from the default value +of ON to OFF can result in significant gains in Kea performance; on slow systems, the gain +can be over 1000%. It can be set per-session for testing: + +.. code-block:: psql + + postgres=# SET synchronous_commit = OFF; + +or permanently via command (preferred method): + +.. code-block:: psql + + postgres=# ALTER SYSTEM SET synchronous_commit=OFF; + +or permanently in ``/etc/postgresql/[version]/main/postgresql.conf``: + +.. code-block:: ini + + synchronous_commit = off + +Changing this value can cause problems during data recovery +after a crash, so we recommend a careful read of the `PostgreSQL documentation +<https://www.postgresql.org/docs/current/wal-async-commit.html>`__. +With the default value of ON, PostgreSQL writes changes to disk after every INSERT or UPDATE query +(in Kea terms, every time a client gets a new lease or renews an existing lease). When +``synchronous_commit`` is set to OFF, PostgreSQL adds some delay before writing the changes. +Batching writes gives a substantial performance boost, +but in the worst-case scenario, all changes in the last moment before a crash +could be lost. Since Kea is stable software and crashes very rarely, +most deployments find the performance benefits outweigh the potential risks. + +Using Read-Only Databases With Host Reservations +------------------------------------------------ + +If a read-only database is used for storing host reservations, Kea must +be explicitly configured to operate on the database in read-only mode. +Sections :ref:`read-only-database-configuration4` and +:ref:`read-only-database-configuration6` describe when such +a configuration may be required, and how to configure Kea to operate in +this way for both DHCPv4 and DHCPv6. + +Limitations Related to the Use of SQL Databases +----------------------------------------------- + +Year 2038 Issue +~~~~~~~~~~~~~~~ + +The lease expiration time in Kea is stored in the SQL database for each lease +as a timestamp value. Kea developers have observed that the MySQL database +does not accept timestamps beyond 2147483647 seconds (the maximum signed +32-bit number) from the beginning of the UNIX epoch (00:00:00 on 1 +January 1970). Some versions of PostgreSQL do accept greater values, but +the value is altered when it is read back. For this reason, the lease +database backends put a restriction on the maximum timestamp to be +stored in the database, which is equal to the maximum signed 32-bit +number. This effectively means that the current Kea version cannot store +leases whose expiration time is later than 2147483647 seconds since the +beginning of the epoch (around the year 2038). This will be fixed when +database support for longer timestamps is available. diff --git a/doc/sphinx/arm/agent.rst b/doc/sphinx/arm/agent.rst new file mode 100644 index 0000000..328c03a --- /dev/null +++ b/doc/sphinx/arm/agent.rst @@ -0,0 +1,314 @@ +.. _kea-ctrl-agent: + +********************* +The Kea Control Agent +********************* + +.. _agent-overview: + +Overview of the Kea Control Agent +================================= + +The Kea Control Agent (CA) is a daemon which exposes a RESTful control +interface for managing Kea servers. The daemon can receive control +commands over HTTP and either forward these commands to the respective +Kea servers or handle these commands on its own. The determination +whether the command should be handled by the CA or forwarded is made by +checking the value of the ``service`` parameter, which may be included in +the command from the controlling client. The details of the supported +commands, as well as their structures, are provided in +:ref:`ctrl-channel`. + +The CA can use hook libraries to provide support for additional commands +or to program custom behavior of existing commands. Such hook libraries must +implement callouts for the ``control_command_receive`` hook point. Details +about creating new hook libraries and supported hook points can be found +in the `Kea Developer's +Guide <https://reports.kea.isc.org/dev_guide/>`__. + +The CA processes received commands according to the following algorithm: + +- Pass command into any installed hooks (regardless of service + value(s)). If the command is handled by a hook, return the response. + +- If the service specifies one or more services, forward the command to + the specified services and return the accumulated responses. + +- If the service is not specified or is an empty list, handle the + command if the CA supports it. + +.. _agent-configuration: + +Configuration +============= + +The following example demonstrates the basic CA configuration. + +.. code-block:: json + + { + "Control-agent": { + "http-host": "10.20.30.40", + "http-port": 8000, + "trust-anchor": "/path/to/the/ca-cert.pem", + "cert-file": "/path/to/the/agent-cert.pem", + "key-file": "/path/to/the/agent-key.pem", + "cert-required": true, + "authentication": { + "type": "basic", + "realm": "kea-control-agent", + "clients": [ + { + "user": "admin", + "password": "1234" + } ] + }, + + "control-sockets": { + "dhcp4": { + "comment": "main server", + "socket-type": "unix", + "socket-name": "/path/to/the/unix/socket-v4" + }, + "dhcp6": { + "socket-type": "unix", + "socket-name": "/path/to/the/unix/socket-v6", + "user-context": { "version": 3 } + }, + "d2": { + "socket-type": "unix", + "socket-name": "/path/to/the/unix/socket-d2" + } + }, + + "hooks-libraries": [ + { + "library": "/opt/local/custom_hooks_example.so", + "parameters": { + "param1": "foo" + } + } ], + + "loggers": [ { + "name": "kea-ctrl-agent", + "severity": "INFO" + } ] + } + } + +The ``http-host`` and ``http-port`` parameters specify an IP address and +port to which HTTP service will be bound. In the example configuration +provided above, the RESTful service will be available at the URL +``https://10.20.30.40:8000/``. If these parameters are not specified, the +default URL is ``http://127.0.0.1:8000/``. + +When using Kea's HA hook library with multi-threading, +the address:port combination used for CA must be +different from the HA peer URLs, which are strictly +for internal HA traffic between the peers. User commands should +still be sent via the CA. + +The ``trust-anchor``, ``cert-file``, ``key-file``, and ``cert-required`` +parameters specify the TLS setup for HTTP, i.e. HTTPS. If these parameters +are not specified, HTTP is used. The TLS/HTTPS support in Kea is +described in :ref:`tls`. + +As mentioned in :ref:`agent-overview`, the CA can forward +received commands to the Kea servers for processing. For example, +:isccmd:`config-get` is sent to retrieve the configuration of one of the Kea +services. When the CA receives this command, including a ``service`` +parameter indicating that the client wishes to retrieve the +configuration of the DHCPv4 server, the CA forwards the command to that +server and passes the received response back to the client. More about +the ``service`` parameter and the general structure of commands can be +found in :ref:`ctrl-channel`. + +The CA uses UNIX domain sockets to forward control commands and receive +responses from other Kea services. The ``dhcp4``, ``dhcp6``, and ``d2`` +maps specify the files to which UNIX domain sockets are bound. In the +configuration above, the CA connects to the DHCPv4 server via +``/path/to/the/unix/socket-v4`` to forward the commands to it. +Obviously, the DHCPv4 server must be configured to listen to connections +via this same socket. In other words, the command-socket configuration +for the DHCPv4 server and the CA (for that server) must match. Consult +:ref:`dhcp4-ctrl-channel`, :ref:`dhcp6-ctrl-channel`, and +:ref:`d2-ctrl-channel` to learn how the socket configuration is +specified for the DHCPv4, DHCPv6, and D2 services. + +User contexts can store arbitrary data as long as they are in valid JSON +syntax and their top-level element is a map (i.e. the data must be +enclosed in curly brackets). Some hook libraries may expect specific +formatting; please consult the relevant hook library documentation for +details. + +User contexts can be specified on either global scope, control socket, +basic authentication, or loggers. One other useful feature is the +ability to store comments or descriptions; the parser translates a +"comment" entry into a user context with the entry, which allows a +comment to be attached within the configuration itself. + +Basic HTTP authentication protects +against unauthorized uses of the control agent by local users. For +protection against remote attackers, HTTPS and reverse proxy of +:ref:`agent-secure-connection` provide stronger security. + +The authentication is described in the ``authentication`` block +with the mandatory ``type`` parameter, which selects the authentication. +Currently only the basic HTTP authentication (type basic) is supported. + +The ``realm`` authentication parameter is used for error messages when +the basic HTTP authentication is required but the client is not +authorized. + +When the ``clients`` authentication list is configured and not empty, +basic HTTP authentication is required. Each element of the list +specifies a user ID and a password. The user ID is mandatory, must +be not empty, and must not contain the colon (:) character. The +password is optional; when it is not specified an empty password +is used. + +.. note:: + + The basic HTTP authentication user ID and password are encoded + in UTF-8, but the current Kea JSON syntax only supports the Latin-1 + (i.e. 0x00..0xff) Unicode subset. + +To avoid exposing the user ID and/or the associated +password, these values can be read from files. The syntax is extended by: + +- The ``directory`` authentication parameter, which handles the common + part of file paths. The default value is the empty string. + +- The ``password-file`` client parameter, which, alongside the ``directory`` + parameter, specifies the path of a file that can contain the password, + or when no user ID is given, the whole basic HTTP authentication secret. + +- The ``user-file`` client parameter, which, with the ``directory`` parameter, + specifies the path of a file where the user ID can be read. + +When files are used, they are read when the configuration is loaded, +to detect configuration errors as soon as possible. + +Hook libraries can be loaded by :iscman:`kea-ctrl-agent` in the same way as +they are loaded by :iscman:`kea-dhcp4` and :iscman:`kea-dhcp6`. The CA currently +supports one hook point - ``control_command_receive`` - which makes it +possible to delegate the processing of some commands to the hook library. +The ``hooks-libraries`` list contains the list of hook libraries that +should be loaded by :iscman:`kea-ctrl-agent`, along with their configuration information +specified with ``parameters``. + +Please consult :ref:`logging` for the details on how to configure +logging. The CA's root logger's name is :iscman:`kea-ctrl-agent`, as given in +the example above. + +.. _agent-secure-connection: + +Secure Connections +================== + +The Kea Control Agent natively supports secure +HTTP connections using TLS. This allows protection against users from +the node where the agent runs, something that a reverse proxy cannot +provide. More about TLS/HTTPS support in Kea can be found in :ref:`tls`. + +TLS is configured using three string parameters with file names, and +a boolean parameter: + +- The ``trust-anchor`` specifies the Certification Authority file name or + directory path. + +- The ``cert-file`` specifies the server certificate file name. + +- The ``key-file`` specifies the private key file name. The file must not + be encrypted. + +- The ``cert-required`` specifies whether client certificates are required + or optional. The default is to require them and to perform mutual + authentication. + +The file format is PEM. Either all the string parameters are specified and +HTTP over TLS (HTTPS) is used, or none is specified and plain HTTP is used. +Configuring only one or two string parameters results in an error. + +.. note:: + + When client certificates are not required, only the server side is + authenticated, i.e. the communication is encrypted with an unknown + client. This protects only against passive attacks; active + attacks, such as "man-in-the-middle," are still possible. + +.. note:: + + No standard HTTP authentication scheme cryptographically binds its end + entity with TLS. This means that the TLS client and server can be + mutually authenticated, but there is no proof they are the same as + for the HTTP authentication. + +The :iscman:`kea-shell` tool also supports TLS. + +.. _agent-launch: + +Starting and Stopping the Control Agent +======================================= + +:iscman:`kea-ctrl-agent` accepts the following command-line switches: + +- ``-c file`` - specifies the configuration file. + +- ``-d`` - specifies whether the agent logging should be switched to + debug/verbose mode. In verbose mode, the logging severity and + debuglevel specified in the configuration file are ignored and + "debug" severity and the maximum debuglevel (99) are assumed. The + flag is convenient for temporarily switching the server into maximum + verbosity, e.g. when debugging. + +- ``-t file`` - specifies the configuration file to be tested. + :iscman:`kea-netconf` attempts to load it and conducts sanity checks; + certain checks are possible only while running the actual server. The + actual status is reported with exit code (0 = configuration appears valid, + 1 = error encountered). Kea prints out log messages to standard + output and error to standard error when testing the configuration. + +- ``-v`` - displays the version of :iscman:`kea-ctrl-agent` and exits. + +- ``-V`` - displays the extended version information for :iscman:`kea-ctrl-agent` + and exits. The listing includes the versions of the libraries + dynamically linked to Kea. + +- ``-W`` - displays the Kea configuration report and exits. The report + is a copy of the ``config.report`` file produced by ``./configure``; + it is embedded in the executable binary. + + The contents of the ``config.report`` file may also be accessed by examining + certain libraries in the installation tree or in the source tree. + + .. code-block:: shell + + # from installation using libkea-process.so + $ strings ${prefix}/lib/libkea-process.so | sed -n 's/;;;; //p' + + # from sources using libkea-process.so + $ strings src/lib/process/.libs/libkea-process.so | sed -n 's/;;;; //p' + + # from sources using libkea-process.a + $ strings src/lib/process/.libs/libkea-process.a | sed -n 's/;;;; //p' + + # from sources using libcfgrpt.a + $ strings src/lib/process/cfgrpt/.libs/libcfgrpt.a | sed -n 's/;;;; //p' + +The CA is started by running its binary and specifying the configuration +file it should use. For example: + +.. code-block:: console + + $ ./kea-ctrl-agent -c /usr/local/etc/kea/kea-ctrl-agent.conf + +It can be started by :iscman:`keactrl` as well (see :ref:`keactrl`). + +.. _agent-clients: + +Connecting to the Control Agent +=============================== + +For an example of a tool that can take advantage of the RESTful API, see +:ref:`kea-shell`. diff --git a/doc/sphinx/arm/classify.rst b/doc/sphinx/arm/classify.rst new file mode 100644 index 0000000..7f011ec --- /dev/null +++ b/doc/sphinx/arm/classify.rst @@ -0,0 +1,1265 @@ +.. _classify: + +********************* +Client Classification +********************* + +Client Classification Overview +============================== + +In certain cases it is useful to differentiate among different types +of clients and treat them accordingly. Common reasons include: + +- The clients represent different pieces of topology, e.g. a cable + modem is not the same as the clients behind that modem. + +- The clients have different behavior, e.g. a smartphone behaves + differently from a laptop. + +- The clients require different values for some options, e.g. a + docsis3.0 cable modem requires different settings from a docsis2.0 + cable modem. + +To make management easier, different clients can be grouped into a +client class to receive common options. + +An incoming packet can be associated with a client class in several +ways: + +- Implicitly, using a vendor class option or another built-in condition. + +- Using an expression which evaluates to ``true``. + +- Using static host reservations, a shared network, a subnet, etc. + +- Using a hook. + +Client classification can be used to change the behavior of almost any +part of the DHCP message processing. There are currently nine +mechanisms that take advantage of client classification: + +- Dropping queries. + +- Subnet selection. + +- Pool selection. + +- Lease limiting. + +- Rate limiting. + +- DDNS tuning. + +- Defining DHCPv4 private (codes 224-254) and code 43 options. + +- Assigning different options. + +- Setting specific options for use with the TFTP server address + and the boot file field for DHCPv4 cable modems. + +.. _classify-classification-steps: + +Classification Steps +-------------------- + +The classification process is conducted in several steps: + +1. The ``ALL`` class is associated with the incoming packet. + +2. Vendor class options are processed. + +3. Classes with matching expressions and not marked for later evaluation ("on + request" or depending on the ``KNOWN``/``UNKNOWN`` built-in classes) + are processed in the order they are defined in the + configuration; the boolean expression is evaluated and, if it + returns ``true`` (a match), the incoming packet is associated with the + class. + +4. If a private or code 43 DHCPv4 option is received, it is decoded + following its client-class or global (or, for option 43, + last-resort) definition. + +5. When the incoming packet belongs to the special class ``DROP``, it is + dropped and an informational message is logged with the packet + information. + +.. note:: + + The ``pkt4_receive`` and ``pkt6_receive`` callouts are called here. + +6. When the ``early-global-reservations-lookup`` global parameter is + configured to ``true``, the process looks up global reservations and + partially performs steps 8, 9, and 10. The lookup is limited to + global reservations; if one is found the ``KNOWN`` class is set, + but if none is found the ``UNKNOWN`` class is **not** set. + +7. A subnet is chosen, possibly based on the class information when + some subnets are reserved. More precisely: when choosing a subnet, + the server iterates over all of the subnets that are feasible given + the information found in the packet (client address, relay address, + etc.). It uses the first subnet it finds that either has no + class associated with it, or has a class which matches one of the + packet's classes. + +.. note:: + + The ``subnet4_select`` and ``subnet6_select`` callouts are called here. + +8. The server looks for host reservations. If an identifier from the + incoming packet matches a host reservation in the subnet or shared + network, the packet is associated with the ``KNOWN`` class and all + classes of the host reservation. If a reservation is not found, the + packet is assigned to the ``UNKNOWN`` class. + +9. Classes with matching expressions - directly, or indirectly using the + ``KNOWN``/``UNKNOWN`` built-in classes and not marked for later evaluation + ("on request") - are processed in the order they are defined + in the configuration; the boolean expression is evaluated and, if it + returns ``true`` (a match), the incoming packet is associated with the + class. After a subnet is selected, the server determines whether + there is a reservation for a given client. Therefore, it is not + possible to use the ``UNKNOWN`` class to select a shared network or + a subnet. For the ``KNOWN`` class, only global reservations are used and the + ``early-global-reservations-lookup`` parameter must be configured to + ``true``. + +10. When the incoming packet belongs to the special class ``DROP``, it is + dropped and an informational message is logged with the packet + information. Since Kea version 1.9.8, it is permissible to make the ``DROP`` + class dependent on the ``KNOWN``/``UNKNOWN`` classes. + +11. If needed, addresses and prefixes from pools are assigned, possibly + based on the class information when some pools are reserved for + class members. + +.. note:: + + The ``lease4_select``, ``lease4_renew``, ``lease6_select``, ``lease6_renew``, and ``lease6_rebind`` + callouts are called here. + +12. Classes marked as "required" are evaluated in the order in which + they are listed: first the shared network, then the subnet, and + finally the pools that assigned resources belong to. + +13. Options are assigned, again possibly based on the class information + in the order that classes were associated with the incoming packet. + For DHCPv4 private and code 43 options, this includes option + definitions specified within classes. + +.. note:: + + Care should be taken with client classification, as it is easy for + clients that do not meet any class criteria to be denied service + altogether. + +.. _built-in-client-classes: + +Built-in Client Classes +======================= + +Some classes are built-in, so they do not need to be explicitly defined. They +can be defined if there is a need to associate lease lifetimes, option data, +etc. with them. + +Vendor class information is the primary example: the server checks whether an +incoming DHCPv4 packet includes the vendor class identifier option (60) +or an incoming DHCPv6 packet includes the vendor class option (16). If +it does, the content of that option is prepended with ``VENDOR_CLASS_`` +and the result is interpreted as a class for that packet. The content that is +considered is the whole class identifier for DHCPv4, and the first vendor class +data field for DHCPv6. The enterprise number and subsequent vendor class data +fields are not used for the purpose of classification. For example, modern cable +modems send such options with value ``docsis3.0``, so the packet belongs to +class ``VENDOR_CLASS_docsis3.0``. + +The ``HA_`` prefix is used by :ischooklib:`libdhcp_ha.so` to +designate certain servers to process DHCP packets as a result of load +balancing. The class name is constructed by prepending the ``HA_`` prefix +to the name of the server which should process the DHCP packet. This +server uses an appropriate pool or subnet to allocate IP addresses +(and/or prefixes), based on the assigned client classes. The details can +be found in :ref:`hooks-high-availability`. + +The ``SPAWN_`` prefix is used by template classes to generate spawned class +names at runtime. The spawned class name is constructed by prepending the +``SPAWN_`` prefix to the template class name and the evaluated value: +``SPAWN_<template-class-name>_<evaluated-value>``. +More details can be found in :ref:`classification-configuring`. + +The ``BOOTP`` class is used by :ischooklib:`libdhcp_bootp.so` to classify and +respond to inbound BOOTP queries. + +The ``SKIP_DDNS`` class is used by the DDNS-tuning hook library to suppress +DDNS updates on a per client basis. + +Other examples are the ``ALL`` class, to which all incoming packets belong, +and the ``KNOWN`` class, assigned when host reservations exist for a +particular client. By convention, the names of built-in classes begin with all +capital letters. + +Currently recognized built-in class names are ``ALL``, ``KNOWN`` and ``UNKNOWN``, +and the prefixes ``VENDOR_CLASS_``, ``HA_``, ``AFTER_``, ``EXTERNAL_``, +``SKIP_DDNS``. Although the ``AFTER_`` prefix is a provision for an +as-yet-unwritten hook, the ``EXTERNAL_`` prefix can be freely used; built-in +classes are implicitly defined so they never raise warnings if they do not +appear in the configuration. + +.. _classification-using-expressions: + +Using Expressions in Classification +=================================== + +The expression portion of a classification definition contains operators +and values. All values are currently strings; operators take a string or +strings and return another string. When all the operations have +completed, the result should be a value of ``true`` or ``false``. The packet +belongs to the class (and the class name is added to the list of +classes) if the result is ``true``. Expressions are written in standard +format and can be nested. + +Expressions are pre-processed during the parsing of the configuration +file and converted to an internal representation. This allows certain +types of errors to be caught and logged during parsing. Examples of +these errors include an incorrect number or type of argument to an +operator. The evaluation code also checks for this class of error and +generally throws an exception, though this should not occur in a +normally functioning system. + +Other issues, such as the starting position of a substring being +outside of the substring or an option not existing in the packet, result +in the operator returning an empty string. + +Dependencies between classes are also checked. For instance, forward +dependencies are rejected when the configuration is parsed; an +expression can only depend on already-defined classes (including built-in +classes) which are evaluated in a previous or the same evaluation phase. +This does not apply to the ``KNOWN`` or ``UNKNOWN`` classes. + +.. table:: List of classification values + + +-----------------------+-------------------------------+-----------------------+ + | Name | Example expression | Example value | + +=======================+===============================+=======================+ + | String literal | 'example' | 'example' | + +-----------------------+-------------------------------+-----------------------+ + | Hexadecimal string | 0x5a7d | 'Z}' | + | literal | | | + +-----------------------+-------------------------------+-----------------------+ + | IP address literal | 10.0.0.1 | 0x0a000001 | + +-----------------------+-------------------------------+-----------------------+ + | Integer literal | 123 | '123' | + +-----------------------+-------------------------------+-----------------------+ + | Binary content of the | option[123].hex | '(content of the | + | option | | option)' | + +-----------------------+-------------------------------+-----------------------+ + | Option existence | option[123].exists | 'true' | + +-----------------------+-------------------------------+-----------------------+ + | Binary content of the | option[12].option[34].hex | '(content of the | + | sub-option | | sub-option)' | + +-----------------------+-------------------------------+-----------------------+ + | Sub-Option existence | option[12].option[34].exists | 'true' | + +-----------------------+-------------------------------+-----------------------+ + | Client class | member('foobar') | 'true' | + | membership | | | + +-----------------------+-------------------------------+-----------------------+ + | Known client | known | member('KNOWN') | + +-----------------------+-------------------------------+-----------------------+ + | Unknown client | unknown | not member('KNOWN') | + +-----------------------+-------------------------------+-----------------------+ + | DHCPv4 relay agent | relay4[123].hex | '(content of the RAI | + | sub-option | | sub-option)' | + +-----------------------+-------------------------------+-----------------------+ + | DHCPv6 Relay Options | relay6[nest].option[code].hex | (value of the option) | + +-----------------------+-------------------------------+-----------------------+ + | DHCPv6 Relay Peer | relay6[nest].peeraddr | 2001:DB8::1 | + | Address | | | + +-----------------------+-------------------------------+-----------------------+ + | DHCPv6 Relay Link | relay6[nest].linkaddr | 2001:DB8::1 | + | Address | | | + +-----------------------+-------------------------------+-----------------------+ + | Interface name of | pkt.iface | eth0 | + | packet | | | + +-----------------------+-------------------------------+-----------------------+ + | Source address of | pkt.src | 10.1.2.3 | + | packet | | | + +-----------------------+-------------------------------+-----------------------+ + | Destination address | pkt.dst | 10.1.2.3 | + | of packet | | | + +-----------------------+-------------------------------+-----------------------+ + | Length of packet | pkt.len | 513 | + +-----------------------+-------------------------------+-----------------------+ + | Hardware address in | pkt4.mac | 0x010203040506 | + | DHCPv4 packet | | | + +-----------------------+-------------------------------+-----------------------+ + | Hardware length in | pkt4.hlen | 6 | + | DHCPv4 packet | | | + +-----------------------+-------------------------------+-----------------------+ + | Hardware type in | pkt4.htype | 6 | + | DHCPv4 packet | | | + +-----------------------+-------------------------------+-----------------------+ + | ciaddr field in | pkt4.ciaddr | 192.0.2.1 | + | DHCPv4 packet | | | + +-----------------------+-------------------------------+-----------------------+ + | giaddr field in | pkt4.giaddr | 192.0.2.1 | + | DHCPv4 packet | | | + +-----------------------+-------------------------------+-----------------------+ + | yiaddr field in | pkt4.yiaddr | 192.0.2.1 | + | DHCPv4 packet | | | + +-----------------------+-------------------------------+-----------------------+ + | siaddr field in | pkt4.siaddr | 192.0.2.1 | + | DHCPv4 packet | | | + +-----------------------+-------------------------------+-----------------------+ + | Message type in | pkt4.msgtype | 1 | + | DHCPv4 packet | | | + +-----------------------+-------------------------------+-----------------------+ + | Transaction ID (xid) | pkt4.transid | 12345 | + | in DHCPv4 packet | | | + +-----------------------+-------------------------------+-----------------------+ + | Message type in | pkt6.msgtype | 1 | + | DHCPv6 packet | | | + +-----------------------+-------------------------------+-----------------------+ + | Transaction ID in | pkt6.transid | 12345 | + | DHCPv6 packet | | | + +-----------------------+-------------------------------+-----------------------+ + | Vendor option | vendor[*].exists | 'true' | + | existence (any | | | + | vendor) | | | + +-----------------------+-------------------------------+-----------------------+ + | Vendor option | vendor[4491].exists | 'true' | + | existence (specific | | | + | vendor) | | | + +-----------------------+-------------------------------+-----------------------+ + | Enterprise-id from | vendor.enterprise | 4491 | + | vendor option | | | + +-----------------------+-------------------------------+-----------------------+ + | Vendor sub-option | vendor[4491].option[1].exists | 'true' | + | existence | | | + +-----------------------+-------------------------------+-----------------------+ + | Vendor sub-option | vendor[4491].option[1].hex | docsis3.0 | + | content | | | + +-----------------------+-------------------------------+-----------------------+ + | Vendor class option | vendor-class[*].exists | 'true' | + | existence (any | | | + | vendor) | | | + +-----------------------+-------------------------------+-----------------------+ + | Vendor class option | vendor-class[4491].exists | 'true' | + | existence (specific | | | + | vendor) | | | + +-----------------------+-------------------------------+-----------------------+ + | Enterprise-id from | vendor-class.enterprise | 4491 | + | vendor class option | | | + +-----------------------+-------------------------------+-----------------------+ + | First data chunk from | vendor-class[4491].data | docsis3.0 | + | vendor class option | | | + +-----------------------+-------------------------------+-----------------------+ + | Specific data chunk | vendor-class[4491].data[3] | docsis3.0 | + | from vendor class | | | + | option | | | + +-----------------------+-------------------------------+-----------------------+ + +Notes: + +- Hexadecimal strings are converted into a string as expected. The + starting ``0X`` or ``0x`` is removed, and if the string is an odd number + of characters a "0" is prepended to it. + +- IP addresses are converted into strings of length 4 or 16. IPv4, + IPv6, and IPv4-embedded IPv6 (e.g. IPv4-mapped IPv6) addresses are + supported. + +- Integers in an expression are converted to 32-bit unsigned integers + and are represented as four-byte strings; for example, 123 is + represented as ``0x0000007b``. All expressions that return numeric values + use 32-bit unsigned integers, even if the field in the packet is + smaller. In general, it is easier to use decimal notation to + represent integers, but it is also possible to use hexadecimal + notation. When writing an integer in hexadecimal, care should be + taken to make sure the value is represented as 32 bits, e.g. use + ``0x00000001`` instead of ``0x1`` or ``0x01``. Also, make sure the value is + specified in network order, e.g. 1 is represented as ``0x00000001``. + +- ``option[code].hex`` extracts the value of the option with the code + ``code`` from the incoming packet. If the packet does not contain the + option, it returns an empty string. The string is presented as a byte + string of the option payload, without the type code or length fields. + +- ``option[code].exists`` checks whether an option with the code ``code`` + is present in the incoming packet. It can be used with empty options. + +- ``member('foobar')`` checks whether the packet belongs to the client + class ``foobar``. To avoid dependency loops, the configuration file + parser verifies whether client classes were already defined or are + built-in, i.e., beginning with ``VENDOR_CLASS_``, ``AFTER_`` (for the + to-come "after" hook) and ``EXTERNAL_`` or equal to ``ALL``, ``KNOWN``, + ``UNKNOWN``, etc. + + ``known`` and ``unknown`` are shorthand for ``member('KNOWN')`` and ``not + member('KNOWN')``. Note that the evaluation of any expression using + the ``KNOWN`` class (directly or indirectly) is deferred after the host + reservation lookup (i.e. when the ``KNOWN`` or ``UNKNOWN`` partition is + determined). + +- ``relay4[code].hex`` attempts to extract the value of the sub-option + ``code`` from the option inserted as the DHCPv4 Relay Agent Information + (82) option. If the packet does not contain a RAI option, or the RAI + option does not contain the requested sub-option, the expression + returns an empty string. The string is presented as a byte string of + the option payload without the type code or length fields. This + expression is allowed in DHCPv4 only. + +- ``relay4`` shares the same representation types as ``option``; for + instance, ``relay4[code].exists`` is supported. + +- ``relay6[nest]`` allows access to the encapsulations used by any DHCPv6 + relays that forwarded the packet. The ``nest`` level specifies the + relay from which to extract the information, with a value of 0 + indicating the relay closest to the DHCPv6 server. Negative values + allow relays to be specified counting from the DHCPv6 client, with -1 indicating + the relay closest to the client. If the requested + encapsulation does not exist, an empty string ``""`` is returned. This + expression is allowed in DHCPv6 only. + +- ``relay6[nest].option[code]`` shares the same representation types as + ``option``; for instance, ``relay6[nest].option[code].exists`` is + supported. + +- Expressions starting with ``pkt4`` can be used only in DHCPv4. They + allow access to DHCPv4 message fields. + +- ``pkt6`` refers to information from the client request. To access any + information from an intermediate relay, use ``relay6``. ``pkt6.msgtype`` + and ``pkt6.transid`` output a 4-byte binary string for the message type + or transaction ID. For example, the message type ``SOLICIT`` is + ``0x00000001`` or simply 1, as in ``pkt6.msgtype == 1``. + +- "Vendor option" means the Vendor-Identifying Vendor-Specific Information + option in DHCPv4 (code 125; see `Section 4 of RFC + 3925 <https://tools.ietf.org/html/rfc3925#section-4>`__) and the + Vendor-Specific Information Option in DHCPv6 (code 17, defined in + `Section 21.17 of RFC + 8415 <https://tools.ietf.org/html/rfc8415#section-21.17>`__). "Vendor + class option" means the Vendor-Identifying Vendor Class Option in DHCPv4 + (code 124; see `Section 3 of RFC + 3925 <https://tools.ietf.org/html/rfc3925#section-3>`__) in DHCPv4 and + the Class Option in DHCPv6 (code 16; see `Section 21.16 of RFC + 8415 <https://tools.ietf.org/html/rfc8415#section-21.16>`__). Vendor + options may have sub-options that are referenced by their codes. + Vendor class options do not have sub-options, but rather data chunks, + which are referenced by index value. Index 0 means the first data + chunk, index 1 is for the second data chunk (if present), etc. + +- In the vendor and vendor-class constructs an asterisk (*) or 0 can be + used to specify a wildcard ``enterprise-id`` value, i.e. it will match + any ``enterprise-id`` value. + +- Vendor Class Identifier (option 60 in DHCPv4) can be accessed using the + option[60] expression. + +- `RFC 3925 <https://tools.ietf.org/html/rfc3925>`__ and `RFC + 8415 <https://tools.ietf.org/html/rfc8415>`__ allow for multiple + instances of vendor options to appear in a single message. The client + classification code currently examines the first instance if more + than one appear. For the ``vendor.enterprise`` and ``vendor-class.enterprise`` + expressions, the value from the first instance is returned. Please + submit a feature request on the + `Kea GitLab site <https://gitlab.isc.org/isc-projects/kea>`__ to request + support for multiple instances. + +.. table:: List of classification expressions + + +-----------------------+-------------------------+-----------------------+ + | Name | Example | Description | + +=======================+=========================+=======================+ + | Equal | 'foo' == 'bar' | Compare the two | + | | | values and return | + | | | ``true`` or ``false`` | + +-----------------------+-------------------------+-----------------------+ + | Not | not ('foo' == 'bar') | Logical negation | + +-----------------------+-------------------------+-----------------------+ + | And | ('foo' == 'bar') and | Logical and | + | | ('bar' == 'foo') | | + +-----------------------+-------------------------+-----------------------+ + | Or | ('foo' == 'bar') or | Logical or | + | | ('bar' == 'foo') | | + +-----------------------+-------------------------+-----------------------+ + | Substring | substring('foobar',0,3) | Return the requested | + | | | substring | + +-----------------------+-------------------------+-----------------------+ + | Concat | concat('foo','bar') | Return the | + | | | concatenation of the | + | | | strings | + +-----------------------+-------------------------+-----------------------+ + | Concat (operator +) | 'foo' + 'bar' | Return the | + | | | concatenation of the | + | | | strings | + +-----------------------+-------------------------+-----------------------+ + | Ifelse | ifelse('foo' == | Return the branch | + | | 'bar','us','them') | value according to | + | | | the condition | + +-----------------------+-------------------------+-----------------------+ + | Hexstring | hexstring('foo', '-') | Converts the value to | + | | | a hexadecimal string, | + | | | e.g. 66-6F-6F | + +-----------------------+-------------------------+-----------------------+ + | Lcase | lcase('LoWeR') | Converts the value of | + | | | a string expression | + | | | to lower case e.g. | + | | | 'lower' | + +-----------------------+-------------------------+-----------------------+ + | Ucase | ucase('uPpEr') | Converts the value of | + | | | a string expression | + | | | to upper case e.g. | + | | | 'UPPER' | + +-----------------------+-------------------------+-----------------------+ + | Split | split('foo.bar', '.', 2)| Return the second | + | | | field, splitting on | + | | | dots. | + +-----------------------+-------------------------+-----------------------+ + +.. table:: List of conversion-to-text expressions + + +-----------------------+---------------------------+------------------------+ + | Name | Example | Description | + +=======================+===========================+========================+ + | AddressToText | addrtotext (192.10.0.1) | Represent the 4 bytes | + | | addrtotext (2003:db8::) | of an IPv4 address or | + | | | the 16 bytes of an | + | | | IPv6 address in human | + | | | readable format | + +-----------------------+---------------------------+------------------------+ + | Int8ToText | int8totext (-1) | Represents the 8-bit | + | | | signed integer in text | + | | | format | + +-----------------------+---------------------------+------------------------+ + | Int16ToText | int16totext (-1) | Represents the 16-bit | + | | | signed integer in text | + | | | format | + +-----------------------+---------------------------+------------------------+ + | Int32ToText | int32totext (-1) | Represents the 32-bit | + | | | signed integer in text | + | | | format | + +-----------------------+---------------------------+------------------------+ + | UInt8ToText | uint8totext (255) | Represents the 8-bit | + | | | unsigned integer in | + | | | text format | + +-----------------------+---------------------------+------------------------+ + | UInt16ToText | uint16totext (65535) | Represents the 16-bit | + | | | unsigned integer in | + | | | text format | + +-----------------------+---------------------------+------------------------+ + | UInt32ToText | uint32totext (4294967295) | Represents the 32-bit | + | | | unsigned integer in | + | | | text format | + +-----------------------+---------------------------+------------------------+ + +Notes: + +The conversion operators can be used to transform data from binary to the text +representation. The only requirement is that the input data type length matches +an expected value. + +The ``AddressToText`` token expects 4 bytes for IPv4 addresses or 16 bytes for IPv6 +addresses. The ``Int8ToText`` and ``UInt8ToText`` tokens expect 1 byte, the ``Int16ToText`` and +``UInt16ToText`` tokens expect 2 bytes, and ``Int32ToText`` and ``UInt32ToText`` expect 4 bytes. +For all conversion tokens, if the data length is 0, the result string is empty. + +Logical Operators +----------------- + +The Not, And, and Or logical operators are the common operators. Not has +the highest precedence and Or the lowest. And and Or are (left) +associative. Parentheses around a logical expression can be used to +enforce a specific grouping; for instance, in "A and (B or C)". Without +parentheses, "A and B or C" means "(A and B) or C". + +Substring +--------- + +The substring operator ``substring(value, start, length)`` accepts both +positive and negative values for the starting position and the length. +For ``start``, a value of 0 is the first byte in the string while -1 is +the last byte. If the starting point is outside of the original string +an empty string is returned. ``length`` is the number of bytes to extract. +A negative number means to count towards the beginning of the string but +does not include the byte pointed to by ``start``. The special value ``all`` +means to return all bytes from start to the end of the string. If the length +is longer than the remaining portion of the string, then the entire +remaining portion is returned. Some examples may be helpful: +:: + + substring('foobar', 0, 6) == 'foobar' + substring('foobar', 3, 3) == 'bar' + substring('foobar', 3, all) == 'bar' + substring('foobar', 1, 4) == 'ooba' + substring('foobar', -5, 4) == 'ooba' + substring('foobar', -1, -3) == 'oba' + substring('foobar', 4, -2) == 'ob' + substring('foobar', 10, 2) == '' + + +Concat +------ + +The concat function ``concat(string1, string2)`` returns the concatenation +of its two arguments. For instance: +:: + + concat('foo', 'bar') == 'foobar' + +For user convenience, Kea version 1.9.8 added an associative operator +version of the concat function. For instance: +:: + + 'abc' + 'def' + 'ghi' + 'jkl' + '...' + +is the same as: +:: + + concat(concat(concat(concat('abc', 'def'), 'ghi'), 'jkl'), '...') + +or: +:: + + concat('abc', concat('def', concat('ghi', concat('jkl', '...')))) + +or: +:: + + 'abcdefghijkl...' + +Split +--------- + +The split operator ``split(value, delimiters, field-number)`` accepts a list +of characters to use as delimiters and a positive field number of the +desired field when the value is split into fields separated by the delimiters. +Adjacent delimiters are not compressed out, rather they result in an empty +string for that field number. If value is an empty string, the result will be an +empty string. If the delimiters list is empty, the result will be the original +value. If the field-number is less than one or larger than the number of +fields, the result will be an empty string. Some examples follow: +:: + + split ('one.two..four', '.', 1) == 'one' + split ('one.two..four', '.', 2) == 'two' + split ('one.two..four', '.', 3) == '' + split ('one.two..four', '.', 4) == 'four' + split ('one.two..four', '.', 5) == '' + +.. note:: + + To use a hard-to-escape character as a delimiter, use its ASCII hex value. + For example, split by ``single quote`` using ``0x27``: + ``split(option[39].text, 0x27, 1)`` + +Ifelse +------ + +The ifelse function ``ifelse(cond, iftrue, ifelse)`` returns the ``iftrue`` +or ``ifelse`` branch value following the boolean condition ``cond``. For +instance: +:: + + ifelse(option[230].exists, option[230].hex, 'none') + + +Hexstring +--------- + +The hexstring function ``hexstring(binary, separator)`` returns the binary +value as its hexadecimal string representation: pairs of hexadecimal +digits separated by the separator, e.g ``':'``, ``'-'``, ``''`` (empty separator). +:: + + hexstring(pkt4.mac, ':') + + +.. note:: + + The expression for each class is executed on each packet received. If + the expressions are overly complex, the time taken to execute them + may impact the performance of the server. Administrators who need complex or + time-consuming expressions should consider writing a + :ref:`hook <hooks-libraries>` to perform the necessary work. + +.. _classification-configuring: + +Configuring Classes +=================== + +A client class definition can contain the following properties: + - The ``name`` parameter is mandatory and must be unique among all classes. + - The ``test`` expression is not mandatory and represents a string containing the + logical expression used to determine membership in the class. The entire + expression is included in double quotes (``"``). The result should evaluate + to a boolean value (``true`` or ``false``). + - The ``template-test`` expression is not mandatory and represents a string + containing the logical expression used to generate a spawning class. The + entire expression is included in double quotes (``"``). The result should + evaluate to a string value representing the variable part of the spawned + class name. If the resulting string is empty, no spawning class is generated. + The resulting spawned class has the following generated name format: + ``SPAWN_<template-class-name>_<evaluated-value>``. + After classes are evaluated and a spawned class is generated, the corresponding + template class name is also associated with the packet. + - The ``option-data`` list is not mandatory and contains options that should be + assigned to members of this class. In the case of a template class, these + options are assigned to the generated spawned class. + - The ``option-def`` list is not mandatory and is used to define custom options. + - The ``only-if-required`` flag is not mandatory; when its value is set to + ``false`` (the default), membership is determined during classification and is + available for subnet selection, for instance. When the value is set to + ``true``, membership is evaluated only when required and is usable only for + option configuration. + - The ``user-context`` is not mandatory and represents a map with user-defined data + and possibly configuration options for hook libraries. + - The ``next-server`` parameter is not mandatory and configures the ``siaddr`` field in + packets associated with this class. It is used in DHCPv4 only. + - The ``server-hostname`` is not mandatory and configures the ``sname`` field in + packets associated with this class. It is used in DHCPv4 only. + - The ``boot-file-name`` is not mandatory and configures the ``file`` field in + packets associated with this class. It is used in DHCPv4 only. + - The ``valid-lifetime``, ``min-valid-lifetime``, and ``max-valid-lifetime`` are + not mandatory and configure the valid lifetime fields for this client class. + - The ``preferred-lifetime``, ``min-preferred-lifetime``, and + ``max-preferred-lifetime`` are not mandatory and configure the preferred + lifetime fields for this client class. It is used in DHCPv6 only. + + +.. note:: + + ``test`` and ``template-test`` are mutually exclusive in a client class + definition. Use either one, or neither, but not both. If both are provided, + the configuration is rejected. + +In the following example, the class named ``Client_foo`` is defined. It is +comprised of all clients whose client IDs (option 61) start with the string +``foo``. Members of this class will be given 192.0.2.1 and 192.0.2.2 as their +domain name servers. + +:: + + "Dhcp4": { + "client-classes": [ + { + "name": "Client_foo", + "test": "substring(option[61].hex,0,3) == 'foo'", + "option-data": [ + { + "name": "domain-name-servers", + "code": 6, + "space": "dhcp4", + "csv-format": true, + "data": "192.0.2.1, 192.0.2.2" + } + ] + }, + ... + ], + ... + } + +The next example shows a client class being defined for use by the DHCPv6 +server. In it the class named "Client_enterprise" is defined. It is +comprised of all clients whose client identifiers start with the given +hex string (which would indicate a DUID based on an enterprise ID of +``0x0002AABBCCDD``). Members of this class will be given 2001:db8:0::1 and +2001:db8:2::1 as their domain name servers. + +:: + + "Dhcp6": { + "client-classes": [ + { + "name": "Client_enterprise", + "test": "substring(option[1].hex,0,6) == 0x0002AABBCCDD", + "option-data": [ + { + "name": "dns-servers", + "code": 23, + "space": "dhcp6", + "csv-format": true, + "data": "2001:db8:0::1, 2001:db8:2::1" + } + ] + }, + ... + ], + ... + } + +It is also possible to have both left and right operands of the evaluated +expression processed at runtime. Expressions related to packets can appear in +the expression as many times as needed; there is no limit. However, each token +has a small impact on performance and excessively complex expressions may cause a +bottleneck. + +:: + + "Dhcp4": { + "client-classes": [ + { + "name": "Infrastructure", + "test": "option[82].option[2].hex == pkt4.mac", + ... + }, + ... + ], + ... + } + +.. _template-classes: + +Template Classes +---------------- + +The ``template-test`` parameter indicates that the class is a template class. + +:: + + "Dhcp4": { + "client-classes": [ + { + "name": "Client-ID", + "template-test": "substring(option[61].hex,0,3)", + ... + }, + ... + ], + ... + } + +If the received DHCPv4 packet contains option 61, then the first three bytes represent +the value ``foo`` in ASCII, and the spawned class uses the +``SPAWN_Client-ID_foo`` name. +Both the ``SPAWN_Client-ID_foo`` and ``Client-ID`` classes are associated with +the packet. + +.. note :: + + Template classes can also be used to spawn classes which match regular + classes, effectively associating the regular class to the packet. + To achieve this, the regular class must also contain the fixed part of the + spawned class name: + + ``SPAWN_<template-class-name-used-to-activate-this-regular-class>_<evaluated-value-filtering-this-regular-class>`` + +:: + + "Dhcp6": { + "client-classes": [ + { + "name": "SPAWN_Client-ID_foobar", + "test": "substring(option[1].hex,0,6) == 0x0002AABBCCDD", + ... + }, + { + "name": "Client-ID", + "template-test": "substring(option[1].hex,0,6)", + ... + }, + ... + ], + ... + } + +If the received DHCPv6 packet contains option 1 (client identifier) with hex +value ``0x0002AABBCCDD``, then the ``SPAWN_Client-ID_foobar`` is associated +with the packet. Moreover, if the first six bytes represent value ``foobar`` in +ASCII, then the spawned class uses the ``SPAWN_Client-ID_foobar`` name, +effectively associating the regular class to the packet. In this second case, +both the ``SPAWN_Client-ID_foobar`` and ``Client-ID`` classes are associated +with the packet. +The ``test`` expression on the regular class ``SPAWN_Client-ID_foobar`` is not +mandatory and can be omitted, but it is used here with a different match +expression for example purposes. + +Usually the ``test`` and ``template-test`` expressions are evaluated before +subnet selection, but in some cases it is useful to evaluate it later when the +subnet, shared network, or pools are known but output-option processing has not +yet been done. For this purpose, the ``only-if-required`` flag, which is +``false`` by default, allows the evaluation of the ``test`` expression or the +``template-test`` expression only when it is required, i.e. in a +``require-client-classes`` list of the selected subnet, shared network, or pool. + +The ``require-client-classes`` list, which is valid for shared-network, subnet, +and pool scope, specifies the classes which are evaluated in the second pass +before output-option processing. The list is built in reverse-precedence +order of the option data, i.e. an option data item in a subnet takes precedence over +one in a shared network, but a required class in a subnet is added after one in a +shared network. The mechanism is related to the ``only-if-required`` flag but it +is not mandatory that the flag be set to ``true``. + +.. note :: + + The ``template-test`` expression can also be used to filter generated spawned + classes, so that they are created only when needed by using the ``ifelse`` + instruction. + +:: + + "Dhcp4": { + "client-classes": [ + { + "name": "Client-ID", + "template-test": "ifelse(substring(option[61].hex,4,3) == 'foo', substring(option[12].hex,0,12), '')", + ... + }, + ... + ], + ... + } + +.. note :: + + The template classes can be used to configure limits which, just like + options, are associated with the spawned class. This permits the configuration of + limits that apply to all packets associated with a class spawned at + runtime, according to the ``template-test`` expression in the parent template + class. For a more detailed description of how to configure limits using the + limits hook library, see :ref:`hooks-limits-configuration`. + For example, using the configuration below, ingress DHCPv6 packets that have + client ID values (in the format expressed by the Kea evaluator) ``foobar`` + and ``foofoo`` both amount to the same limit of 60 packets per day, while + other packets that have the first three hextets different than ``foo`` are put + in separate rate-limiting buckets. + +:: + + "Dhcp6": { + "client-classes": [ + { + "name": "Client-ID", + "template-test": "substring(option[1].hex,0,3)", + "user-context" : { + "limits": { + "rate-limit": "60 packets per day" + } + }, + ... + }, + ... + ], + ... + } + + +.. _classification-using-host-reservations: + +Using Static Host Reservations in Classification +================================================ + +Classes can be statically assigned to clients using techniques +described in :ref:`reservation4-client-classes` and +:ref:`reservation6-client-classes`. + +Subnet host reservations are searched after subnet selection. +Global host reservations are searched at the same time by default but +the ``early-global-reservations-lookup`` allows to change this behavior +into searching them before the subnet selection. + +Pool selection is performed after all host reservations lookups. + +.. _classification-subnets: + +Configuring Subnets With Class Information +========================================== + +In certain cases it is beneficial to restrict access to certain subnets +only to clients that belong to a given class, using the ``client-class`` +keyword when defining the subnet. + +Let's assume that the server is connected to a network segment that uses the +192.0.2.0/24 prefix. The administrator of that network has decided that +addresses from the range 192.0.2.10 to 192.0.2.20 will be managed by the DHCPv4 +server. Only clients belonging to client class ``Client_foo`` are allowed to use +this subnet. Such a configuration can be achieved in the following way: + +:: + + "Dhcp4": { + "client-classes": [ + { + "name": "Client_foo", + "test": "substring(option[61].hex,0,3) == 'foo'", + "option-data": [ + { + "name": "domain-name-servers", + "code": 6, + "space": "dhcp4", + "csv-format": true, + "data": "192.0.2.1, 192.0.2.2" + } + ] + }, + ... + ], + "subnet4": [ + { + "id": 1, + "subnet": "192.0.2.0/24", + "pools": [ { "pool": "192.0.2.10 - 192.0.2.20" } ], + "client-class": "Client_foo" + }, + ... + ], + ... + } + +The following example shows how to restrict access to a DHCPv6 subnet. This +configuration restricts use of the addresses in the range 2001:db8:1::1 to +2001:db8:1::FFFF to members of the "Client_enterprise" class. + +:: + + "Dhcp6": { + "client-classes": [ + { + "name": "Client_enterprise", + "test": "substring(option[1].hex,0,6) == 0x0002AABBCCDD", + "option-data": [ + { + "name": "dns-servers", + "code": 23, + "space": "dhcp6", + "csv-format": true, + "data": "2001:db8:0::1, 2001:db8:2::1" + } + ] + }, + ... + ], + "subnet6": [ + { + "id": 1, + "subnet": "2001:db8:1::/64", + "pools": [ { "pool": "2001:db8:1::-2001:db8:1::ffff" } ], + "client-class": "Client_enterprise" + } + ], + ... + } + +.. _classification-pools: + +Configuring Pools With Class Information +======================================== + +Similar to subnets, in certain cases access to certain address or prefix +pools must be restricted to only clients that belong to a given class, +using the ``client-class`` when defining the pool. + +Let's assume that the server is connected to a network segment that uses the +192.0.2.0/24 prefix. The administrator of that network has decided that +addresses from the range 192.0.2.10 to 192.0.2.20 are going to be managed by the +DHCPv4 server. Only clients belonging to client class ``Client_foo`` are allowed +to use this pool. Such a configuration can be achieved in the following way: + +:: + + "Dhcp4": { + "client-classes": [ + { + "name": "Client_foo", + "test": "substring(option[61].hex,0,3) == 'foo'", + "option-data": [ + { + "name": "domain-name-servers", + "code": 6, + "space": "dhcp4", + "csv-format": true, + "data": "192.0.2.1, 192.0.2.2" + } + ] + }, + ... + ], + "subnet4": [ + { + "id": 1, + "subnet": "192.0.2.0/24", + "pools": [ + { + "pool": "192.0.2.10 - 192.0.2.20", + "client-class": "Client_foo" + } + ] + }, + ... + ], + ... + } + +The following example shows how to restrict access to an address pool. This +configuration restricts use of the addresses in the range 2001:db8:1::1 to +2001:db8:1::FFFF to members of the "Client_enterprise" class. + +:: + + "Dhcp6": { + "client-classes": [ + { + "name": "Client_enterprise_", + "test": "substring(option[1].hex,0,6) == 0x0002AABBCCDD", + "option-data": [ + { + "name": "dns-servers", + "code": 23, + "space": "dhcp6", + "csv-format": true, + "data": "2001:db8:0::1, 2001:db8:2::1" + } + ] + }, + ... + ], + "subnet6": [ + { + "id": 1, + + "subnet": "2001:db8:1::/64", + + "pools": [ + { + "pool": "2001:db8:1::-2001:db8:1::ffff", + "client-class": "Client_foo" + } + ] + }, + ... + ], + ... + } + +Class Priority +============== + +Client classes in Kea follow the order in which they are specified in the +configuration (vs. alphabetical order). Required classes follow the order in +which they are required. + +When determining which client-class information (comprising of +options, lease lifetimes or DHCPv4 field values) that is part of class +definitions, to include in the response, the server examines the union of +options from all of the assigned classes. If two or more classes include the +same class information, the value from the first assigned class is used. +``ALL`` is always the first class, hence the class with the highest +priority, and matching required classes are last, so they have the +lowest priority. + +Optons defined in classes override any global options, and in turn will be +overridden by options defined for an individual subnet, shared network, pool or +reservation. + +On the other hand, lease lifetimes and DHCPv4 field values defined at class +scope override any values defined globally, in a subnet scope, or in a +shared-network scope. + +As an example, imagine that an incoming packet matches two classes. +Class ``foo`` defines values for an NTP server (option 42 in DHCPv4) and +an SMTP server (option 69 in DHCPv4), while class ``bar`` defines values +for an NTP server and a POP3 server (option 70 in DHCPv4). The server +examines the three options - NTP, SMTP, and POP3 - and returns any that +the client requested. As the NTP server was defined twice, the server +chooses only one of the values for the reply; the class from which the +value is obtained is determined as explained in the previous paragraphs. + +Classes and Hooks +================= + +Hooks may be used to classify packets. This may be useful if the +expression would be complex or time-consuming to write, and could be +better or more easily written as code. Once the hook has added the proper class name +to the packet, the rest of the classification system will work as expected +in choosing a subnet and selecting options. For a description of hooks, +see :ref:`hooks-libraries`; for information on configuring classes, +see :ref:`classification-configuring` and :ref:`classification-subnets`. + +Debugging Expressions +===================== + +While constructing classification expressions, administrators may find +it useful to enable logging; see :ref:`logging` for a more complete +description of the logging facility. + +To enable the debug statements in the classification system, +the severity must be set to ``DEBUG`` and the debug level to at least 55. +The specific loggers are ``kea-dhcp4.eval`` and ``kea-dhcp6.eval``. + +To understand the logging statements, it is essential to understand a bit about +how expressions are evaluated; for a more complete description, refer to +[the design document](https://gitlab.isc.org/isc-projects/kea/-/wikis/designs/client-classification-design). +In brief, there are two structures used during the evaluation of an +expression: a list of tokens which represent the expressions, and a value +stack which represents the values being manipulated. + +The list of tokens is created when the configuration file is processed, +with most expressions and values being converted to a token. The list is +organized in reverse Polish notation. During execution, the list is +traversed in order; as each token is executed, it is able to pop +values from the top of the stack and eventually push its result on the +top of the stack. Imagine the following expression: + +:: + + "test": "substring(option[61].hex,0,3) == 'foo'", + + +This will result in the following tokens: + +:: + + option, number (0), number (3), substring, text ('foo'), equals + + +In this example, the first three tokens will simply push values onto the +stack. The substring token will then remove those three values and +compute a result that it places on the stack. The text option also +places a value on the stack, and finally the equals token removes the two +tokens on the stack and places its result on the stack. + +When debug logging is enabled, each time a token is evaluated it +emits a log message indicating the values of any objects that were popped +off of the value stack, and any objects that were pushed onto the value +stack. + +The values are displayed as either text, if the command is known to +use text values, or hexadecimal, if the command either uses binary values +or can manipulate either text or binary values. For expressions that pop +multiple values off the stack, the values are displayed in the order +they were popped. For most expressions this will not matter, but for the +concat expression the values are displayed in reverse order from their +written order in the expression. + +Let us assume that the following test has been entered into the +configuration. This example skips most of the configuration to +concentrate on the test. + +:: + + "test": "substring(option[61].hex,0,3) == 'foo'", + + +The logging might then resemble this: + +:: + + 2016-05-19 13:35:04.163 DEBUG [kea.eval/44478] EVAL_DEBUG_OPTION Pushing option 61 with value 0x666F6F626172 + 2016-05-19 13:35:04.164 DEBUG [kea.eval/44478] EVAL_DEBUG_STRING Pushing text string '0' + 2016-05-19 13:35:04.165 DEBUG [kea.eval/44478] EVAL_DEBUG_STRING Pushing text string '3' + 2016-05-19 13:35:04.166 DEBUG [kea.eval/44478] EVAL_DEBUG_SUBSTRING Popping length 3, start 0, string 0x666F6F626172 pushing result 0x666F6F + 2016-05-19 13:35:04.167 DEBUG [kea.eval/44478] EVAL_DEBUG_STRING Pushing text string 'foo' + 2016-05-19 13:35:04.168 DEBUG [kea.eval/44478] EVAL_DEBUG_EQUAL Popping 0x666F6F and 0x666F6F pushing result 'true' + +.. note:: + + The debug logging may be quite verbose if there are multiple + expressions to evaluate; it is intended as an aid in helping + create and debug expressions. Administrators should plan to disable debug + logging when expressions are working correctly. Users may also + wish to include only one set of expressions at a time in the + configuration file while debugging them, to limit the log + statements. For example, when adding a new set of expressions, an administrator + might find it more convenient to create a configuration file that + only includes the new expressions until they are working + correctly, and then add the new set to the main configuration file. diff --git a/doc/sphinx/arm/config-backend.rst b/doc/sphinx/arm/config-backend.rst new file mode 100644 index 0000000..f83bf5c --- /dev/null +++ b/doc/sphinx/arm/config-backend.rst @@ -0,0 +1,327 @@ +.. _config-backend: + +Kea Configuration Backend +========================= + +.. _cb-applicability: + +Applicability +------------- + +Kea Configuration Backend (CB or config backend) gives Kea servers the ability +to manage and fetch their configuration from one or more databases. In +this documentation, the term "Configuration Backend" may also refer to +the particular Kea module providing support to manage and fetch the +configuration information from the particular database type. For +example, the MySQL Configuration Backend is the logic implemented within +:ischooklib:`libdhcp_mysql_cb.so`, which provides a complete set of functions to +manage and fetch the configuration information from the MySQL database. +The PostgreSQL Configuration Backend is the logic implemented within +:ischooklib:`libdhcp_pgsql_cb.so`, which provides a complete set of functions to +manage and fetch the configuration information from the PostgreSQL database. +From herein, the term "database" is used to refer to either a MySQL or +PostgreSQL database. + +In small deployments, e.g. those comprising a single DHCP server +instance with limited and infrequently changing number of subnets, it +may be impractical to use the CB as a configuration repository because +it requires additional third-party software to be installed and +configured - in particular the database server, client and libraries. +Once the number of DHCP servers and/or the number of managed subnets in the +network grows, the usefulness of the CB becomes obvious. + +One use case for the CB is a pair of Kea DHCP servers that are configured +to support High Availability as described in +:ref:`hooks-high-availability`. The configurations of both servers +(including the value of the ``server-tag`` parameter) +are almost exactly the same: they may differ by the server identifier +and designation of the server as a primary or standby (or secondary), and/or +by their interfaces' configuration. Typically, the +subnets, shared networks, option definitions, and global parameters are the +same for both servers and can be sourced from a single database instance +to both Kea servers. + +Using the database as a single source of configuration for subnets +and/or other configuration information supported by the CB has the +advantage that any modifications to the configuration in the database are +automatically applied to both servers. + +Another case when the centralized configuration repository is useful is +in deployments including a large number of DHCP servers, possibly +using a common lease database to provide redundancy. New servers can +be added to the pool frequently to fulfill growing scalability +requirements. Adding a new server does not require replicating the +entire configuration to the new server when a common database is used. + +Using the database as a configuration repository for Kea servers also +brings other benefits, such as: + +- the ability to use database specific tools to access the configuration + information; + +- the ability to create customized statistics based on the information + stored in the database; and + +- the ability to backup the configuration information using the database's + built-in replication mechanisms. + +.. _cb-limitations: + +CB Capabilities and Limitations +------------------------------- + +Currently, the Kea CB has the following limitations: + +- It is only supported for MySQL and PostgreSQL databases. + +- It is only supported for the DHCPv4 and DHCPv6 daemons; the Control Agent, + D2 daemon, and the NETCONF daemon cannot be configured from the database, + +- Only certain DHCP configuration parameters can be set in the + database: global parameters, option definitions, global options, client + classes, shared networks, and subnets. Other configuration parameters + must be sourced from a JSON configuration file. + +Kea CB stores data in a schema that is public. It is possible to +insert configuration data into the tables manually or automatically +using SQL scripts, but this requires SQL and schema knowledge. +The supported method for managing the data is through :ischooklib:`libdhcp_cb_cmds.so`, +which provides management commands for config backends. It simplifies many +typical operations, such as listing, adding, retrieving, and deleting global +parameters, shared networks, subnets, pools, options, option definitions, and +client classes. In addition, it provides essential business logic that ensures +the logical integrity of the data. See commands starting with ``remote-`` in +Appendix A of this manual for a complete list. + +.. note:: + + :ischooklib:`libdhcp_cb_cmds.so` is available only to ISC customers with + a paid support contract. For more information on subscription options, please + complete the form at https://www.isc.org/contact. + +The schema creation scripts can be found at +`dhcpdb_create.mysql <https://gitlab.isc.org/isc-projects/kea/blob/master/src/share/database/scripts/mysql/dhcpdb_create.mysql>`__ +and +`dhcpdb_create.pgsql <https://gitlab.isc.org/isc-projects/kea/blob/master/src/share/database/scripts/pgsql/dhcpdb_create.pgsql>`__. +Other related design documents are stored in our GitLab: +`CB Design <https://gitlab.isc.org/isc-projects/kea/wikis/designs/configuration-in-db-design>`__ +and +`Client Classes in CB Design <https://gitlab.isc.org/isc-projects/kea/wikis/designs/client-classes-in-cb>`__. + +We strongly recommend against duplication of configuration information +in both the file and the database. For example, when specifying subnets +for the DHCP server, please store them in either the configuration backend +or in the configuration file, not both. Storing some subnets in the database +and others in the file may put users at risk of potential configuration +conflicts. Note that the configuration instructions from the database take +precedence over instructions from the file, so parts of the configuration +specified in the file may be overridden if contradicted by information in +the database. + +Although it is not recommended, it is possible to specify certain parameter +types both in a configuration file and the database. For example, a subnet +can be specified in the configuration file and another subnet in the database; +in this case, the server will use both subnets. DHCP client classes, however, +must not be specified in both the configuration file and the database, even if +they do not overlap. If any client classes are specified in the database +for a particular DHCP server, this server will use these classes and ignore +all classes present in its configuration file. This behavior was introduced +to ensure that the server receives a consistent set of client classes +specified in an expected order with all inter-class dependencies fulfilled. +It is impossible to guarantee consistency when client classes are specified +in two independent configuration sources. + +.. note:: + + It is recommended that :ischooklib:`libdhcp_subnet_cmds.so` not be used to + manage subnets when the configuration backend is used as a source + of information about the subnets. :ischooklib:`libdhcp_subnet_cmds.so` + modifies the local subnets configuration in the server's memory, + not in the database. Use :ischooklib:`libdhcp_cb_cmds.so` to manage the + subnets information in the database instead. + +.. note:: + + Using custom option formats requires creating definitions for these options. + Suppose a user wishes to set option data in the configuration backend. In + that case, we recommend specifying the definition for that option in the + configuration backend as well. It is essential when multiple servers are + managed via the configuration backend, and may differ in their + configurations. The option data parser can search for an option definition + appropriate for the server for which the option data is specified. + + In a single-server deployment, or when all servers share the same + configuration file information, it is possible to specify option + definitions in the configuration files and option data in the configuration + backend. The server receiving a command to set option data must have a + valid definition in its configuration file, even when it sets option data + for another server. + + It is not supported to specify option definitions in the configuration + backend and the corresponding option data in the server configuration files. + +CB Components +------------- + +To use a MySQL configuration backend you must compile +:ischooklib:`libdhcp_mysql_cb.so` and configure the DHCP servers to load it. +It is compiled when the ``--with-mysql`` configuration switch is used during the Kea build. +The MySQL C client libraries must be installed, as explained in :ref:`dhcp-install-configure`. + +To use a PostgreSQL configuration backend you must compile :ischooklib:`libdhcp_pgsql_cb.so` +and configure the DHCP servers to load it. It is compiled when +the ``--with-pgsql`` configuration switch is used during the Kea build. The PostgreSQL +C client libraries must be installed, as explained in :ref:`dhcp-install-configure`. + +.. note:: + + An existing database schema must be upgraded to the latest schema + required by the particular Kea version using the :iscman:`kea-admin` tool, + as described in :ref:`kea-admin`. + +:ischooklib:`libdhcp_cb_cmds.so` provides a complete set of commands to manage the +servers' configuration information within the database. This library can +be attached to both DHCPv4 and DHCPv6 server instances. While it is +possible to manage the configuration information without :ischooklib:`libdhcp_cb_cmds.so` +with commonly available tools, such as MySQL Workbench or +the command-line MySQL client, or by directly working with the database; +these avenues are neither recommended nor supported. + +The DHCPv4 and DHCPv6 server-specific configurations of the CB, as well as +the list of supported configuration parameters, can be found in +:ref:`dhcp4-cb` and :ref:`dhcp6-cb`, respectively. + +.. _cb-sharing: + +Configuration Sharing and Server Tags +------------------------------------- + +The configuration database is designed to store configuration information +for multiple Kea servers. Depending on the use case, the entire configuration +may be shared by all servers; parts of the configuration may be shared by +multiple servers and the rest of the configuration may be different for these +servers; or each server may have its own non-shared configuration. + +The configuration elements in the database are associated with the servers +by "server tags." The server tag is an arbitrary string holding the name +of the Kea server instance. The tags of the DHCPv4 and DHCPv6 servers are +independent in the database, i.e. the same server tag can be created for +both the DHCPv4 and the DHCPv6 server. The value is configured +using the ``server-tag`` parameter in the ``Dhcp4`` or ``Dhcp6`` scope. The current +server tag can be checked with the :isccmd:`server-tag-get` command. + +The server definition, which consists of the server tag and the server +description, must be stored in the configuration database prior to creating +the dedicated configuration for that server. In cases when all servers use +the same configuration, e.g. a pair of servers running as High Availability +peers, there is no need to configure the server tags for these +servers in the database. + +Commands which contain the logical server `all` are applied to all servers +connecting to the database. The `all` server cannot be +deleted or modified, and it is not returned among other servers +as a result of the :isccmd:`remote-server4-get-all`, :isccmd:`remote-server6-get-all` commands. + +In most cases, there are no server tags defined in the configuration +database; all connecting servers get the same configuration +regardless of the server tag they use. The server tag that a +particular Kea instance presents to the database to fetch its configuration +is specified in the Kea configuration file, using the +`config-control` map (please refer to the :ref:`dhcp4-cb-json` and +:ref:`dhcp6-cb-json` for details). All Kea instances presenting the same +server tag to the configuration database +are given the same configuration. + +It is the administrator's choice whether +multiple Kea instances use the same server tag or each Kea instance uses +a different server tag. There is no requirement that the instances +running on the same physical or virtual machine use the same server tag. It is +even possible to configure the Kea server without assigning it a server tag. +In such a case the server will be given the configuration specified for `all` +servers. + +To differentiate between different Kea server configurations, a +list of the server tags used by the servers must be stored in the +database. For the DHCPv4 and DHCPv6 servers, it can be done using the +:isccmd:`remote-server4-set` and :isccmd:`remote-server6-set` commands. The +server tags can then be used to associate the configuration information with +the servers. However, it is important to note that some DHCP +configuration elements may be associated with multiple server tags (known +as "shareable" elements), while +other configuration elements may be associated with only one +server tag ("non-shareable" elements). The :ref:`dhcp4-cb` +and :ref:`dhcp6-cb` sections list the DHCP-specific shareable and +non-shareable configuration elements; however, in this section we +briefly explain the differences between them. + +A shareable configuration element is one which has some unique +property identifying it, and which may appear only once in +the database. An example of a shareable DHCP element is a subnet +instance: the subnet is a part of the network topology and we assume +that any particular subnet may have only one definition within this +network. Each subnet has two unique identifiers: the subnet identifier and the +subnet prefix. The subnet identifier is used in Kea to uniquely +identify the subnet within the network and to connect it with other configuration elements, +e.g. in host reservations. Some commands provided by +:ischooklib:`libdhcp_cb_cmds.so` allow the subnet +information to be accessed by either subnet identifier or prefix, and explicitly prohibit +using the server tag to access the subnet. This is because, in +general, the subnet definition is associated with multiple servers +rather than a single server. In fact, it may even be associated +with no servers (unassigned). Still, the unassigned subnet has an +identifier and prefix which can be used to access the subnet. + +A shareable configuration element may be associated with multiple +servers, one server, or no servers. Deletion of the server which is +associated with the shareable element does not cause the deletion of +the shareable element. It merely deletes the association of the +deleted server with the element. + +Unlike a shareable element, a non-shareable element must not be +explicitly associated with more than one server and must not exist +after the server is deleted (must not remain unassigned). A +non-shareable element only exists within the context of the server. +An example of a non-shareable element in DHCP is a global +parameter, e.g. `renew-timer`. The renew timer +is the value to be used by a particular server and only this +server. Other servers may have their respective renew timers +set to the same or different values. The renew timer +parameter has no unique identifier by which it could be +accessed, modified, or otherwise used. Global parameters like +the renew timer can be accessed by the parameter name and the +tag of the server for which they are configured. For example, the +:isccmd:`remote-global-parameter4-get` and +:isccmd:`remote-global-parameter6-get` commands allow +the value of the global parameter to be fetched by the parameter name and +the server name. Getting the global parameter only by its name (without +specifying the server tag) is not possible, because there may be many +global parameters with a given name in the database. + +When the server associated with a non-shareable configuration element +is deleted, the configuration element is automatically deleted from +the database along with the server because the non-shareable element +must be always assigned to a server (or the logical server `all`). + +The terms "shareable" and "non-shareable" only apply to associations +with user-defined servers; all configuration elements associated with +the logical server `all` are by definition shareable. For example: the +`renew-timer` associated with `all` servers is used +by all servers connecting to the database which do not have their specific +renew timers defined. In a special case, when none of the configuration +elements are associated with user-defined servers, the entire +configuration in the database is shareable because all its pieces +belong to `all` servers. + +.. note:: + + Be very careful when associating configuration elements with + different server tags. The configuration backend does not protect + against some possible misconfigurations that may arise from the + wrong server tags' assignments. For example: if a shared + network is assigned to one server and the subnets belonging to this shared network + to another server, the servers will fail upon trying to fetch and + use this configuration. The server fetching the subnets will be + aware that the subnets are associated with the shared network, but + the shared network will not be found by this server since it doesn't + belong to it. In such a case, both the shared network and the subnets + should be assigned to the same set of servers. diff --git a/doc/sphinx/arm/config-templates.rst b/doc/sphinx/arm/config-templates.rst new file mode 100644 index 0000000..caff036 --- /dev/null +++ b/doc/sphinx/arm/config-templates.rst @@ -0,0 +1,74 @@ +.. _config-templates: + +Configuration Templates +======================= + +The following sections include configuration templates for +certain deployment types. The example configuration files are also available in the Kea sources, +in the ``doc/examples`` directory. + +.. include:: template-power-user-home.md + +Some tweaking of these templates may be required to match specific system needs: at a +minimum, the lines highlighted in yellow must be adjusted to match the actual deployment. + +Server1's Control Agent configuration file: + +.. literalinclude:: template-power-user-home-ca-1.conf + :language: javascript + :emphasize-lines: 9, 12 + :linenos: + +Server1's DHCPv4 configuration file: + +.. literalinclude:: template-power-user-home-dhcp4-1.conf + :language: javascript + :emphasize-lines: 25, 79, 84, 124, 136, 151, 155, 158-162, 170-184, 194-203 + :linenos: + +Server2's Control Agent configuration file: + +.. literalinclude:: template-power-user-home-ca-2.conf + :language: javascript + :emphasize-lines: 9, 12 + :linenos: + +Server2's DHCPv4 configuration file: + +.. literalinclude:: template-power-user-home-dhcp4-2.conf + :language: javascript + :emphasize-lines: 25, 79, 84, 124, 136, 151, 155, 158-162, 170-184, 194-203 + :linenos: + +.. include:: template-ha-mt-tls.md + +Some tweaking of these templates may be required to match specific system needs: at a +minimum, the lines highlighted in yellow must be adjusted to match the actual deployment. + +Server1's Control Agent configuration file: + +.. literalinclude:: template-ha-mt-tls-ca-1.conf + :language: javascript + :emphasize-lines: 10, 14, 18, 21, 24, 36 + :linenos: + +Server1's DHCPv4 configuration file: + +.. literalinclude:: template-ha-mt-tls-dhcp4-1.conf + :language: javascript + :emphasize-lines: 25, 38-54, 98, 103, 139-152, 161, 163, 165, 167, 181, 183, 185, 187, 204, 208, 211-215 + :linenos: + +Server2's Control Agent configuration file: + +.. literalinclude:: template-ha-mt-tls-ca-2.conf + :language: javascript + :emphasize-lines: 10, 14, 18, 21, 24, 36 + :linenos: + +Server2's DHCPv4 configuration file: + +.. literalinclude:: template-ha-mt-tls-dhcp4-2.conf + :language: javascript + :emphasize-lines: 25, 38-54, 98, 103, 139-152, 161, 163, 165, 167, 181, 183, 185, 187, 204, 208, 211-215 + :linenos: diff --git a/doc/sphinx/arm/config.rst b/doc/sphinx/arm/config.rst new file mode 100644 index 0000000..46833a3 --- /dev/null +++ b/doc/sphinx/arm/config.rst @@ -0,0 +1,339 @@ +.. _kea-config: + +***************** +Kea Configuration +***************** + +Kea uses JSON structures to represent server configurations. The +following sections describe how the configuration structures are +organized. + +.. _json: + +JSON Configuration +================== + +JSON is the notation used throughout the Kea project. The most obvious +usage is for the configuration file, but JSON is also used for sending +commands over the Management API (see :ref:`ctrl-channel`) and for +communicating between DHCP servers and the DDNS update daemon. + +Typical usage assumes that the servers are started from the command +line, either directly or using a script, e.g. :iscman:`keactrl`. The +configuration file is specified upon startup using the ``-c`` parameter. + +.. _json-format: + +JSON Syntax +----------- + +Configuration files for the DHCPv4, DHCPv6, DDNS, Control Agent, and +NETCONF modules are defined in an extended JSON format. Basic JSON is +defined in `RFC 7159 <https://tools.ietf.org/html/rfc7159>`__ and `ECMA +404 <https://www.ecma-international.org/publications/standards/Ecma-404.htm>`__. +In particular, the only boolean values allowed are true or false (all +lowercase). The capitalized versions (True or False) are not accepted. + +Even though the JSON standard (ECMA 404) does not require JSON objects +(i.e. name/value maps) to have unique entries, Kea implements them +using a C++ STL map with unique entries. Therefore, if there are multiple +values for the same name in an object/map, the last value overwrites previous values. +Since Kea 1.9.0, configuration file parsers raise a syntax error in such cases. + +Kea components use extended JSON with additional features allowed: + +- Shell comments: any text after the hash (#) character is ignored. + +- C comments: any text after the double slashes (//) character is + ignored. + +- Multiline comments: any text between /\* and \*/ is ignored. This + comment can span multiple lines. + +- File inclusion: JSON files can include other JSON files by using a + statement of the form \<?include "file.json"?\>. + +- Extra commas: to remove the inconvenience of errors caused by leftover commas + after making changes to configuration. While parsing, a warning is printed + with the location of the comma to give the user the ability to correct a + potential mistake. + +.. warning:: + + These features are meant to be used in a JSON configuration file. + Their usage in any other way may result in errors. + +The configuration file consists of a single object (often colloquially +called a map) started with a curly bracket. It comprises only one of +the "Dhcp4", "Dhcp6", "DhcpDdns", "Control-agent", or "Netconf" objects. +It is possible to define additional elements but they will be ignored. + +A very simple configuration for DHCPv4 could look like this: + +:: + + # The whole configuration starts here. + { + # DHCPv4 specific configuration starts here. + "Dhcp4": { + "interfaces-config": { + "interfaces": [ "eth0" ], + "dhcp-socket-type": "raw" + }, + "valid-lifetime": 4000, + "renew-timer": 1000, + "rebind-timer": 2000, + "subnet4": [{ + "pools": [ { "pool": "192.0.2.1-192.0.2.200" } ], + "subnet": "192.0.2.0/24", + "id": 1 + }], + + # Now loggers are inside the DHCPv4 object. + "loggers": [{ + "name": "*", + "severity": "DEBUG" + }] + } + + # The whole configuration structure ends here. + } + +More examples are available in the installed ``share/doc/kea/examples`` +directory. + +To avoid repetition of mostly similar structures, examples in the rest +of this guide will showcase only the subset of parameters appropriate +for a given context. For example, when discussing the IPv6 subnets +configuration in DHCPv6, only subnet6 parameters will be mentioned. It +is implied that the remaining elements (the global map that holds Dhcp6) +are present, but they are omitted for clarity. Usually, +locations where extra parameters may appear are denoted by an ellipsis +(...). + +.. _user-context: + +Comments and User Context +------------------------- + +Shell, C, or C++ style comments are all permitted in the JSON configuration file if +the file is used locally. This is convenient and works in simple cases where +the configuration is kept statically using a local file. However, since comments +are not part of JSON syntax, most JSON tools detect them as +errors. Another problem with them is that once Kea loads its configuration, the +shell, C, and C++ style comments are ignored. If commands such as +:isccmd:`config-get` or :isccmd:`config-write` are used, those comments are lost. An example of such +comments was presented in the previous section. + +Historically, to address the problem, Kea code allowed the use of `comment` strings +as valid JSON entities. This had the benefit of being retained through various +operations (such as :isccmd:`config-get`), or allowing processing by JSON tools. An +example JSON comment looks like this: + +:: + + "Dhcp4": { + "subnet4": [{ + "id": 1, + "subnet": "192.0.2.0/24", + "pools": [{ "pool": "192.0.2.10 - 192.0.2.20" }], + "comment": "second floor" + }] + } + +However, the facts that the comment could only be a single line, and that it was not +possible to add any other information in a more structured form, were frustrating. One specific +example was a request to add floor levels and building numbers to subnets. This +was one of the reasons why the concept of user context was introduced. It +allows adding an arbitrary JSON structure to most Kea configuration structures. + +This has a number of benefits compared to earlier approaches. First, it is fully +compatible with JSON tools and Kea commands. Second, it allows storing simple +comment strings, but it can also store much more complex data, such as +multiple lines (as a string array), extra typed data (such as floor numbers being +actual numbers), and more. Third, the data is exposed to hooks, so it is possible +to develop third-party hooks that take advantage of that extra information. An +example user context looks like this: + +:: + + "Dhcp4": { + "subnet4": [{ + "id": 1, + "subnet": "192.0.2.0/24", + "pools": [{ "pool": "192.0.2.10 - 192.0.2.20" }], + "user-context": { + "comment": "second floor", + "floor": 2 + } + }] + } + +User contexts can store an arbitrary data file as long as it has valid JSON +syntax and its top-level element is a map (i.e. the data must be enclosed in +curly brackets). However, some hook libraries may expect specific formatting; +please consult the specific hook library documentation for details. + +In a sense the user-context mechanism has superseded the JSON comment +capabilities; ISC encourages administrators to use user-context instead of +the older mechanisms. To promote this way of storing comments, Kea compared +converts JSON comments to user-context on the fly. + +However, if the configuration uses the old JSON +comment, the :isccmd:`config-get` command returns a slightly modified +configuration. It is not uncommon for a call for :isccmd:`config-set` followed by a +:isccmd:`config-get` to receive a slightly different structure. +The best way to avoid this problem is simply to abandon JSON comments and +use user-context. + +Kea supports user contexts at the following levels: global scope, +interfaces configuration, shared networks, +subnets, client classes, option data and definitions, host +reservations, control socket, DHCP-DDNS, loggers, leases, and server ID. These +are supported in both DHCPv4 and DHCPv6, with the exception of server ID, +which is DHCPv6 only. + +User context can be added and edited in structures supported by commands. + +We encourage Kea users to utilize these functions to store information +used by other systems and custom hooks. + +For example, the :isccmd:`subnet4-update` command can be used to add user context data +to an existing subnet. + +:: + + { + "subnet4": [ { + "id": 1, + "subnet": "10.20.30.0/24", + "user-context": { + "building": "Main", + "floor": 1 + } + } ] + } + +The same can be done with many other commands, like :isccmd:`lease6-add`, etc. + +Kea also uses user context to store non-standard data. +Currently, only :ref:`dhcp4-store-extended-info` uses this feature. + +When enabled, it adds the ISC key in ``user-context`` to differentiate automatically +added content. + +Example of relay information stored in a lease: + +:: + + { + "arguments": { + "client-id": "42:42:42:42:42:42:42:42", + "cltt": 12345678, + "fqdn-fwd": false, + "fqdn-rev": true, + "hostname": "myhost.example.com.", + "hw-address": "08:08:08:08:08:08", + "ip-address": "192.0.2.1", + "state": 0, + "subnet-id": 44, + "valid-lft": 3600, + "user-context": { + "ISC": { + "relays": [ + { + "hop": 2, + "link": "2001:db8::1", + "peer": "2001:db8::2" + }, + { + "hop": 1, + "link": "2001:db8::3", + "options": "0x00C800080102030405060708", + "peer": "2001:db8::4" + }] + } + } + } + } + + +User context can store configuration for multiple hooks and comments at once. + +For a discussion about user context used in hooks, see :ref:`user-context-hooks`. + + +Simplified Notation +------------------- + +It is sometimes convenient to refer to a specific element in the +configuration hierarchy. Each hierarchy level is separated by a slash. +If there is an array, a specific instance within that array is +referenced by a number in square brackets (with numbering starting at +zero). For example, in the above configuration the valid-lifetime in the +Dhcp4 component can be referred to as Dhcp4/valid-lifetime, and the pool +in the first subnet defined in the DHCPv4 configuration as +Dhcp4/subnet4[0]/pool. + + +.. include:: config-backend.rst + + +Configuration Files Inclusion +----------------------------- + +The parser provides the ability to include files. The syntax was chosen +to look similar to how Apache includes PHP scripts in HTML code. This particular +syntax was chosen to emphasize that the include directive is an additional +feature and not a part of JSON syntax. + +The inclusion is implemented as a stack of files. You can use the include directive +in nested includes. Up to ten nesting levels are supported. This arbitrarily chosen +limit is protection against recursive inclusions. + +The include directive has the form: + +:: + + <?include "[PATH]"?> + +The *[PATH]* pattern should be replaced with an absolute path or a path relative to +the current working directory at the time the Kea process was launched. + +To include one file from another, use the following syntax: + +.. code-block:: javascript + + { + "Dhcp6": { + "interfaces-config": { + "interfaces": [ "*" ]}, + "preferred-lifetime": 3000, + "rebind-timer": 2000, + "renew-timer": 1000, + <?include "subnets.json"?> + "valid-lifetime": 4000 + } + } + +where the content of "subnets.json" may be: + +:: + + { + "subnet4": [ + { + "id": 123, + "subnet": "192.0.2.0/24" + }, + { + "id": 234, + "subnet": "192.0.3.0/24" + }, + { + "id": 345, + "subnet": "10.0.0.0/8" + } + ], + ... + } diff --git a/doc/sphinx/arm/congestion-handling.rst b/doc/sphinx/arm/congestion-handling.rst new file mode 100644 index 0000000..68b7913 --- /dev/null +++ b/doc/sphinx/arm/congestion-handling.rst @@ -0,0 +1,129 @@ +.. _congestion-handling: + +******************* +Congestion Handling +******************* + +.. _congestion-handling-background: + +What is Congestion? +=================== + +Congestion occurs when servers are subjected to client queries faster +than those queries can be processed. As a result, the servers begin accumulating +a backlog of pending queries. The longer the high rate of traffic +continues, the farther behind the servers fall. Depending on the client +implementations, those that fail to get leases either give up or simply +continue to retry forever. In the former case, the server may eventually +recover, but the latter case is a vicious cycle from which the server is +unable to escape. + +Congestion typically occurs when there is a network event that causes overly large +numbers of clients to simultaneously need leases, such as recovery after +a network outage. In a well-planned deployment, the number and capacity of servers is +matched to the maximum expected client load. If the load is routinely too +heavy, then the deployment needs to be re-evaluated. + +The goal of congestion handling is to help servers mitigate the peak in +traffic by fulfilling as many of the most relevant requests as possible +until the congestion subsides. + +.. _congestion-handling-solution: + +Configuring Congestion Handling +=============================== + +Congestion handling +offers the ability to configure the server to use a separate thread to +read packets from the interface socket buffers. As the thread reads +packets from the buffers, they are added to an internal packet queue, +and the server's main application thread processes packets from this +queue rather than from the socket buffers. By structuring it this way, a +configurable layer has been introduced which can make decisions on which +packets to process, how to store them, and the order in which they are +processed by the server. + +The default packet queue implementation for both :iscman:`kea-dhcp4` and :iscman:`kea-dhcp6` +is a simple ring buffer. Once it reaches capacity, new packets get added +to the back of the queue by discarding packets from the front of the +queue. Rather than always discarding the newest packets, Kea now always +discards the oldest packets. The capacity of the buffer, i.e. the maximum +number of packets the buffer can contain, is configurable. A reasonable +starting point is to match the capacity to the number of leases +per second a specific installation of Kea can handle. This +figure varies widely depending on the specifics of an individual deployment. + +As there is no one algorithm that can best handle the dynamics of all +sites, and because over time new approaches will evolve, the packet +queue is implemented as a plug-in, which can be replaced by a custom queue +implementation via a hook library. This should make it straightforward +for interested parties to experiment with their own solutions. +(Developers can refer to ``isc::dhcp::PacketQueue`` and +``isc::dhcp::PacketQueueMgr``, described in the +`Kea Developer's Guide <https://reports.kea.isc.org/dev_guide/index.html>`__.) + +Packet queue behavior is configured in both :iscman:`kea-dhcp4` and :iscman:`kea-dhcp6` +servers through an optional, top-level, configuration element, +``dhcp-queue-control``. Omitting this element disables packet queueing: + +:: + + "dhcp-queue-control": { + "enable-queue": true, // true|false + "queue-type": "queue type", + "capacity" : 256 // n packets + } + +where: + +- ``enable-queue`` - enables or disables packet queueing. + When ``true``, the server processes packets from the packet queue, which + is filled by a separate thread. When ``false``, the server processes + packets directly from the socket buffers in the main thread. It is + disabled (``false``) by default. + +- ``queue-type`` - the name of the queue implementation to use. This value + exists so that custom implementations can be registered (via a hook + library) and then selected. There is a default packet queue + implementation that is pre-registered during server start up: + "kea-ring4" for :iscman:`kea-dhcp4` and "kea-ring6" for :iscman:`kea-dhcp6`. + +- ``capacity`` - this is the maximum number of packets the + queue can hold before packets are discarded. The optimal value for + this is extremely site-dependent. The default value is 64 for both + "kea-ring4" and "kea-ring6". + +The following example enables the default packet queue for :iscman:`kea-dhcp4`, +with a queue capacity of 250 packets: + +:: + + "Dhcp4": + { + "dhcp-queue-control": { + "enable-queue": true, + "queue-type": "kea-ring4", + "capacity" : 250 + }, + ... + } + +The following example enables the default packet queue for :iscman:`kea-dhcp6`, +with a queue capacity of 300 packets: + +:: + + "Dhcp6": + { + "dhcp-queue-control": { + "enable-queue": true, + "queue-type": "kea-ring6", + "capacity" : 300 + }, + ... + } + +.. note:: + + Congestion handling is currently incompatible with multi-threading; + when both are enabled, congestion handling is silently disabled. diff --git a/doc/sphinx/arm/ctrl-channel.rst b/doc/sphinx/arm/ctrl-channel.rst new file mode 100644 index 0000000..b6a5cd8 --- /dev/null +++ b/doc/sphinx/arm/ctrl-channel.rst @@ -0,0 +1,906 @@ +.. _ctrl-channel: + +************** +Management API +************** + +A classic approach to daemon configuration assumes that the server's +configuration is stored in configuration files and, when the +configuration is changed, the daemon is restarted. This approach has the +significant disadvantage of introducing periods of downtime when client +traffic is not handled. Another risk is that if the new configuration is +invalid for any reason, the server may refuse to start, which will +further extend the downtime period until the issue is resolved. + +To avoid such problems, the DHCPv4, DHCPv6, and D2 servers in Kea include +support for a mechanism that allows online reconfiguration without +requiring server shutdown. Both servers can be instructed to open +control sockets, which is a communications channel. The server is able +to receive commands on that channel, act on them, and report back +status. + +The DHCPv4, DHCPv6, and D2 servers receive commands over the UNIX domain +sockets. For details on how to configure these sockets, see +:ref:`dhcp4-ctrl-channel` and :ref:`dhcp6-ctrl-channel`. While +it is possible to control the servers directly using UNIX domain sockets, +that requires that the controlling client be running on the same machine +as the server. SSH is usually used to connect remotely to the controlled +machine. + +Network administrators usually prefer using some form of a RESTful API +to control the servers, rather than using UNIX domain sockets directly. +Therefore, Kea includes a component called the Control Agent (CA), which +exposes a RESTful API to the controlling clients and can forward +commands to the respective Kea services over the UNIX domain sockets. +The CA configuration is described in +:ref:`agent-configuration`. + +The HTTP requests received by the CA contain the control commands +encapsulated within HTTP requests. Simply speaking, the CA is +responsible for stripping the HTTP layer from the received commands and +forwarding the commands in a JSON format over the UNIX domain sockets to +the respective services. Because the CA receives commands for all +services, it requires additional "forwarding" information to be included +in the client's messages. This forwarding information is carried within +the ``service`` parameter of the received command. If the ``service`` +parameter is not included, or if the parameter is a blank list, the CA +assumes that the control command is targeted at the CA itself and +attempts to respond. + +Control connections over both HTTP and UNIX domain sockets are guarded +with timeouts. The timeout value is set to 10 seconds and is not +configurable. + +This API can be used by external tools to manage and monitor Kea operation. +An example of such a monitoring tool is ISC's Stork. For details, see +:ref:`stork`. + +.. _ctrl-channel-syntax: + +Data Syntax +=========== + +Communication over the control channel is conducted using JSON +structures. If configured, Kea opens a socket and listens for +incoming connections. A process connecting to this socket is expected to +send JSON commands structured as follows: + +:: + + { + "command": "foo", + "service": [ "dhcp4" ], + "arguments": { + "param1": "value1", + "param2": "value2", + ... + } + } + +The same command sent over the RESTful interface to the CA has the +following structure: + +:: + + POST / HTTP/1.1\r\n + Content-Type: application/json\r\n + Content-Length: 147\r\n\r\n + { + "command": "foo", + "service": [ "dhcp4" ], + "arguments": { + "param1": "value1", + "param2": "value2", + ... + } + } + +The ``command`` parameter contains the name of the command to execute and it +is mandatory. +The ``arguments`` map contains the parameters required to carry out the +given command. The exact content and format of the map are command-specific. + +The ``service`` list contains the servers at which the control command is +targeted. In the example above, the control command is targeted at the +DHCPv4 server. In most cases, the CA simply forwards this command to +the DHCPv4 server for processing via a UNIX domain socket. Sometimes, +the command including a service value may also be processed by the CA, +if the CA is running a hook library which handles such a command for +the given server. As an example, the hook library loaded by the CA may +perform some operations on the database, such as adding host +reservations, modifying leases, etc. An advantage of performing +DHCPv4-specific administrative operations in the CA, rather than +forwarding it to the DHCPv4 server, is the ability to perform these +operations without disrupting the DHCPv4 service, since the DHCPv4 +server does not have to stop processing DHCP messages to apply changes to +the database. Nevertheless, these situations are rather rare; in +most cases, when the ``service`` parameter contains a name of the +service, the commands are simply forwarded by the CA. The forwarded +command includes the ``service`` parameter, but this parameter is ignored +by the receiving server. This parameter is only meaningful to the CA. + +If the command received by the CA does not include a ``service`` +parameter or this list is empty, the CA simply processes this message on +its own. For example, a :isccmd:`config-get` command which includes no service +parameter returns the Control Agent's own configuration. The :isccmd:`config-get` +command with a service value "dhcp4" is forwarded to the DHCPv4 server and +returns the DHCPv4 server's configuration. + +The following list shows the mapping of the values carried within the +``service`` parameter to the servers to which the commands are +forwarded: + +- ``dhcp4`` - the command is forwarded to the :iscman:`kea-dhcp4` server. + +- ``dhcp6`` - the command is forwarded to the :iscman:`kea-dhcp6` server. + +- ``d2`` - the command is forwarded to the :iscman:`kea-dhcp-ddns` server. + +The server processing the incoming command sends a response of the +form: + +:: + + { + "result": 0, // 0|1|2|3|4 + "text": "textual description", + "arguments": { + "argument1": "value1", + "argument2": "value2", + ... + } + } + +The ``result`` value is a status code indicating a result of the command. The +following general status codes are currently supported: + +- ``0`` - the command has been processed successfully. +- ``1`` - a general error or failure has occurred during the command processing. +- ``2`` - the specified command is unsupported by the server receiving it. +- ``3`` - the requested operation has been completed but the requested + resource was not found. This status code is returned when a command + returns no resources or affects no resources. +- ``4`` - the well-formed command has been processed but the requested + changes could not be applied, because they were in conflict with the + server state or its notion of the configuration. + +For example, a well-formed command that requests a subnet that exists +in a server's configuration returns the result 0. If the server encounters +an error condition, it returns 1. If the command asks for an IPv6 subnet, +but was sent to a DHCPv4 server, it returns 2. If the query asks for a +subnet with ``subnet-id`` that has matches, the result is 3. +If the command attempts to update a lease but the specified ``subnet-id`` +does not match the identifier in the server's configuration, the result +is 4. + +Hook libraries can sometimes return additional status codes specific +to their use cases. + +The ``text`` field typically appears when the result is non-zero and +contains a description of the error encountered, but it often also +appears for successful outcomes. The exact text is command-specific, but +in general uses plain English to describe the outcome of the command. +The ``arguments`` map contains additional data values returned by the server +which are specific to the command issued. The map may be present, but that +depends on the specific command. + +.. note:: + + Since Kea 1.9.7, it is possible to put comments in commands as + in the configuration file. For instance: + +:: + + { + "command": "foo", + // service is a list + "service": [ "dhcp4" ], + # command arguments are here. + "arguments": { + "param1": "value1", + ... + /* + "param2": "value2", + ... + */ + } + } + +.. _ctrl-channel-control-agent-command-response-format: + +Control Agent Command Response Format +===================================== + +When sending commands via the Control Agent, it is possible to specify +multiple services at which the command is targeted. CA forwards this +command to each service individually. Thus, the CA response to the +controlling client is always wrapped in an array (JSON list) of +individual responses. For example, the response for a command sent +to one service would be structured as follows: + +:: + + [ + { + "result": 0, // 0|1|2|3|4 + "text": "textual description", + "arguments": { + "argument1": "value1", + "argument2": "value2", + ... + } + } + ] + + +If the command is sent to more than one service, the array would +contain responses from each service, in the order they were requested: + +:: + + [ + { + "result": 0, // 0|1|2|3|4 + "text": "textual description", + "arguments": { + "argument1": "value1", + "argument2": "value2", + ... + } + }, + { + "result": 0, // 0|1|2|3|4 + "text": "textual description", + "arguments": { + "argument1": "value1", + "argument2": "value2", + ... + } + }, + ... + ] + +An exception to this are authentication or authorization errors which cause CA +to reject the command entirely. The response to such an error is formatted +as a single entry (JSON map) as follows: + +:: + + { + "result": 403, + "text": "Forbidden" + } + + +These types of errors are possible on systems configured for either basic +authentication or agents that load :ischooklib:`libca_rbac.so`. + +.. _ctrl-channel-client: + +Using the Control Channel +========================= + +The easiest way to start interacting with the control API is to use +common UNIX/Linux tools such as ``socat`` and ``curl``. + +In order to control the given Kea service via a UNIX domain socket, use +``socat`` in interactive mode as follows: + +.. code-block:: console + + $ socat UNIX:/path/to/the/kea/socket - + +or in batch mode, include the "ignoreeof" option as shown below to +ensure ``socat`` waits long enough for the server to respond: + +.. code-block:: console + + $ echo "{ some command...}" | socat UNIX:/path/to/the/kea/socket -,ignoreeof + +where ``/path/to/the/kea/socket`` is the path specified in the +``Dhcp4/control-socket/socket-name`` parameter in the Kea configuration +file. Text passed to ``socat`` is sent to Kea and the responses received +from Kea are printed to standard output. This approach communicates with +the specific server directly and bypasses the Control Agent. + +It is also easy to open a UNIX socket programmatically. An example of a +simple client written in C is available in the Kea Developer's Guide, in +the Control Channel Overview chapter, in the +`Using Control Channel <https://reports.kea.isc.org/dev_guide/d2/d96/ctrlSocket.html#ctrlSocketClient>`__ +section. + +To use Kea's RESTful API with ``curl``, use the following: + +.. code-block:: console + + $ curl -X POST -H "Content-Type: application/json" -d '{ "command": "config-get", "service": [ "dhcp4" ] }' http://ca.example.org:8000/ + +This assumes that the Control Agent is running on host +``ca.example.org`` and is running the RESTful service on port 8000. + +.. _commands-common: + +Commands Supported by Both the DHCPv4 and DHCPv6 Servers +======================================================== + +.. isccmd:: build-report +.. _command-build-report: + +The ``build-report`` Command +---------------------------- + +The :isccmd:`build-report` command returns on the control channel what the +command line ``-W`` argument displays, i.e. the embedded content of the +``config.report`` file. This command does not take any parameters. + +:: + + { + "command": "build-report" + } + +.. isccmd:: config-get +.. _command-config-get: + +The ``config-get`` Command +-------------------------- + +The :isccmd:`config-get` command retrieves the current configuration used by the +server. This command does not take any parameters. The configuration +returned is roughly equal to the configuration that was loaded using the +``-c`` command-line option during server start-up, or was later set using the +:isccmd:`config-set` command. However, there may be certain differences, as +comments are not retained. If the original configuration used file +inclusion, the returned configuration includes all parameters from +all included files. Starting with 2.4.0, the successful response also +contains a SHA-256 digest that can be used to easily determine if a +configuration has changed or not. + +.. warning:: + + The returned configuration is not redacted, i.e. it + contains database passwords in plain text, if those were specified in the + original configuration. Care should be taken not to expose the command + channel to unprivileged users. + +An example command invocation looks like this: + +:: + + { + "command": "config-get" + } + +.. isccmd:: config-hash-get +.. _command-config-hash-get: + +The ``config-hash-get`` Command +------------------------------- + +The ``config-hash-get`` command retrieves the SHA-256 hash of the current +configuration used by the server. This command does not take any parameters. +The returned hash can be used to detect configuration changes. + +An example command invocation looks like this: + +:: + + { + "command": "config-hash-get" + } + +And the server's response: + +:: + + { + "result": 0, + "arguments": { + "hash": "5C3C90EF7035249E2FF74D003C19F34EE0B83A3D329E741B52B2EF95A2C9CC5C" + } + } + +Starting with 2.4.0, also ``config-set`` and ``config-get`` return the SHA-256 hash +of the new or current configuration. This may be used to later determine if a configuration +has changed or not. + +.. isccmd:: config-reload +.. _command-config-reload: + +The ``config-reload`` Command +----------------------------- + +The :isccmd:`config-reload` command instructs Kea to load again the +configuration file that was used previously. This operation is useful if +the configuration file has been changed by some external source; for +example, a system administrator can tweak the configuration file and use this +command to force Kea pick up the changes. + +Caution should be taken when mixing this with the :isccmd:`config-set` command. Kea +remembers the location of the configuration file it was started with, +and this configuration can be significantly changed using the :isccmd:`config-set` +command. When :isccmd:`config-reload` is issued after :isccmd:`config-set`, Kea attempts +to reload its original configuration from the file, possibly losing all +changes introduced using :isccmd:`config-set` or other commands. + +The :isccmd:`config-reload` command does not take any parameters. An example command +invocation looks like this: + +:: + + { + "command": "config-reload" + } + +If the configuration file is incorrect, reloading it can raise an error +which leaves the server in an unusable state. See :ref:`command-config-set` +to learn how to recover from a non-working server. + +.. isccmd:: config-test +.. _command-config-test: + +The ``config-test`` Command +--------------------------- + +The :isccmd:`config-test` command instructs the server to check whether the new +configuration supplied in the command's arguments can be loaded. The +supplied configuration is expected to be the full configuration for the +target server, along with an optional logger configuration. The configuration +is sanity-checked to the extent possible without the server actually +attempting to load it; it is possible for a configuration which successfully +passes this command to still fail in the :isccmd:`config-set` command or at launch +time. The structure of the command is as follows: + +:: + + { + "command": "config-test", + "arguments": { + "<server>": { + } + } + } + +where <server> is the configuration element name for a given server, such +as "Dhcp4" or "Dhcp6". For example: + +:: + + { + "command": "config-test", + "arguments": { + "Dhcp6": { + ... + } + } + } + +The server's response contains a numeric code, ``result`` (0 for +success, non-zero on failure), and a string, ``text``, describing the +outcome: + +:: + + {"result": 0, "text": "Configuration seems sane..." } + + or + + {"result": 1, "text": "unsupported parameter: BOGUS (<string>:16:26)" } + +.. isccmd:: config-write +.. _command-config-write: + +The ``config-write`` Command +---------------------------- + +The :isccmd:`config-write` command instructs the Kea server to write its current +configuration to a file on disk. It takes one optional argument, called +"filename", that specifies the name of the file to write the +configuration to. If not specified, the name used when starting Kea +(passed as a ``-c`` argument) is used. If a relative path is specified, +Kea writes its files only in the directory where it is running. + +An example command invocation looks like this: + +:: + + { + "command": "config-write", + "arguments": { + "filename": "config-modified-2017-03-15.json" + } + } + +.. isccmd:: leases-reclaim +.. _command-leases-reclaim: + +The ``leases-reclaim`` Command +------------------------------ + +The :isccmd:`leases-reclaim` command instructs the server to reclaim all expired +leases immediately. The command has the following JSON syntax: + +:: + + { + "command": "leases-reclaim", + "arguments": { + "remove": true + } + } + +The ``remove`` boolean parameter is mandatory and indicates whether the +reclaimed leases should be removed from the lease database (if ``true``), or +left in the ``expired-reclaimed`` state (if ``false``). The latter facilitates +lease affinity, i.e. the ability to re-assign an expired lease to a +returning client that previously used that lease. See :ref:`lease-affinity` +for details. Also, see :ref:`lease-reclamation` for general +information about the processing of expired leases (lease reclamation). + +.. isccmd:: libreload +.. _command-libreload: + +The ``libreload`` Command +------------------------- + +This command is now deprecated and will be removed in future Kea versions. + +The :isccmd:`libreload` command first unloads and then loads all currently +loaded hook libraries. This is primarily intended to allow one or more +hook libraries to be replaced with newer versions, without requiring Kea +servers to be reconfigured or restarted. The hook libraries +are passed the same parameter values (if any) that were passed when they +originally loaded. + +:: + + { + "command": "libreload", + "arguments": { } + } + +The server responds with a result of either 0, indicating success, +or 1, indicating failure. + +.. isccmd:: list-commands +.. _command-list-commands: + +The ``list-commands`` Command +----------------------------- + +The :isccmd:`list-commands` command retrieves a list of all commands supported +by the server. It does not take any arguments. An example command may +look like this: + +:: + + { + "command": "list-commands", + "arguments": { } + } + +The server responds with a list of all supported commands. The arguments +element is a list of strings, each of which conveys one supported +command. + +.. isccmd:: config-set +.. _command-config-set: + +The ``config-set`` Command +-------------------------- + +The :isccmd:`config-set` command instructs the server to replace its current +configuration with the new configuration supplied in the command's +arguments. The supplied configuration is expected to be the full +configuration for the target server, along with an optional logger +configuration. While optional, the logger configuration is highly +recommended, as without it the server reverts to its default logging +configuration. The structure of the command is as follows: + +:: + + { + "command": "config-set", + "arguments": { + "<server>": { + } + } + } + +where <server> is the configuration element name for a given server, such +as "Dhcp4" or "Dhcp6". For example: + +:: + + { + "command": "config-set", + "arguments": { + "Dhcp6": { + ... + } + } + } + +If the new configuration proves to be invalid, the server retains its +current configuration; however, in some cases a fatal error message is logged +indicating that the server is no longer providing any service: a working +configuration must be loaded as soon as possible. If the control channel +is dead, the configuration file can still be reloaded using the ``SIGHUP`` +signal. If that is unsuccessful, restart the server. + +Please note that the new configuration is +retained in memory only; if the server is restarted or a configuration +reload is triggered via a signal, the server uses the configuration +stored in its configuration file. The server's response contains a +numeric code, ``result`` (0 for success, non-zero on failure), and a +string, ``text``, describing the outcome: + +:: + + {"result": 0, "text": "Configuration successful." } + + or + + {"result": 1, "text": "unsupported parameter: BOGUS (<string>:16:26)" } + +Starting with 2.4.0, the successful response from a DHCPv4, DHCPv6, or DHCP-DDNS daemons +also contain a SHA-256 digest of the newly set configuration. The digest can be used to easily +determine if a configuration has changed or not. + +.. isccmd:: shutdown +.. _command-shutdown: + +The ``shutdown`` Command +------------------------ + +The :isccmd:`shutdown` command instructs the server to initiate its shutdown +procedure. It is the equivalent of sending a ``SIGTERM`` signal to the +process. This command does not take any arguments. An example command +may look like this: + +:: + + { + "command": "shutdown", + "arguments": { + "exit-value": 3 + } + } + +The server responds with a confirmation that the shutdown procedure has +been initiated. The optional parameter, ``exit-value``, specifies the +numeric value with which the server process exits to the system. +The default value is zero. + +The DDNS daemon supports an extra parameter, ``type``, which controls the way +the process cleans up on exit. The supported shutdown types are: + + - "normal" - stops the queue manager and finishes all current transactions + before exiting. This is the default. + + - "drain_first" - stops the queue manager but continues processing requests + from the queue until it is empty. + + - "now" - exits immediately. + +An example command may look like this: + +:: + + { + "command": "shutdown", + "arguments": { + "exit-value": 3, + "type": "drain_first" + } + } + +.. isccmd:: dhcp-disable +.. _command-dhcp-disable: + +The ``dhcp-disable`` Command +---------------------------- + +The :isccmd:`dhcp-disable` command globally disables the DHCP service. The +server continues to operate, but it drops all received DHCP messages. +This command is useful when the server's maintenance requires that the +server temporarily stop allocating new leases and renew existing leases. +It is also useful in failover-like configurations during a +synchronization of the lease databases at startup, or recovery after a +failure. The optional parameter ``max-period`` specifies the time in +seconds after which the DHCP service should be automatically re-enabled, +if the :isccmd:`dhcp-enable` command is not sent before this time elapses. + +Since Kea 1.9.4, there is an additional ``origin`` parameter that specifies the +command source. A server administrator should typically omit this parameter +because the default value "user" indicates that the administrator sent the +command. This command can also be sent by the partner server running HA hooks +library. In that case, the partner server sets the parameter to a unique +integer identifier of an HA service. The integer values are reserved for the +communication between HA partners and should not be specified in the +administrator's commands, as it may interfere with HA operation. The +administrator should either omit this parameter or set it to "user". + +:: + + { + "command": "dhcp-disable", + "arguments": { + "max-period": 20, + "origin": "user" + } + } + +.. isccmd:: dhcp-enable +.. _command-dhcp-enable: + +The ``dhcp-enable`` Command +--------------------------- + +The :isccmd:`dhcp-enable` command globally enables the DHCP service. + +Since Kea 1.9.4, there is an additional ``origin`` parameter that specifies the +command source. A server administrator should typically omit this parameter +because the default value "user" indicates that the administrator sent the +command. This command can also be sent by the partner server running the HA hook +library. In that case, the partner server sets the parameter to a unique +integer identifier of an HA service. The integer values are reserved for the +communication between HA partners and should not be specified in the +administrator's commands, as it may interfere with HA operation. The +administrator should either omit this parameter or set it to +"user". + +:: + + { + "command": "dhcp-enable", + "arguments": { + "origin": "user" + } + } + +.. isccmd:: status-get +.. _command-status-get: + +The ``status-get`` Command +-------------------------- + +The :isccmd:`status-get` command returns the server's runtime information: + + - ``pid``: the process ID. + + - ``uptime``: the number of seconds since the start of the server. + + - ``reload``: the number of seconds since the last configuration (re)load. + + - ``high-availability``: HA-specific status information about the DHCP servers + configured to use the HA hook library: + + * ``local``: the state, the role (primary, + secondary, ...), and the scopes (i.e. what the server is actually + processing) of the local server. + + * ``remote``: the remote server's last known state, its served + HA scopes, and the role of the remote server in the HA relationship. + + - ``multi-threading-enabled``: a flag indicating whether multi-threading is enabled. + + - ``thread-pool-size``: the number of DHCP service threads. + + - ``packet-queue-size``: the maximum size of the packet queue. There is one queue, + regardless of the number of running threads. + + - ``packet-queue-statistics``: the average queue size for the last 10, 100, and 1000 + packets, using an approach similar to the UNIX ``top`` command. + The average queue size for the last 10 packets can be considered an + instantaneous value, while the average for the last 1000 packets shows + a longer-term trend. + +The ``high-availability`` information is returned only when the command is +sent to the DHCP servers in an HA setup. This parameter is +never returned when the :isccmd:`status-get` command is sent to the +Control Agent or DDNS daemon. + +The ``thread-pool-size``, ``packet-queue-size`` and +``packet-queue-statistics`` parameters are returned only when the +command is sent to DHCP servers with multi-threading enabled. These +three parameters and ``multi-threading-enabled`` are never returned when +the :isccmd:`status-get` command is sent to the Control Agent or DDNS daemon. + +To learn more about the HA status information returned by the +:isccmd:`status-get` command, please refer to the :ref:`command-ha-status-get` +section. + + +.. isccmd:: server-tag-get +.. _command-server-tag-get: + +The ``server-tag-get`` Command: +------------------------------- + +The :isccmd:`server-tag-get` command returns the configured server tag of +the DHCPv4 or DHCPv6 server (:ref:`cb-sharing` explains the server tag concept). + +.. isccmd:: config-backend-pull +.. _command-config-backend-pull: + +The ``config-backend-pull`` Command: +------------------------------------ + +The :isccmd:`config-backend-pull` command triggers the polling of configuration backends +(which must be configured for this command to have an effect), +explained in :ref:`dhcp4-cb-json`. + +.. isccmd:: version-get +.. _command-version-get: + +The ``version-get`` Command +--------------------------- + +The :isccmd:`version-get` command returns extended information about the Kea +version. It is the same information available via the ``-V`` +command-line argument. This command does not take any parameters. + +:: + + { + "command": "version-get" + } + +Commands Supported by the D2 Server +=================================== + +The D2 server supports only a subset of the DHCPv4/DHCPv6 server commands: + +- :isccmd:`build-report` + +- :isccmd:`config-get` + +- :isccmd:`config-hash-get` + +- :isccmd:`config-reload` + +- :isccmd:`config-set` + +- :isccmd:`config-test` + +- :isccmd:`config-write` + +- :isccmd:`list-commands` + +- :isccmd:`shutdown` + +- :isccmd:`status-get` + +- :isccmd:`version-get` + +.. _agent-commands: + +Commands Supported by the Control Agent +======================================= + +The following commands, listed in :ref:`commands-common`, are also supported by the +Control Agent; when the ``service`` parameter is blank, the +commands are handled by the CA and they relate to the CA process itself: + +- :isccmd:`build-report` + +- :isccmd:`config-get` + +- :isccmd:`config-hash-get` + +- :isccmd:`config-reload` + +- :isccmd:`config-set` + +- :isccmd:`config-test` + +- :isccmd:`config-write` + +- :isccmd:`list-commands` + +- :isccmd:`shutdown` + +- :isccmd:`status-get` + +- :isccmd:`version-get` diff --git a/doc/sphinx/arm/database-connectivity.rst b/doc/sphinx/arm/database-connectivity.rst new file mode 100644 index 0000000..8d61d64 --- /dev/null +++ b/doc/sphinx/arm/database-connectivity.rst @@ -0,0 +1,104 @@ +.. _database-connectivity: + +********************* +Database Connectivity +********************* + +The Kea servers (:iscman:`kea-dhcp4` and :iscman:`kea-dhcp6`) can be configured to use a variety of +database backends for leases, hosts, and configuration. They can be +configured to support automatic recovery when connectivity is lost, via +the ``on-fail`` and ``retry-on-startup`` parameters. +(The ``reconnect-wait-time`` and ``max-reconnect-tries`` parameters are +described in :ref:`database-configuration4` and :ref:`database-configuration6`.) + +It is important to understand how and when automatic recovery comes into play. +Automatic recovery, when configured, only operates after a successful startup +or reconfiguration during which connectivity to all backends has been +successfully established. + +During server startup, the inability to connect to any of the configured +backends is considered fatal only if ``retry-on-startup`` is set to ``false`` +(the default). A fatal error is logged and the server exits, based on the idea +that the configuration should be valid at startup. Exiting to the operating +system allows nanny scripts to detect the problem. +If ``retry-on-startup`` is set to ``true``, the server will start reconnection +attempts even at server startup or on reconfigure events, and will honor the +action specified in the ``on-fail`` parameter. +Database connection retries are not attempted on startup if the +:ischooklib:`libdhcp_limits.so` is loaded because the hook library requires a +valid connection to the database to check if JSON format is supported and to +recount class limits. + +During dynamic reconfiguration, all backends are disconnected and then +reconnected using the new configuration. If connectivity to any of the +backends cannot be established, the server logs a fatal error but remains +up. It is able to process commands but does not serve clients. This +allows the configuration to be corrected via the :isccmd:`config-set` or +``remote-*`` commands, if required. + +During normal operations, if connectivity to any of the backends is lost and +automatic recovery for that backend is enabled, the server disconnects from the +respective backend and then attempts to reconnect. During the recovery process, +the server ceases to serve clients according to the ``on-fail`` configured +option but continues to respond to commands. + +The ``on-fail`` parameter configures the actions the server should take when a +connection is lost. It can have one of the following values: + +- ``stop-retry-exit`` - indicates that the server should stop the service + while it tries to recover the connection, and exit if recovery is not + successful after ``max-reconnect-tries``. + +- ``serve-retry-exit`` - indicates that the server should not stop the + service while it tries to recover the connection, and exit if recovery is not + successful after ``max-reconnect-tries``. + +- ``serve-retry-continue`` - indicates that the server should not stop the + service while it tries to recover the connection, and not exit if recovery is + not successful after ``max-reconnect-tries``. + +If connectivity to all backends is restored, the server returns to normal +operations. If the connection cannot be restored and the server is configured +to exit, it issues a fatal error before shutdown. + +For Kea DHCP servers to work with database backends, the schema has to be +created and has to have the version specific to the version of the running Kea +server. If the version check fails on a database backend that is not configured +as readonly, Kea attempts to initialize the schema. + +.. note:: + + Schema upgrades are not attempted to not accidentally remove the + opportunity for prior administrative actions that users may be interested in, + like, for example, backing up the database or temporarily shutting off running + Kea servers that are currently operating on the database. + +The connection to the database server can optionally be protected by TLS. +Corresponding database configuration parameters for Kea servers are: + +- The ``trust-anchor`` specifies the Certification Authority file name or + directory path. + +- The ``cert-file`` specifies the client certificate file name. + +- The ``key-file`` specifies the private key file name. + +- The ``cipher-list`` specifies the list of TLS ciphers (the syntax of + the content of this parameter is described in the OpenSSL ciphers + manual). + +These parameters are similar to the parameters of the secure connections +with the agent but are interpreted by different backends using database +configurations too. + +Currently the support for each database is: + +- MySQL supports the whole set, additional configuration must be done + in the MySQL local setup, for instance certificate revocation list, + choice of a specific TLS version, mutual authentication, etc. + When a TLS connection was required but the actual connection is in + clear text an error log is emitted. + +- PostgreSQL only uses the configuration to enable the SSL/TLS support + in the client library (libpq). Anything else must be done in the + PostgreSQL local configuration. diff --git a/doc/sphinx/arm/ddns.rst b/doc/sphinx/arm/ddns.rst new file mode 100644 index 0000000..9b3464e --- /dev/null +++ b/doc/sphinx/arm/ddns.rst @@ -0,0 +1,1027 @@ +.. _dhcp-ddns-server: + +******************** +The DHCP-DDNS Server +******************** + +.. _dhcp-ddns-overview: + +Overview +======== + +The DHCP-DDNS Server (:iscman:`kea-dhcp-ddns`, known informally as D2) conducts +the client side of the Dynamic DNS protocol (DDNS, defined in `RFC +2136 <https://tools.ietf.org/html/rfc2136>`__) on behalf of the DHCPv4 +and DHCPv6 servers (:iscman:`kea-dhcp4` and :iscman:`kea-dhcp6` respectively). +The DHCP servers construct DDNS update requests, known as NameChangeRequests +(NCRs), based on DHCP lease change events and then post them to D2. D2 +attempts to match each request to the appropriate DNS server(s) and +carries out the necessary conversation with those servers to update the +DNS data. + +For the ability to generate host names procedurally, based on an expression, and +for the ability to skip DDNS updates on a per-client basis, or fine-tuning +various DNS update aspects, the :iscman:`kea-dhcp4` and :iscman:`kea-dhcp6` can +load the premium hook library `libdhcp_ddns_tuning.so` which is available from +ISC. Please refer to :ref:`hooks-ddns-tuning` documentation for the +configuration options. + +.. _dhcp-ddns-dns-server-selection: + +DNS Server Selection +-------------------- + +To match a request to the appropriate DNS servers, D2 must have +a catalog of servers from which to select. In fact, D2 has two such +catalogs, one for forward DNS and one for reverse DNS; these catalogs +are referred to as "DDNS domain lists." Each list consists of one or more +named DDNS domains. Further, each DDNS domain has a list of one or more +DNS servers that publish the DNS data for that domain. + +When conducting forward-domain matching, D2 compares the fully qualified +domain name (FQDN) in the request against the name of each forward DDNS +domain in its catalog. The domain whose name matches the longest portion +of the FQDN is considered the best match. For example, if the FQDN is +"myhost.sample.example.com.", and there are two forward domains in the +catalog, "sample.example.com." and "example.com.", the former is +regarded as the best match. In some cases, it may not be possible to +find a suitable match. Given the same two forward domains there would be +no match for the FQDN "bogus.net", so the request would be rejected. +Finally, if there are no forward DDNS domains defined, D2 simply +disregards the forward-update portion of requests. + +When conducting reverse-domain matching, D2 constructs a reverse FQDN +from the lease address in the request and compares that against the name +of each reverse DDNS domain. Again, the domain whose name matches the +longest portion of the FQDN is considered the best match. For instance, +if the lease address is "172.16.1.40" and there are two reverse domains +in the catalog, "1.16.172.in-addr.arpa." and "16.172.in-addr.arpa", the +former is the best match. As with forward matching, D2 may not find a +suitable match. Given the same two domains, there would be no match for +the lease address, "192.168.1.50", and the request would be rejected. +As with forward-domain matching, if there are no reverse DDNS domains defined, D2 simply +disregards the reverse-update portion of requests. + +.. _dhcp-ddns-conflict-resolution: + +Conflict Resolution +------------------- + +D2 implements the conflict resolution strategy prescribed by `RFC +4703 <https://tools.ietf.org/html/rfc4703>`__. Conflict resolution is +intended to prevent different clients from mapping to the same FQDN at +the same time. To make this possible, the RFC requires that forward DNS +entries for a given FQDN must be accompanied by a DHCID resource record +(RR). This record contains a client identifier that uniquely identifies +the client to whom the name belongs. Furthermore, any DNS updater that +wishes to update or remove existing forward entries for an FQDN may only +do so if their client matches that of the DHCID RR. + +In other words, the DHCID RR maps an FQDN to the client to whom it +belongs, and thereafter changes to that mapping can only be done by +or at the behest of that client. + +Conflict resolution can be indirectly enabled or disabled via +the configuration parameter ``ddns-use-conflict-resolution``, supported +by both :iscman:`kea-dhcp4` and :iscman:`kea-dhcp6`. These servers use this parameter to +set a flag within each NameChangeRequest they send that tells D2 +whether conflict resolution should be employed for that request. +By default, conflict resolution is enabled. For more details, please refer +to discussions of ``ddns-use-conflict-resolution`` in :ref:`dhcp4-ddns-config` and :ref:`dhcp6-ddns-config`. + +When conflict resolution is disabled, D2 still adds DHCID RRs but does +not use them to enforce client ownership of DNS entries. Disabling it should +only be used after careful consideration. + +.. _dhcp-ddns-dual-stack: + +Dual-Stack Environments +----------------------- + +`RFC 4703, section +5.2, <https://tools.ietf.org/html/rfc4703#section-5.2>`__ describes +issues that may arise with dual-stack clients. These are clients that +wish to have both IPv4 and IPv6 mappings for the same FQDN. +To work properly, clients must embed their IPv6 DUID +within their IPv4 client identifier option, as described in `RFC +4361 <https://tools.ietf.org/html/rfc4361>`__. In this way, DNS updates +for both IPv4 and IPv6 can be managed under the same DHCID RR. This feature +is supported by Kea beginning with release 2.1.2. + +.. _dhcp-ddns-server-start-stop: + +Starting and Stopping the DHCP-DDNS Server +========================================== + +:iscman:`kea-dhcp-ddns` is the Kea DHCP-DDNS server and, due to the nature of +DDNS, it runs alongside either the DHCPv4 or DHCPv6 component (or both). +Like other parts of Kea, it is a separate binary that can be run on its +own or through :iscman:`keactrl` (see :ref:`keactrl`). In normal +operation, controlling :iscman:`kea-dhcp-ddns` with :iscman:`keactrl` is +recommended; however, it is also possible to run the DHCP-DDNS server +directly. It accepts the following command-line switches: + +- ``-c file`` - specifies the configuration file. This is the only + mandatory switch. + +- ``-d`` - specifies whether server logging should be switched to + debug/verbose mode. In verbose mode, the logging severity and + debuglevel specified in the configuration file are ignored and + "debug" severity and the maximum debuglevel (99) are assumed. The + flag is convenient for temporarily switching the server into maximum + verbosity, e.g. when debugging. + +- ``-v`` - displays the Kea version and exits. + +- ``-W`` - displays the Kea configuration report and exits. The report + is a copy of the ``config.report`` file produced by ``./configure``; + it is embedded in the executable binary. + +- ``-t file`` - specifies the configuration file to be tested. + :iscman:`kea-dhcp-ddns` attempts to load it and conducts sanity checks. + Certain checks are possible only while running the actual + server. The actual status is reported with an exit code (0 = + configuration looks okay, 1 = error encountered). Kea prints out log + messages to standard output and errors to standard error when testing + the configuration. + + The contents of the ``config.report`` file may also be accessed by examining + certain libraries in the installation tree or in the source tree. + + .. code-block:: shell + + # from installation using libkea-process.so + $ strings ${prefix}/lib/libkea-process.so | sed -n 's/;;;; //p' + + # from sources using libkea-process.so + $ strings src/lib/process/.libs/libkea-process.so | sed -n 's/;;;; //p' + + # from sources using libkea-process.a + $ strings src/lib/process/.libs/libkea-process.a | sed -n 's/;;;; //p' + + # from sources using libcfgrpt.a + $ strings src/lib/process/cfgrpt/.libs/libcfgrpt.a | sed -n 's/;;;; //p' + +Upon startup, the module loads its configuration and begins listening +for NCRs based on that configuration. + +During startup, the server attempts to create a PID file of the form: +``[runstatedir]/[conf name].kea-dhcp-ddns.pid`` where: + +- ``runstatedir`` - is the value as passed into the build configure + script; it defaults to "/usr/local/var/run". Note that this value may be + overridden at runtime by setting the environment variable + ``KEA_PIDFILE_DIR``. This is intended primarily for testing purposes. + +- ``conf name`` - is the configuration file name used to start the server, + minus all preceding paths and the file extension. For example, given + a pathname of "/usr/local/etc/kea/myconf.txt", the portion used would + be "myconf". + +If the file already exists and contains the PID of a live process, the +server issues a ``DHCP_DDNS_ALREADY_RUNNING`` log message and exits. It +is possible, though unlikely, that the file is a remnant of a system +crash and the process to which the PID belongs is unrelated to Kea. In +such a case it is necessary to manually delete the PID file. + +.. _d2-configuration: + +Configuring the DHCP-DDNS Server +================================ + +Before starting the :iscman:`kea-dhcp-ddns` module for the first time, a +configuration file must be created. The following default configuration +is a template that can be customized to individual requirements. + +:: + + "DhcpDdns": { + "ip-address": "127.0.0.1", + "port": 53001, + "dns-server-timeout": 500, + "ncr-protocol": "UDP", + "ncr-format": "JSON", + "tsig-keys": [ ], + "forward-ddns": { + "ddns-domains": [ ] + }, + "reverse-ddns": { + "ddns-domains": [ ] + } + } + +The configuration can be divided into the following sections, each of +which is described below: + +- *Global Server Parameters* - define values which control connectivity and + global server behavior. + +- *Control Socket* - defines the Control Socket type and name. + +- *TSIG Key Info* - defines the TSIG keys used for secure traffic with + DNS servers. + +- *Forward DDNS* - defines the catalog of forward DDNS domains. + +- *Reverse DDNS* - defines the catalog of reverse DDNS domains. + +.. _d2-server-parameter-config: + +Global Server Parameters +------------------------ + +- ``ip-address`` - the IP address on which D2 listens for requests. The + default is the local loopback interface at address 127.0.0.1. + Either an IPv4 or IPv6 address may be specified. + +- ``port`` - the port on which D2 listens for requests. The default value + is 53001. + +- ``dns-server-timeout`` - the maximum amount of time, in milliseconds, + that D2 will wait for a response from a DNS server to a single DNS + update message. The default is 500 ms. + +- ``ncr-protocol`` - the socket protocol to use when sending requests to + D2. Currently only UDP is supported. + +- ``ncr-format`` - the packet format to use when sending requests to D2. + Currently only JSON format is supported. + +D2 must listen for change requests on a known address and port. By +default it listens at 127.0.0.1 on port 53001. The following example +illustrates how to change D2's global parameters so it will listen at +192.168.1.10 port 900: + +:: + + "DhcpDdns": { + "ip-address": "192.168.1.10", + "port": 900, + ... + } + +.. warning:: + + It is possible for a malicious attacker to send bogus + NameChangeRequests to the DHCP-DDNS server. Addresses other than the + IPv4 or IPv6 loopback addresses (127.0.0.1 or ::1) should only be + used for testing purposes; note that local users may still + communicate with the DHCP-DDNS server. + +.. note:: + + If the ``ip-address`` and ``port`` are changed, the corresponding values in + the DHCP servers' ``dhcp-ddns`` configuration section must be changed. + +.. _d2-ctrl-channel: + +Management API for the D2 Server +-------------------------------- + +The management API allows the issuing of specific management commands, +such as configuration retrieval or shutdown. For more details, see +:ref:`ctrl-channel`. Currently, the only supported communication +channel type is the UNIX stream socket. By default there are no sockets +open; to instruct Kea to open a socket, the following entry in the +configuration file can be used: + +:: + + "DhcpDdns": { + "control-socket": { + "socket-type": "unix", + "socket-name": "/path/to/the/unix/socket" + }, + ... + } + +The length of the path specified by the ``socket-name`` parameter is +restricted by the maximum length for the UNIX socket name on the +operating system, i.e. the size of the ``sun_path`` field in the +``sockaddr_un`` structure, decreased by 1. This value varies on +different operating systems, between 91 and 107 characters. Typical +values are 107 on Linux and 103 on FreeBSD. + +Communication over the control channel is conducted using JSON structures. +See the `Control Channel section in the Kea Developer's +Guide <https://reports.kea.isc.org/dev_guide/d2/d96/ctrlSocket.html>`__ +for more details. + +The D2 server supports the following operational commands: + +- :isccmd:`build-report` +- :isccmd:`config-get` +- :isccmd:`config-hash-get` +- :isccmd:`config-reload` +- :isccmd:`config-set` +- :isccmd:`config-test` +- :isccmd:`config-write` +- :isccmd:`list-commands` +- :isccmd:`shutdown` +- :isccmd:`status-get` +- :isccmd:`version-get` + +Since Kea version 2.0.0, the D2 server also supports the following +operational commands for statistics: + +- :isccmd:`statistic-get` +- :isccmd:`statistic-get`-all +- :isccmd:`statistic-reset` +- :isccmd:`statistic-reset`-all + +The :isccmd:`shutdown` command supports the extra ``type`` argument, which controls the +way the D2 server cleans up on exit. +The supported shutdown types are: + +- ``normal`` - stops the queue manager and finishes all current transactions + before exiting. This is the default. + +- ``drain_first`` - stops the queue manager but continues processing requests + from the queue until it is empty. + +- ``now`` - exits immediately. + +An example command may look like this: + +:: + + { + "command": "shutdown", + "arguments": { + "exit-value": 3, + "type": "drain_first" + } + } + +.. _d2-tsig-key-list-config: + +TSIG Key List +------------- + +A DDNS protocol exchange can be conducted with or without a transaction +signature, or TSIG (defined +in `RFC 2845 <https://tools.ietf.org/html/rfc2845>`__). This +configuration section allows the administrator to define the set of TSIG +keys that may be used in such exchanges. + +To use TSIG when updating entries in a DNS domain, a key must be defined +in the TSIG key list and referenced by name in that domain's +configuration entry. When D2 matches a change request to a domain, it +checks whether the domain has a TSIG key associated with it. If so, D2 +uses that key to sign DNS update messages sent to and verify +responses received from the domain's DNS server(s). For each TSIG key +required by the DNS servers that D2 is working with, there must be +a corresponding TSIG key in the TSIG key list. + +As one might gather from the name, the ``tsig-key`` section of the D2 +configuration lists the TSIG keys. Each entry describes a TSIG key used +by one or more DNS servers to authenticate requests and sign responses. +Every entry in the list has three parameters: + +- ``name`` - is a unique text label used to identify this key within the + list. This value is used to specify which key (if any) should be used + when updating a specific domain. As long as the name is unique its + content is arbitrary, although for clarity and ease of maintenance it + is recommended that it match the name used on the DNS server(s). This + field cannot be blank. + +- ``algorithm`` - specifies which hashing algorithm should be used with + this key. This value must specify the same algorithm used for the key + on the DNS server(s). The supported algorithms are listed below: + + - HMAC-MD5 + - HMAC-SHA1 + - HMAC-SHA224 + - HMAC-SHA256 + - HMAC-SHA384 + - HMAC-SHA512 + + This value is not case-sensitive. + +- ``digest-bits`` - is used to specify the minimum truncated length in + bits. The default value 0 means truncation is forbidden; non-zero + values must be an integral number of octets, and be greater than both + 80 and half of the full length. (Note that in BIND 9 this parameter + is appended to the algorithm name, after a dash.) + +- ``secret`` - is used to specify the shared secret key code for this + key. This value is case-sensitive and must exactly match the value + specified on the DNS server(s). It is a base64-encoded text value. + +As an example, suppose that a domain D2 will be updating is maintained +by a BIND 9 DNS server, which requires dynamic updates to be secured +with TSIG. Suppose further that the entry for the TSIG key in BIND 9's +named.conf file looks like this: + +:: + + : + key "key.four.example.com." { + algorithm hmac-sha224; + secret "bZEG7Ow8OgAUPfLWV3aAUQ=="; + }; + : + +By default, the TSIG key list is empty: + +:: + + "DhcpDdns": { + "tsig-keys": [ ], + ... + } + +A new key must be added to the list: + +:: + + "DhcpDdns": { + "tsig-keys": [ + { + "name": "key.four.example.com.", + "algorithm": "HMAC-SHA224", + "secret": "bZEG7Ow8OgAUPfLWV3aAUQ==" + } + ], + ... + } + +These steps must be repeated for each TSIG key needed, although the +same TSIG key can be used with more than one domain. + +.. _d2-forward-ddns-config: + +Forward DDNS +------------ + +The forward DDNS section is used to configure D2's forward-update +behavior. Currently it contains a single parameter, the catalog of +forward DDNS domains, which is a list of structures. + +:: + + "DhcpDdns": { + "forward-ddns": { + "ddns-domains": [ ] + }, + ... + } + +By default, this list is empty, which causes the server to ignore +the forward-update portions of requests. + +.. _add-forward-ddns-domain: + +Adding Forward DDNS Domains +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A forward DDNS domain maps a forward DNS zone to a set of DNS servers +which maintain the forward DNS data (i.e. name-to-address mapping) for +that zone. Each zone served needs one forward DDNS domain. +Some or all of the zones may be maintained by the same +servers, but one DDNS domain is still needed for each zone. Remember that +matching a request to the appropriate server(s) is done by zone and a +DDNS domain only defines a single zone. + +This section describes how to add forward DDNS domains; repeat these +steps for each forward DDNS domain desired. Each forward DDNS domain has +the following parameters: + +- ``name`` - this is the fully qualified domain name (or zone) that this DDNS + domain can update. This value is compared against the request FQDN + during forward matching. It must be unique within the catalog. + +- ``key-name`` - if TSIG is used with this domain's servers, this value + should be the name of the key from the TSIG key list. If the + value is blank (the default), TSIG will not be used in DDNS + conversations with this domain's servers. + +- ``dns-servers`` - this is a list of one or more DNS servers which can conduct + the server side of the DDNS protocol for this domain. The servers are + used in a first-to-last preference; in other words, when D2 begins to + process a request for this domain, it will pick the first server in + this list and attempt to communicate with it. If that attempt fails, + D2 will move to the next one in the list and so on, until either it + is successful or the list is exhausted. + +To create a new forward DDNS domain, add a new domain element and set +its parameters: + +:: + + "DhcpDdns": { + "forward-ddns": { + "ddns-domains": [ + { + "name": "other.example.com.", + "key-name": "", + "dns-servers": [ + ] + } + ] + } + } + +It is possible to add a domain without any servers; however, if that +domain matches a request, the request will fail. To make the domain +useful, at least one DNS server must be added to it. + +.. _add-forward-dns-servers: + +Adding Forward DNS Servers +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This section describes how to add DNS servers to a forward DDNS domain. +Repeat these instructions as needed for all the servers in each domain. + +Forward DNS server entries represent actual DNS servers which support +the server side of the DDNS protocol. Each forward DNS server has the +following parameters: + +- ``hostname`` - the resolvable host name of the DNS server; this + parameter is not yet implemented. + +- ``ip-address`` - the IP address at which the server listens for DDNS + requests. This may be either an IPv4 or an IPv6 address. + +- ``port`` - the port on which the server listens for DDNS requests. It + defaults to the standard DNS service port of 53. + +To create a new forward DNS server, a new server element must be added to +the domain and its parameters filled in. If, for example, the service is +running at "172.88.99.10", set the forward DNS server as follows: + +:: + + "DhcpDdns": { + "forward-ddns": { + "ddns-domains": [ + { + "name": "other.example.com.", + "key-name": "", + "dns-servers": [ + { + "ip-address": "172.88.99.10", + "port": 53 + } + ] + } + ] + } + } + +.. note:: + + Since ``hostname`` is not yet supported, the parameter ``ip-address`` + must be set to the address of the DNS server. + +.. _d2-reverse-ddns-config: + +Reverse DDNS +------------ + +The reverse DDNS section is used to configure D2's reverse update +behavior, and the concepts are the same as for the forward DDNS section. +Currently it contains a single parameter, the catalog of reverse DDNS +domains, which is a list of structures. + +:: + + "DhcpDdns": { + "reverse-ddns": { + "ddns-domains": [ ] + }, + ... + } + +By default, this list is empty, which causes the server to ignore +the reverse-update portions of requests. + +.. _add-reverse-ddns-domain: + +Adding Reverse DDNS Domains +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A reverse DDNS domain maps a reverse DNS zone to a set of DNS servers +which maintain the reverse DNS data (address-to-name mapping) for that +zone. Each zone served needs one reverse DDNS domain. +Some or all of the zones may be maintained by the same servers, but +one DDNS domain entry is needed for each zone. Remember that +matching a request to the appropriate server(s) is done by zone and a +DDNS domain only defines a single zone. + +This section describes how to add reverse DDNS domains; repeat these +steps for each reverse DDNS domain desired. Each reverse DDNS domain has +the following parameters: + +- ``name`` - this is the fully qualified reverse zone that this DDNS domain can + update. This is the value used during reverse matching, which + compares it with a reversed version of the request's lease address. + The zone name should follow the appropriate standards; for example, + to support the IPv4 subnet 172.16.1, the name should be + "1.16.172.in-addr.arpa.". Similarly, to support an IPv6 subnet of + 2001:db8:1, the name should be "1.0.0.0.8.B.D.0.1.0.0.2.ip6.arpa." + The name must be unique within the catalog. + +- ``key-name`` - if TSIG is used with this domain's servers, + this value should be the name of the key from the TSIG key list. If + the value is blank (the default), TSIG will not be used in DDNS + conversations with this domain's servers. + +- ``dns-servers`` - this is a list of one or more DNS servers which can conduct + the server side of the DDNS protocol for this domain. Currently, the + servers are used in a first-to-last preference; in other words, when + D2 begins to process a request for this domain, it will pick the + first server in this list and attempt to communicate with it. If that + attempt fails, D2 will move to the next one in the list and so on, + until either it is successful or the list is exhausted. + +To create a new reverse DDNS domain, a new domain element must be added +and its parameters set. For example, to support subnet 2001:db8:1::, the +following configuration could be used: + +:: + + "DhcpDdns": { + "reverse-ddns": { + "ddns-domains": [ + { + "name": "1.0.0.0.8.B.D.0.1.0.0.2.ip6.arpa.", + "key-name": "", + "dns-servers": [ + ] + } + ] + } + } + +It is possible to add a domain without any servers; however, if that +domain matches a request, the request will fail. To make the domain +useful, at least one DNS server must be added to it. + +.. _add-reverse-dns-servers: + +Adding Reverse DNS Servers +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This section describes how to add DNS servers to a reverse DDNS domain. +Repeat these instructions as needed for all the servers in each domain. + +Reverse DNS server entries represent actual DNS servers which support +the server side of the DDNS protocol. Each reverse DNS server has the +following parameters: + +- ``hostname`` - the resolvable host name of the DNS server; this value + is currently ignored. + +- ``ip-address`` - the IP address at which the server listens for DDNS + requests. + +- ``port`` - the port on which the server listens for DDNS requests. It + defaults to the standard DNS service port of 53. + +To create a new reverse DNS server, a new server +element must be added to the domain and its parameters specified. If, for example, the +service is running at "172.88.99.10", then set it as follows: + +:: + + "DhcpDdns": { + "reverse-ddns": { + "ddns-domains": [ + { + "name": "1.0.0.0.8.B.D.0.1.0.0.2.ip6.arpa.", + "key-name": "", + "dns-servers": [ + { + "ip-address": "172.88.99.10", + "port": 53 + } + ] + } + ] + } + } + +.. note:: + + Since ``hostname`` is not yet supported, the parameter ``ip-address`` + must be set to the address of the DNS server. + +.. _per-server-keys: + +Per-DNS-Server TSIG Keys +~~~~~~~~~~~~~~~~~~~~~~~~ + +Since Kea version 2.0.0, a TSIG key can be specified in a DNS server +configuration. The priority rule is: + +- if a not-empty key name is specified in a DNS server entry, this TSIG + key protects DNS updates sent to this server. + +- if the DNS server entry is empty, but a + not-empty key name is specified in the parent's domain entry, the parent domain's + TSIG key protects DNS updates sent to this server. + +- if the DNS server entry is empty, and no key name is specified in its parent + domain entry, no TSIG protects DNS updates sent to this server. + +For instance, in this configuration: + +:: + + "DhcpDdns": { + "forward-ddns": { + "ddns-domains": [ + { + "name": "other.example.com.", + "key-name": "foo", + "dns-servers": [ + { + "ip-address": "172.88.99.10", + "port": 53 + }, + { + "ip-address": "172.88.99.11", + "port": 53, + "key-name": "bar" + } + ] + } + ] + }, + "reverse-ddns": { + "ddns-domains": [ + { + "name": "1.0.0.0.8.B.D.0.1.0.0.2.ip6.arpa.", + "dns-servers": [ + { + "ip-address": "172.88.99.12", + "port": 53 + }, + { + "ip-address": "172.88.99.13", + "port": 53, + "key-name": "bar" + } + ] + } + ] + }, + "tsig-keys": [ + { + "name": "foo", + "algorithm": "HMAC-MD5", + "secret": "LSWXnfkKZjdPJI5QxlpnfQ==" + }, + { + "name": "bar", + "algorithm": "HMAC-SHA224", + "secret": "bZEG7Ow8OgAUPfLWV3aAUQ==" + } + ] + } + + +The 172.88.99.10 server will use the "foo" TSIG key, the 172.88.99.11 and +172.88.99.13 servers will use the "bar" key. and 172.88.99.12 will not use TSIG. + +.. _d2-user-contexts: + +User Contexts in DDNS +--------------------- + +See :ref:`user-context` for additional background regarding the user +context idea. + +User contexts can be specified on a global scope, a DDNS domain, a DNS server, +a TSIG key, and loggers. One other useful usage is the ability to store +comments or descriptions; the parser translates a "comment" entry into a +user context with the entry, which allows a comment to be attached +inside the configuration itself. + +.. _d2-example-config: + +Example DHCP-DDNS Server Configuration +-------------------------------------- + +This section provides a sample DHCP-DDNS server configuration, based on +a small example network. Let's suppose our example network has three +domains, each with their own subnet. + +.. table:: Our example network + + +------------------+-----------------+-----------------+-----------------+ + | Domain | Subnet | Forward DNS | Reverse DNS | + | | | Servers | Servers | + +==================+=================+=================+=================+ + | four.example.com | 192.0.2.0/24 | 172.16.1.5, | 172.16.1.5, | + | | | 172.16.2.5 | 172.16.2.5 | + +------------------+-----------------+-----------------+-----------------+ + | six.example.com | 2001:db8:1::/64 | 3001:1::50 | 3001:1::51 | + +------------------+-----------------+-----------------+-----------------+ + | example.com | 192.0.0.0/16 | 172.16.2.5 | 172.16.2.5 | + +------------------+-----------------+-----------------+-----------------+ + +We need to construct three forward DDNS domains: + +.. table:: Forward DDNS domains needed + + +----+-------------------+------------------------+ + | # | DDNS Domain Name | DNS Servers | + +====+===================+========================+ + | 1. | four.example.com. | 172.16.1.5, 172.16.2.5 | + +----+-------------------+------------------------+ + | 2. | six.example.com. | 3001:1::50 | + +----+-------------------+------------------------+ + | 3. | example.com. | 172.16.2.5 | + +----+-------------------+------------------------+ + +As discussed earlier, FQDN-to-domain matching is based on the longest +match. The FQDN "myhost.four.example.com." matches the first domain +("four.example.com"), while "admin.example.com." matches the third +domain ("example.com"). The FQDN "other.example.net." fails to +match any domain and is rejected. + +The following example configuration specifies the forward DDNS domains. + +:: + + "DhcpDdns": { + "comment": "example configuration: forward part", + "forward-ddns": { + "ddns-domains": [ + { + "name": "four.example.com.", + "key-name": "", + "dns-servers": [ + { "ip-address": "172.16.1.5" }, + { "ip-address": "172.16.2.5" } + ] + }, + { + "name": "six.example.com.", + "key-name": "", + "dns-servers": [ + { "ip-address": "2001:db8::1" } + ] + }, + { + "name": "example.com.", + "key-name": "", + "dns-servers": [ + { "ip-address": "172.16.2.5" } + ], + "user-context": { "backup": false } + }, + ... + ] + } + } + +Similarly, we need to construct the three reverse DDNS domains: + +.. table:: Reverse DDNS domains needed + + +----+-----------------------------------+------------------------+ + | # | DDNS Domain Name | DNS Servers | + +====+===================================+========================+ + | 1. | 2.0.192.in-addr.arpa. | 172.16.1.5, 172.16.2.5 | + +----+-----------------------------------+------------------------+ + | 2. | 1.0.0.0.8.d.b.0.1.0.0.2.ip6.arpa. | 3001:1::50 | + +----+-----------------------------------+------------------------+ + | 3. | 0.182.in-addr.arpa. | 172.16.2.5 | + +----+-----------------------------------+------------------------+ + +An address of "192.0.2.150" matches the first domain, +"2001:db8:1::10" matches the second domain, and "192.0.50.77" matches the +third domain. + +These reverse DDNS domains are specified as follows: + +:: + + "DhcpDdns": { + "comment": "example configuration: reverse part", + "reverse-ddns": { + "ddns-domains": [ + { + "name": "2.0.192.in-addr.arpa.", + "key-name": "", + "dns-servers": [ + { "ip-address": "172.16.1.5" }, + { "ip-address": "172.16.2.5" } + ] + }, + { + "name": "1.0.0.0.8.B.D.0.1.0.0.2.ip6.arpa.", + "key-name": "", + "dns-servers": [ + { "ip-address": "2001:db8::1" } + ] + }, + { + "name": "0.192.in-addr.arpa.", + "key-name": "", + "dns-servers": [ + { "ip-address": "172.16.2.5" } + ] + }, + ... + ] + } + } + +DHCP-DDNS Server Statistics +=========================== + +Kea version 2.0.0 introduced statistics support for DHCP-DDNS. + +Statistics are divided into three groups: NameChangeRequests, DNS updates, +and per-TSIG-key DNS updates. While the statistics of the first two groups +are cumulative, i.e. not affected by configuration change or reload, +per-key statistics are reset to 0 when the underlying object is +(re)created. + +Currently Kea's statistics management has the following limitations: + +- only integer samples (i.e. a counter and a timestamp) are used; +- the maximum sample count is 1; +- there is no API to remove one or all statistics; +- there is no API to set the maximum sample count or age. + +.. note:: + + Hook libraries, such as the ISC subscriber-only GSS-TSIG library, + make new statistics available in Kea. + +More information about Kea statistics can be found at :ref:`stats`. + +NCR Statistics +-------------- + +The NameChangeRequest statistics are: + +- ``ncr-received`` - the number of received valid NCRs +- ``ncr-invalid`` - the number of received invalid NCRs +- ``ncr-error`` - the number of errors in NCR receptions other than an I/O cancel on shutdown + +DNS Update Statistics +--------------------- + +The global DNS update statistics are: + +- ``update-sent`` - the number of DNS updates sent +- ``update-signed`` - the number of DNS updates sent and protected by TSIG +- ``update-unsigned`` - the number of DNS updates sent and not protected by TSIG +- ``update-success`` - the number of DNS updates which successfully completed +- ``update-timeout`` - the number of DNS updates which completed on timeout +- ``update-error`` - the number of DNS updates which completed with an error other than + timeout + +Per-TSIG-Key DNS Update Statistics +---------------------------------- + +The per TSIG key DNS update statistics are: + +- ``update-sent`` - the number of DNS updates sent +- ``update-success`` - the number of DNS updates which successfully completed +- ``update-timeout`` - the number of DNS updates which completed on timeout +- ``update-error`` - the number of DNS updates which completed with an error other than + timeout + +The name format for per-key statistics is ``key[<key-DNS-name>].<stat-name>``: +for instance, the name of the ``update-sent`` statistics for the +``key.example.com.`` TSIG key is ``key[key.example.com.].update-sent``. + +DHCP-DDNS Server Limitations +============================ + +The following are the current limitations of the DHCP-DDNS server. + +- Requests received from the DHCP servers are placed in a queue until + they are processed. Currently, all queued requests are lost if the + server shuts down. + +Supported Standards +=================== + +The following RFCs are supported by the DHCP-DDNS server: + +- *Secret Key Transaction Authentication for DNS (TSIG)*, `RFC 2845 + <https://tools.ietf.org/html/rfc2845>`__: All DNS update packets sent and + received by the DHCP-DDNS server can be protected by TSIG signatures. + +- *Dynamic Updates in the Domain Name System (DNS UPDATE)*, `RFC 2136 + <https://tools.ietf.org/html/rfc2136>`__: The complete DNS update mechanism is + supported. + +- *Resolution of Fully Qualified Domain Name (FQDN) Conflicts among Dynamic Host + Configuration Protocol (DHCP) Clients*, `RFC 4703 + <https://tools.ietf.org/html/rfc4703>`__: DHCP-DDNS takes care of + conflict resolution, for both DHCPv4 and DHCPv6 servers. + +- *A DNS Resource Record (RR) for Encoding Dynamic Host Configuration Protocol + (DHCP) Information (DHCID RR)*, `RFC 4701 + <https://tools.ietf.org/html/rfc4701>`__: The DHCP-DDNS server uses DHCID + records. diff --git a/doc/sphinx/arm/dhcp4-srv.rst b/doc/sphinx/arm/dhcp4-srv.rst new file mode 100644 index 0000000..eea2648 --- /dev/null +++ b/doc/sphinx/arm/dhcp4-srv.rst @@ -0,0 +1,8455 @@ +.. _dhcp4: + +***************** +The DHCPv4 Server +***************** + +.. _dhcp4-start-stop: + +Starting and Stopping the DHCPv4 Server +======================================= + +It is recommended that the Kea DHCPv4 server be started and stopped +using :iscman:`keactrl` (described in :ref:`keactrl`); however, it is also +possible to run the server directly via the :iscman:`kea-dhcp4` command, which accepts +the following command-line switches: + +- ``-c file`` - specifies the configuration file. This is the only + mandatory switch. + +- ``-d`` - specifies whether the server logging should be switched to + debug/verbose mode. In verbose mode, the logging severity and debuglevel + specified in the configuration file are ignored; "debug" severity + and the maximum debuglevel (99) are assumed. The flag is convenient + for temporarily switching the server into maximum verbosity, e.g. + when debugging. + +- ``-p server-port`` - specifies the local UDP port on which the server + listens. This is only useful during testing, as a DHCPv4 server + listening on ports other than the standard ones is not able to + handle regular DHCPv4 queries. + +- ``-P client-port`` - specifies the remote UDP port to which the + server sends all responses. This is only useful during testing, + as a DHCPv4 server sending responses to ports other than the standard + ones is not able to handle regular DHCPv4 queries. + +- ``-t file`` - specifies a configuration file to be tested. :iscman:`kea-dhcp4` + loads it, checks it, and exits. During the test, log messages are + printed to standard output and error messages to standard error. The + result of the test is reported through the exit code (0 = + configuration looks OK, 1 = error encountered). The check is not + comprehensive; certain checks are possible only when running the + server. + +- ``-T file`` - specifies a configuration file to be tested. :iscman:`kea-dhcp4` + loads it, checks it, and exits. It performs extra checks beyond what ``-t`` + offers, such as establishing database connections (for the lease backend, + host reservations backend, configuration backend, and forensic logging + backend), loading hook libraries, parsing hook-library configurations, etc. + It does not open UNIX or TCP/UDP sockets, nor does it open or rotate + files, as any of these actions could interfere with a running process on the + same machine. + +- ``-v`` - displays the Kea version and exits. + +- ``-V`` - displays the Kea extended version with additional parameters + and exits. The listing includes the versions of the libraries + dynamically linked to Kea. + +- ``-W`` - displays the Kea configuration report and exits. The report + is a copy of the ``config.report`` file produced by ``./configure``; + it is embedded in the executable binary. + + The contents of the ``config.report`` file may also be accessed by examining + certain libraries in the installation tree or in the source tree. + + .. code-block:: shell + + # from installation using libkea-process.so + $ strings ${prefix}/lib/libkea-process.so | sed -n 's/;;;; //p' + + # from sources using libkea-process.so + $ strings src/lib/process/.libs/libkea-process.so | sed -n 's/;;;; //p' + + # from sources using libkea-process.a + $ strings src/lib/process/.libs/libkea-process.a | sed -n 's/;;;; //p' + + # from sources using libcfgrpt.a + $ strings src/lib/process/cfgrpt/.libs/libcfgrpt.a | sed -n 's/;;;; //p' + +On startup, the server detects available network interfaces and +attempts to open UDP sockets on all interfaces listed in the +configuration file. Since the DHCPv4 server opens privileged ports, it +requires root access; this daemon must be run as root. + +During startup, the server attempts to create a PID file of the +form: ``[runstatedir]/kea/[conf name].kea-dhcp4.pid``, where: + +- ``runstatedir``: The value as passed into the build configure + script; it defaults to ``/usr/local/var/run``. Note that this value may be + overridden at runtime by setting the environment variable + ``KEA_PIDFILE_DIR``, although this is intended primarily for testing + purposes. + +- ``conf name``: The configuration file name used to start the server, + minus all preceding paths and the file extension. For example, given + a pathname of ``/usr/local/etc/kea/myconf.txt``, the portion used would + be ``myconf``. + +If the file already exists and contains the PID of a live process, the +server issues a ``DHCP4_ALREADY_RUNNING`` log message and exits. It is +possible, though unlikely, that the file is a remnant of a system crash +and the process to which the PID belongs is unrelated to Kea. In such a +case, it would be necessary to manually delete the PID file. + +The server can be stopped using the ``kill`` command. When running in a +console, the server can also be shut down by pressing Ctrl-c. Kea detects +the key combination and shuts down gracefully. + +The reconfiguration of each Kea server is triggered by the SIGHUP signal. +When a server receives the SIGHUP signal it rereads its configuration file and, +if the new configuration is valid, uses the new configuration. +If the new configuration proves to be invalid, the server retains its +current configuration; however, in some cases a fatal error message is logged +indicating that the server is no longer providing any service: a working +configuration must be loaded as soon as possible. + +.. _dhcp4-configuration: + +DHCPv4 Server Configuration +=========================== + +Introduction +------------ + +This section explains how to configure the Kea DHCPv4 server using a +configuration file. + +Before DHCPv4 is started, its configuration file must +be created. The basic configuration is as follows: + +:: + + { + # DHCPv4 configuration starts on the next line + "Dhcp4": { + + # First we set up global values + "valid-lifetime": 4000, + "renew-timer": 1000, + "rebind-timer": 2000, + + # Next we set up the interfaces to be used by the server. + "interfaces-config": { + "interfaces": [ "eth0" ] + }, + + # And we specify the type of lease database + "lease-database": { + "type": "memfile", + "persist": true, + "name": "/var/lib/kea/dhcp4.leases" + }, + + # Finally, we list the subnets from which we will be leasing addresses. + "subnet4": [ + { + "id": 1, + "subnet": "192.0.2.0/24", + "pools": [ + { + "pool": "192.0.2.1 - 192.0.2.200" + } + ] + } + ] + # DHCPv4 configuration ends with the next line + } + + } + +The following paragraphs provide a brief overview of the parameters in +the above example, along with their format. Subsequent sections of this +chapter go into much greater detail for these and other parameters. + +The lines starting with a hash (#) are comments and are ignored by the +server; they do not impact its operation in any way. + +The configuration starts in the first line with the initial opening +curly bracket (or brace). Each configuration must contain an object +specifying the configuration of the Kea module using it. In the example +above, this object is called ``Dhcp4``. + +The ``Dhcp4`` configuration starts with the ``"Dhcp4": {`` line and ends +with the corresponding closing brace (in the above example, the brace +after the last comment). Everything defined between those lines is +considered to be the ``Dhcp4`` configuration. + +In general, the order in which those parameters appear does not +matter, but there are two caveats. The first one is that the +configuration file must be well-formed JSON, meaning that the +parameters for any given scope must be separated by a comma, and there +must not be a comma after the last parameter. When reordering a +configuration file, moving a parameter to or from the +last position in a given scope may also require moving the comma. The +second caveat is that it is uncommon — although legal JSON — to repeat +the same parameter multiple times. If that happens, the last occurrence +of a given parameter in a given scope is used, while all previous +instances are ignored. This is unlikely to cause any confusion as there +are no real-life reasons to keep multiple copies of the same parameter +in the configuration file. + +The first few DHCPv4 configuration elements +define some global parameters. ``valid-lifetime`` defines how long the +addresses (leases) given out by the server are valid; the default +is for a client to be allowed to use a given address for 4000 +seconds. (Note that integer numbers are specified as is, without any +quotes around them.) ``renew-timer`` and ``rebind-timer`` are values +(also in seconds) that define the T1 and T2 timers that govern when the +client begins the renewal and rebind processes. + +.. note:: + + The lease valid lifetime is expressed as a triplet with minimum, default, and + maximum values using configuration entries + ``min-valid-lifetime``, ``valid-lifetime``, and ``max-valid-lifetime``. + Since Kea 1.9.5, these values may be specified in client classes. The procedure + the server uses to select which lifetime value to use is as follows: + + If the client query is a BOOTP query, the server always uses the + infinite lease time (e.g. 0xffffffff). Otherwise, the server must + determine which configured triplet to use by first searching all + classes assigned to the query, and then the subnet selected for + the query. + + Classes are searched in the order they were assigned to the query; the + server uses the triplet from the first class that specifies it. + If no classes specify the triplet, the server uses the triplet + specified by the subnet selected for the client. If the subnet does not + explicitly specify it, the server next looks at the subnet's + shared-network (if one exists), then for a global specification, and + finally the global default. + + If the client requested a lifetime value via DHCP option 51, then the + lifetime value used is the requested value bounded by the configured + triplet. In other words, if the requested lifetime is less than the + configured minimum, the configured minimum is used; if it is more + than the configured maximum, the configured maximum is used. If + the client did not provide a requested value, the lifetime value used + is the triplet default value. + +.. note:: + + Both ``renew-timer`` and ``rebind-timer`` + are optional. The server only sends ``rebind-timer`` to the client, + via DHCPv4 option code 59, if it is less than ``valid-lifetime``; and it + only sends ``renew-timer``, via DHCPv4 option code 58, if it is less + than ``rebind-timer`` (or ``valid-lifetime`` if ``rebind-timer`` was not + specified). In their absence, the client should select values for T1 + and T2 timers according to `RFC 2131 <https://tools.ietf.org/html/rfc2131>`_. + See section :ref:`dhcp4-t1-t2-times` + for more details on generating T1 and T2. + +The ``interfaces-config`` map specifies the network interfaces on which the +server should listen to DHCP messages. The ``interfaces`` parameter specifies +a list of network interfaces on which the server should listen. Lists are +opened and closed with square brackets, with elements separated by commas. To +listen on two interfaces, the ``interfaces-config`` element should look like +this: + +:: + + { + "interfaces-config": { + "interfaces": [ "eth0", "eth1" ] + }, + ... + } + +The next lines define the lease database, the place where the +server stores its lease information. This particular example tells the +server to use memfile, which is the simplest and fastest database +backend. It uses an in-memory database and stores leases on disk in a +CSV (comma-separated values) file. This is a very simple configuration example; +usually the lease database configuration is more extensive and contains +additional parameters. Note that ``lease-database`` is an object and opens up a +new scope, using an opening brace. Its parameters (just one in this example: +``type``) follow. If there were more than one, they would be separated +by commas. This scope is closed with a closing brace. As more parameters +for the ``Dhcp4`` definition follow, a trailing comma is present. + +Finally, we need to define a list of IPv4 subnets. This is the most +important DHCPv4 configuration structure, as the server uses that +information to process clients' requests. It defines all subnets from +which the server is expected to receive DHCP requests. The subnets are +specified with the ``subnet4`` parameter. It is a list, so it starts and +ends with square brackets. Each subnet definition in the list has +several attributes associated with it, so it is a structure and is +opened and closed with braces. At a minimum, a subnet definition must +have at least two parameters: ``subnet``, which defines the whole +subnet; and ``pools``, which is a list of dynamically allocated pools +that are governed by the DHCP server. + +The example contains a single subnet. If more than one were defined, +additional elements in the ``subnet4`` parameter would be specified and +separated by commas. For example, to define three subnets, the following +syntax would be used: + +:: + + { + "subnet4": [ + { + "id": 1, + "pools": [ { "pool": "192.0.2.1 - 192.0.2.200" } ], + "subnet": "192.0.2.0/24" + }, + { + "id": 2, + "pools": [ { "pool": "192.0.3.100 - 192.0.3.200" } ], + "subnet": "192.0.3.0/24" + }, + { + "id": 3, + "pools": [ { "pool": "192.0.4.1 - 192.0.4.254" } ], + "subnet": "192.0.4.0/24" + } + ], + ... + } + +Note that indentation is optional and is used for aesthetic purposes +only. In some cases it may be preferable to use more compact notation. + +After all the parameters have been specified, there are two contexts open: +``global`` and ``Dhcp4``; thus, two closing curly brackets must be used to close +them. + +Lease Storage +------------- + +All leases issued by the server are stored in the lease database. +There are three database backends available: memfile +(the default), MySQL, PostgreSQL. + +Memfile - Basic Storage for Leases +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The server is able to store lease data in different repositories. Larger +deployments may elect to store leases in a database; +:ref:`database-configuration4` describes this option. In +typical smaller deployments, though, the server stores lease +information in a CSV file rather than a database. As well as requiring +less administration, an advantage of using a file for storage is that it +eliminates a dependency on third-party database software. + +The configuration of the memfile backend is controlled through +the ``Dhcp4``/``lease-database`` parameters. The ``type`` parameter is mandatory +and specifies which storage for leases the server should use, through +the ``"memfile"`` value. The following list gives additional optional parameters +that can be used to configure the memfile backend. + +- ``persist``: controls whether the new leases and updates to existing + leases are written to the file. It is strongly recommended that the + value of this parameter be set to ``true`` at all times during the + server's normal operation. Not writing leases to disk means that if a + server is restarted (e.g. after a power failure), it will not know + which addresses have been assigned. As a result, it may assign new clients + addresses that are already in use. The value of + ``false`` is mostly useful for performance-testing purposes. The + default value of the ``persist`` parameter is ``true``, which enables + writing lease updates to the lease file. + +- ``name``: specifies an absolute location of the lease file in which + new leases and lease updates are recorded. The default value for + this parameter is ``"[kea-install-dir]/var/lib/kea/kea-leases4.csv"``. + +- ``lfc-interval``: specifies the interval, in seconds, at which the + server will perform a lease file cleanup (LFC). This removes + redundant (historical) information from the lease file and + effectively reduces the lease file size. The cleanup process is + described in more detail later in this section. The default + value of the ``lfc-interval`` is ``3600``. A value of ``0`` disables the LFC. + +- ``max-row-errors``: specifies the number of row errors before the server + stops attempting to load a lease file. When the server loads a lease file, it is processed + row by row, each row containing a single lease. If a row is flawed and + cannot be processed correctly the server logs it, discards the row, + and goes on to the next row. This parameter can be used to set a limit on + the number of such discards that can occur, after which the server + abandons the effort and exits. The default value of ``0`` disables the limit + and allows the server to process the entire file, regardless of how many + rows are discarded. + +An example configuration of the memfile backend is presented below: + +:: + + "Dhcp4": { + "lease-database": { + "type": "memfile", + "persist": true, + "name": "/tmp/kea-leases4.csv", + "lfc-interval": 1800, + "max-row-errors": 100 + } + } + +This configuration selects ``/tmp/kea-leases4.csv`` as the storage +for lease information and enables persistence (writing lease updates to +this file). It also configures the backend to perform a periodic cleanup +of the lease file every 1800 seconds (30 minutes) and sets the maximum number of +row errors to 100. + +Why Is Lease File Cleanup Necessary? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +It is important to know how the lease file contents are organized to +understand why the periodic lease file cleanup is needed. Every time the +server updates a lease or creates a new lease for a client, the new +lease information must be recorded in the lease file. For performance +reasons, the server does not update the existing client's lease in the +file, as this would potentially require rewriting the entire file. +Instead, it simply appends the new lease information to the end of the +file; the previous lease entries for the client are not removed. When +the server loads leases from the lease file, e.g. at server startup, +it assumes that the latest lease entry for the client is the valid one. +Previous entries are discarded, meaning that the server can +reconstruct accurate information about the leases even though there +may be many lease entries for each client. However, storing many entries +for each client results in a bloated lease file and impairs the +performance of the server's startup and reconfiguration, as it needs to +process a larger number of lease entries. + +Lease file cleanup (LFC) removes all previous entries for each client +and leaves only the latest ones. The interval at which the cleanup is +performed is configurable, and it should be selected according to the +frequency of lease renewals initiated by the clients. The more frequent +the renewals, the smaller the value of ``lfc-interval`` should be. Note, +however, that the LFC takes time and thus it is possible (although +unlikely) that, if the ``lfc-interval`` is too short, a new cleanup may +be started while the previous one is still running. The server would +recover from this by skipping the new cleanup when it detected that the +previous cleanup was still in progress, but it implies that the actual +cleanups will be triggered more rarely than the configured interval. Moreover, +triggering a new cleanup adds overhead to the server, which is not +able to respond to new requests for a short period of time when the new +cleanup process is spawned. Therefore, it is recommended that the +``lfc-interval`` value be selected in a way that allows the LFC +to complete the cleanup before a new cleanup is triggered. + +Lease file cleanup is performed by a separate process (in the +background) to avoid a performance impact on the server process. To +avoid conflicts between two processes using the same lease +files, the LFC process starts with Kea opening a new lease file; the +actual LFC process operates on the lease file that is no longer used by +the server. There are also other files created as a side effect of the +lease file cleanup. The detailed description of the LFC process is located later +in this Kea Administrator's Reference Manual: :ref:`kea-lfc`. + +.. _database-configuration4: + +Lease Database Configuration +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + + Lease database access information must be configured for the DHCPv4 + server, even if it has already been configured for the DHCPv6 server. + The servers store their information independently, so each server can + use a separate database or both servers can use the same database. + +.. note:: + + Kea requires the database timezone to match the system timezone. + For more details, see :ref:`mysql-database-create` and + :ref:`pgsql-database-create`. + +Lease database configuration is controlled through the +``Dhcp4``/``lease-database`` parameters. The database type must be set to +``memfile``, ``mysql`` or ``postgresql``, e.g.: + +:: + + "Dhcp4": { "lease-database": { "type": "mysql", ... }, ... } + +Next, the name of the database to hold the leases must be set; this is +the name used when the database was created (see +:ref:`mysql-database-create` or :ref:`pgsql-database-create`). + +For MySQL or PostgreSQL: + +:: + + "Dhcp4": { "lease-database": { "name": "database-name" , ... }, ... } + +If the database is located on a different system from the DHCPv4 server, +the database host name must also be specified: + +:: + + "Dhcp4": { "lease-database": { "host": "remote-host-name", ... }, ... } + +Normally, the database is on the same machine as the DHCPv4 server. +In this case, set the value to the empty string: + +:: + + "Dhcp4": { "lease-database": { "host" : "", ... }, ... } + +Should the database use a port other than the default, it may be +specified as well: + +:: + + "Dhcp4": { "lease-database": { "port" : 12345, ... }, ... } + +Should the database be located on a different system, the administrator may need to +specify a longer interval for the connection timeout: + +:: + + "Dhcp4": { "lease-database": { "connect-timeout" : timeout-in-seconds, ... }, ... } + +The default value of five seconds should be more than adequate for local +connections. If a timeout is given, though, it should be an integer +greater than zero. + +The maximum number of times the server automatically attempts to +reconnect to the lease database after connectivity has been lost may be +specified: + +:: + + "Dhcp4": { "lease-database": { "max-reconnect-tries" : number-of-tries, ... }, ... } + +If the server is unable to reconnect to the database after making the +maximum number of attempts, the server will exit. A value of 0 (the +default) disables automatic recovery and the server will exit +immediately upon detecting a loss of connectivity (MySQL and PostgreSQL +only). + +The number of milliseconds the server waits between attempts to +reconnect to the lease database after connectivity has been lost may +also be specified: + +:: + + "Dhcp4": { "lease-database": { "reconnect-wait-time" : number-of-milliseconds, ... }, ... } + +The default value for MySQL and PostgreSQL is 0, which disables automatic +recovery and causes the server to exit immediately upon detecting the +loss of connectivity. + +:: + + "Dhcp4": { "lease-database": { "on-fail" : "stop-retry-exit", ... }, ... } + +The possible values are: + +- ``stop-retry-exit`` - disables the DHCP service while trying to automatically + recover lost connections. Shuts down the server on failure after exhausting + ``max-reconnect-tries``. This is the default value for the lease backend, + the host backend, and the configuration backend. + +- ``serve-retry-exit`` - continues the DHCP service while trying to + automatically recover lost connections. Shuts down the server on failure + after exhausting ``max-reconnect-tries``. + +- ``serve-retry-continue`` - continues the DHCP service and does not shut down + the server even if the recovery fails. This is the default value for forensic + logging. + +.. note:: + + Automatic reconnection to database backends is configured individually per + backend; this allows users to tailor the recovery parameters to each backend + they use. We suggest that users enable it either for all backends or none, + so behavior is consistent. + + Losing connectivity to a backend for which reconnection is disabled results + (if configured) in the server shutting itself down. This includes cases when + the lease database backend and the hosts database backend are connected to + the same database instance. + + It is highly recommended not to change the ``stop-retry-exit`` default + setting for the lease manager, as it is critical for the connection to be + active while processing DHCP traffic. Change this only if the server is used + exclusively as a configuration tool. + +:: + + "Dhcp4": { "lease-database": { "retry-on-startup" : true, ... }, ... } + +During server startup, the inability to connect to any of the configured +backends is considered fatal only if ``retry-on-startup`` is set to ``false`` +(the default). A fatal error is logged and the server exits, based on the idea +that the configuration should be valid at startup. Exiting to the operating +system allows nanny scripts to detect the problem. +If ``retry-on-startup`` is set to ``true``, the server will start reconnection +attempts even at server startup or on reconfigure events, and will honor the +action specified in the ``on-fail`` parameter. + +The host parameter is used by the MySQL and PostgreSQL backends. + +Finally, the credentials of the account under which the server will +access the database should be set: + +:: + + "Dhcp4": { + "lease-database": { + "user": "user-name", + "password": "password", + ... + }, + ... + } + +If there is no password to the account, set the password to the empty +string ``""``. (This is the default.) + +.. _tuning-database-timeouts4: + +Tuning Database Timeouts +~~~~~~~~~~~~~~~~~~~~~~~~ + +In rare cases, reading or writing to the database may hang. This can be +caused by a temporary network issue, or by misconfiguration of the proxy +server switching the connection between different database instances. +These situations are rare, but users have reported +that Kea sometimes hangs while performing database IO operations. +Setting appropriate timeout values can mitigate such issues. + +MySQL exposes two distinct connection options to configure the read and +write timeouts. Kea's corresponding ``read-timeout`` and ``write-timeout`` +configuration parameters specify the timeouts in seconds. For example: + +:: + + "Dhcp4": { "lease-database": { "read-timeout" : 10, "write-timeout": 20, ... }, ... } + + +Setting these parameters to 0 is equivalent to not specifying them, and +causes the Kea server to establish a connection to the database with the +MySQL defaults. In this case, Kea waits indefinitely for the completion of +the read and write operations. + +MySQL versions earlier than 5.6 do not support setting timeouts for +read and write operations. Moreover, the ``read-timeout`` and ``write-timeout`` +parameters can only be specified for the MySQL backend; setting them for +any other backend database type causes a configuration error. + +To set a timeout in seconds for PostgreSQL, use the ``tcp-user-timeout`` +parameter. For example: + +:: + + "Dhcp4": { "lease-database": { "tcp-user-timeout" : 10, ... }, ... } + + +Specifying this parameter for other backend types causes a configuration +error. + +.. note:: + + The timeouts described here are only effective for TCP connections. + Please note that the MySQL client library used by the Kea servers + typically connects to the database via a UNIX domain socket when the + ``host`` parameter is ``localhost``, but establishes a TCP connection + for ``127.0.0.1``. + + +.. _hosts4-storage: + +Hosts Storage +------------- + +Kea is also able to store information about host reservations in the +database. The hosts database configuration uses the same syntax as the +lease database. In fact, the Kea server opens independent connections for +each purpose, be it lease or hosts information, which gives +the most flexibility. Kea can keep leases and host reservations +separately, but can also point to the same database. Currently the +supported hosts database types are MySQL and PostgreSQL. + +The following configuration can be used to configure a +connection to MySQL: + +:: + + "Dhcp4": { + "hosts-database": { + "type": "mysql", + "name": "kea", + "user": "kea", + "password": "secret123", + "host": "localhost", + "port": 3306 + } + } + +Depending on the database configuration, many of the +parameters may be optional. + +Please note that usage of hosts storage is optional. A user can define +all host reservations in the configuration file, and that is the +recommended way if the number of reservations is small. However, when +the number of reservations grows, it is more convenient to use host +storage. Please note that both storage methods (the configuration file and +one of the supported databases) can be used together. If hosts are +defined in both places, the definitions from the configuration file are +checked first and external storage is checked later, if necessary. + +Host information can be placed in multiple stores. Operations +are performed on the stores in the order they are defined in the +configuration file, although this leads to a restriction in ordering +in the case of a host reservation addition; read-only stores must be +configured after a (required) read-write store, or the addition will +fail. + +.. note:: + + Kea requires the database timezone to match the system timezone. + For more details, see :ref:`mysql-database-create` and + :ref:`pgsql-database-create`. + +.. _hosts-databases-configuration4: + +DHCPv4 Hosts Database Configuration +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Hosts database configuration is controlled through the +``Dhcp4``/``hosts-database`` parameters. If enabled, the type of database must +be set to ``mysql`` or ``postgresql``. + +:: + + "Dhcp4": { "hosts-database": { "type": "mysql", ... }, ... } + +Next, the name of the database to hold the reservations must be set; +this is the name used when the lease database was created (see +:ref:`supported-databases` for instructions on how to set up the +desired database type): + +:: + + "Dhcp4": { "hosts-database": { "name": "database-name" , ... }, ... } + +If the database is located on a different system than the DHCPv4 server, +the database host name must also be specified: + +:: + + "Dhcp4": { "hosts-database": { "host": remote-host-name, ... }, ... } + +Normally, the database is on the same machine as the DHCPv4 server. +In this case, set the value to the empty string: + +:: + + "Dhcp4": { "hosts-database": { "host" : "", ... }, ... } + +Should the database use a port different than the default, it may be +specified as well: + +:: + + "Dhcp4": { "hosts-database": { "port" : 12345, ... }, ... } + +The maximum number of times the server automatically attempts to +reconnect to the host database after connectivity has been lost may be +specified: + +:: + + "Dhcp4": { "hosts-database": { "max-reconnect-tries" : number-of-tries, ... }, ... } + +If the server is unable to reconnect to the database after making the +maximum number of attempts, the server will exit. A value of 0 (the +default) disables automatic recovery and the server will exit +immediately upon detecting a loss of connectivity (MySQL and PostgreSQL +only). + +The number of milliseconds the server waits between attempts to +reconnect to the host database after connectivity has been lost may also +be specified: + +:: + + "Dhcp4": { "hosts-database": { "reconnect-wait-time" : number-of-milliseconds, ... }, ... } + +The default value for MySQL and PostgreSQL is 0, which disables automatic +recovery and causes the server to exit immediately upon detecting the +loss of connectivity. + +:: + + "Dhcp4": { "hosts-database": { "on-fail" : "stop-retry-exit", ... }, ... } + +The possible values are: + +- ``stop-retry-exit`` - disables the DHCP service while trying to automatically + recover lost connections. Shuts down the server on failure after exhausting + ``max-reconnect-tries``. This is the default value for MySQL and PostgreSQL. + +- ``serve-retry-exit`` - continues the DHCP service while trying to automatically + recover lost connections. Shuts down the server on failure after exhausting + ``max-reconnect-tries``. + +- ``serve-retry-continue`` - continues the DHCP service and does not shut down the + server even if the recovery fails. + +.. note:: + + Automatic reconnection to database backends is configured individually per + backend. This allows users to tailor the recovery parameters to each backend + they use. We suggest that users enable it either for all backends or none, + so behavior is consistent. + + Losing connectivity to a backend for which reconnection is disabled results + (if configured) in the server shutting itself down. This includes cases when + the lease database backend and the hosts database backend are connected to + the same database instance. + +:: + + "Dhcp4": { "hosts-database": { "retry-on-startup" : true, ... }, ... } + +During server startup, the inability to connect to any of the configured +backends is considered fatal only if ``retry-on-startup`` is set to ``false`` +(the default). A fatal error is logged and the server exits, based on the idea +that the configuration should be valid at startup. Exiting to the operating +system allows nanny scripts to detect the problem. +If ``retry-on-startup`` is set to ``true``, the server will start reconnection +attempts even at server startup or on reconfigure events, and will honor the +action specified in the ``on-fail`` parameter. +Database connection retries are not attempted on startup if the +:ischooklib:`libdhcp_limits.so` is loaded because the hook library requires a +valid connection to the database to check if JSON format is supported and to +recount class limits. + +Finally, the credentials of the account under which the server will +access the database should be set: + +:: + + "Dhcp4": { + "hosts-database": { + "user": "user-name", + "password": "password", + ... + }, + ... + } + +If there is no password to the account, set the password to the empty +string ``""``. (This is the default.) + +The multiple-storage extension uses a similar syntax; a configuration is +placed into a ``hosts-databases`` list instead of into a ``hosts-database`` +entry, as in: + +:: + + "Dhcp4": { "hosts-databases": [ { "type": "mysql", ... }, ... ], ... } + +If the same host is configured both in-file and in-database, Kea does not issue a warning, +as it would if both were specified in the same data source. +Instead, the host configured in-file has priority over the one configured +in-database. + +.. _read-only-database-configuration4: + +Using Read-Only Databases for Host Reservations With DHCPv4 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In some deployments, the user whose name is specified in the +database backend configuration may not have write privileges to the +database. This is often required by the policy within a given network to +secure the data from being unintentionally modified. In many cases +administrators have deployed inventory databases, which contain +substantially more information about the hosts than just the static +reservations assigned to them. The inventory database can be used to +create a view of a Kea hosts database and such a view is often +read-only. + +Kea host-database backends operate with an implicit configuration to +both read from and write to the database. If the user does not +have write access to the host database, the backend will fail to start +and the server will refuse to start (or reconfigure). However, if access +to a read-only host database is required for retrieving reservations +for clients and/or assigning specific addresses and options, it is +possible to explicitly configure Kea to start in "read-only" mode. This +is controlled by the ``readonly`` boolean parameter as follows: + +:: + + "Dhcp4": { "hosts-database": { "readonly": true, ... }, ... } + +Setting this parameter to ``false`` configures the database backend to +operate in "read-write" mode, which is also the default configuration if +the parameter is not specified. + +.. note:: + + The ``readonly`` parameter is only supported for MySQL and + PostgreSQL databases. + + +Tuning Database Timeouts for Hosts Storage +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +See :ref:`tuning-database-timeouts4`. + +.. _dhcp4-interface-configuration: + +Interface Configuration +----------------------- + +The DHCPv4 server must be configured to listen on specific network +interfaces. The simplest network interface configuration tells the +server to listen on all available interfaces: + +:: + + "Dhcp4": { + "interfaces-config": { + "interfaces": [ "*" ] + }, + ... + } + +The asterisk plays the role of a wildcard and means "listen on all +interfaces." However, it is usually a good idea to explicitly specify +interface names: + +:: + + "Dhcp4": { + "interfaces-config": { + "interfaces": [ "eth1", "eth3" ] + }, + ... + } + + +It is possible to use an interface wildcard (*) concurrently +with explicit interface names: + +:: + + "Dhcp4": { + "interfaces-config": { + "interfaces": [ "eth1", "eth3", "*" ] + }, + ... + } + +This format should only be used when it is +desired to temporarily override a list of interface names and listen on +all interfaces. + +Some deployments of DHCP servers require that the servers listen on +interfaces with multiple IPv4 addresses configured. In these situations, +the address to use can be selected by appending an IPv4 address to the +interface name in the following manner: + +:: + + "Dhcp4": { + "interfaces-config": { + "interfaces": [ "eth1/10.0.0.1", "eth3/192.0.2.3" ] + }, + ... + } + + +Should the server be required to listen on multiple IPv4 addresses +assigned to the same interface, multiple addresses can be specified for +an interface as in the example below: + +:: + + "Dhcp4": { + "interfaces-config": { + "interfaces": [ "eth1/10.0.0.1", "eth1/10.0.0.2" ] + }, + ... + } + + +Alternatively, if the server should listen on all addresses for the +particular interface, an interface name without any address should be +specified. + +Kea supports responding to directly connected clients which do not have +an address configured. This requires the server to inject the hardware +address of the destination into the data-link layer of the packet +being sent to the client. The DHCPv4 server uses raw sockets to +achieve this, and builds the entire IP/UDP stack for the outgoing +packets. The downside of raw socket use, however, is that incoming and +outgoing packets bypass the firewalls (e.g. iptables). + +Handling traffic on multiple IPv4 addresses assigned to the same +interface can be a challenge, as raw sockets are bound to the +interface. When the DHCP server is configured to use the raw socket on +an interface to receive DHCP traffic, advanced packet filtering +techniques (e.g. the BPF) must be used to receive unicast traffic on +the desired addresses assigned to the interface. Whether clients use +the raw socket or the UDP socket depends on whether they are directly +connected (raw socket) or relayed (either raw or UDP socket). + +Therefore, in deployments where the server does not need to provision +the directly connected clients and only receives the unicast packets +from the relay agents, the Kea server should be configured to use UDP +sockets instead of raw sockets. The following configuration +demonstrates how this can be achieved: + +:: + + "Dhcp4": { + "interfaces-config": { + "interfaces": [ "eth1", "eth3" ], + "dhcp-socket-type": "udp" + }, + ... + } + + +The ``dhcp-socket-type`` parameter specifies that the IP/UDP sockets will be +opened on all interfaces on which the server listens, i.e. "eth1" and +"eth3" in this example. If ``dhcp-socket-type`` is set to ``raw``, it +configures the server to use raw sockets instead. If the +``dhcp-socket-type`` value is not specified, the default value ``raw`` +is used. + +Using UDP sockets automatically disables the reception of broadcast +packets from directly connected clients. This effectively means that UDP +sockets can be used for relayed traffic only. When using raw sockets, +both the traffic from the directly connected clients and the relayed +traffic are handled. + +Caution should be taken when configuring the server +to open multiple raw sockets on the interface with several IPv4 +addresses assigned. If the directly connected client sends the message +to the broadcast address, all sockets on this link will receive this +message and multiple responses will be sent to the client. Therefore, +the configuration with multiple IPv4 addresses assigned to the interface +should not be used when the directly connected clients are operating on +that link. To use a single address on such an interface, the +"interface-name/address" notation should be used. + +.. note:: + + Specifying the value ``raw`` as the socket type does not guarantee + that raw sockets will be used! The use of raw sockets to handle + traffic from the directly connected clients is currently + supported on Linux and BSD systems only. If raw sockets are not + supported on the particular OS in use, the server issues a warning and + fall back to using IP/UDP sockets. + +In a typical environment, the DHCP server is expected to send back a +response on the same network interface on which the query was received. +This is the default behavior. However, in some deployments it is desired +that the outbound (response) packets be sent as regular traffic and +the outbound interface be determined by the routing tables. This +kind of asymmetric traffic is uncommon, but valid. Kea supports a +parameter called ``outbound-interface`` that controls this behavior. It +supports two values: the first one, ``same-as-inbound``, tells Kea to +send back the response on the same interface where the query packet was +received. This is the default behavior. The second parameter, ``use-routing``, +tells Kea to send regular UDP packets and let the kernel's routing table +determine the most appropriate interface. This only works when +``dhcp-socket-type`` is set to ``udp``. An example configuration looks +as follows: + +:: + + "Dhcp4": { + "interfaces-config": { + "interfaces": [ "eth1", "eth3" ], + "dhcp-socket-type": "udp", + "outbound-interface": "use-routing" + }, + ... + } + +Interfaces are re-detected at each reconfiguration. This behavior can be +disabled by setting the ``re-detect`` value to ``false``, for instance: + +:: + + "Dhcp4": { + "interfaces-config": { + "interfaces": [ "eth1", "eth3" ], + "re-detect": false + }, + ... + } + + +Note that interfaces are not re-detected during :isccmd:`config-test`. + +Usually loopback interfaces (e.g. the ``lo`` or ``lo0`` interface) are not +configured, but if a loopback interface is explicitly configured and +IP/UDP sockets are specified, the loopback interface is accepted. + +For example, this setup can be used to run Kea in a FreeBSD jail having only a +loopback interface, to service a relayed DHCP request: + +:: + + "Dhcp4": { + "interfaces-config": { + "interfaces": [ "lo0" ], + "dhcp-socket-type": "udp" + }, + ... + } + +Kea binds the service sockets for each interface on startup. If another +process is already using a port, then Kea logs the message and suppresses an +error. DHCP service runs, but it is unavailable on some interfaces. + +The "service-sockets-require-all" option makes Kea require all sockets to +be successfully bound. If any opening fails, Kea interrupts the +initialization and exits with a non-zero status. (Default is false). + +:: + + "Dhcp4": { + "interfaces-config": { + "interfaces": [ "eth1", "eth3" ], + "service-sockets-require-all": true + }, + ... + } + +Sometimes, immediate interruption isn't a good choice. The port can be +unavailable only temporary. In this case, retrying the opening may resolve +the problem. Kea provides two options to specify the retrying: +``service-sockets-max-retries`` and ``service-sockets-retry-wait-time``. + +The first defines a maximal number of retries that Kea makes to open a socket. +The zero value (default) means that the Kea doesn't retry the process. + +The second defines a wait time (in milliseconds) between attempts. The default +value is 5000 (5 seconds). + +:: + + "Dhcp4": { + "interfaces-config": { + "interfaces": [ "eth1", "eth3" ], + "service-sockets-max-retries": 5, + "service-sockets-retry-wait-time": 5000 + }, + ... + } + +If "service-sockets-max-retries" is non-zero and "service-sockets-require-all" +is false, then Kea retries the opening (if needed) but does not fail if any +socket is still not opened. + +.. _dhcpinform-unicast-issues: + +Issues With Unicast Responses to DHCPINFORM +------------------------------------------- + +The use of UDP sockets has certain benefits in deployments where the +server receives only relayed traffic; these benefits are mentioned in +:ref:`dhcp4-interface-configuration`. From the +administrator's perspective it is often desirable to configure the +system's firewall to filter out unwanted traffic, and the use of UDP +sockets facilitates this. However, the administrator must also be aware +of the implications related to filtering certain types of traffic, as it +may impair the DHCP server's operation. + +In this section we focus on the case when the server receives the +DHCPINFORM message from the client via a relay. According to `RFC +2131 <https://tools.ietf.org/html/rfc2131>`__, the server should unicast +the DHCPACK response to the address carried in the ``ciaddr`` field. When +the UDP socket is in use, the DHCP server relies on the low-level +functions of an operating system to build the data link, IP, and UDP +layers of the outgoing message. Typically, the OS first uses ARP to +obtain the client's link-layer address to be inserted into the frame's +header, if the address is not cached from a previous transaction that +the client had with the server. When the ARP exchange is successful, the +DHCP message can be unicast to the client, using the obtained address. + +Some system administrators block ARP messages in their network, which +causes issues for the server when it responds to the DHCPINFORM +messages because the server is unable to send the DHCPACK if the +preceding ARP communication fails. Since the OS is entirely responsible +for the ARP communication and then sending the DHCP packet over the +wire, the DHCP server has no means to determine that the ARP exchange +failed and the DHCP response message was dropped. Thus, the server does +not log any error messages when the outgoing DHCP response is dropped. +At the same time, all hooks pertaining to the packet-sending operation +will be called, even though the message never reaches its destination. + +Note that the issue described in this section is not observed when +raw sockets are in use, because, in this case, the DHCP server builds +all the layers of the outgoing message on its own and does not use ARP. +Instead, it inserts the value carried in the ``chaddr`` field of the +DHCPINFORM message into the link layer. + +Server administrators willing to support DHCPINFORM messages via relays +should not block ARP traffic in their networks, or should use raw sockets +instead of UDP sockets. + +.. _ipv4-subnet-id: + +IPv4 Subnet Identifier +---------------------- + +The subnet identifier (subnet ID) is a unique number associated with a particular +subnet. In principle, it is used to associate clients' leases with their +respective subnets. The server configuration should contain unique and stable +identifiers for all subnets. When a subnet identifier is not specified for a +subnet, it is automatically assigned by the configuration mechanism. The identifiers +are assigned starting at 1 and are monotonically increased for each subsequent +subnet: 1, 2, 3, .... + +If there are multiple subnets configured with auto-generated identifiers +and one of them is removed, the subnet identifiers may be renumbered. +For example: if there are four subnets and the third is removed, the +last subnet will be assigned the identifier that the third subnet had +before removal. As a result, the leases stored in the lease database for +subnet 3 are now associated with subnet 4, something that may have +unexpected consequences. It is one of the reasons why auto-generated subnet +identifiers are deprecated starting from Kea version 2.4.0. + +.. note:: + + The auto-generation of the subnet identifiers will be removed in a future + release. Starting from Kea 2.4.0, a subnet without an ``id`` entry + or with the zero value raises a warning at the configuration time. + +.. note:: + + Subnet IDs must be greater than zero and less than 4294967295. + +The following configuration assigns the specified subnet identifier +to a newly configured subnet: + +:: + + "Dhcp4": { + "subnet4": [ + { + "subnet": "192.0.2.0/24", + "id": 1024, + ... + } + ] + } + +This identifier will not change for this subnet unless the ``id`` +parameter is removed or set to 0. The value of 0 forces auto-generation +of the subnet identifier. + +.. _ipv4-subnet-prefix: + +IPv4 Subnet Prefix +------------------ + +The subnet prefix is the second way to identify a subnet. Kea can +accept non-canonical subnet addresses; for instance, +this configuration is accepted: + +:: + + "Dhcp4": { + "subnet4": [ + { + "subnet": "192.0.2.1/24", + ... + } + ] + } + +This works even if there is another subnet with the "192.0.2.0/24" prefix; +only the textual form of subnets are compared to avoid duplicates. + +.. note:: + + Abuse of this feature can lead to incorrect subnet selection + (see :ref:`dhcp4-subnet-selection`). + +.. _dhcp4-address-config: + +Configuration of IPv4 Address Pools +----------------------------------- + +The main role of a DHCPv4 server is address assignment. For this, the +server must be configured with at least one subnet and one pool of +dynamic addresses to be managed. For example, assume that the server is +connected to a network segment that uses the 192.0.2.0/24 prefix. The +administrator of that network decides that addresses from the range +192.0.2.10 to 192.0.2.20 are going to be managed by the DHCPv4 server. +Such a configuration can be achieved in the following way: + +:: + + "Dhcp4": { + "subnet4": [ + { + "subnet": "192.0.2.0/24", + "pools": [ + { "pool": "192.0.2.10 - 192.0.2.20" } + ], + ... + } + ] + } + +Note that ``subnet`` is defined as a simple string, but the ``pools`` +parameter is actually a list of pools; for this reason, the pool +definition is enclosed in square brackets, even though only one range of +addresses is specified. + +Each ``pool`` is a structure that contains the parameters that describe +a single pool. Currently there is only one parameter, ``pool``, which +gives the range of addresses in the pool. + +It is possible to define more than one pool in a subnet; continuing the +previous example, further assume that 192.0.2.64/26 should also be +managed by the server. It could be written as 192.0.2.64 to 192.0.2.127, +or it can be expressed more simply as 192.0.2.64/26. Both +formats are supported by ``Dhcp4`` and can be mixed in the pool list. For +example, the following pools could be defined: + +:: + + "Dhcp4": { + "subnet4": [ + { + "subnet": "192.0.2.0/24", + "pools": [ + { "pool": "192.0.2.10-192.0.2.20" }, + { "pool": "192.0.2.64/26" } + ], + ... + } + ], + ... + } + +White space in pool definitions is ignored, so spaces before and after +the hyphen are optional. They can be used to improve readability. + +The number of pools is not limited, but for performance reasons it is +recommended to use as few as possible. + +The server may be configured to serve more than one subnet. To add a +second subnet, use a command similar to the following: + +:: + + "Dhcp4": { + "subnet4": [ + { + "subnet": "192.0.2.0/24", + "pools": [ { "pool": "192.0.2.1 - 192.0.2.200" } ], + ... + }, + { + "subnet": "192.0.3.0/24", + "pools": [ { "pool": "192.0.3.100 - 192.0.3.200" } ], + ... + }, + { + "subnet": "192.0.4.0/24", + "pools": [ { "pool": "192.0.4.1 - 192.0.4.254" } ], + ... + } + ] + } + +When configuring a DHCPv4 server using prefix/length notation, please +pay attention to the boundary values. When specifying that the server +can use a given pool, it is also able to allocate the first +(typically a network address) and the last (typically a broadcast +address) address from that pool. In the aforementioned example of pool +192.0.3.0/24, both the 192.0.3.0 and 192.0.3.255 addresses may be +assigned as well. This may be invalid in some network configurations. To +avoid this, use the ``min-max`` notation. + +In a subnet whose prefix length is less than 24, users may wish to exclude all +addresses ending in .0 and .255 from being dynamically allocated. For +instance, in the subnet 10.0.0.0/8, an administrator may wish to exclude 10.x.y.0 +and 10.x.y.255 for all +values of x and y, even though only 10.0.0.0 and 10.255.255.255 must be +excluded according to RFC standards. The ``exclude-first-last-24`` configuration +compatibility flag (:ref:`dhcp4-compatibility`) does this +automatically, rather than requiring explicit configuration of many pools or +reservations for fake hosts. When ``true``, it applies only to subnets of +24 prefix length or smaller i.e. larger address space; the default is ``false``. + +In this case, "exclude" means to skip these addresses in the free address pickup +routine of the allocation engine; if a client explicitly requests or +has a host reservation for an address in .0 or .255, it will get it. + +.. note:: + + Here are some liberties and limits to the values that subnets and pools can + take in unusual Kea configurations: + + +-------------------------------------------------------------+---------+--------------------------------------------------------------------------------------+ + | Kea configuration case | Allowed | Comment | + +=============================================================+=========+======================================================================================+ + | Overlapping subnets | Yes | Administrator should consider how clients are matched to these subnets. | + +-------------------------------------------------------------+---------+--------------------------------------------------------------------------------------+ + | Overlapping pools in one subnet | No | Startup error: DHCP4_PARSER_FAIL | + +-------------------------------------------------------------+---------+--------------------------------------------------------------------------------------+ + | Overlapping address pools in different subnets | Yes | Specifying the same address pool in different subnets can be used as an equivalent | + | | | of the global address pool. In that case, the server can assign addresses from the | + | | | same range regardless of the client's subnet. If an address from such a pool is | + | | | assigned to a client in one subnet, the same address will be renewed for this | + | | | client if it moves to another subnet. Another client in a different subnet will | + | | | not be assigned an address already assigned to the client in any of the subnets. | + +-------------------------------------------------------------+---------+--------------------------------------------------------------------------------------+ + | Pools not matching the subnet prefix | No | Startup error: DHCP4_PARSER_FAIL | + +-------------------------------------------------------------+---------+--------------------------------------------------------------------------------------+ + +.. _dhcp4-t1-t2-times: + +Sending T1 (Option 58) and T2 (Option 59) +----------------------------------------- + +According to `RFC 2131 <https://tools.ietf.org/html/rfc2131>`__, +servers should send values for T1 and T2 that are 50% and 87.5% of the +lease lifetime, respectively. By default, :iscman:`kea-dhcp4` does not send +either value; it can be configured to send values that are either specified +explicitly or that are calculated as percentages of the lease time. The +server's behavior is governed by a combination of configuration +parameters, two of which have already been mentioned. +To send specific, fixed values use the following two parameters: + +- ``renew-timer`` - specifies the value of T1 in seconds. + +- ``rebind-timer`` - specifies the value of T2 in seconds. + +The server only sends T2 if it is less than the valid lease time. T1 +is only sent if T2 is being sent and T1 is less than T2; or T2 +is not being sent and T1 is less than the valid lease time. + +Calculating the values is controlled by the following three parameters. + +- ``calculate-tee-times`` - when true, T1 and T2 are calculated as + percentages of the valid lease time. It defaults to false. + +- ``t1-percent`` - the percentage of the valid lease time to use for + T1. It is expressed as a real number between 0.0 and 1.0 and must be + less than ``t2-percent``. The default value is 0.50, per RFC 2131. + +- ``t2-percent`` - the percentage of the valid lease time to use for + T2. It is expressed as a real number between 0.0 and 1.0 and must be + greater than ``t1-percent``. The default value is .875, per RFC 2131. + +.. note:: + + In the event that both explicit values are specified and + ``calculate-tee-times`` is true, the server will use the explicit values. + Administrators with a setup where some subnets or shared-networks + use explicit values and some use calculated values must + not define the explicit values at any level higher than where they + will be used. Inheriting them from too high a scope, such as + global, will cause them to have explicit values at every level underneath + (shared-networks and subnets), effectively disabling calculated + values. + +.. _dhcp4-std-options: + +Standard DHCPv4 Options +----------------------- + +One of the major features of the DHCPv4 server is the ability to provide +configuration options to clients. Most of the options are sent by the +server only if the client explicitly requests them using the Parameter +Request List option. Those that do not require inclusion in the +Parameter Request List option are commonly used options, e.g. "Domain +Server", and options which require special behavior, e.g. "Client FQDN", +which is returned to the client if the client has included this option +in its message to the server. + +:ref:`dhcp4-std-options-list` comprises the list of the +standard DHCPv4 options whose values can be configured using the +configuration structures described in this section. This table excludes +the options which require special processing and thus cannot be +configured with fixed values. The last column of the table +indicates which options can be sent by the server even when they are not +requested in the Parameter Request List option, and those which are sent +only when explicitly requested. + +The following example shows how to configure the addresses of DNS +servers, which is one of the most frequently used options. Options +specified in this way are considered global and apply to all configured +subnets. + +:: + + "Dhcp4": { + "option-data": [ + { + "name": "domain-name-servers", + "code": 6, + "space": "dhcp4", + "csv-format": true, + "data": "192.0.2.1, 192.0.2.2" + }, + ... + ] + } + + +Note that either ``name`` or ``code`` is required; there is no need to +specify both. ``space`` has a default value of ``dhcp4``, so this can be skipped +as well if a regular (not encapsulated) DHCPv4 option is defined. +Finally, ``csv-format`` defaults to ``true``, so it too can be skipped, unless +the option value is specified as a hexadecimal string. Therefore, +the above example can be simplified to: + +:: + + "Dhcp4": { + "option-data": [ + { + "name": "domain-name-servers", + "data": "192.0.2.1, 192.0.2.2" + }, + ... + ] + } + + +Defined options are added to the response when the client requests them, +with a few exceptions which are always added. To enforce the addition of +a particular option, set the ``always-send`` flag to ``true`` as in: + +:: + + "Dhcp4": { + "option-data": [ + { + "name": "domain-name-servers", + "data": "192.0.2.1, 192.0.2.2", + "always-send": true + }, + ... + ] + } + + +The effect is the same as if the client added the option code in the +Parameter Request List option (or its equivalent for vendor options): + +:: + + "Dhcp4": { + "option-data": [ + { + "name": "domain-name-servers", + "data": "192.0.2.1, 192.0.2.2", + "always-send": true + }, + ... + ], + "subnet4": [ + { + "subnet": "192.0.3.0/24", + "option-data": [ + { + "name": "domain-name-servers", + "data": "192.0.3.1, 192.0.3.2" + }, + ... + ], + ... + }, + ... + ], + ... + } + + +In the example above, the ``domain-name-servers`` option respects the global +``always-send`` flag and is always added to responses, but for subnet +``192.0.3.0/24``, the value is taken from the subnet-level option data +specification. + +Contrary to ``always-send``, if the ``never-send`` flag is set to +``true`` for a particular option, the server does not add it to the response. +The effect is the same as if the client removed the option code in the +Parameter Request List option (or its equivalent for vendor options): + +:: + + "Dhcp4": { + "option-data": [ + { + "name": "domain-name-servers", + "data": "192.0.2.1, 192.0.2.2" + }, + ... + ], + "subnet4": [ + { + "subnet": "192.0.3.0/24", + "option-data": [ + { + "name": "domain-name-servers", + "never-send": true + }, + ... + ], + ... + }, + ... + ], + ... + } + +In the example above, the ``domain-name-servers`` option is never added to +responses on subnet ``192.0.3.0/24``. ``never-send`` has precedence over +``always-send``, so if both are ``true`` the option is not added. + +.. note:: + + The ``always-send`` and ``never-send`` flags are sticky, meaning + they do not follow the usual configuration inheritance rules. + Instead, if they are enabled at least once along the configuration + inheritance chain, they are applied - even if they are + disabled in other places which would normally receive a higher priority. + For instance, if one of the flags is enabled in the global scope, + but disabled at the subnet level, it is enabled, + disregarding the subnet-level setting. + +.. note:: + + The ``never-send`` flag is less powerful than :ischooklib:`libdhcp_flex_option.so`; + for instance, it has no effect on options managed by the server itself. + Both ``always-send`` and ``never-send`` have no effect on options + which cannot be requested, for instance from a custom space. + +The ``name`` parameter specifies the option name. For a list of +currently supported names, see :ref:`dhcp4-std-options-list` +below. The ``code`` parameter specifies the option code, which must +match one of the values from that list. The next line specifies the +option space, which must always be set to ``dhcp4`` as these are standard +DHCPv4 options. For other option spaces, including custom option spaces, +see :ref:`dhcp4-option-spaces`. The next line specifies the format in +which the data will be entered; use of CSV (comma-separated values) is +recommended. The sixth line gives the actual value to be sent to +clients. The data parameter is specified as normal text, with values separated by +commas if more than one value is allowed. + +Options can also be configured as hexadecimal values. If ``csv-format`` +is set to ``false``, option data must be specified as a hexadecimal string. +The following commands configure the ``domain-name-servers`` option for all +subnets with the following addresses: 192.0.3.1 and 192.0.3.2. Note that +``csv-format`` is set to ``false``. + +:: + + "Dhcp4": { + "option-data": [ + { + "name": "domain-name-servers", + "code": 6, + "space": "dhcp4", + "csv-format": false, + "data": "C0 00 03 01 C0 00 03 02" + }, + ... + ], + ... + } + +Kea supports the following formats when specifying hexadecimal data: + +- ``Delimited octets`` - one or more octets separated by either colons or + spaces (":" or " "). While each octet may contain one or two digits, + we strongly recommend always using two digits. Valid examples are + "ab:cd:ef" and "ab cd ef". + +- ``String of digits`` - a continuous string of hexadecimal digits with + or without a "0x" prefix. Valid examples are "0xabcdef" and "abcdef". + +Care should be taken to use proper encoding when using hexadecimal +format; Kea's ability to validate data correctness in hexadecimal is +limited. + +It is also possible to specify data for binary options as +a single-quoted text string within double quotes as shown (note that +``csv-format`` must be set to ``false``): + +:: + + "Dhcp4": { + "option-data": [ + { + "name": "user-class", + "code": 77, + "space": "dhcp4", + "csv-format": false, + "data": "'convert this text to binary'" + }, + ... + ], + ... + } + +Most of the parameters in the ``option-data`` structure are optional and +can be omitted in some circumstances, as discussed in :ref:`dhcp4-option-data-defaults`. + +It is possible to specify or override options on a per-subnet basis. If +clients connected to most subnets are expected to get the same +values of a given option, administrators should use global options. On the other +hand, if different values are used in each subnet, it does not make sense +to specify global option values; rather, only +subnet-specific ones should be set. + +The following commands override the global DNS servers option for a +particular subnet, setting a single DNS server with address 192.0.2.3: + +:: + + "Dhcp4": { + "subnet4": [ + { + "option-data": [ + { + "name": "domain-name-servers", + "code": 6, + "space": "dhcp4", + "csv-format": true, + "data": "192.0.2.3" + }, + ... + ], + ... + }, + ... + ], + ... + } + +In some cases it is useful to associate some options with an address +pool from which a client is assigned a lease. Pool-specific option +values override subnet-specific and global option values; it +is not possible to prioritize assignment of pool-specific +options via the order of pool declarations in the server +configuration. + +The following configuration snippet demonstrates how to specify the DNS +servers option, which is assigned to a client only if the client +obtains an address from the given pool: + +:: + + "Dhcp4": { + "subnet4": [ + { + "pools": [ + { + "pool": "192.0.2.1 - 192.0.2.200", + "option-data": [ + { + "name": "domain-name-servers", + "data": "192.0.2.3" + }, + ... + ], + ... + }, + ... + ], + ... + }, + ... + ], + ... + } + +Options can also be specified in class or host-reservation scope. The +current Kea options precedence order is (from most important to least): host +reservation, pool, subnet, shared network, class, global. + +When a data field is a string and that string contains the comma (``,``; +U+002C) character, the comma must be escaped with two backslashes (``\\,``; +U+005C). This double escape is required because both the routine +splitting of CSV data into fields and JSON use the same escape character; a +single escape (``\,``) would make the JSON invalid. For example, the string +"foo,bar" must be represented as: + +:: + + "Dhcp4": { + "subnet4": [ + { + "pools": [ + { + "option-data": [ + { + "name": "boot-file-name", + "data": "foo\\,bar" + } + ] + }, + ... + ], + ... + }, + ... + ], + ... + } + +Some options are designated as arrays, which means that more than one +value is allowed. For example, the option ``time-servers`` +allows the specification of more than one IPv4 address, enabling clients +to obtain the addresses of multiple NTP servers. + +:ref:`dhcp4-custom-options` describes the +configuration syntax to create custom option definitions (formats). +Creation of custom definitions for standard options is generally not +permitted, even if the definition being created matches the actual +option format defined in the RFCs. However, there is an exception to this rule +for standard options for which Kea currently does not provide a +definition. To use such options, a server administrator must +create a definition as described in +:ref:`dhcp4-custom-options` in the ``dhcp4`` option space. This +definition should match the option format described in the relevant RFC, +but the configuration mechanism allows any option format as there is +currently no way to validate it. + +The currently supported standard DHCPv4 options are listed in +the table below. "Name" and "Code" are the +values that should be used as a name/code in the option-data structures. +"Type" designates the format of the data; the meanings of the various +types are given in :ref:`dhcp-types`. + +.. _dhcp4-std-options-list: + +.. table:: List of standard DHCPv4 options configurable by an administrator + + +----------------------------------------+------+---------------------------+-------------+-------------+ + | Name | Code | Type | Array? | Returned if | + | | | | | not | + | | | | | requested? | + +========================================+======+===========================+=============+=============+ + | time-offset | 2 | int32 | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | routers | 3 | ipv4-address | true | true | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | time-servers | 4 | ipv4-address | true | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | name-servers | 5 | ipv4-address | true | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | domain-name-servers | 6 | ipv4-address | true | true | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | log-servers | 7 | ipv4-address | true | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | cookie-servers | 8 | ipv4-address | true | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | lpr-servers | 9 | ipv4-address | true | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | impress-servers | 10 | ipv4-address | true | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | resource-location-servers | 11 | ipv4-address | true | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | boot-size | 13 | uint16 | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | merit-dump | 14 | string | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | domain-name | 15 | fqdn | false | true | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | swap-server | 16 | ipv4-address | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | root-path | 17 | string | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | extensions-path | 18 | string | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | ip-forwarding | 19 | boolean | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | non-local-source-routing | 20 | boolean | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | policy-filter | 21 | ipv4-address | true | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | max-dgram-reassembly | 22 | uint16 | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | default-ip-ttl | 23 | uint8 | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | path-mtu-aging-timeout | 24 | uint32 | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | path-mtu-plateau-table | 25 | uint16 | true | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | interface-mtu | 26 | uint16 | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | all-subnets-local | 27 | boolean | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | broadcast-address | 28 | ipv4-address | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | perform-mask-discovery | 29 | boolean | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | mask-supplier | 30 | boolean | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | router-discovery | 31 | boolean | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | router-solicitation-address | 32 | ipv4-address | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | static-routes | 33 | ipv4-address | true | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | trailer-encapsulation | 34 | boolean | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | arp-cache-timeout | 35 | uint32 | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | ieee802-3-encapsulation | 36 | boolean | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | default-tcp-ttl | 37 | uint8 | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | tcp-keepalive-interval | 38 | uint32 | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | tcp-keepalive-garbage | 39 | boolean | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | nis-domain | 40 | string | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | nis-servers | 41 | ipv4-address | true | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | ntp-servers | 42 | ipv4-address | true | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | vendor-encapsulated-options | 43 | empty | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | netbios-name-servers | 44 | ipv4-address | true | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | netbios-dd-server | 45 | ipv4-address | true | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | netbios-node-type | 46 | uint8 | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | netbios-scope | 47 | string | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | font-servers | 48 | ipv4-address | true | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | x-display-manager | 49 | ipv4-address | true | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | dhcp-option-overload | 52 | uint8 | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | dhcp-server-identifier | 54 | ipv4-address | false | true | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | dhcp-message | 56 | string | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | dhcp-max-message-size | 57 | uint16 | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | vendor-class-identifier | 60 | string | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | nwip-domain-name | 62 | string | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | nwip-suboptions | 63 | binary | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | nisplus-domain-name | 64 | string | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | nisplus-servers | 65 | ipv4-address | true | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | tftp-server-name | 66 | string | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | boot-file-name | 67 | string | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | mobile-ip-home-agent | 68 | ipv4-address | true | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | smtp-server | 69 | ipv4-address | true | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | pop-server | 70 | ipv4-address | true | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | nntp-server | 71 | ipv4-address | true | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | www-server | 72 | ipv4-address | true | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | finger-server | 73 | ipv4-address | true | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | irc-server | 74 | ipv4-address | true | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | streettalk-server | 75 | ipv4-address | true | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | streettalk-directory-assistance-server | 76 | ipv4-address | true | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | user-class | 77 | binary | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | slp-directory-agent | 78 | record (boolean, | true | false | + | | | ipv4-address) | | | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | slp-service-scope | 79 | record (boolean, string) | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | nds-server | 85 | ipv4-address | true | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | nds-tree-name | 86 | string | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | nds-context | 87 | string | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | bcms-controller-names | 88 | fqdn | true | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | bcms-controller-address | 89 | ipv4-address | true | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | client-system | 93 | uint16 | true | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | client-ndi | 94 | record (uint8, uint8, | false | false | + | | | uint8) | | | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | uuid-guid | 97 | record (uint8, binary) | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | uap-servers | 98 | string | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | geoconf-civic | 99 | binary | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | pcode | 100 | string | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | tcode | 101 | string | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | v6-only-preferred | 108 | uint32 | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | netinfo-server-address | 112 | ipv4-address | true | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | netinfo-server-tag | 113 | string | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | v4-captive-portal | 114 | string | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | auto-config | 116 | uint8 | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | name-service-search | 117 | uint16 | true | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | domain-search | 119 | fqdn | true | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | classless-static-route | 121 | internal | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | vivco-suboptions | 124 | record (uint32, binary) | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | vivso-suboptions | 125 | uint32 | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | pana-agent | 136 | ipv4-address | true | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | v4-lost | 137 | fqdn | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | capwap-ac-v4 | 138 | ipv4-address | true | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | sip-ua-cs-domains | 141 | fqdn | true | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | v4-sztp-redirect | 143 | tuple | true | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | rdnss-selection | 146 | record (uint8, | true | false | + | | | ipv4-address, | | | + | | | ipv4-address, fqdn) | | | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | v4-portparams | 159 | record (uint8, psid) | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | v4-dnr | 162 | record (uint16, uint16, | false | false | + | | | uint8, fqdn, binary) | | | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | option-6rd | 212 | record (uint8, uint8, | true | false | + | | | ipv6-address, | | | + | | | ipv4-address) | | | + +----------------------------------------+------+---------------------------+-------------+-------------+ + | v4-access-domain | 213 | fqdn | false | false | + +----------------------------------------+------+---------------------------+-------------+-------------+ + +.. note:: + + The ``default-url`` option was replaced with ``v4-captive-portal`` in Kea 2.1.2, as introduced by + `RFC 8910 <https://tools.ietf.org/html/rfc8910>`_. The new option has exactly the same format as the + old one. The general perception is that ``default-url`` was seldom used. If you used it and migrating, + please replace ``default-url`` with ``v4-captive-portal`` and your configuration will continue to work + as before. + +Kea also supports other options than those listed above; the following options +are returned by the Kea engine itself and in general should not be configured +manually. + +.. table:: List of standard DHCPv4 options managed by Kea on its own and not directly configurable by an administrator + + +--------------------------------+-------+---------------------------------------+-------------------------------------------------------------------+ + | Name | Code | Type | Description | + +================================+=======+=======================================+===================================================================+ + | subnet-mask | 1 | ipv4-address | calculated automatically, based on subnet definition. | + +--------------------------------+-------+---------------------------------------+-------------------------------------------------------------------+ + | host-name | 12 | string | sent by client, generally governed by the DNS configuration. | + +--------------------------------+-------+---------------------------------------+-------------------------------------------------------------------+ + | dhcp-requested-address | 50 | ipv4-address | may be sent by the client and the server should not set it. | + +--------------------------------+-------+---------------------------------------+-------------------------------------------------------------------+ + | dhcp-lease-time | 51 | uint32 | set automatically based on the ``valid-lifetime`` parameter. | + +--------------------------------+-------+---------------------------------------+-------------------------------------------------------------------+ + | dhcp-message-type | 53 | string | sent by clients and servers. Set by the Kea engine depending on | + | | | | the situation and should never be configured explicitly. | + +--------------------------------+-------+---------------------------------------+-------------------------------------------------------------------+ + | dhcp-parameter-request-list | 55 | uint8 array | sent by clients and should never be sent by the server. | + +--------------------------------+-------+---------------------------------------+-------------------------------------------------------------------+ + | dhcp-renewal-time | 58 | uint32 | governed by ``renew-timer`` parameter. | + +--------------------------------+-------+---------------------------------------+-------------------------------------------------------------------+ + | dhcp-rebinding-time | 59 | uint32 | governed by ``rebind-timer`` parameter. | + +--------------------------------+-------+---------------------------------------+-------------------------------------------------------------------+ + | dhcp-client-identifier | 61 | binary | sent by client, echoed back with the value sent by the client. | + +--------------------------------+-------+---------------------------------------+-------------------------------------------------------------------+ + | fqdn | 81 | record (uint8, uint8, uint8, fqdn) | part of the DDNS and D2 configuration. | + +--------------------------------+-------+---------------------------------------+-------------------------------------------------------------------+ + | dhcp-agent-options | 82 | empty | sent by the relay agent. This is an empty container option; see | + | | | | RAI option detail later in this section. | + +--------------------------------+-------+---------------------------------------+-------------------------------------------------------------------+ + | authenticate | 90 | binary | sent by client, Kea does not yet validate it. | + +--------------------------------+-------+---------------------------------------+-------------------------------------------------------------------+ + | client-last-transaction-time | 91 | uint32 | sent by client, server does not set it. | + +--------------------------------+-------+---------------------------------------+-------------------------------------------------------------------+ + | associated-ip | 92 | ipv4-address array | sent by client, server responds with list of addresses. | + +--------------------------------+-------+---------------------------------------+-------------------------------------------------------------------+ + | subnet-selection | 118 | ipv4-address | if present in client's messages, will be used in the subnet | + | | | | selection process. | + +--------------------------------+-------+---------------------------------------+-------------------------------------------------------------------+ + +The following table lists all option types used in the previous two tables with a description of +what values are accepted for them. + +.. _dhcp-types: + +.. table:: List of standard DHCP option types + + +-----------------+-------------------------------------------------------+ + | Name | Meaning | + +=================+=======================================================+ + | binary | An arbitrary string of bytes, specified as a set | + | | of hexadecimal digits. | + +-----------------+-------------------------------------------------------+ + | boolean | A boolean value with allowed | + | | values true or false. | + +-----------------+-------------------------------------------------------+ + | empty | No value; data is carried in | + | | sub-options. | + +-----------------+-------------------------------------------------------+ + | fqdn | Fully qualified domain name (e.g. | + | | www.example.com). | + +-----------------+-------------------------------------------------------+ + | ipv4-address | IPv4 address in the usual | + | | dotted-decimal notation (e.g. | + | | 192.0.2.1). | + +-----------------+-------------------------------------------------------+ + | ipv6-address | IPv6 address in the usual colon | + | | notation (e.g. 2001:db8::1). | + +-----------------+-------------------------------------------------------+ + | ipv6-prefix | IPv6 prefix and prefix length | + | | specified using CIDR notation, | + | | e.g. 2001:db8:1::/64. This data | + | | type is used to represent an | + | | 8-bit field conveying a prefix | + | | length and the variable length | + | | prefix value. | + +-----------------+-------------------------------------------------------+ + | psid | PSID and PSID length separated by | + | | a slash, e.g. 3/4 specifies | + | | PSID=3 and PSID length=4. In the | + | | wire format it is represented by | + | | an 8-bit field carrying PSID | + | | length (in this case equal to 4) | + | | and the 16-bits-long PSID value | + | | field (in this case equal to | + | | "0011000000000000b" using binary | + | | notation). Allowed values for a | + | | PSID length are 0 to 16. See `RFC | + | | 7597 <https://tools.ietf.org/html/rfc7597>`__ | + | | for details about the PSID wire | + | | representation. | + +-----------------+-------------------------------------------------------+ + | record | Structured data that may be | + | | comprised of any types (except | + | | "record" and "empty"). The array | + | | flag applies to the last field | + | | only. | + +-----------------+-------------------------------------------------------+ + | string | Any text. Please note that Kea | + | | silently discards any | + | | terminating/trailing nulls from | + | | the end of "string" options when | + | | unpacking received packets. This | + | | is in keeping with `RFC 2132, | + | | Section | + | | 2 <https://tools.ietf.org/html/rfc2132#section-2>`__. | + +-----------------+-------------------------------------------------------+ + | tuple | A length encoded as an 8-bit (16-bit | + | | for DHCPv6) unsigned integer | + | | followed by a string of this | + | | length. | + +-----------------+-------------------------------------------------------+ + | uint8 | An 8-bit unsigned integer with | + | | allowed values 0 to 255. | + +-----------------+-------------------------------------------------------+ + | uint16 | A 16-bit unsigned integer with | + | | allowed values 0 to 65535. | + +-----------------+-------------------------------------------------------+ + | uint32 | A 32-bit unsigned integer with | + | | allowed values 0 to 4294967295. | + +-----------------+-------------------------------------------------------+ + | int8 | An 8-bit signed integer with allowed | + | | values -128 to 127. | + +-----------------+-------------------------------------------------------+ + | int16 | A 16-bit signed integer with | + | | allowed values -32768 to 32767. | + +-----------------+-------------------------------------------------------+ + | int32 | A 32-bit signed integer with | + | | allowed values -2147483648 to | + | | 2147483647. | + +-----------------+-------------------------------------------------------+ + +Kea also supports the Relay Agent Information (RAI, defined in +`RFC 3046 <https://tools.ietf.org/html/rfc3046>`_) option, sometimes referred to as the relay option, agent +option, or simply option 82. The option itself is just a container and does not convey any information +on its own. The following table contains a list of RAI sub-options that Kea can understand. The RAI +and its sub-options are inserted by the relay agent and received by Kea; there is no need for Kea +to be configured with those options. Kea's classification and flex-id in host reservations can be +used to process those and other options no listed in the table below. + +.. table:: List of RAI sub-options that Kea can understand + + +--------------------+------+----------------------------------------------------------------------+ + | Name | Code | Comment | + +====================+======+======================================================================+ + | circuit-id | 1 | Used when host-reservation-identifiers is set to `circuit-id`. | + +--------------------+------+----------------------------------------------------------------------+ + | remote-id | 2 | Can be used with flex-id to identify hosts. | + +--------------------+------+----------------------------------------------------------------------+ + | link-selection | 5 | If present, used to select the appropriate subnet. | + +--------------------+------+----------------------------------------------------------------------+ + | subscriber-id | 6 | Can be used with flex-id to identify hosts. | + +--------------------+------+----------------------------------------------------------------------+ + | server-id-override | 11 | If sent by the relay, Kea accepts it as the `server-id`. | + +--------------------+------+----------------------------------------------------------------------+ + | relay-id | 12 | Identifies the relay | + +--------------------+------+----------------------------------------------------------------------+ + | relay-port | 19 | If sent by the relay, Kea sends back its responses to this port. | + +--------------------+------+----------------------------------------------------------------------+ + +All other RAI sub-options (including those not listed here) can be used in client classification to +classify incoming packets to specific classes and/or by :ischooklib:`libdhcp_flex_id.so` to +construct a unique device identifier. For more information about expressions used in client +classification, and flex-id, see :ref:`classify`. The RAI sub-options can be +referenced using ``relay4[option-code].hex``. For example, to classify packets based on the +``remote-id`` (sub-option code 2), one would use ``relay4[2].hex``. An example client class that +would include all packets with a specific ``remote-id`` value would looks as follows: + +:: + + "Dhcp4": { + "client-classes": [ + { + "name": "remote-id-1020304", + "test": "relay4[2].hex == 0x01020304", + ... + } + ], + ... + } + +Classes may be used to segregate traffic into a relatively small number of groups, which then +can be used to select specific subnets, pools and extra options and more. If per host behavior +is necessary, using host reservations with flex-id is strongly recommended. + +.. _dhcp4-custom-options: + +Custom DHCPv4 Options +--------------------- + +Kea supports custom (non-standard) DHCPv4 options. Let's say that we want +to define a new DHCPv4 option called ``foo``, which will have code 222 +and will convey a single, unsigned, 32-bit integer value. +Such an option can be defined by putting the following entry in the configuration file: + +:: + + "Dhcp4": { + "option-def": [ + { + "name": "foo", + "code": 222, + "type": "uint32", + "array": false, + "record-types": "", + "space": "dhcp4", + "encapsulate": "" + }, + ... + ], + ... + } + +The ``false`` value of the ``array`` parameter determines that the +option does NOT comprise an array of ``uint32`` values but is, instead, a +single value. Two other parameters have been left blank: +``record-types`` and ``encapsulate``. The former specifies the +comma-separated list of option data fields, if the option comprises a +record of data fields. The ``record-types`` value should be non-empty if +``type`` is set to "record"; otherwise it must be left blank. The latter +parameter specifies the name of the option space being encapsulated by +the particular option. If the particular option does not encapsulate any +option space, the parameter should be left blank. Note that the ``option-def`` +configuration statement only defines the format of an option and does +not set its value(s). + +The ``name``, ``code``, and ``type`` parameters are required; all others +are optional. The ``array`` parameter default value is ``false``. The +``record-types`` and ``encapsulate`` parameters default values are blank +(``""``). The default ``space`` is ``dhcp4``. + +Once the new option format is defined, its value is set in the same way +as for a standard option. For example, the following commands set a +global value that applies to all subnets. + +:: + + "Dhcp4": { + "option-data": [ + { + "name": "foo", + "code": 222, + "space": "dhcp4", + "csv-format": true, + "data": "12345" + }, + ... + ], + ... + } + +New options can take more complex forms than the simple use of primitives +(uint8, string, ipv4-address, etc.); it is possible to define an option +comprising a number of existing primitives. + +For example, say we want to define a new option that will consist of +an IPv4 address, followed by an unsigned 16-bit integer, followed by a +boolean value, followed by a text string. Such an option could be +defined in the following way: + +:: + + "Dhcp4": { + "option-def": [ + { + "name": "bar", + "code": 223, + "space": "dhcp4", + "type": "record", + "array": false, + "record-types": "ipv4-address, uint16, boolean, string", + "encapsulate": "" + }, + ... + ], + ... + } + +The ``type`` parameter is set to ``"record"`` to indicate that the option +contains multiple values of different types. These types are given as a +comma-separated list in the ``record-types`` field and should be ones +from those listed in :ref:`dhcp-types`. + +The option's values are set in an ``option-data`` statement as follows: + +:: + + "Dhcp4": { + "option-data": [ + { + "name": "bar", + "space": "dhcp4", + "code": 223, + "csv-format": true, + "data": "192.0.2.100, 123, true, Hello World" + } + ], + ... + } + +The ``csv-format`` parameter is set to ``true`` to indicate that the ``data`` +field comprises a comma-separated list of values. The values in ``data`` must +correspond to the types set in the ``record-types`` field of the option +definition. + +When ``array`` is set to ``true`` and ``type`` is set to ``"record"``, the +last field is an array, i.e. it can contain more than one value, as in: + +:: + + "Dhcp4": { + "option-def": [ + { + "name": "bar", + "code": 223, + "space": "dhcp4", + "type": "record", + "array": true, + "record-types": "ipv4-address, uint16", + "encapsulate": "" + }, + ... + ], + ... + } + +The new option content is one IPv4 address followed by one or more 16-bit +unsigned integers. + +.. note:: + + In general, boolean values are specified as ``true`` or ``false``, + without quotes. Some specific boolean parameters may also accept + ``"true"``, ``"false"``, ``0``, ``1``, ``"0"``, and ``"1"``. + +.. note:: + + Numbers can be specified in decimal or hexadecimal format. The + hexadecimal format can be either plain (e.g. abcd) or prefixed with + 0x (e.g. 0xabcd). + +.. _dhcp4-private-opts: + +DHCPv4 Private Options +---------------------- + +Options with a code between 224 and 254 are reserved for private use. +They can be defined at the global scope or at the client-class local +scope; this allows option definitions to be used depending on context, +and option data to be set accordingly. For instance, to configure an old +PXEClient vendor: + +:: + + "Dhcp4": { + "client-classes": [ + { + "name": "pxeclient", + "test": "option[vendor-class-identifier].text == 'PXEClient'", + "option-def": [ + { + "name": "configfile", + "code": 209, + "type": "string" + } + ], + ... + }, + ... + ], + ... + } + +As the Vendor-Specific Information (VSI) option (code 43) has a vendor-specific +format, i.e. can carry either raw binary value or sub-options, this +mechanism is also available for this option. + +In the following example taken from a real configuration, two vendor +classes use option 43 for different and incompatible purposes: + +:: + + "Dhcp4": { + "option-def": [ + { + "name": "cookie", + "code": 1, + "type": "string", + "space": "APC" + }, + { + "name": "mtftp-ip", + "code": 1, + "type": "ipv4-address", + "space": "PXE" + }, + ... + ], + "client-classes": [ + { + "name": "APC", + "test": "option[vendor-class-identifier].text == 'APC'", + "option-def": [ + { + "name": "vendor-encapsulated-options", + "type": "empty", + "encapsulate": "APC" + } + ], + "option-data": [ + { + "name": "cookie", + "space": "APC", + "data": "1APC" + }, + { + "name": "vendor-encapsulated-options" + }, + ... + ], + ... + }, + { + "name": "PXE", + "test": "option[vendor-class-identifier].text == 'PXE'", + "option-def": [ + { + "name": "vendor-encapsulated-options", + "type": "empty", + "encapsulate": "PXE" + } + ], + "option-data": [ + { + "name": "mtftp-ip", + "space": "PXE", + "data": "0.0.0.0" + }, + { + "name": "vendor-encapsulated-options" + }, + ... + ], + ... + }, + ... + ], + ... + } + +The definition used to decode a VSI option is: + +1. The local definition of a client class the incoming packet belongs + to; + +2. If none, the global definition; + +3. If none, the last-resort definition described in the next section, + :ref:`dhcp4-vendor-opts` (backward-compatible with previous Kea versions). + +.. note:: + + This last-resort definition for the Vendor-Specific Information + option (code 43) is not compatible with a raw binary value. When + there are known cases where a raw binary value will be used, a + client class must be defined with both a classification expression + matching these cases and an option definition for the VSI option with + a binary type and no encapsulation. + +.. note:: + + By default, in the Vendor-Specific Information option (code 43), + sub-option code 0 and 255 mean PAD and END respectively, according to + `RFC 2132 <https://tools.ietf.org/html/rfc2132>`_. In other words, the + sub-option code values of 0 and 255 are reserved. Kea does, however, + allow users to define sub-option codes from 0 to 255. If + sub-options with codes 0 and/or 255 are defined, bytes with that value are + no longer treated as a PAD or an END, but as the sub-option code + when parsing a VSI option in an incoming query. + + Option 43 input processing (also called unpacking) is deferred so that it + happens after classification. This means clients cannot be classified + using option 43 sub-options. The definition used to unpack option 43 + is determined as follows: + + - If defined at the global scope, this definition is used. + - If defined at client class scope and the packet belongs to this + class, the client class definition is used. + - If not defined at global scope nor in a client class to which the + packet belongs, the built-in last resort definition is used. This + definition only says the sub-option space is + ``"vendor-encapsulated-options-space"``. + + The output definition selection is a bit simpler: + + - If the packet belongs to a client class which defines the option + 43, use this definition. + - If defined at the global scope, use this definition. + - Otherwise, use the built-in last-resort definition. + + Since they use a specific/per vendor option space, sub-options + are defined at the global scope. + +.. note:: + + Option definitions in client classes are allowed only for this + limited option set (codes 43 and from 224 to 254), and only for + DHCPv4. + +.. _dhcp4-vendor-opts: + +DHCPv4 Vendor-Specific Options +------------------------------ + +Currently there are two option spaces defined for :iscman:`kea-dhcp4`: +``dhcp4`` (for the top-level DHCPv4 options) and +``"vendor-encapsulated-options-space"``, which is empty by default but in +which options can be defined. Those options are carried in the +Vendor-Specific Information option (code 43). The following examples +show how to define an option ``foo`` with code 1 that +comprises an IPv4 address, an unsigned 16-bit integer, and a string. The +``foo`` option is conveyed in a Vendor-Specific Information option. + +The first step is to define the format of the option: + +:: + + "Dhcp4": { + "option-def": [ + { + "name": "foo", + "code": 1, + "space": "vendor-encapsulated-options-space", + "type": "record", + "array": false, + "record-types": "ipv4-address, uint16, string", + "encapsulate": "" + } + ], + ... + } + +Note that the option space is set to ``"vendor-encapsulated-options-space"``. +Once the option format is defined, the next step is to define actual values +for that option: + +:: + + "Dhcp4": { + "option-data": [ + { + "name": "foo", + "space": "vendor-encapsulated-options-space", + "code": 1, + "csv-format": true, + "data": "192.0.2.3, 123, Hello World" + } + ], + ... + } + +In this example, we also include the Vendor-Specific Information option, which +conveys our sub-option ``foo``. This is required; otherwise, the option +will not be included in messages sent to the client. + +:: + + "Dhcp4": { + "option-data": [ + { + "name": "vendor-encapsulated-options" + } + ], + ... + } + +Alternatively, the option can be specified using its code. + +:: + + "Dhcp4": { + "option-data": [ + { + "code": 43 + } + ], + ... + } + +Another popular option that is often somewhat imprecisely called the "vendor +option" is option 125. Its proper name is the "vendor-independent +vendor-specific information option" or "vivso". The idea behind vivso options +is that each vendor has its own unique set of options with their own custom +formats. The vendor is identified by a 32-bit unsigned integer called +``enterprise-number`` or ``vendor-id``. + + +The standard spaces defined in Kea and their options are: + +- ``vendor-4491``: Cable Television Laboratories, Inc. for DOCSIS3 options: + ++-------------+--------------+------------------------------------------------------------------------+ +| option code | option name | option description | ++=============+==============+========================================================================+ +| 1 | oro | ORO (or Option Request Option), used by clients to request a list of | +| | | options they are interested in. | ++-------------+--------------+------------------------------------------------------------------------+ +| 2 | tftp-servers | a list of IPv4 addresses of TFTP servers to be used by the cable modem | ++-------------+--------------+------------------------------------------------------------------------+ + +In Kea, each vendor is represented by its own vendor space. Since there are +hundreds of vendors and they sometimes use different option definitions for +different hardware, it is impossible for Kea to support them all natively. +Fortunately, it is easy to define support for new vendor options. As an +example, the Genexis home gateway device requires the vivso 125 option to be +sent with a sub-option 2 that contains a string with the TFTP server URL. To +support such a device, three steps are needed: first, establish option +definitions that explain how the option is supposed to be formed; second, +define option values; and third, tell Kea when to send those +specific options, via client classification. + +An example snippet of a configuration could look similar to the +following: + +:: + + "Dhcp4": { + // First, we need to define that the sub-option 2 in vivso option for + // vendor-id 25167 has a specific format (it's a plain string in this example). + // After this definition, we can specify values for option tftp. + "option-def": [ + { + // We define a short name, so the option can be referenced by name. + // The option has code 2 and resides within vendor space 25167. + // Its data is a plain string. + "name": "tftp", + "code": 2, + "space": "vendor-25167", + "type": "string" + } + ], + + "client-classes": [ + { + // We now need to tell Kea how to recognize when to use vendor space 25167. + // Usually we can use a simple expression, such as checking if the device + // sent a vivso option with specific vendor-id, e.g. "vendor[4491].exists". + // Unfortunately, Genexis is a bit unusual in this aspect, because it + // doesn't send vivso. In this case we need to look into the vendor class + // (option code 60) and see if there's a specific string that identifies + // the device. Alternatively, one can make use of the automated `VENDOR_CLASS_` + // client class and replace "name" and "test" with `"name": "VENDOR_CLASS_HMC1000"` + // and no test expression. + "name": "cpe_genexis", + "test": "substring(option[60].hex,0,7) == 'HMC1000'", + + // Once the device is recognized, we want to send two options: + // the vivso option with vendor-id set to 25167, and a sub-option 2. + "option-data": [ + { + "name": "vivso-suboptions", + "data": "25167" + }, + + // The sub-option 2 value is defined as any other option. However, + // we want to send this sub-option 2, even when the client didn't + // explicitly request it (often there is no way to do that for + // vendor options). Therefore we use always-send to force Kea + // to always send this option when 25167 vendor space is involved. + { + "name": "tftp", + "space": "vendor-25167", + "data": "tftp://192.0.2.1/genexis/HMC1000.v1.3.0-R.img", + "always-send": true + } + ] + } + ] + } + +By default, Kea sends back only those options that are requested by a client, +unless there are protocol rules that tell the DHCP server to always send an +option. This approach works nicely in most cases and avoids problems with +clients refusing responses with options they do not understand. However, the +situation with vendor options is more complex, as they are not requested the +same way as other options, are not well-documented in official RFCs, or vary by +vendor. + +Some vendors (such as DOCSIS, identified by vendor option 4491) have a mechanism +to request specific vendor options and Kea is able to honor those (sub-option 1). +Unfortunately, for many other vendors, such as Genexis (25167, discussed above), +Kea does not have such a mechanism, so it cannot send any sub-options on its own. +To solve this issue, we devised the concept of persistent options. Kea can be +told to always send options, even if the client did not request them. This can +be achieved by adding ``"always-send": true`` to the option data entry. Note +that in this particular case an option is defined in vendor space 25167. With +``always-send`` enabled, the option is sent every time there is a need to deal +with vendor space 25167. + +This is also how :iscman:`kea-dhcp4` can be configured to send multiple vendor options +from different vendors, along with each of their specific vendor ID. +If these options need to be sent by the server regardless of whether the client +specified any enterprise number, ``"always-send": true`` must be configured +for the suboptions that will be included in the ``vivso-suboptions`` option (code 125). + +:: + + "Dhcp4": { + "option-data": [ + # Typically DHCPv4 clients will send a Parameter Request List option (code 55) for + # vivso-suboptions (code 125), and that is enough for Kea to understand that it needs to + # send the option. These options still need to be defined in the configuration, one per + # each vendor, but they don't need "always-send" enabled in that case. For misbehaving + # clients that to do not explicitly request it, one may alternatively set "always-send" + # to true for them as well. This is referring to the following two entries in option-data. + { + "name": "vivso-suboptions", + "space": "dhcp4", + "data": "2234" + }, + { + "name": "vivso-suboptions", + "space": "dhcp4", + "data": "3561" + }, + { + "always-send": true, + "data": "tagged", + "name": "tag", + "space": "vendor-2234" + }, + { + "always-send": true, + "data": "https://example.com:1234/path", + "name": "url", + "space": "vendor-3561" + } + ], + "option-def": [ + { + "code": 22, + "name": "tag", + "space": "vendor-2234", + "type": "string" + }, + { + "code": 11, + "name": "url", + "space": "vendor-3561", + "type": "string" + } + ] + } + +Another possibility is to redefine the option; see :ref:`dhcp4-private-opts`. + +Kea comes with several example configuration files. Some of them showcase +how to configure options 60 and 43. See ``doc/examples/kea4/vendor-specific.json`` +and ``doc/examples/kea4/vivso.json`` in the Kea sources. + +.. note:: + + :iscman:`kea-dhcp4` is able to recognize multiple Vendor Class Identifier + options (code 60) with different vendor IDs in the client requests and to + send multiple vivso options (code 125) in the responses, one for each vendor. + + :iscman:`kea-dhcp4` honors DOCSIS sub-option 1 (ORO) and adds only requested options + if this sub-option is present in the client request. + + Currently only one vendor is supported for the ``vivco-suboptions`` + (code 124) option. Specifying multiple enterprise numbers within a single + option instance or multiple options with different enterprise numbers is not + supported. + +.. _dhcp4-option-spaces: + +Nested DHCPv4 Options (Custom Option Spaces) +-------------------------------------------- + +It is sometimes useful to define a completely new option space, such as +when a user creates a new option in the standard option space +(``dhcp4``) and wants this option to convey sub-options. Since they are in +a separate space, sub-option codes have a separate numbering scheme +and may overlap with the codes of standard options. + +Note that the creation of a new option space is not required when +defining sub-options for a standard option, because one is created by +default if the standard option is meant to convey any sub-options (see +:ref:`dhcp4-vendor-opts`). + +If we want a DHCPv4 option called ``container`` with code 222, +that conveys two sub-options with codes 1 and 2, we first need to +define the new sub-options: + +:: + + "Dhcp4": { + "option-def": [ + { + "name": "subopt1", + "code": 1, + "space": "isc", + "type": "ipv4-address", + "record-types": "", + "array": false, + "encapsulate": "" + }, + { + "name": "subopt2", + "code": 2, + "space": "isc", + "type": "string", + "record-types": "", + "array": false, + "encapsulate": "" + } + ], + ... + } + +Note that we have defined the options to belong to a new option space +(in this case, ``"isc"``). + +The next step is to define a regular DHCPv4 option with the desired code +and specify that it should include options from the new option space: + +:: + + "Dhcp4": { + "option-def": [ + { + "name": "container", + "code": 222, + "space": "dhcp4", + "type": "empty", + "array": false, + "record-types": "", + "encapsulate": "isc" + }, + ... + ], + ... + } + +The name of the option space in which the sub-options are defined is set +in the ``encapsulate`` field. The ``type`` field is set to ``"empty"``, to +indicate that this option does not carry any data other than +sub-options. + +Finally, we can set values for the new options: + +.. code-block:: json + + { + "Dhcp4": { + "option-data": [ + { + "name": "subopt1", + "code": 1, + "space": "isc", + "data": "192.0.2.3" + }, + { + "name": "subopt2", + "code": 2, + "space": "isc", + "data": "Hello world" + }, + { + "name": "container", + "code": 222, + "space": "dhcp4" + } + ] + } + } + +It is possible to create an option which carries some data in +addition to the sub-options defined in the encapsulated option space. +For example, if the ``container`` option from the previous example were +required to carry a uint16 value as well as the sub-options, the +``type`` value would have to be set to ``"uint16"`` in the option +definition. (Such an option would then have the following data +structure: DHCP header, uint16 value, sub-options.) The value specified +with the ``data`` parameter — which should be a valid integer enclosed +in quotes, e.g. ``"123"`` — would then be assigned to the ``uint16`` field in +the ``container`` option. + +.. _dhcp4-option-data-defaults: + +Unspecified Parameters for DHCPv4 Option Configuration +------------------------------------------------------ + +In many cases it is not required to specify all parameters for an option +configuration, and the default values can be used. However, it is +important to understand the implications of not specifying some of them, +as it may result in configuration errors. The list below explains the +behavior of the server when a particular parameter is not explicitly +specified: + +- ``name`` - the server requires either an option name or an option code to + identify an option. If this parameter is unspecified, the option code + must be specified. + +- ``code`` - the server requires either an option name or an option code to + identify an option; this parameter may be left unspecified if the + ``name`` parameter is specified. However, this also requires that the + particular option have a definition (either as a standard option or + an administrator-created definition for the option using an + ``option-def`` structure), as the option definition associates an + option with a particular name. It is possible to configure an option + for which there is no definition (unspecified option format). + Configuration of such options requires the use of the option code. + +- ``space`` - if the option space is unspecified it defaults to + ``dhcp4``, which is an option space holding standard DHCPv4 options. + +- ``data`` - if the option data is unspecified it defaults to an empty + value. The empty value is mostly used for the options which have no + payload (boolean options), but it is legal to specify empty values + for some options which carry variable-length data and for which the + specification allows a length of 0. For such options, the data + parameter may be omitted in the configuration. + +- ``csv-format`` - if this value is not specified, the server + assumes that the option data is specified as a list of comma-separated + values to be assigned to individual fields of the DHCP option. + +.. _dhcp4-support-for-long-options: + +Support for Long Options +------------------------ + +The :iscman:`kea-dhcp4` server partially supports long options (RFC3396). +Since Kea 2.1.6, the server accepts configuring long options and sub-options +(longer than 255 bytes). The options and sub-options are stored internally +in their unwrapped form and they can be processed as usual using the parser +language. On send, the server splits long options and sub-options into multiple +options and sub-options, using the respective option code. + +:: + + { + "option-def": [ + { + "array": false, + "code": 240, + "encapsulate": "", + "name": "my-option", + "space": "dhcp4", + "type": "string" + } + ], + "subnet4": [ + { + "id": 1, + "subnet": "192.0.2.0/24", + "reservations": [ + { + "hw-address": "aa:bb:cc:dd:ee:ff", + "option-data": [ + { + "always-send": false, + "code": 240, + "name": "my-option", + "csv-format": true, + "data": "data \ + -00010203040506070809-00010203040506070809-00010203040506070809-00010203040506070809 \ + -00010203040506070809-00010203040506070809-00010203040506070809-00010203040506070809 \ + -00010203040506070809-00010203040506070809-00010203040506070809-00010203040506070809 \ + -data", + "space": "dhcp4" + } + ] + } + ] + } + ], + ... + } + +.. note:: + + In the example above, the data has been wrapped into several lines for clarity, + but Kea does not support wrapping in the configuration file. + +This example illustrates configuring a custom long option (exceeding 255 octets) +in a reservation. When sending a response, the server splits this option +into two options, each with the code 240. + +.. note:: + + Currently the server does not support storing long options in databases, + either host reservations or the configuration backend. + +The server is also able to receive packets with split options (options using +the same option code) and to fuse the data chunks into one option. This is +also supported for sub-options if each sub-option data chunk also contains the +sub-option code and sub-option length. + +.. _dhcp4-stateless-configuration: + +Stateless Configuration of DHCPv4 Clients +----------------------------------------- + +The DHCPv4 server supports stateless client configuration, whereby +the client has an IP address configured (e.g. using manual +configuration) and only contacts the server to obtain other +configuration parameters, such as addresses of DNS servers. To +obtain the stateless configuration parameters, the client sends the +DHCPINFORM message to the server with the ``ciaddr`` set to the address +that the client is currently using. The server unicasts the DHCPACK +message to the client that includes the stateless configuration +("yiaddr" not set). + +The server responds to the DHCPINFORM when the client is associated +with a subnet defined in the server's configuration. An example subnet +configuration looks like this: + +:: + + "Dhcp4": { + "subnet4": [ + { + "id": 1, + "subnet": "192.0.2.0/24", + "option-data": [ + { + "name": "domain-name-servers", + "code": 6, + "data": "192.0.2.200,192.0.2.201", + "csv-format": true, + "space": "dhcp4" + } + ] + } + ] + } + +This subnet specifies the single option which will be included in the +DHCPACK message to the client in response to DHCPINFORM. The +subnet definition does not require the address pool configuration if it +will be used solely for stateless configuration. + +This server will associate the subnet with the client if one of the +following conditions is met: + +- The DHCPINFORM is relayed and the ``giaddr`` matches the configured + subnet. + +- The DHCPINFORM is unicast from the client and the ``ciaddr`` matches the + configured subnet. + +- The DHCPINFORM is unicast from the client and the ``ciaddr`` is not set, + but the source address of the IP packet matches the configured + subnet. + +- The DHCPINFORM is not relayed and the IP address on the interface on + which the message is received matches the configured subnet. + +.. _dhcp4-client-classifier: + +Client Classification in DHCPv4 +------------------------------- + +The DHCPv4 server includes support for client classification. For a +deeper discussion of the classification process, see :ref:`classify`. + +In certain cases it is useful to configure the server to differentiate +between DHCP client types and treat them accordingly. Client +classification can be used to modify the behavior of almost any part of +DHCP message processing. Kea currently offers client classification +via private options and option 43 deferred unpacking; subnet selection; +pool selection; assignment of different options; and, for cable modems, +specific options for use with the TFTP server address and the boot file +field. + +Kea can be instructed to limit access to given subnets based on class +information. This is particularly useful for cases where two types of +devices share the same link and are expected to be served from two +different subnets. The primary use case for such a scenario is cable +networks, where there are two classes of devices: the cable modem +itself, which should be handed a lease from subnet A; and all other +devices behind the modem, which should get leases from subnet B. That +segregation is essential to prevent overly curious end-users from playing +with their cable modems. For details on how to set up class restrictions +on subnets, see :ref:`classification-subnets`. + +When subnets belong to a shared network, the classification applies to +subnet selection but not to pools; that is, a pool in a subnet limited to a +particular class can still be used by clients which do not belong to the +class, if the pool they are expected to use is exhausted. The limit +on access based on class information is also available at the pool +level within a subnet: see :ref:`classification-pools`. This is +useful when segregating clients belonging to the same subnet into +different address ranges. + +In a similar way, a pool can be constrained to serve only known clients, +i.e. clients which have a reservation, using the built-in ``KNOWN`` or +``UNKNOWN`` classes. Addresses can be assigned to registered clients +without giving a different address per reservation: for instance, when +there are not enough available addresses. The determination whether +there is a reservation for a given client is made after a subnet is +selected, so it is not possible to use ``KNOWN``/``UNKNOWN`` classes to select a +shared network or a subnet. + +The process of classification is conducted in five steps. The first step +is to assess an incoming packet and assign it to zero or more classes. +The second step is to choose a subnet, possibly based on the class +information. When the incoming packet is in the special class ``DROP``, +it is dropped and a debug message logged. +The next step is to evaluate class expressions depending on +the built-in ``KNOWN``/``UNKNOWN`` classes after host reservation lookup, +using them for pool selection and assigning classes from host +reservations. The list of required classes is then built and each class +of the list has its expression evaluated; when it returns ``true``, the +packet is added as a member of the class. The last step is to assign +options, again possibly based on the class information. More complete +and detailed information is available in :ref:`classify`. + +There are two main methods of classification. The first is automatic and +relies on examining the values in the vendor class options or the +existence of a host reservation. Information from these options is +extracted, and a class name is constructed from it and added to the +class list for the packet. The second method specifies an expression that is +evaluated for each packet. If the result is ``true``, the packet is a +member of the class. + +.. note:: + + The new ``early-global-reservations-lookup`` global parameter flag + enables a lookup for global reservations before the subnet selection + phase. This lookup is similar to the general lookup described above + with two differences: + + - the lookup is limited to global host reservations + + - the ``UNKNOWN`` class is never set + +.. note:: + + Care should be taken with client classification, as it is easy for + clients that do not meet class criteria to be denied all service. + +Setting Fixed Fields in Classification +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +It is possible to specify that clients belonging to a particular class +should receive packets with specific values in certain fixed fields. In +particular, three fixed fields are supported: ``next-server`` (conveys +an IPv4 address, which is set in the ``siaddr`` field), ``server-hostname`` +(conveys a server hostname, can be up to 64 bytes long, and is sent in +the ``sname`` field) and ``boot-file-name`` (conveys the configuration file, +can be up to 128 bytes long, and is sent using the ``file`` field). + +Obviously, there are many ways to assign clients to specific classes, +but for PXE clients the client architecture type option (code 93) +seems to be particularly suited to make the distinction. The following +example checks whether the client identifies itself as a PXE device with +architecture EFI x86-64, and sets several fields if it does. See +`Section 2.1 of RFC +4578 <https://tools.ietf.org/html/rfc4578#section-2.1>`__) or the +client documentation for specific values. + +:: + + "Dhcp4": { + "client-classes": [ + { + "name": "ipxe_efi_x64", + "test": "option[93].hex == 0x0009", + "next-server": "192.0.2.254", + "server-hostname": "hal9000", + "boot-file-name": "/dev/null" + }, + ... + ], + ... + } + +If an incoming packet is matched to multiple classes, then the +value used for each field will come from the first class that +specifies the field, in the order the classes are assigned to the +packet. + +.. note:: + + The classes are ordered as specified in the configuration. + +Using Vendor Class Information in Classification +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The server checks whether an incoming packet includes the vendor class +identifier option (60). If it does, the content of that option is +prepended with ``VENDOR_CLASS_``, and it is interpreted as a class. For +example, modern cable modems send this option with value +``docsis3.0``, so the packet belongs to the class +``VENDOR_CLASS_docsis3.0``. + +.. note:: + + Certain special actions for clients in ``VENDOR_CLASS_docsis3.0`` can be + achieved by defining ``VENDOR_CLASS_docsis3.0`` and setting its + ``next-server`` and ``boot-file-name`` values appropriately. + +This example shows a configuration using an automatically generated +``VENDOR_CLASS_`` class. The administrator of the network has decided that +addresses from the range 192.0.2.10 to 192.0.2.20 are going to be managed by +the Dhcp4 server and only clients belonging to the DOCSIS 3.0 client +class are allowed to use that pool. + +:: + + "Dhcp4": { + "subnet4": [ + { + "id": 1, + "subnet": "192.0.2.0/24", + "pools": [ { "pool": "192.0.2.10 - 192.0.2.20" } ], + "client-class": "VENDOR_CLASS_docsis3.0" + } + ], + ... + } + +Defining and Using Custom Classes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following example shows how to configure a class using an expression +and a subnet using that class. This configuration defines the class +named ``Client_foo``. It is comprised of all clients whose client IDs +(option 61) start with the string ``foo``. Members of this class will be +given addresses from 192.0.2.10 to 192.0.2.20 and the addresses of their +DNS servers set to 192.0.2.1 and 192.0.2.2. + +:: + + "Dhcp4": { + "client-classes": [ + { + "name": "Client_foo", + "test": "substring(option[61].hex,0,3) == 'foo'", + "option-data": [ + { + "name": "domain-name-servers", + "code": 6, + "space": "dhcp4", + "csv-format": true, + "data": "192.0.2.1, 192.0.2.2" + } + ] + }, + ... + ], + "subnet4": [ + { + "id": 1, + "subnet": "192.0.2.0/24", + "pools": [ { "pool": "192.0.2.10 - 192.0.2.20" } ], + "client-class": "Client_foo" + }, + ... + ], + ... + } + +.. _dhcp4-required-class: + +Required Classification +~~~~~~~~~~~~~~~~~~~~~~~ + +In some cases it is useful to limit the scope of a class to a +shared network, subnet, or pool. There are two parameters which are used +to limit the scope of the class by instructing the server to evaluate test +expressions when required. + +The first one is the per-class ``only-if-required`` flag, which is ``false`` +by default. When it is set to ``true``, the test expression of the class +is not evaluated at the reception of the incoming packet but later, and +only if the class evaluation is required. + +The second is ``require-client-classes``, which takes a list of class +names and is valid in shared-network, subnet, and pool scope. Classes in +these lists are marked as required and evaluated after selection of this +specific shared network/subnet/pool and before output-option processing. + +In this example, a class is assigned to the incoming packet when the +specified subnet is used: + +:: + + "Dhcp4": { + "client-classes": [ + { + "name": "Client_foo", + "test": "member('ALL')", + "only-if-required": true + }, + ... + ], + "subnet4": [ + { + "subnet": "192.0.2.0/24", + "pools": [ { "pool": "192.0.2.10 - 192.0.2.20" } ], + "require-client-classes": [ "Client_foo" ], + ... + }, + ... + ], + ... + } + +Required evaluation can be used to express complex dependencies like +subnet membership. It can also be used to reverse the +precedence; if ``option-data`` is set in a subnet, it takes precedence +over ``option-data`` in a class. If ``option-data`` is moved to a +required class and required in the subnet, a class evaluated earlier +may take precedence. + +Required evaluation is also available at the shared-network and pool levels. +The order in which required classes are considered is: shared-network, +subnet, and pool, i.e. in the reverse order from the way in which +``option-data`` is processed. + +.. note:: + + Vendor-Identifying Vendor Options are a special case: for all other + options an option is identified by its code point, but ``vivco-suboptions`` + (124) and ``vivso-suboptions`` (125) are identified by the pair of + code point and vendor identifier. This has no visible effect for + ``vivso-suboptions``, whose value is the vendor identifier, but it + is different for ``vivco-suboptions``, where the value is a record + with the vendor identifier and a binary value. For instance, in: + +:: + + "Dhcp4": { + "option-data": [ + { + "name": "vivco-suboptions", + "always-send": true, + "data": "1234, 03666f6f" + }, + { + "name": "vivco-suboptions", + "always-send": true, + "data": "5678, 03626172" + }, + ... + ], + ... + } + +The first ``option-data`` entry does not hide the second one, because +vendor identifiers (1234 and 5678) are different: the responses will carry +two instances of the ``vivco-suboptions`` option, each for a different vendor. + +.. _dhcp4-ddns-config: + +DDNS for DHCPv4 +--------------- + +As mentioned earlier, :iscman:`kea-dhcp4` can be configured to generate requests +to the DHCP-DDNS server, :iscman:`kea-dhcp-ddns`, (referred to herein as "D2") to +update DNS entries. These requests are known as NameChangeRequests or +NCRs. Each NCR contains the following information: + +1. Whether it is a request to add (update) or remove DNS entries. + +2. Whether the change requests forward DNS updates (A records), reverse + DNS updates (PTR records), or both. + +3. The Fully Qualified Domain Name (FQDN), lease address, and DHCID + (information identifying the client associated with the FQDN). + +DDNS-related parameters are split into two groups: + +1. Connectivity Parameters + + These are parameters which specify where and how :iscman:`kea-dhcp4` connects to + and communicates with D2. These parameters can only be specified + within the top-level ``dhcp-ddns`` section in the :iscman:`kea-dhcp4` + configuration. The connectivity parameters are listed below: + + - ``enable-updates`` + - ``server-ip`` + - ``server-port`` + - ``sender-ip`` + - ``sender-port`` + - ``max-queue-size`` + - ``ncr-protocol`` + - ``ncr-format"`` + +2. Behavioral Parameters + + These parameters influence behavior such as how client host names and + FQDN options are handled. They have been moved out of the ``dhcp-ddns`` + section so that they may be specified at the global, shared-network, + and/or subnet levels. Furthermore, they are inherited downward from global to + shared-network to subnet. In other words, if a parameter is not specified at + a given level, the value for that level comes from the level above it. + The behavioral parameters are as follows: + + - ``ddns-send-updates`` + - ``ddns-override-no-update`` + - ``ddns-override-client-update`` + - ``ddns-replace-client-name"`` + - ``ddns-generated-prefix`` + - ``ddns-qualifying-suffix`` + - ``ddns-update-on-renew`` + - ``ddns-conflict-resolution-mode`` + - ``ddns-ttl-percent`` + - ``hostname-char-set`` + - ``hostname-char-replacement`` + +.. note:: + + For backward compatibility, configuration parsing still recognizes + the original behavioral parameters specified in ``dhcp-ddns``, + by translating the parameter into its global equivalent. If a + parameter is specified both globally and in ``dhcp-ddns``, the latter + value is ignored. In either case, a log is emitted explaining + what has occurred. Specifying these values within ``dhcp-ddns`` is + deprecated and support for it will be removed. + +The default configuration and values would appear as follows: + +:: + + "Dhcp4": { + "dhcp-ddns": { + // Connectivity parameters + "enable-updates": false, + "server-ip": "127.0.0.1", + "server-port":53001, + "sender-ip":"", + "sender-port":0, + "max-queue-size":1024, + "ncr-protocol":"UDP", + "ncr-format":"JSON" + }, + + // Behavioral parameters (global) + "ddns-send-updates": true, + "ddns-override-no-update": false, + "ddns-override-client-update": false, + "ddns-replace-client-name": "never", + "ddns-generated-prefix": "myhost", + "ddns-qualifying-suffix": "", + "ddns-update-on-renew": false, + "ddns-conflict-resolution-mode": "check-with-dhcid", + "hostname-char-set": "", + "hostname-char-replacement": "", + ... + } + +There are two parameters which determine if :iscman:`kea-dhcp4` +can generate DDNS requests to D2: the existing ``dhcp-ddns:enable-updates`` +parameter, which now only controls whether :iscman:`kea-dhcp4` connects to D2; +and the new behavioral parameter, ``ddns-send-updates``, which determines +whether DDNS updates are enabled at a given level (i.e. global, shared-network, +or subnet). The following table shows how the two parameters function +together: + +.. table:: Enabling and disabling DDNS updates + + +-----------------+--------------------+-------------------------------------+ + | dhcp-ddns: | Global | Outcome | + | enable-updates | ddns-send-updates | | + +=================+====================+=====================================+ + | false (default) | false | no updates at any scope | + +-----------------+--------------------+-------------------------------------+ + | false | true (default) | no updates at any scope | + +-----------------+--------------------+-------------------------------------+ + | true | false | updates only at scopes with | + | | | a local value of ``true`` for | + | | | ``ddns-enable-updates`` | + +-----------------+--------------------+-------------------------------------+ + | true | true | updates at all scopes except those | + | | | with a local value of ``false`` | + | | | for ``ddns-enable-updates`` | + +-----------------+--------------------+-------------------------------------+ + +Kea 1.9.1 added two new parameters; the first is ``ddns-update-on-renew``. +Normally, when leases are renewed, the server only updates DNS if the DNS +information for the lease (e.g. FQDN, DNS update direction flags) has changed. +Setting ``ddns-update-on-renew`` to ``true`` instructs the server to always update +the DNS information when a lease is renewed, even if its DNS information has not +changed. This allows Kea to "self-heal" if it was previously unable +to add DNS entries or they were somehow lost by the DNS server. + +.. note:: + + Setting ``ddns-update-on-renew`` to ``true`` may impact performance, especially + for servers with numerous clients that renew often. + +The second parameter added in Kea 1.9.1 is ``ddns-use-conflict-resolution``. This +boolean parameter was passed through to D2 and enabled or disabled conflict resolution +as described in `RFC 4703 <https://tools.ietf.org/html/rfc4703>`__. Beginning with +Kea 2.5.0, it is deprecated and replaced by ``ddns-conflict-resolution-mode`` which +offers four modes of conflict resolution-related behavior: + + - ``check-with-dhcid`` - The default mode, it instructs D2 to carry out RFC + 4703-compliant conflict resolution. Existing DNS entries may only be + overwritten if they have a DHCID record and it matches the client's DHCID. + This is equivalent to ``ddns-use-conflict-resolution``: true; + + - ``no-check-with-dhcid`` - Existing DNS entries may be overwritten by any + client, whether or not those entries include a DHCID record. The new entries + will include a DHCID record for the client to whom they belong. + This is equivalent to ``ddns-use-conflict-resolution``: false; + + - ``check-exists-with-dhcid`` - Existing DNS entries may only be overwritten + if they have a DHCID record. The DHCID record need not match the client's DHCID. + This mode provides a way to protect static DNS entries (those that do not have + a DHCID record) while allowing dynamic entries (those that do have a DHCID + record) to be overwritten by any client. This behavior was not supported + prior to Kea 2.4.0. + + - ``no-check-without-dhcid`` - Existing DNS entries may be overwritten by + any client. New entries will not include DHCID records. This behavior was + not supported prior to Kea 2.4.0. + +.. note:: + + For backward compatibility, ddns-use-conflict-resolution is still accepted in + JSON configuration. The server will replace the value internally, with the + ``ddns-conflict-resolution-mode`` and an appropriate value: ` + `check-with-dhcid`` for ``true`` and ``no-check-with-dhcid`` for ``false``. + +.. note:: + + Setting ``ddns-conflict-resolution-mode`` to any value other than + ``check-with-dhcid`` disables the one or more overwrite safeguards + that the rules of conflict resolution (from + `RFC 4703 <https://tools.ietf.org/html/rfc4703>`__) are intended to + prevent. This means that existing entries for an FQDN or an + IP address made for Client-A can be deleted or replaced by entries + for Client-B. Furthermore, there are two scenarios by which entries + for multiple clients for the same key (e.g. FQDN or IP) can be created. + + 1. Client-B uses the same FQDN as Client-A but a different IP address. + In this case, the forward DNS entries (A and DHCID RRs) for + Client-A will be deleted as they match the FQDN and new entries for + Client-B will be added. The reverse DNS entries (PTR and DHCID RRs) + for Client-A, however, will not be deleted as they belong to a different + IP address, while new entries for Client-B will still be added. + + 2. Client-B uses the same IP address as Client-A but a different FQDN. + In this case the reverse DNS entries (PTR and DHCID RRs) for Client-A + will be deleted as they match the IP address, and new entries for + Client-B will be added. The forward DNS entries (A and DHCID RRs) + for Client-A, however, will not be deleted, as they belong to a different + FQDN, while new entries for Client-B will still be added. + + Disabling conflict resolution should be done only after careful review of + specific use cases. The best way to avoid unwanted DNS entries is to + always ensure lease changes are processed through Kea, whether they are + released, expire, or are deleted via the :isccmd:`lease4-del` command, prior to + reassigning either FQDNs or IP addresses. Doing so causes :iscman:`kea-dhcp4` + to generate DNS removal requests to D2. + +The DNS entries Kea creates contain a value for TTL (time to live). +The :iscman:`kea-dhcp4` server calculates that value based on +`RFC 4702, Section 5 <https://tools.ietf.org/html/rfc4702#section-5>`__, +which suggests that the TTL value be 1/3 of the lease's lifetime, with +a minimum value of 10 minutes. + +The parameter ``ddns-ttl-percent``, when specified, +causes the TTL to be calculated as a simple percentage of the lease's +lifetime, using the parameter's value as the percentage. It is specified +as a decimal percent (e.g. .25, .75, 1.00) and may be specified at the +global, shared-network, and subnet levels. By default it is unspecified. + +.. _dhcpv4-d2-io-config: + +DHCP-DDNS Server Connectivity +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For NCRs to reach the D2 server, :iscman:`kea-dhcp4` must be able to communicate +with it. :iscman:`kea-dhcp4` uses the following configuration parameters to +control this communication: + +- ``enable-updates`` - Enables connectivity to :iscman:`kea-dhcp-ddns` such that DDNS + updates can be constructed and sent. + It must be ``true`` for NCRs to be generated and sent to D2. + It defaults to ``false``. + +- ``server-ip`` - This is the IP address on which D2 listens for requests. The + default is the local loopback interface at address 127.0.0.1. + Either an IPv4 or IPv6 address may be specified. + +- ``server-port`` - This is the port on which D2 listens for requests. The default + value is ``53001``. + +- ``sender-ip`` - This is the IP address which :iscman:`kea-dhcp4` uses to send requests to + D2. The default value is blank, which instructs :iscman:`kea-dhcp4` to select a + suitable address. + +- ``sender-port`` - This is the port which :iscman:`kea-dhcp4` uses to send requests to D2. + The default value of ``0`` instructs :iscman:`kea-dhcp4` to select a suitable port. + +- ``max-queue-size`` - This is the maximum number of requests allowed to queue + while waiting to be sent to D2. This value guards against requests + accumulating uncontrollably if they are being generated faster than + they can be delivered. If the number of requests queued for + transmission reaches this value, DDNS updating is turned off + until the queue backlog has been sufficiently reduced. The intent is + to allow the :iscman:`kea-dhcp4` server to continue lease operations without + running the risk that its memory usage grows without limit. The + default value is ``1024``. + +- ``ncr-protocol`` - This specifies the socket protocol to use when sending requests to + D2. Currently only UDP is supported. + +- ``ncr-format`` - This specifies the packet format to use when sending requests to D2. + Currently only JSON format is supported. + +By default, :iscman:`kea-dhcp-ddns` is assumed to be running on the same machine +as :iscman:`kea-dhcp4`, and all of the default values mentioned above should be +sufficient. If, however, D2 has been configured to listen on a different +address or port, these values must be altered accordingly. For example, if +D2 has been configured to listen on 192.168.1.10 port 900, the following +configuration is required: + +:: + + "Dhcp4": { + "dhcp-ddns": { + "server-ip": "192.168.1.10", + "server-port": 900, + ... + }, + ... + } + +.. _dhcpv4-d2-rules-config: + +When Does the :iscman:`kea-dhcp4` Server Generate a DDNS Request? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The :iscman:`kea-dhcp4` server follows the behavior prescribed for DHCP servers in +`RFC 4702 <https://tools.ietf.org/html/rfc4702>`__. It is important to keep +in mind that :iscman:`kea-dhcp4` makes the initial decision of when and what to +update and forwards that information to D2 in the form of NCRs. Carrying +out the actual DNS updates and dealing with such things as conflict +resolution are within the purview of D2 itself +(see :ref:`dhcp-ddns-server`). This section describes when :iscman:`kea-dhcp4` +generates NCRs and the configuration parameters that can be used to +influence this decision. It assumes that both the connectivity parameter +``enable-updates`` and the behavioral parameter ``ddns-send-updates``, +are ``true``. + +In general, :iscman:`kea-dhcp4` generates DDNS update requests when: + +1. A new lease is granted in response to a DHCPREQUEST; + +2. An existing lease is renewed but the FQDN associated with it has + changed; or + +3. An existing lease is released in response to a DHCPRELEASE. + +In the second case, lease renewal, two DDNS requests are issued: one +request to remove entries for the previous FQDN, and a second request to +add entries for the new FQDN. In the third case, a lease release - a +single DDNS request - to remove its entries will be made. + +As for the first case, the decisions involved when granting a new lease are +more complex. When a new lease is granted, :iscman:`kea-dhcp4` generates a +DDNS update request if the DHCPREQUEST contains either the FQDN option +(code 81) or the Host Name option (code 12). If both are present, the +server uses the FQDN option. +By default, :iscman:`kea-dhcp4` respects the FQDN N and S flags +specified by the client as shown in the following table: + +.. table:: Default FQDN flag behavior + + +------------+-----------------+-----------------+-------------+ + | Client | Client Intent | Server Response | Server | + | Flags:N-S | | | Flags:N-S-O | + +============+=================+=================+=============+ + | 0-0 | Client wants to | Server | 1-0-0 | + | | do forward | generates | | + | | updates, server | reverse-only | | + | | should do | request | | + | | reverse updates | | | + +------------+-----------------+-----------------+-------------+ + | 0-1 | Server should | Server | 0-1-0 | + | | do both forward | generates | | + | | and reverse | request to | | + | | updates | update both | | + | | | directions | | + +------------+-----------------+-----------------+-------------+ + | 1-0 | Client wants no | Server does not | 1-0-0 | + | | updates done | generate a | | + | | | request | | + +------------+-----------------+-----------------+-------------+ + +The first row in the table above represents "client delegation." Here +the DHCP client states that it intends to do the forward DNS updates and +the server should do the reverse updates. By default, :iscman:`kea-dhcp4` +honors the client's wishes and generates a DDNS request to the D2 server +to update only reverse DNS data. The parameter +``ddns-override-client-update`` can be used to instruct the server to +override client delegation requests. When this parameter is ``true``, +:iscman:`kea-dhcp4` disregards requests for client delegation and generates a +DDNS request to update both forward and reverse DNS data. In this case, +the N-S-O flags in the server's response to the client will be 0-1-1 +respectively. + +(Note that the flag combination N=1, S=1 is prohibited according to `RFC +4702 <https://tools.ietf.org/html/rfc4702>`__. If such a combination is +received from the client, the packet will be dropped by :iscman:`kea-dhcp4`.) + +To override client delegation, set the following values in the +configuration file: + +:: + + "Dhcp4": { + "ddns-override-client-update": true, + ... + } + +The third row in the table above describes the case in which the client +requests that no DNS updates be done. The parameter +``ddns-override-no-update`` can be used to instruct the server to disregard +the client's wishes. When this parameter is ``true``, :iscman:`kea-dhcp4` +generates DDNS update requests to :iscman:`kea-dhcp-ddns` even if the client +requests that no updates be done. The N-S-O flags in the server's response to +the client will be 0-1-1. + +To override client delegation, issue the following commands: + +:: + + "Dhcp4": { + "ddns-override-no-update": true, + ... + } + +The :iscman:`kea-dhcp4` server always generates DDNS update requests if the +client request only contains the Host Name option. In addition, it includes +an FQDN option in the response to the client with the FQDN N-S-O flags +set to 0-1-0, respectively. The domain name portion of the FQDN option +is the name submitted to D2 in the DDNS update request. + +.. _dhcpv4-fqdn-name-generation: + +:iscman:`kea-dhcp4` Name Generation for DDNS Update Requests +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Each NameChangeRequest must of course include the fully qualified domain +name whose DNS entries are to be affected. :iscman:`kea-dhcp4` can be configured +to supply a portion or all of that name, based on what it receives +from the client in the DHCPREQUEST. + +The default rules for constructing the FQDN that will be used for DNS +entries are: + +1. If the DHCPREQUEST contains the client FQDN option, take the + candidate name from there; otherwise, take it from the Host Name + option. + +2. If the candidate name is a partial (i.e. unqualified) name, then add + a configurable suffix to the name and use the result as the FQDN. + +3. If the candidate name provided is empty, generate an FQDN using a + configurable prefix and suffix. + +4. If the client provides neither option, then take no DNS action. + +These rules can be amended by setting the ``ddns-replace-client-name`` +parameter, which provides the following modes of behavior: + +- ``never`` - use the name the client sent. If the client sent no name, + do not generate one. This is the default mode. + +- ``always`` - replace the name the client sent. If the client sent no + name, generate one for the client. + +- ``when-present`` - replace the name the client sent. If the client + sent no name, do not generate one. + +- ``when-not-present`` - use the name the client sent. If the client + sent no name, generate one for the client. + +.. note:: + + In early versions of Kea, this parameter was a boolean and permitted only + values of ``true`` and ``false``. Boolean values have been deprecated + and are no longer accepted. Administrators currently using booleans + must replace them with the desired mode name. A value of ``true`` + maps to ``when-present``, while ``false`` maps to ``never``. + +For example, to instruct :iscman:`kea-dhcp4` to always generate the FQDN for a +client, set the parameter ``ddns-replace-client-name`` to ``always`` as +follows: + +:: + + "Dhcp4": { + "ddns-replace-client-name": "always", + ... + } + +The prefix used in the generation of an FQDN is specified by the +``ddns-generated-prefix`` parameter. The default value is "myhost". To alter +its value, simply set it to the desired string: + +:: + + "Dhcp4": { + "ddns-generated-prefix": "another.host", + ... + } + +The suffix used when generating an FQDN, or when qualifying a partial +name, is specified by the ``ddns-qualifying-suffix`` parameter. It is +strongly recommended that the user supply a value for the qualifying +suffix when DDNS updates are enabled. For obvious reasons, we cannot +supply a meaningful default. + +:: + + "Dhcp4": { + "ddns-qualifying-suffix": "foo.example.org", + ... + } + +When qualifying a partial name, :iscman:`kea-dhcp4` constructs the name in the +format: + +``[candidate-name].[ddns-qualifying-suffix].`` + +where ``candidate-name`` is the partial name supplied in the DHCPREQUEST. +For example, if the FQDN domain name value is "some-computer" and the +``ddns-qualifying-suffix`` is "example.com", the generated FQDN is: + +``some-computer.example.com.`` + +When generating the entire name, :iscman:`kea-dhcp4` constructs the name in +the format: + +``[ddns-generated-prefix]-[address-text].[ddns-qualifying-suffix].`` + +where ``address-text`` is simply the lease IP address converted to a +hyphenated string. For example, if the lease address is 172.16.1.10, the +qualifying suffix is "example.com", and the default value is used for +``ddns-generated-prefix``, the generated FQDN is: + +``myhost-172-16-1-10.example.com.`` + +.. _dhcp4-host-name-sanitization: + +Sanitizing Client Host Name and FQDN Names +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Some DHCP clients may provide values in the Host Name +option (option code 12) or FQDN option (option code 81) that contain undesirable +characters. It is possible to configure :iscman:`kea-dhcp4` to sanitize these +values. The most typical use case is ensuring that only characters that +are permitted by RFC 1035 be included: A-Z, a-z, 0-9, and "-". This may be +accomplished with the following two parameters: + +- ``hostname-char-set`` - a regular expression describing the invalid + character set. This can be any valid, regular expression using POSIX + extended expression syntax. Embedded nulls (0x00) are always + considered an invalid character to be replaced (or omitted). + The default is ``"[^A-Za-z0-9.-]"``. This matches any character that is not + a letter, digit, dot, hyphen, or null. + +- ``hostname-char-replacement`` - a string of zero or more characters + with which to replace each invalid character in the host name. An empty + string causes invalid characters to be OMITTED rather than replaced. + The default is ``""``. + +The following configuration replaces anything other than a letter, +digit, dot, or hyphen with the letter "x": +:: + + "Dhcp4": { + "hostname-char-set": "[^A-Za-z0-9.-]", + "hostname-char-replacement": "x", + ... + } + +Thus, a client-supplied value of "myhost-$[123.org" would become +"myhost-xx123.org". Sanitizing is performed only on the portion of the +name supplied by the client, and it is performed before applying a +qualifying suffix (if one is defined and needed). + +.. note:: + + Name sanitizing is meant to catch the more common cases of invalid + characters through a relatively simple character-replacement scheme. + It is difficult to devise a scheme that works well in all cases, for + both Host Name and FQDN options. + Administrators who find they have clients with odd corner cases of + character combinations that cannot be readily handled with this + mechanism should consider writing a hook that can carry out + sufficiently complex logic to address their needs. + + If clients include domain names in the Host Name option and the administrator + wants these preserved, they need to make sure that the dot, ".", + is considered a valid character by the ``hostname-char-set`` expression, + such as this: ``"[^A-Za-z0-9.-]"``. This does not affect dots in FQDN + Option values. + When scrubbing FQDNs, dots are treated as delimiters and used to separate + the option value into individual domain labels that are scrubbed and + then re-assembled. + + If clients are sending values that differ only by characters + considered as invalid by the ``hostname-char-set``, be aware that + scrubbing them will yield identical values. In such cases, DDNS + conflict rules will permit only one of them to register the name. + + Finally, given the latitude clients have in the values they send, it + is virtually impossible to guarantee that a combination of these two + parameters will always yield a name that is valid for use in DNS. For + example, using an empty value for ``hostname-char-replacement`` could + yield an empty domain label within a name, if that label consists + only of invalid characters. + +.. note:: + + It is possible to specify ``hostname-char-set`` + and/or ``hostname-char-replacement`` at the global scope. This allows + host names to be sanitized without requiring a ``dhcp-ddns`` entry. When + a ``hostname-char`` parameter is defined at both the global scope and + in a ``dhcp-ddns`` entry, the second (local) value is used. + + For the ability to generate host names procedurally, based on an expression, and + for the ability to skip DDNS updates on a per-client basis, or fine-tuning various + DNS update aspects, the :iscman:`kea-dhcp4` can load the premium hook library + `libdhcp_ddns_tuning.so` which is available from ISC. Please refer to + :ref:`hooks-ddns-tuning` documentation for the configuration options. + +.. _dhcp4-next-server: + +Next Server (``siaddr``) +------------------------ + +In some cases, clients want to obtain configuration from a TFTP server. +Although there is a dedicated option for it, some devices may use the +``siaddr`` field in the DHCPv4 packet for that purpose. That specific field +can be configured using the ``next-server`` directive. It is possible to +define it in the global scope or for a given subnet only. If both are +defined, the subnet value takes precedence. The value in the subnet can be +set to "0.0.0.0", which means that ``next-server`` should not be sent. It +can also be set to an empty string, which is equivalent to it +not being defined at all; that is, it uses the global value. + +The ``server-hostname`` (which conveys a server hostname, can be up to +64 bytes long, and is in the ``sname`` field) and +``boot-file-name`` (which conveys the configuration file, can be up to +128 bytes long, and is sent using the ``file`` field) directives are +handled the same way as ``next-server``. + +:: + + "Dhcp4": { + "next-server": "192.0.2.123", + "boot-file-name": "/dev/null", + "subnet4": [ + { + "next-server": "192.0.2.234", + "server-hostname": "some-name.example.org", + "boot-file-name": "bootfile.efi", + ... + } + ], + ... + } + +.. _dhcp4-echo-client-id: + +Echoing Client-ID (RFC 6842) +---------------------------- + +The original DHCPv4 specification (`RFC +2131 <https://tools.ietf.org/html/rfc2131>`__) states that the DHCPv4 +server must not send back client-id options when responding to clients. +However, in some cases that results in confused clients that do not have a MAC +address or client-id; see `RFC +6842 <https://tools.ietf.org/html/rfc6842>`__ for details. That behavior +changed with the publication of `RFC +6842 <https://tools.ietf.org/html/rfc6842>`__, which updated `RFC +2131 <https://tools.ietf.org/html/rfc2131>`__. That update states that +the server must send the client-id if the client sent it, and that is Kea's +default behavior. However, in some cases older devices that do not +support `RFC 6842 <https://tools.ietf.org/html/rfc6842>`__ may refuse to +accept responses that include the client-id option. To enable backward +compatibility, an optional configuration parameter has been introduced. +To configure it, use the following configuration statement: + +:: + + "Dhcp4": { + "echo-client-id": false, + ... + } + +.. _dhcp4-match-client-id: + +Using Client Identifier and Hardware Address +-------------------------------------------- + +The DHCP server must be able to identify the client from which it +receives the message and distinguish it from other clients. There are +many reasons why this identification is required; the most important +ones are: + +- When the client contacts the server to allocate a new lease, the + server must store the client identification information in the lease + database as a search key. + +- When the client tries to renew or release the existing lease, the + server must be able to find the existing lease entry in the database + for this client, using the client identification information as a + search key. + +- Some configurations use static reservations for the IP addresses and + other configuration information. The server's administrator uses + client identification information to create these static assignments. + +- In dual-stack networks there is often a need to correlate the lease + information stored in DHCPv4 and DHCPv6 servers for a particular + host. Using common identification information by the DHCPv4 and + DHCPv6 clients allows the network administrator to achieve this + correlation and better administer the network. Beginning with + release 2.1.2, Kea supports DHCPv6 DUIDs embedded within DHCPv4 + Client Identifier options as described in + `RFC 4361 <https://tools.ietf.org/html/rfc4361>`__. + +DHCPv4 uses two distinct identifiers which are placed by the client in +the queries sent to the server and copied by the server to its responses +to the client: ``chaddr`` and ``client-identifier``. The former was +introduced as a part of the BOOTP specification and it is also used by +DHCP to carry the hardware address of the interface used to send the +query to the server (MAC address for the Ethernet). The latter is +carried in the client-identifier option, introduced in `RFC +2132 <https://tools.ietf.org/html/rfc2132>`__. + +`RFC 2131 <https://tools.ietf.org/html/rfc2131>`__ indicates that the +server may use both of these identifiers to identify the client but the +client identifier, if present, takes precedence over ``chaddr``. One of +the reasons for this is that the client identifier is independent from the +hardware used by the client to communicate with the server. For example, +if the client obtained the lease using one network card and then the +network card is moved to another host, the server will wrongly identify +this host as the one which obtained the lease. Moreover, `RFC +4361 <https://tools.ietf.org/html/rfc4361>`__ gives the recommendation +to use a DUID (see `RFC 8415 <https://tools.ietf.org/html/rfc8415>`__, +the DHCPv6 specification) carried as a client identifier when dual-stack +networks are in use to provide consistent identification information for +the client, regardless of the type of protocol it is using. Kea adheres to +these specifications, and the client identifier by default takes +precedence over the value carried in the ``chaddr`` field when the server +searches, creates, updates, or removes the client's lease. + +When the server receives a DHCPDISCOVER or DHCPREQUEST message from the +client, it tries to find out if the client already has a lease in the +database; if it does, the server hands out that lease rather than allocates a new one. +Each lease in the lease database is associated with the client +identifier and/or ``chaddr``. The server first uses the client +identifier (if present) to search for the lease; if one is found, the +server treats this lease as belonging to the client, even if the +current ``chaddr`` and the ``chaddr`` associated with the lease do not +match. This facilitates the scenario when the network card on the client +system has been replaced and thus the new MAC address appears in the +messages sent by the DHCP client. If the server fails to find the lease +using the client identifier, it performs another lookup using the +``chaddr``. If this lookup returns no result, the client is considered to +not have a lease and a new lease is created. + +A common problem reported by network operators is that poor client +implementations do not use stable client identifiers, instead generating +a new client identifier each time the client connects to the network. +Another well-known case is when the client changes its client +identifier during the multi-stage boot process (PXE). In such cases, +the MAC address of the client's interface remains stable, and using the +``chaddr`` field to identify the client guarantees that the particular +system is considered to be the same client, even though its client +identifier changes. + +To address this problem, Kea includes a configuration option which +enables client identification using ``chaddr`` only. This instructs the +server to ignore the client identifier during lease lookups and allocations +for a particular subnet. Consider the following simplified server configuration: + +.. code-block:: json + + { + "Dhcp4": { + "match-client-id": true, + "subnet4": [ + { + "id": 1, + "subnet": "192.0.10.0/24", + "pools": [ { "pool": "192.0.2.23-192.0.2.87" } ], + "match-client-id": false + }, + { + "id": 1, + "subnet": "10.0.0.0/8", + "pools": [ { "pool": "10.0.0.23-10.0.2.99" } ] + } + ] + } + } + +The ``match-client-id`` parameter is a boolean value which controls this +behavior. The default value of ``true`` indicates that the server will use +the client identifier for lease lookups and ``chaddr`` if the first lookup +returns no results. ``false`` means that the server will only use +the ``chaddr`` to search for the client's lease. Whether the DHCID for DNS +updates is generated from the client identifier or ``chaddr`` is +controlled through the same parameter. + +The ``match-client-id`` parameter may appear both in the global +configuration scope and/or under any subnet declaration. In the example +shown above, the effective value of the ``match-client-id`` will be +``false`` for the subnet 192.0.10.0/24, because the subnet-specific +setting of the parameter overrides the global value of the parameter. +The effective value of the ``match-client-id`` for the subnet 10.0.0.0/8 +will be set to ``true``, because the subnet declaration lacks this +parameter and the global setting is by default used for this subnet. In +fact, the global entry for this parameter could be omitted in this case, +because ``true`` is the default value. + +It is important to understand what happens when the client obtains its +lease for one setting of the ``match-client-id`` and then renews it when +the setting has been changed. First, consider the case when the client +obtains the lease and the ``match-client-id`` is set to ``true``. The +server stores the lease information, including the client identifier +(if supplied) and ``chaddr``, in the lease database. When the setting is +changed and the client renews the lease, the server will determine that +it should use the ``chaddr`` to search for the existing lease. If the +client has not changed its MAC address, the server should successfully +find the existing lease. The client identifier associated with the +returned lease will be ignored and the client will be allowed to use this lease. +When the lease is renewed only the ``chaddr`` will be recorded for this lease, +according to the new server setting. + +In the second case, the client has the lease with only a ``chaddr`` value +recorded. When the ``match-client-id`` setting is changed to ``true``, +the server will first try to use the client identifier to find the +existing client's lease. This will return no results because the client +identifier was not recorded for this lease. The server will then use +the ``chaddr`` and the lease will be found. If the lease appears to have +no client identifier recorded, the server will assume that this lease +belongs to the client and that it was created with the previous setting +of the ``match-client-id``. However, if the lease contains a client +identifier which is different from the client identifier used by the +client, the lease will be assumed to belong to another client and a +new lease will be allocated. + +For a more visual representation of how Kea recognizes the same client, +check :ref:`uml-recognizing-same-client`. + +.. _dhcp4-authoritative: + +Authoritative DHCPv4 Server Behavior +------------------------------------ + +The original DHCPv4 specification (`RFC +2131 <https://tools.ietf.org/html/rfc2131>`__) states that if a client +requests an address in the INIT-REBOOT state of which the server has no +knowledge, the server must remain silent, except if the server knows +that the client has requested an IP address from the wrong network. By +default, Kea follows the behavior of the ISC ``dhcpd`` daemon instead of the +specification and also remains silent if the client requests an IP +address from the wrong network, because configuration information about +a given network segment is not known to be correct. Kea only rejects a +client's DHCPREQUEST with a DHCPNAK message if it already has a lease +for the client with a different IP address. Administrators can +override this behavior through the boolean ``authoritative`` (``false`` +by default) setting. + +In authoritative mode, ``authoritative`` set to ``true``, Kea always +rejects INIT-REBOOT requests from unknown clients with DHCPNAK messages. +The ``authoritative`` setting can be specified in global, +shared-network, and subnet configuration scope and is automatically +inherited from the parent scope, if not specified. All subnets in a +shared-network must have the same ``authoritative`` setting. + +.. _dhcp4-dhcp4o6-config: + +DHCPv4-over-DHCPv6: DHCPv4 Side +------------------------------- + +The support of DHCPv4-over-DHCPv6 transport is described in `RFC +7341 <https://tools.ietf.org/html/rfc7341>`__ and is implemented using +cooperating DHCPv4 and DHCPv6 servers. This section is about the +configuration of the DHCPv4 side (the DHCPv6 side is described in +:ref:`dhcp6-dhcp4o6-config`). + +.. note:: + + DHCPv4-over-DHCPv6 support is experimental and the details of the + inter-process communication may change; for instance, the + support of port relay (RFC 8357) introduced an incompatible change. + Both the DHCPv4 and DHCPv6 sides should be running the same version of Kea. + +The ``dhcp4o6-port`` global parameter specifies the first of the two +consecutive ports of the UDP sockets used for the communication between +the DHCPv6 and DHCPv4 servers. The DHCPv4 server is bound to ::1 on +``port`` + 1 and connected to ::1 on ``port``. + +With DHCPv4-over-DHCPv6, the DHCPv4 server does not have access to +several of the identifiers it would normally use to select a subnet. To +address this issue, three new configuration entries are available; the +presence of any of these allows the subnet to be used with +DHCPv4-over-DHCPv6. These entries are: + +- ``4o6-subnet``: takes a prefix (i.e., an IPv6 address followed by a + slash and a prefix length) which is matched against the source + address. + +- ``4o6-interface-id``: takes a relay interface ID option value. + +- ``4o6-interface``: takes an interface name which is matched against + the incoming interface name. + +ISC tested the following configuration: + +:: + + { + + # DHCPv4 conf + "Dhcp4": { + + "interfaces-config": { + "interfaces": [ "eno33554984" ] + }, + + "lease-database": { + "type": "memfile", + "name": "leases4" + }, + + "valid-lifetime": 4000, + + "subnet4": [ + { + "id": 1, + "subnet": "10.10.10.0/24", + "4o6-interface": "eno33554984", + "4o6-subnet": "2001:db8:1:1::/64", + "pools": [ { "pool": "10.10.10.100 - 10.10.10.199" } ] + } + ], + + "dhcp4o6-port": 6767, + + "loggers": [ + { + "name": "kea-dhcp4", + "output-options": [ + { + "output": "/tmp/kea-dhcp4.log" + } + ], + "severity": "DEBUG", + "debuglevel": 0 + } + ] + } + + } + +.. _sanity-checks4: + +Sanity Checks in DHCPv4 +----------------------- + +An important aspect of a well-running DHCP system is an assurance that +the data remains consistent; however, in some cases it may be convenient +to tolerate certain inconsistent data. For example, a network +administrator who temporarily removes a subnet from a configuration +would not want all the leases associated with it to disappear from the +lease database. Kea has a mechanism to implement sanity checks for situations +like this. + +Kea supports a configuration scope called ``sanity-checks``. +A parameter, called ``lease-checks``, +governs the verification carried out when a new lease is loaded from a +lease file. This mechanism permits Kea to attempt to correct inconsistent data. + +Every subnet has a ``subnet-id`` value; this is how Kea internally +identifies subnets. Each lease has a ``subnet-id`` parameter as well, which +identifies the subnet it belongs to. However, if the configuration has +changed, it is possible that a lease could exist with a ``subnet-id`` but +without any subnet that matches it. Also, it is possible that the +subnet's configuration has changed and the ``subnet-id`` now belongs to a +subnet that does not match the lease. + +Kea's corrective algorithm first +checks to see if there is a subnet with the ``subnet-id`` specified by the +lease. If there is, it verifies whether the lease belongs to that +subnet. If not, depending on the ``lease-checks`` setting, the lease is +discarded, a warning is displayed, or a new subnet is selected for the +lease that matches it topologically. + +There are five levels which are supported: + +- ``none`` - do no special checks; accept the lease as is. + +- ``warn`` - if problems are detected display a warning, but + accept the lease data anyway. This is the default value. + +- ``fix`` - if a data inconsistency is discovered, try to + correct it. If the correction is not successful, insert the incorrect data + anyway. + +- ``fix-del`` - if a data inconsistency is discovered, try to + correct it. If the correction is not successful, reject the lease. + This setting ensures the data's correctness, but some + incorrect data may be lost. Use with care. + +- ``del`` - if any inconsistency is + detected, reject the lease. This is the strictest mode; use with care. + +This feature is currently implemented for the memfile backend. The +sanity check applies to the lease database in memory, not to the lease file, +i.e. inconsistent leases will stay in the lease file. + +An example configuration that sets this parameter looks as follows: + +:: + + "Dhcp4": { + "sanity-checks": { + "lease-checks": "fix-del" + }, + ... + } + +.. _dhcp4-store-extended-info: + +Storing Extended Lease Information +---------------------------------- + +To support such features as DHCP Leasequery +(`RFC 4388 <https://tools.ietf.org/html/rfc4388>`__), +additional information must be stored with each lease. Because the amount +of information for each lease has ramifications in terms of +performance and system resource consumption, storage of this additional +information is configurable through the ``store-extended-info`` parameter. +It defaults to ``false`` and may be set at the global, shared-network, and +subnet levels. + +:: + + "Dhcp4": { + "store-extended-info": true, + ... + } + +When set to ``true``, information relevant to the DHCPREQUEST asking for the lease is +added into the lease's user-context as a map element labeled "ISC". Since +Kea version 2.3.2, when the DHCPREQUEST received contains the option +(DHCP Option 82), the map contains the ``relay-agent-info`` map +with the content option (DHCP Option 82) in the ``sub-options`` entry and, +when present, the ``remote-id`` and ``relay-id`` options. +Since DHCPREQUESTs sent as renewals are not likely to contain this +information, the values taken from the last DHCPREQUEST that did contain it are +retained on the lease. The lease's user-context looks something like this: + +:: + + { "ISC": { "relay-agent-info": { "sub-options": "0x0104AABBCCDD" } } } + +Or with remote and relay sub-options: + +:: + + { + "ISC": { + "relay-agent-info": { + "sub-options": "0x02030102030C03AABBCC", + "remote-id": "03010203", + "relay-id": "AABBCC" + } + } + } + +.. note:: + + It is possible that other hook libraries are already using ``user-context``. + Enabling ``store-extended-info`` should not interfere with any other ``user-context`` + content, as long as it does not also use an element labeled "ISC". In other + words, ``user-context`` is intended to be a flexible container serving multiple + purposes. As long as no other purpose also writes an "ISC" element to + ``user-context`` there should not be a conflict. + +Extended lease information is also subject to configurable sanity checking. +The parameter in the ``sanity-checks`` scope is named ``extended-info-checks`` +and supports these levels: + +- ``none`` - do no check nor upgrade. This level should be used only when + extended info is not used at all or when no badly formatted extended + info, including using the old format, is expected. + +- ``fix`` - fix some common inconsistencies and upgrade extended info + using the old format to the new one. It is the default level and is + convenient when the Leasequery hook library is not loaded. + +- ``strict`` - fix all inconsistencies which have an impact on the (Bulk) + Leasequery hook library. + +- ``pedantic`` - enforce full conformance to the format produced by the + Kea code; for instance, no extra entries are allowed with the exception + of ``comment``. + +.. note:: + + This feature is currently implemented only for the memfile + backend. The sanity check applies to the lease database in memory, + not to the lease file, i.e. inconsistent leases stay in the lease + file. + +.. _dhcp4-multi-threading-settings: + +Multi-Threading Settings +------------------------ + +The Kea server can be configured to process packets in parallel using multiple +threads. These settings can be found under the ``multi-threading`` structure and are +represented by: + +- ``enable-multi-threading`` - use multiple threads to process packets in + parallel. The default is ``true``. + +- ``thread-pool-size`` - specify the number of threads to process packets in + parallel. It may be set to ``0`` (auto-detect), or any positive number that + explicitly sets the thread count. The default is ``0``. + +- ``packet-queue-size`` - specify the size of the queue used by the thread + pool to process packets. It may be set to ``0`` (unlimited), or any positive + number that explicitly sets the queue size. The default is ``64``. + +An example configuration that sets these parameters looks as follows: + +:: + + "Dhcp4": { + "multi-threading": { + "enable-multi-threading": true, + "thread-pool-size": 4, + "packet-queue-size": 16 + }, + ... + } + +Multi-Threading Settings With Different Database Backends +--------------------------------------------------------- + +The Kea DHCPv4 server is benchmarked by ISC to determine which settings +give the best performance. Although this section describes our results, they are merely +recommendations and are very dependent on the particular hardware used +for benchmarking. We strongly advise that administrators run their own performance benchmarks. + +A full report of performance results for the latest stable Kea version can be found +`here <https://reports.kea.isc.org/>`_. +This includes hardware and benchmark scenario descriptions, as well as +current results. + +After enabling multi-threading, the number of threads is set by the ``thread-pool-size`` +parameter. Results from our experiments show that the best settings for +:iscman:`kea-dhcp4` are: + +- ``thread-pool-size``: 4 when using ``memfile`` for storing leases. + +- ``thread-pool-size``: 12 or more when using ``mysql`` for storing leases. + +- ``thread-pool-size``: 8 when using ``postgresql``. + +Another very important parameter is ``packet-queue-size``; in our benchmarks we +used it as a multiplier of ``thread-pool-size``. The actual setting strongly depends +on ``thread-pool-size``. + +We saw the best results in our benchmarks with the following settings: + +- ``packet-queue-size``: 7 * ``thread-pool-size`` when using ``memfile`` for + storing leases; in our case it was 7 * 4 = 28. This means that at any given + time, up to 28 packets could be queued. + +- ``packet-queue-size``: 66 * ``thread-pool-size`` when using ``mysql`` for + storing leases; in our case it was 66 * 12 = 792. This means that up to + 792 packets could be queued. + +- ``packet-queue-size``: 11 * ``thread-pool-size`` when using ``postgresql`` for + storing leases; in our case it was 11 * 8 = 88. + +IPv6-Only Preferred Networks +---------------------------- + +`RFC8925 <https://tools.ietf.org/html/rfc8925>`_, recently published by the IETF, +specifies a DHCPv4 option to indicate that a host supports an IPv6-only mode and is willing to +forgo obtaining an IPv4 address if the network provides IPv6 connectivity. The general idea is that +a network administrator can enable this option to signal to compatible dual-stack devices that +IPv6 connectivity is available and they can shut down their IPv4 stack. The new option +``v6-only-preferred`` content is a 32-bit unsigned integer and specifies for how long the device +should disable its stack. The value is expressed in seconds. + +The RFC mentions the ``V6ONLY_WAIT`` timer. This is implemented in Kea by setting the value of +the ``v6-only-preferred`` option. This follows the usual practice of setting options; the +option value can be specified on the pool, subnet, shared network, or global levels, or even +via host reservations. + +There is no special processing involved; it follows the standard Kea option processing +regime. The option is not sent back unless the client explicitly requests it. For example, to +enable the option for the whole subnet, the following configuration can be used: + +:: + + { + "subnet4": [ + { + "id": 1, + "pools": [ { "pool": "192.0.2.1 - 192.0.2.200" } ], + "subnet": "192.0.2.0/24", + "option-data": [ + { + // This will make the v6-only capable devices to disable their + // v4 stack for half an hour and then try again + "name": "v6-only-preferred", + "data": "1800" + } + ] + } + ], + ... + } + +Lease Caching +------------- + +Clients that attempt multiple renewals in a short period can cause the server to update +and write to the database frequently, resulting in a performance impact +on the server. The cache parameters instruct the DHCP server to avoid +updating leases too frequently, thus avoiding this behavior. Instead, +the server assigns the same lease (i.e. reuses it) with no +modifications except for CLTT (Client Last Transmission Time), which +does not require disk operations. + +The two parameters are the ``cache-threshold`` double and the +``cache-max-age`` integer; they have no default setting, i.e. the lease caching +feature must be explicitly enabled. These parameters can be configured +at the global, shared-network, and subnet levels. The subnet level has +precedence over the shared-network level, while the global level is used +as a last resort. For example: + +:: + + { + "subnet4": [ + { + "pools": [ { "pool": "192.0.2.1 - 192.0.2.200" } ], + "subnet": "192.0.2.0/24", + "cache-threshold": .25, + "cache-max-age": 600, + "valid-lifetime": 2000, + ... + } + ], + ... + } + +When an already-assigned lease can fulfill a client query: + + - any important change, e.g. for DDNS parameter, hostname, or + valid lifetime reduction, makes the lease not reusable. + + - lease age, i.e. the difference between the creation or last modification + time and the current time, is computed (elapsed duration). + + - if ``cache-max-age`` is explicitly configured, it is compared with the lease age; + leases that are too old are not reusable. This means that the value 0 + for ``cache-max-age`` disables the lease cache feature. + + - if ``cache-threshold`` is explicitly configured and is between 0.0 and 1.0, + it expresses the percentage of the lease valid lifetime which is + allowed for the lease age. Values below and including 0.0 and + values greater than 1.0 disable the lease cache feature. + +In our example, a lease with a valid lifetime of 2000 seconds can be +reused if it was committed less than 500 seconds ago. With a lifetime +of 3000 seconds, a maximum age of 600 seconds applies. + +In outbound client responses (e.g. DHCPACK messages), the +``dhcp-lease-time`` option is set to the reusable valid lifetime, +i.e. the expiration date does not change. Other options based on the +valid lifetime e.g. ``dhcp-renewal-time`` and ``dhcp-rebinding-time``, +also depend on the reusable lifetime. + +Temporary Allocation on DHCPDISCOVER +------------------------------------ + +By default, :iscman:`kea-dhcp4` does not allocate or store a lease when offering an address +to a client in response to a DHCPDISCOVER. In general, :iscman:`kea-dhcp4` can fulfill client +demands faster by deferring lease allocation and storage until it receives DHCPREQUESTs +for them. Release 2.3.6 added a new parameter to :iscman:`kea-dhcp4`, ``offer-lifetime``, which +(when not zero) instructs the server to allocate and persist a lease when generating a +DHCPOFFER. In addition: + +- The persisted lease's lifetime is equal to ``offer-lifetime`` (in seconds). + +- The lifetime sent to the client in the DHCPOFFER via option 51 is still based + on ``valid-lifetime``. This avoids issues with clients that may reject offers whose + lifetimes they perceive as too short. + +- DDNS updates are not performed. As with the default behavior, those updates occur on DHCPREQUEST. + +- Updates are not sent to HA peers. + +- Assigned lease statistics are incremented. + +- Expiration processing and reclamation behave just as they do for leases allocated + during DHCPREQUEST processing. + +- Lease caching, if enabled, is honored. + +- In sites running multiple instances of :iscman:`kea-dhcp4` against a single, shared lease store, races + for given address values are lost during DHCPDISCOVER processing rather than during DHCPREQUEST + processing. Servers that lose the race for the address simply do not respond to the client, + rather than NAK them. The client in turn simply retries its DHCPDISCOVER. This should reduce + the amount of traffic such conflicts incur. + +- Clients repeating DHCPDISCOVERs are offered the same address each time. + +An example subnet configuration is shown below: + +:: + + { + "subnet4": [ + { + "pools": [ { "pool": "192.0.2.1 - 192.0.2.200" } ], + "subnet": "192.0.2.0/24", + "offer-lifetime": 60, + "valid-lifetime": 2000, + ... + } + ], + ... + } + +Here ``offer-lifetime`` has been configured to be 60 seconds, with a ``valid-lifetime`` +of 2000 seconds. This instructs :iscman:`kea-dhcp4` to persist leases for 60 seconds when +sending them back in DHCPOFFERs, and then extend them to 2000 seconds when clients +DHCPREQUEST them. + +The value, which defaults to 0, is supported at the global, shared-network, subnet, +and class levels. Choosing an appropriate value for ``offer-lifetime`` is extremely +site-dependent, but a value between 60 and 120 seconds is a reasonable starting +point. + +.. _dnr4-options: + +DNR (Discovery of Network-designated Resolvers) Options for DHCPv4 +------------------------------------------------------------------ + +One of the more recently added options is the Discovery of +Network-designated Resolvers or DNR option, +introduced in `RFC 9463 <https://tools.ietf.org/html/rfc9463>`__. The goal of that RFC is +to provide a way to communicate location of DNS resolvers available over means other than +the classic DNS over UDP over port 53. At the time of this writing, the supported technologies +are DoT (DNS-over-TLS), DoH (DNS-over-HTTPS), and DoQ (DNS-over-QUIC), but the option was +designed to be extensible to accommodate other protocols in the future. + +The DHCPv4 option and its corresponding DHCPv6 options are almost exactly the same, +with the exception of cardinality. Only one DHCPv4 option is allowed, while for DHCPv6 +multiple options are allowed. To be able to convey multiple entries, the DHCPv4 is an +array that allows multiple DNS instances. Each instance is logically equal to one +DHCPv6 option, except the minor difference of using IPv4 rather than IPv6 addresses. + +For detailed example how to configure DNR option, see :ref:`dnr6-options`. +The only difference for DNR DHCPv4 options configuration is that it allows +to configure more than one DNR instance and the DNR instances are separated +with the "pipe" (``0x7C``) character. +For each DNR Instance comma delimited fields must be provided in the following order: + +- Service Priority (mandatory), +- ADN FQDN (mandatory), +- IP address(es) (optional - if more than one - they must be space-separated) +- SvcParams as a set of key=value pairs (optional - if more than one - they must be space-separated; + to provide more than one alpn-id separate them with double backslash escaped comma like in the + example below). + +Example usage: + +:: + + { + "name": "v4-dnr", + // 2 DNR Instances: + // - Service priority 2, ADN, resolver IPv4 address and Service Parameters + // - Service priority 3, ADN - this is ADN-only mode as per RFC9463 3.1.6 + "data": "2, resolver.example., 10.0.5.6, alpn=dot\\,doq port=8530 | 3, fooexp.resolver.example." + } + + +.. note:: + + Note that whenever "comma" or "pipe" characters need to be used not as the delimiters, they must be escaped with + double backslash (``\\,`` or ``\\|``). E.g. one must use escaped commas when configuring more than one ``ALPN`` + protocol to separate them. One might want to use "pipe" (``0x7C``) character in ``dohpath`` Service Parameter, + as it is allowed in URI. In that case it must be escaped with double backslash. + +Examples for DNR DHCPv4 options are provided in the Kea sources in +`all-options.json` in the `doc/examples/kea4` directory. + + +.. _host-reservation-v4: + +Host Reservations in DHCPv4 +=========================== + +There are many cases where it is useful to provide a configuration on a +per-host basis. The most obvious one is to reserve a specific, static +address for exclusive use by a given client (host); the returning client +receives the same address from the server every time, and other +clients generally do not receive that address. Host +reservations are also convenient when a host has +specific requirements, e.g. a printer that needs additional DHCP +options. Yet another possible use case is to define unique names for +hosts. + +There may be cases when a new reservation has been made for a +client for an address currently in use by another client. We call this +situation a "conflict." +These conflicts get resolved automatically over time, as described in +subsequent sections. Once a conflict is resolved, the correct client will +receive the reserved configuration when it renews. + +Host reservations are defined as parameters for each subnet. Each host +must have its own unique identifier, such as the hardware/MAC +address. There is an optional ``reservations`` array in the ``subnet4`` +structure; each element in that array is a structure that holds +information about reservations for a single host. In particular, the +structure has an identifier that uniquely identifies a host. In +the DHCPv4 context, the identifier is usually a hardware or MAC address. +In most cases an IP address will be specified. It is also possible to +specify a hostname, host-specific options, or fields carried within the +DHCPv4 message such as ``siaddr``, ``sname``, or ``file``. + +.. note:: + + The reserved address must be within the subnet. + +The following example shows how to reserve addresses for specific hosts +in a subnet: + +:: + + { + "subnet4": [ + { + "id": 1, + "pools": [ { "pool": "192.0.2.1 - 192.0.2.200" } ], + "subnet": "192.0.2.0/24", + "interface": "eth0", + "reservations": [ + { + "hw-address": "1a:1b:1c:1d:1e:1f", + "ip-address": "192.0.2.202" + }, + { + "duid": "0a:0b:0c:0d:0e:0f", + "ip-address": "192.0.2.100", + "hostname": "alice-laptop" + }, + { + "circuit-id": "'charter950'", + "ip-address": "192.0.2.203" + }, + { + "client-id": "01:11:22:33:44:55:66", + "ip-address": "192.0.2.204" + } + ] + } + ], + ... + } + +The first entry reserves the 192.0.2.202 address for the client that +uses a MAC address of 1a:1b:1c:1d:1e:1f. The second entry reserves the +address 192.0.2.100 and the hostname of "alice-laptop" for the client +using a DUID 0a:0b:0c:0d:0e:0f. (If DNS updates are planned, +it is strongly recommended that the hostnames be unique.) The +third example reserves address 192.0.3.203 for a client whose request +would be relayed by a relay agent that inserts a ``circuit-id`` option with +the value "charter950". The fourth entry reserves address 192.0.2.204 +for a client that uses a client identifier with value +01:11:22:33:44:55:66. + +The above example is used for illustrational purposes only; in actual +deployments it is recommended to use as few types as possible +(preferably just one). See :ref:`reservations4-tuning` for a detailed discussion of this +point. + +Making a reservation for a mobile host that may visit multiple subnets +requires a separate host definition in each subnet that host is expected to +visit. It is not possible to define multiple host definitions with the +same hardware address in a single subnet. Multiple host definitions with +the same hardware address are valid if each is in a different subnet. + +Adding host reservations incurs a performance penalty. In principle, when +a server that does not support host reservation responds to a query, it +needs to check whether there is a lease for a given address being +considered for allocation or renewal. The server that does support host +reservation has to perform additional checks: not only whether the +address is currently used (i.e., if there is a lease for it), but also +whether the address could be used by someone else (i.e., if there is a +reservation for it). That additional check incurs extra overhead. + +.. _reservation4-types: + +Address Reservation Types +------------------------- + +In a typical Kea scenario there is an IPv4 subnet defined, e.g. +192.0.2.0/24, with a certain part of it dedicated for dynamic allocation +by the DHCPv4 server. That dynamic part is referred to as a dynamic pool +or simply a pool. In principle, a host reservation can reserve any +address that belongs to the subnet. The reservations that specify +addresses that belong to configured pools are called "in-pool +reservations." In contrast, those that do not belong to dynamic pools +are called "out-of-pool reservations." There is no formal difference in +the reservation syntax and both reservation types are handled uniformly. + +Kea supports global host reservations. These are reservations that are +specified at the global level within the configuration and that do not +belong to any specific subnet. Kea still matches inbound client +packets to a subnet as before, but when the subnet's reservation mode is +set to "global", Kea looks for host reservations only among the +global reservations defined. Typically, such reservations would be used +to reserve hostnames for clients which may move from one subnet to +another. + +.. note:: + + Global reservations, while useful in certain circumstances, have aspects + that must be given due consideration when using them. Please see + :ref:`reservation4-conflict` for more details. + +.. note:: + + Since Kea 1.9.1, reservation mode has been replaced by three + boolean flags, ``reservations-global``, ``reservations-in-subnet``, + and ``reservations-out-of-pool``, which allow the configuration of + host reservations both globally and in a subnet. In such cases a subnet + host reservation has preference over a global reservation + when both exist for the same client. + +.. _reservation4-conflict: + +Conflicts in DHCPv4 Reservations +-------------------------------- + +As reservations and lease information are stored separately, conflicts +may arise. Consider the following series of events: the server has +configured the dynamic pool of addresses from the range of 192.0.2.10 to +192.0.2.20. Host A requests an address and gets 192.0.2.10. Now the +system administrator decides to reserve address 192.0.2.10 for Host B. +In general, reserving an address that is currently assigned to someone +else is not recommended, but there are valid use cases where such an +operation is warranted. + +The server now has a conflict to resolve. If Host B boots up and +requests an address, the server cannot immediately assign the reserved +address 192.0.2.10. A naive approach would to be immediately remove the +existing lease for Host A and create a new one for Host B. That would +not solve the problem, though, because as soon as Host B gets the +address, it will detect that the address is already in use (by Host A) and +will send a DHCPDECLINE message. Therefore, in this situation, the +server has to temporarily assign a different address from the dynamic +pool (not matching what has been reserved) to Host B. + +When Host A renews its address, the server will discover that the +address being renewed is now reserved for another host - Host B. +The server will inform Host A that it is no longer allowed to +use it by sending a DHCPNAK message. The server will not remove the +lease, though, as there's a small chance that the DHCPNAK will not be delivered if +the network is lossy. If that happens, the client will not receive any +responses, so it will retransmit its DHCPREQUEST packet. Once the +DHCPNAK is received by Host A, it will revert to server discovery and +will eventually get a different address. Besides allocating a new lease, +the server will also remove the old one. As a result, address 192.0.2.10 +will become free. + +When Host B tries to renew its temporarily assigned +address, the server will detect that it has a valid lease, but will note +that there is a reservation for a different address. The server will +send DHCPNAK to inform Host B that its address is no longer usable, but +will keep its lease (again, the DHCPNAK may be lost, so the server will +keep it until the client returns for a new address). Host B will revert +to the server discovery phase and will eventually send a DHCPREQUEST +message. This time the server will find that there is a reservation for +that host and that the reserved address 192.0.2.10 is not used, so it +will be granted. It will also remove the lease for the temporarily +assigned address that Host B previously obtained. + +This recovery will succeed, even if other hosts attempt to get the +reserved address. If Host C requests the address 192.0.2.10 after the +reservation is made, the server will either offer a different address +(when responding to DHCPDISCOVER) or send DHCPNAK (when responding to +DHCPREQUEST). + +This mechanism allows the server to fully recover from a case +where reservations conflict with existing leases; however, this procedure +takes roughly as long as the value set for ``renew-timer``. The +best way to avoid such a recovery is not to define new reservations that +conflict with existing leases. Another recommendation is to use +out-of-pool reservations; if the reserved address does not belong to a +pool, there is no way that other clients can get it. + +.. note:: + + The conflict-resolution mechanism does not work for global + reservations. Although the global address reservations feature may be useful + in certain settings, it is generally recommended not to use + global reservations for addresses. Administrators who do choose + to use global reservations must manually ensure that the reserved + addresses are not in dynamic pools. + +.. _reservation4-hostname: + +Reserving a Hostname +-------------------- + +When the reservation for a client includes the ``hostname``, the server +returns this hostname to the client in the Client FQDN or Hostname +option. The server responds with the Client FQDN option only if the +client has included the Client FQDN option in its message to the server. The +server responds with the Hostname option if the client included +the Hostname option in its message to the server, or if the client +requested the Hostname option using the Parameter Request List option. +The server returns the Hostname option even if it is not configured +to perform DNS updates. The reserved hostname always takes precedence +over the hostname supplied by the client or the autogenerated (from the +IPv4 address) hostname. + +The server qualifies the reserved hostname with the value of the +``ddns-qualifying-suffix`` parameter. For example, the following subnet +configuration: + +.. code-block:: json + + { + "subnet4": [ + { + "id": 1, + "subnet": "10.0.0.0/24", + "pools": [ { "pool": "10.0.0.10-10.0.0.100" } ], + "ddns-qualifying-suffix": "example.isc.org.", + "reservations": [ + { + "hw-address": "aa:bb:cc:dd:ee:ff", + "hostname": "alice-laptop" + } + ] + } + ], + "dhcp-ddns": { + "enable-updates": true + } + } + +will result in the "alice-laptop.example.isc.org." hostname being assigned to +the client using the MAC address "aa:bb:cc:dd:ee:ff". If the +``ddns-qualifying-suffix`` is not specified, the default (empty) value will +be used, and in this case the value specified as a ``hostname`` will be +treated as a fully qualified name. Thus, by leaving the +``ddns-qualifying-suffix`` empty it is possible to qualify hostnames for +different clients with different domain names: + +.. code-block:: json + + { + "subnet4": [ + { + "id": 1, + "subnet": "10.0.0.0/24", + "pools": [ { "pool": "10.0.0.10-10.0.0.100" } ], + "reservations": [ + { + "hw-address": "aa:bb:cc:dd:ee:ff", + "hostname": "alice-laptop.isc.org." + }, + { + "hw-address": "12:34:56:78:99:AA", + "hostname": "mark-desktop.example.org." + } + ] + } + ], + "dhcp-ddns": { + "enable-updates": true + } + } + +The above example results in the assignment of the +"alice-laptop.isc.org." hostname to the client using the MAC +address "aa:bb:cc:dd:ee:ff", and the hostname "mark-desktop.example.org." +to the client using the MAC address "12:34:56:78:99:AA". + +.. _reservation4-options: + +Including Specific DHCPv4 Options in Reservations +------------------------------------------------- + +Kea offers the ability to specify options on a per-host basis. These +options follow the same rules as any other options. These can be +standard options (see :ref:`dhcp4-std-options`), +custom options (see :ref:`dhcp4-custom-options`), +or vendor-specific options (see :ref:`dhcp4-vendor-opts`). The following +example demonstrates how standard options can be defined: + +:: + + { + "subnet4": [ + { + "reservations": [ + { + "hw-address": "aa:bb:cc:dd:ee:ff", + "ip-address": "192.0.2.1", + "option-data": [ + { + "name": "cookie-servers", + "data": "10.1.1.202,10.1.1.203" + }, + { + "name": "log-servers", + "data": "10.1.1.200,10.1.1.201" + } + ] + } + ], + ... + } + ], + ... + } + +Vendor-specific options can be reserved in a similar manner: + +:: + + { + "subnet4": [ + { + "reservations": [ + { + "hw-address": "aa:bb:cc:dd:ee:ff", + "ip-address": "10.0.0.7", + "option-data": [ + { + "name": "vivso-suboptions", + "data": "4491" + }, + { + "name": "tftp-servers", + "space": "vendor-4491", + "data": "10.1.1.202,10.1.1.203" + } + ] + } + ], + ... + } + ], + ... + } + +Options defined at the host level have the highest priority. In other words, +if there are options defined with the same type on the global, subnet, +class, and host levels, the host-specific values are used. + +.. _reservation4-message-fields: + +Reserving Next Server, Server Hostname, and Boot File Name +---------------------------------------------------------- + +BOOTP/DHCPv4 messages include "siaddr", "sname", and "file" fields. Even +though DHCPv4 includes corresponding options, such as option 66 and +option 67, some clients may not support these options. For this reason, +server administrators often use the "siaddr", "sname", and "file" fields +instead. + +With Kea, it is possible to make static reservations for these DHCPv4 +message fields: + +:: + + { + "subnet4": [ + { + "reservations": [ + { + "hw-address": "aa:bb:cc:dd:ee:ff", + "next-server": "10.1.1.2", + "server-hostname": "server-hostname.example.org", + "boot-file-name": "/tmp/bootfile.efi" + } + ], + ... + } + ], + ... + } + +Note that those parameters can be specified in combination with other +parameters for a reservation, such as a reserved IPv4 address. These +parameters are optional; a subset of them can be specified, or all +of them can be omitted. + +.. _reservation4-client-classes: + +Reserving Client Classes in DHCPv4 +---------------------------------- + +:ref:`classification-using-expressions` explains how to configure +the server to assign classes to a client, based on the content of the +options that this client sends to the server. Host reservation +mechanisms also allow for the static assignment of classes to clients. +The definitions of these classes are placed in the Kea configuration file or +a database. The following configuration snippet shows how to specify that +a client belongs to the classes ``reserved-class1`` and ``reserved-class2``. Those +classes are associated with specific options sent to the clients which belong +to them. + +:: + + { + "client-classes": [ + { + "name": "reserved-class1", + "option-data": [ + { + "name": "routers", + "data": "10.0.0.200" + } + ] + }, + { + "name": "reserved-class2", + "option-data": [ + { + "name": "domain-name-servers", + "data": "10.0.0.201" + } + ] + } + ], + "subnet4": [ + { + "id": 1, + "subnet": "10.0.0.0/24", + "pools": [ { "pool": "10.0.0.10-10.0.0.100" } ], + "reservations": [ + { + "hw-address": "aa:bb:cc:dd:ee:ff", + + "client-classes": [ "reserved-class1", "reserved-class2" ] + + } + ] + } + ] + } + +In some cases the host reservations can be used in conjunction with client +classes specified within the Kea configuration. In particular, when a +host reservation exists for a client within a given subnet, the "KNOWN" +built-in class is assigned to the client. Conversely, when there is no +static assignment for the client, the "UNKNOWN" class is assigned to the +client. Class expressions within the Kea configuration file can +refer to "KNOWN" or "UNKNOWN" classes using the "member" operator. +For example: + +:: + + { + "client-classes": [ + { + "name": "dependent-class", + "test": "member('KNOWN')", + "only-if-required": true + } + ] + } + +The ``only-if-required`` parameter is needed here to force evaluation +of the class after the lease has been allocated and thus the reserved +class has been also assigned. + +.. note:: + + The classes specified in non-global host reservations + are assigned to the processed packet after all classes with the + ``only-if-required`` parameter set to ``false`` have been evaluated. + This means that these classes must not depend on the + statically assigned classes from the host reservations. If + such a dependency is needed, the ``only-if-required`` parameter must + be set to ``true`` for the dependent classes. Such classes are + evaluated after the static classes have been assigned to the packet. + This, however, imposes additional configuration overhead, because + all classes marked as ``only-if-required`` must be listed in the + ``require-client-classes`` list for every subnet where they are used. + +.. note:: + + Client classes specified within the Kea configuration file may + depend on the classes specified within the global host reservations. + In such a case the ``only-if-required`` parameter is not needed. + Refer to :ref:`pool-selection-with-class-reservations4` and + :ref:`subnet-selection-with-class-reservations4` + for specific use cases. + +.. _reservations4-mysql-pgsql: + +Storing Host Reservations in MySQL or PostgreSQL +------------------------------------------------ + +Kea can store host reservations in MySQL or PostgreSQL. +See :ref:`hosts4-storage` for information on how to +configure Kea to use reservations stored in MySQL or PostgreSQL. +Kea provides a dedicated hook for managing reservations in a +database; section :ref:`hooks-host-cmds` provides detailed information. +The `Kea wiki +<https://gitlab.isc.org/isc-projects/kea/wikis/designs/commands#23-host-reservations-hr-management>`__ +provides some examples of how to conduct common host reservation +operations. + +.. note:: + + In Kea, the maximum length of an option specified per-host-reservation is + arbitrarily set to 4096 bytes. + +.. _reservations4-tuning: + +Fine-Tuning DHCPv4 Host Reservation +----------------------------------- + +The host reservation capability introduces additional restrictions for +the allocation engine (the component of Kea that selects an address for +a client) during lease selection and renewal. In particular, three major +checks are necessary. First, when selecting a new lease, it is not +sufficient for a candidate lease to simply not be in use by another DHCP +client; it also must not be reserved for another client. Similarly, when +renewing a lease, an additional check must be performed to see whether +the address being renewed is reserved for another client. Finally, when +a host renews an address, the server must check whether there is a +reservation for this host, which would mean the existing (dynamically allocated) +address should be revoked and the reserved one be used instead. + +Some of those checks may be unnecessary in certain deployments, and not +performing them may improve performance. The Kea server provides the +``reservation-mode`` configuration parameter to select the types of +reservations allowed for a particular subnet. Each reservation type has +different constraints for the checks to be performed by the server when +allocating or renewing a lease for the client. Although ``reservation-mode`` +was deprecated in Kea 1.9.1, it is still available; the allowed values are: + +- ``all`` - enables both in-pool and out-of-pool host reservation + types. This setting is the default value, and is the safest and most + flexible. However, as all checks are conducted, it is also the slowest. + It does not check against global reservations. + +- ``out-of-pool`` - allows only out-of-pool host reservations. With + this setting in place, the server assumes that all host + reservations are for addresses that do not belong to the dynamic + pool. Therefore, it can skip the reservation checks when dealing with + in-pool addresses, thus improving performance. Do not use this mode + if any reservations use in-pool addresses. Caution is advised + when using this setting; Kea does not sanity-check the reservations + against ``reservation-mode`` and misconfiguration may cause problems. + +- ``global`` - allows only global host reservations. With this setting + in place, the server searches for reservations for a client only + among the defined global reservations. If an address is specified, + the server skips the reservation checks carried out in + other modes, thus improving performance. Caution is advised when + using this setting; Kea does not sanity-check reservations when + ``global`` is set, and misconfiguration may cause problems. + +- ``disabled`` - host reservation support is disabled. As there are no + reservations, the server skips all checks. Any reservations + defined are completely ignored. As checks are skipped, the + server may operate faster in this mode. + +Since Kea 1.9.1, the ``reservation-mode`` parameter is replaced by the +``reservations-global``, ``reservations-in-subnet``, and +``reservations-out-of-pool`` flags. +The flags can be activated independently and can produce various combinations, +some of which were not supported by the deprecated ``reservation-mode``. + +The ``reservation-mode`` parameter can be specified at: + +- global level: ``.Dhcp4["reservation-mode"]`` (lowest priority: gets overridden + by all others) + +- subnet level: ``.Dhcp4.subnet4[]["reservation-mode"]`` (low priority) + +- shared-network level: ``.Dhcp4["shared-networks"][]["reservation-mode"]`` + (high priority) + +- shared-network subnet-level: + ``.Dhcp4["shared-networks"][].subnet4[]["reservation-mode"]`` (highest + priority: overrides all others) + +To decide which ``reservation-mode`` to choose, the +following decision diagram may be useful: + +:: + + O + | + v + +-----------------------------+------------------------------+ + | Is per-host configuration needed, such as | + | reserving specific addresses, | + | assigning specific options or | + | assigning packets to specific classes on per-device basis? | + +-+-----------------+----------------------------------------+ + | | + no| yes| + | | +--------------------------------------+ + | | | For all given hosts, | + +--> "disabled" +-->+ can the reserved resources | + | be used in all configured subnets? | + +--------+---------------------------+-+ + | | + +----------------------------+ |no |yes + | Is | | | + | at least one reservation +<--+ "global" <--+ + | used to reserve addresses? | + +-+------------------------+-+ + | | + no| yes| +---------------------------+ + | | | Is high leases-per-second | + +--> "out-of-pool" +-->+ performance or efficient | + ^ | resource usage | + | | (CPU ticks, RAM usage, | + | | database roundtrips) | + | | important to your setup? | + | +-+----------------+--------+ + | | | + | yes| no| + | | | + | +-------------+ | + | | | + | | +----------------------+ | + | | | Can it be guaranteed | | + | +-->+ that the reserved | | + | | addresses | | + | | aren't part of the | | + | | pools configured | | + | | in the respective | | + | | subnet? | | + | +-+------------------+-+ | + | | | | + | yes| no| | + | | | V + +----------------+ +--> "all" + +An example configuration that disables reservations looks as follows: + +.. code-block:: json + + { + "Dhcp4": { + "subnet4": [ + { + "id": 1, + "pools": [ + { + "pool": "192.0.2.10-192.0.2.100" + } + ], + "reservation-mode": "disabled", + "subnet": "192.0.2.0/24" + } + ] + } + } + +An example configuration using global reservations is shown below: + +.. code-block:: json + + { + "Dhcp4": { + "reservation-mode": "global", + "reservations": [ + { + "hostname": "host-one", + "hw-address": "01:bb:cc:dd:ee:ff" + }, + { + "hostname": "host-two", + "hw-address": "02:bb:cc:dd:ee:ff" + } + ], + "subnet4": [ + { + "id": 1, + "pools": [ + { + "pool": "192.0.2.10-192.0.2.100" + } + ], + "subnet": "192.0.2.0/24" + } + ] + } + } + +The meaning of the reservation flags are: + +- ``reservations-global``: fetch global reservations. + +- ``reservations-in-subnet``: fetch subnet reservations. For a shared network + this includes all subnet members of the shared network. + +- ``reservations-out-of-pool``: this makes sense only when the + ``reservations-in-subnet`` flag is ``true``. When ``reservations-out-of-pool`` + is ``true``, the server assumes that all host reservations are for addresses + that do not belong to the dynamic pool. Therefore, it can skip the reservation + checks when dealing with in-pool addresses, thus improving performance. + The server will not assign reserved addresses that are inside the dynamic + pools to the respective clients. This also means that the addresses matching + the respective reservations from inside the dynamic pools (if any) can be + dynamically assigned to any client. + +The ``disabled`` value from the deprecated ``reservation-mode`` corresponds to: + +.. code-block:: json + + { + "Dhcp4": { + "reservations-global": false, + "reservations-in-subnet": false + } + } + +The ``global`` value from the deprecated ``reservation-mode`` corresponds to: + +.. code-block:: json + + { + "Dhcp4": { + "reservations-global": true, + "reservations-in-subnet": false + } + } + +The ``out-of-pool`` value from the deprecated ``reservation-mode`` corresponds to: + +.. code-block:: json + + { + "Dhcp4": { + "reservations-global": false, + "reservations-in-subnet": true, + "reservations-out-of-pool": true + } + } + +And the ``all`` value from the deprecated ``reservation-mode`` corresponds to: + +.. code-block:: json + + { + "Dhcp4": { + "reservations-global": false, + "reservations-in-subnet": true, + "reservations-out-of-pool": false + } + } + +To activate both ``global`` and ``all``, the following combination can be used: + +.. code-block:: json + + { + "Dhcp4": { + "reservations-global": true, + "reservations-in-subnet": true, + "reservations-out-of-pool": false + } + } + +To activate both ``global`` and ``out-of-pool``, the following combination can +be used: + +.. code-block:: json + + { + "Dhcp4": { + "reservations-global": true, + "reservations-in-subnet": true, + "reservations-out-of-pool": true + } + } + +Enabling ``out-of-pool`` and disabling ``in-subnet`` at the same time +is not recommended because ``out-of-pool`` applies to host reservations in a +subnet, which are fetched only when the ``in-subnet`` flag is ``true``. + +The parameter can be specified at the global, subnet, and shared-network +levels. + +An example configuration that disables reservations looks as follows: + +.. code-block:: json + + { + "Dhcp4": { + "subnet4": [ + { + "reservations-global": false, + "reservations-in-subnet": false, + "subnet": "192.0.2.0/24", + "id": 1 + } + ] + } + } + +An example configuration using global reservations is shown below: + +.. code-block:: json + + { + "Dhcp4": { + "reservations": [ + { + "hostname": "host-one", + "hw-address": "01:bb:cc:dd:ee:ff" + }, + { + "hostname": "host-two", + "hw-address": "02:bb:cc:dd:ee:ff" + } + ], + "reservations-global": true, + "reservations-in-subnet": false, + "subnet4": [ + { + "pools": [ + { + "pool": "192.0.2.10-192.0.2.100" + } + ], + "subnet": "192.0.2.0/24", + "id": 1 + } + ] + } + } + +For more details regarding global reservations, see :ref:`global-reservations4`. + +Another aspect of host reservations is the different types of +identifiers. Kea currently supports four types of identifiers: +``hw-address``, ``duid``, ``client-id``, and ``circuit-id``. This is beneficial from a +usability perspective; however, there is one drawback. For each incoming +packet, Kea has to extract each identifier type and then query the +database to see if there is a reservation by this particular identifier. +If nothing is found, the next identifier is extracted and the next query +is issued. This process continues until either a reservation is found or +all identifier types have been checked. Over time, with an increasing +number of supported identifier types, Kea would become slower and +slower. + +To address this problem, a parameter called +``host-reservation-identifiers`` is available. It takes a list of +identifier types as a parameter. Kea checks only those identifier +types enumerated in ``host-reservation-identifiers``. From a performance +perspective, the number of identifier types should be kept to a minimum, +ideally one. If the deployment uses several reservation types, please +enumerate them from most- to least-frequently used, as this increases +the chances of Kea finding the reservation using the fewest queries. An +example of a ``host-reservation-identifiers`` configuration looks as follows: + +:: + + { + "host-reservation-identifiers": [ "circuit-id", "hw-address", "duid", "client-id" ], + "subnet4": [ + { + "subnet": "192.0.2.0/24", + ... + } + ], + ... + } + +If not specified, the default value is: + +:: + + "host-reservation-identifiers": [ "hw-address", "duid", "circuit-id", "client-id" ] + +.. note:: + + As soon as a host reservation is found the search is stopped so + when a client has two host reservations using different enabled + identifier types the first is always returned and the second + ignored. In other words, this is usually a configuration mistake. + In rare cases when having two reservations for the same host makes sense, + you can control which of those will be used by ordering the list of + identifier types in `host-reservation-identifiers`. + + +.. _global-reservations4: + +Global Reservations in DHCPv4 +----------------------------- + +In some deployments, such as mobile, clients can roam within the network +and certain parameters must be specified regardless of the client's +current location. To meet such a need, Kea offers a global reservation +mechanism. The idea behind it is that regular host +reservations are tied to specific subnets, by using a specific +subnet ID. Kea can specify a global reservation that can be used in +every subnet that has global reservations enabled. + +This feature can be used to assign certain parameters, such as hostname +or other dedicated, host-specific options. It can also be used to assign +addresses. + +An address assigned via global host reservation must be feasible for the +subnet the server selects for the client. In other words, the address must +lie within the subnet; otherwise, it is ignored and the server will +attempt to dynamically allocate an address. If the selected subnet +belongs to a shared network, the server checks for feasibility against +the subnet's siblings, selecting the first in-range subnet. If no such +subnet exists, the server falls back to dynamically allocating the address. + +.. note:: + + Prior to release 2.3.5, the server did not perform feasibility checks on + globally reserved addresses, which allowed the server to be configured to + hand out nonsensical leases for arbitrary address values. Later versions + of Kea perform these checks. + +To use global host reservations, a configuration similar to the +following can be used: + +:: + + "Dhcp4": { + # This specifies global reservations. + # They will apply to all subnets that + # have global reservations enabled. + + "reservations": [ + { + "hw-address": "aa:bb:cc:dd:ee:ff", + "hostname": "hw-host-dynamic" + }, + { + "hw-address": "01:02:03:04:05:06", + "hostname": "hw-host-fixed", + + # Use of IP addresses in global reservations is risky. + # If used outside of a matching subnet, such as 192.0.1.0/24, + # it will result in a broken configuration being handed + # to the client. + "ip-address": "192.0.1.77" + }, + { + "duid": "01:02:03:04:05", + "hostname": "duid-host" + }, + { + "circuit-id": "'charter950'", + "hostname": "circuit-id-host" + }, + { + "client-id": "01:11:22:33:44:55:66", + "hostname": "client-id-host" + } + ], + "valid-lifetime": 600, + "subnet4": [ + { + "id": 1, + "subnet": "10.0.0.0/24", + # It is replaced by the "reservations-global", + # "reservations-in-subnet", and "reservations-out-of-pool" + # parameters. + # "reservation-mode": "global", + # Specify if the server should look up global reservations. + "reservations-global": true, + # Specify if the server should look up in-subnet reservations. + "reservations-in-subnet": false, + # Specify if the server can assume that all reserved addresses + # are out-of-pool. It can be ignored because "reservations-in-subnet" + # is false. + # "reservations-out-of-pool": false, + "pools": [ { "pool": "10.0.0.10-10.0.0.100" } ] + } + ] + } + +When using database backends, the global host reservations are +distinguished from regular reservations by using a ``subnet-id`` value of +0. + +.. _pool-selection-with-class-reservations4: + +Pool Selection with Client Class Reservations +--------------------------------------------- + +Client classes can be specified in the Kea configuration file and/or via +host reservations. The classes specified in the Kea configuration file are +evaluated immediately after receiving the DHCP packet and therefore can be +used to influence subnet selection using the ``client-class`` parameter +specified in the subnet scope. The classes specified within the host +reservations are fetched and assigned to the packet after the server has +already selected a subnet for the client. This means that the client +class specified within a host reservation cannot be used to influence +subnet assignment for this client, unless the subnet belongs to a +shared network. If the subnet belongs to a shared network, the server may +dynamically change the subnet assignment while trying to allocate a lease. +If the subnet does not belong to a shared network, the subnet +is not changed once selected. + +If the subnet does not belong to a shared network, it is possible to +use host reservation-based client classification to select an address pool +within the subnet as follows: + +:: + + "Dhcp4": { + "client-classes": [ + { + "name": "reserved_class" + }, + { + "name": "unreserved_class", + "test": "not member('reserved_class')" + } + ], + "subnet4": [ + { + "id": 1, + "subnet": "192.0.2.0/24", + "reservations": [ + { + "hw-address": "aa:bb:cc:dd:ee:fe", + "client-classes": [ "reserved_class" ] + } + ], + "pools": [ + { + "pool": "192.0.2.10-192.0.2.20", + "client-class": "reserved_class" + }, + { + "pool": "192.0.2.30-192.0.2.40", + "client-class": "unreserved_class" + } + ] + } + ] + } + +The ``reserved_class`` is declared without the ``test`` parameter because +it may only be assigned to the client via the host reservation mechanism. The +second class, ``unreserved_class``, is assigned to clients which do not +belong to the ``reserved_class``. The first pool within the subnet is only +used for clients having a reservation for the ``reserved_class``. The +second pool is used for clients not having such a reservation. The +configuration snippet includes one host reservation which causes the client +with the MAC address aa:bb:cc:dd:ee:fe to be assigned to the +``reserved_class``. Thus, this client will be given an IP address from the +first address pool. + +.. _subnet-selection-with-class-reservations4: + +Subnet Selection with Client Class Reservations +----------------------------------------------- + +There is one specific use case when subnet selection may be influenced by +client classes specified within host reservations: when the +client belongs to a shared network. In such a case it is possible to use +classification to select a subnet within this shared network. Consider the +following example: + +:: + + "Dhcp4": { + "client-classes": [ + { + "name": "reserved_class" + }, + { + "name": "unreserved_class", + "test": "not member('reserved_class')" + } + ], + "reservations": [ + { + "hw-address": "aa:bb:cc:dd:ee:fe", + "client-classes": [ "reserved_class" ] + } + ], + # It is replaced by the "reservations-global", + # "reservations-in-subnet", and "reservations-out-of-pool" parameters. + # Specify if the server should look up global reservations. + "reservations-global": true, + # Specify if the server should look up in-subnet reservations. + "reservations-in-subnet": false, + # Specify if the server can assume that all reserved addresses + # are out-of-pool. It can be ignored because "reservations-in-subnet" + # is false, but if specified, it is inherited by "shared-networks" + # and "subnet4" levels. + # "reservations-out-of-pool": false, + "shared-networks": [ + { + "subnet4": [ + { + "id": 1, + "subnet": "192.0.2.0/24", + "pools": [ + { + "pool": "192.0.2.10-192.0.2.20", + "client-class": "reserved_class" + } + ] + }, + { + "id": 2, + "subnet": "192.0.3.0/24", + "pools": [ + { + "pool": "192.0.3.10-192.0.3.20", + "client-class": "unreserved_class" + } + ] + } + ] + } + ] + } + +This is similar to the example described in +:ref:`pool-selection-with-class-reservations4`. This time, however, there +are two subnets, each of which has a pool associated with a different +class. The clients that do not have a reservation for the ``reserved_class`` +are assigned an address from the subnet 192.0.3.0/24. Clients with +a reservation for the ``reserved_class`` are assigned an address from +the subnet 192.0.2.0/24. The subnets must belong to the same shared network. +In addition, the reservation for the client class must be specified at the +global scope (global reservation) and ``reservations-global`` must be +set to ``true``. + +In the example above, the ``client-class`` could also be specified at the +subnet level rather than the pool level, and would yield the same effect. + +.. _multiple-reservations-same-ip4: + +Multiple Reservations for the Same IP +------------------------------------- + +Host reservations were designed to preclude the creation of multiple +reservations for the same IP address within a particular subnet, to avoid +having two different clients compete for the same address. +When using the default settings, the server returns a configuration error +when it finds two or more reservations for the same IP address within +a subnet in the Kea configuration file. :ischooklib:`libdhcp_host_cmds.so` +returns an error in response to the :isccmd:`reservation-add` command +when it detects that the reservation exists in the database for the IP +address for which the new reservation is being added. + +In some deployments a single host can select one of several network +interfaces to communicate with the DHCP server, and the server must assign +the same IP address to the host regardless of the interface used. Since +each interface is assigned a different MAC address, it implies that +several host reservations must be created to associate all of the MAC +addresses present on this host with IP addresses. Using different +IP addresses for each interface is impractical and is considered a waste +of the IPv4 address space, especially since the host typically uses only one +interface for communication with the server, hence only one IP address +is in use. + +This causes a need to create multiple host reservations for a single +IP address within a subnet; this is supported since the Kea 1.9.1 +release as an optional mode of operation, enabled with the +``ip-reservations-unique`` global parameter. + +The ``ip-reservations-unique`` is a boolean parameter that defaults to +``true``, which forbids the specification of more than one reservation +for the same IP address within a given subnet. Setting this parameter to +``false`` allows such reservations to be created both in the Kea configuration +file and in the host database backend, via :ischooklib:`libdhcp_host_cmds.so`. + +Setting ``ip-reservations-unique`` to ``false`` when using memfile, MySQL or PostgreSQL is supported. +This setting is not supported when using Host Cache (see :ref:`hooks-host-cache`), and the RADIUS backend +(see :ref:`hooks-radius`). These reservation backends simply do not support multiple reservations for the +same IP. If either of these hooks are loaded and ``ip-reservations-unique`` is set to ``false``, then a +configuration error will be emitted and the server will fail to start. + +.. note:: + + When ``ip-reservations-unique`` is set to ``true`` (the default value), + the server ensures that IP reservations are unique for a subnet within + a single host backend and/or Kea configuration file. It does not + guarantee that the reservations are unique across multiple backends. + On server startup, only IP reservations defined in the Kea configuration + file are checked for uniqueness. + +The following is an example configuration with two reservations for +the same IP address but different MAC addresses: + +:: + + "Dhcp4": { + "ip-reservations-unique": false, + "subnet4": [ + { + "id": 1, + "subnet": "192.0.2.0/24", + "reservations": [ + { + "hw-address": "1a:1b:1c:1d:1e:1f", + "ip-address": "192.0.2.11" + }, + { + "hw-address": "2a:2b:2c:2d:2e:2f", + "ip-address": "192.0.2.11" + } + ] + } + ] + } + +It is possible to control the ``ip-reservations-unique`` parameter via the +:ref:`dhcp4-cb`. If the new setting of this parameter conflicts with +the currently used backends (i.e. backends do not support the new setting), +the new setting is ignored and a warning log message is generated. +The backends continue to use the default setting, expecting that +IP reservations are unique within each subnet. To allow the +creation of non-unique IP reservations, the administrator must remove +the backends which lack support for them from the configuration file. + +Administrators must be careful when they have been using multiple +reservations for the same IP address and later decide to return to +the default mode in which this is no longer allowed. They +must make sure that at most one reservation for a given IP address +exists within a subnet, prior to switching back to the default mode. +If such duplicates are left in the configuration file, the server +reports a configuration error. Leaving such reservations in the host +databases does not cause configuration errors but may lead to lease +allocation errors during the server's operation, when it unexpectedly +finds multiple reservations for the same IP address. + +.. note:: + + Currently the Kea server does not verify whether multiple reservations for + the same IP address exist in MySQL and/or PostgreSQL host databases when + ``ip-reservations-unique`` is updated from ``false`` to ``true``. This may + cause issues with lease allocations. The administrator must ensure that there + is at most one reservation for each IP address within each subnet, prior to + the configuration update. + +The ``reservations-lookup-first`` is a boolean parameter which controls whether +host reservations lookup should be performed before lease lookup. This parameter +has effect only when multi-threading is disabled. When multi-threading is +enabled, host reservations lookup is always performed first to avoid lease-lookup +resource locking. The ``reservations-lookup-first`` parameter defaults to ``false`` +when multi-threading is disabled. + +.. _host_reservations_as_basic_access_control4: + +Host Reservations as Basic Access Control +----------------------------------------- + +Starting with Kea 2.3.5, it is possible to define a host reservation that +contains just an identifier, without any address, options, or values. In some +deployments this is useful, as the hosts that have a reservation belong to +the KNOWN class while others do not. This can be used as a basic access control +mechanism. + +The following example demonstrates this concept. It indicates a single IPv4 subnet +and all clients will get an address from it. However, only known clients (those that +have reservations) will get their default router configured. Empty reservations +i.e. reservations that only have the identification criterion, can be +specifically useful in this regard of making the clients known. + +:: + + "Dhcp4": { + "client-classes": [ + { + "name": "KNOWN", + "option-data": [ + { + "name": "routers", + "data": "192.0.2.250" + } + ] + } + ], + "reservations": [ + // Clients on this list will be added to the KNOWN class. + { "hw-address": "aa:bb:cc:dd:ee:fe" }, + { "hw-address": "11:22:33:44:55:66" } + ], + "reservations-in-subnet": true, + + "subnet4": [ + { + "id": 1, + "subnet": "192.0.2.0/24", + "pools": [ + { + "pool": "192.0.2.1-192.0.2.200" + } + ] + } + ] + } + +This concept can be extended further. A good real-life scenario might be a +situation where some customers of an ISP have not paid their bills. A new class can be +defined to use an alternative default router that, instead of relaying traffic, +redirects those customers to a captive portal urging them to bring their accounts up to date. + +:: + + "Dhcp4": { + "client-classes": [ + { + "name": "blocked", + "option-data": [ + { + "name": "routers", + "data": "192.0.2.251" + } + ] + } + ], + "reservations": [ + // Clients on this list will be added to the KNOWN class. Some + // will also be added to the blocked class. + { "hw-address": "aa:bb:cc:dd:ee:fe", + "client-classes": [ "blocked" ] }, + { "hw-address": "11:22:33:44:55:66" } + ], + "reservations-in-subnet": true, + + "subnet4": [ + { + "id": 1, + "subnet": "192.0.2.0/24", + "pools": [ + { + "pool": "192.0.2.1-192.0.2.200" + } + ], + "option-data": [ + { + "name": "routers", + "data": "192.0.2.250" + } + ] + } + ] + } + +.. _shared-network4: + +Shared Networks in DHCPv4 +========================= + +DHCP servers use subnet information in two ways. It is used to +both determine the point of attachment, i.e. where the client is +connected to the network, and to +group information pertaining to a specific location in the network. +Sometimes it is useful to have more than one +logical IP subnet deployed on the same physical link. +Understanding that two or more subnets are used on the same link requires +additional logic in the DHCP server. This capability is called "shared +networks" in Kea, and sometimes also +"shared subnets"; in Microsoft's nomenclature it is called "multinet." + +There are many cases where the shared networks feature is useful; here we +explain just a handful of the most common ones. The first and by far +most common use case is an existing IPv4 network that has grown and is +running out of available address space. Rather than migrating all +devices to a new, larger subnet, it is easier to simply configure +additional subnets on top of the existing one. Sometimes, due to address +space fragmentation (e.g. only many disjointed /24s are available), this +is the only choice. Also, configuring additional subnets has the +advantage of not disrupting the operation of existing devices. + +Another very frequent use case comes from cable networks. There are two +types of devices in cable networks: cable modems and the end-user +devices behind them. It is a common practice to use different subnets +for cable modems to prevent users from tinkering with them. In this +case, the distinction is based on the type of device, rather than +on address-space exhaustion. + +A client connected to a shared network may be assigned an address from +any of the pools defined within the subnets belonging to the shared +network. Internally, the server selects one of the subnets belonging to +a shared network and tries to allocate an address from this subnet. If +the server is unable to allocate an address from the selected subnet +(e.g., due to address-pool exhaustion), it uses another subnet from +the same shared network and tries to allocate an address from this subnet. +The server typically allocates all +addresses available in a given subnet before it starts allocating +addresses from other subnets belonging to the same shared network. +However, in certain situations the client can be allocated an address +from another subnet before the address pools in the first subnet get +exhausted; this sometimes occurs when the client provides a hint that belongs to another +subnet, or the client has reservations in a subnet other than the +default. + +.. note:: + + Deployments should not assume that Kea waits until it has allocated + all the addresses from the first subnet in a shared network before + allocating addresses from other subnets. + +To define a shared network, an additional configuration scope is +introduced: + +:: + + { + "Dhcp4": { + "shared-networks": [ + { + # Name of the shared network. It may be an arbitrary string + # and it must be unique among all shared networks. + "name": "my-secret-lair-level-1", + + # The subnet selector can be specified at the shared-network level. + # Subnets from this shared network will be selected for directly + # connected clients sending requests to the server's "eth0" interface. + "interface": "eth0", + + # This starts a list of subnets in this shared network. + # There are two subnets in this example. + "subnet4": [ + { + "id": 1, + "subnet": "10.0.0.0/8", + "pools": [ { "pool": "10.0.0.1 - 10.0.0.99" } ] + }, + { + "id": 2, + "subnet": "192.0.2.0/24", + "pools": [ { "pool": "192.0.2.100 - 192.0.2.199" } ] + } + ] + } + ], + # end of shared-networks + + # It is likely that in the network there will be a mix of regular, + # "plain" subnets and shared networks. It is perfectly valid to mix + # them in the same configuration file. + # + # This is a regular subnet. It is not part of any shared network. + "subnet4": [ + { + "id": 3, + "subnet": "192.0.3.0/24", + "pools": [ { "pool": "192.0.3.1 - 192.0.3.200" } ], + "interface": "eth1" + } + ] + } + } + +As demonstrated in the example, it is possible to mix shared and regular +("plain") subnets. Each shared network must have a unique name. This is +similar to the ID for subnets, but gives administrators more +flexibility. It is used for logging, but also internally for identifying +shared networks. + +In principle it makes sense to define only shared networks that consist +of two or more subnets. However, for testing purposes, an empty subnet +or a network with just a single subnet is allowed. This is not a +recommended practice in production networks, as the shared network logic +requires additional processing and thus lowers the server's performance. +To avoid unnecessary performance degradation, shared subnets should +only be defined when required by the deployment. + +Shared networks provide the ability to specify many parameters in the +shared network scope that apply to all subnets within it. If +necessary, it is possible to specify a parameter in the shared-network scope and +then override its value in the subnet scope. For example: + +:: + + { + "shared-networks": [ + { + "name": "lab-network3", + + "interface": "eth0", + + # This applies to all subnets in this shared network, unless + # values are overridden on subnet scope. + "valid-lifetime": 600, + + # This option is made available to all subnets in this shared + # network. + "option-data": [ + { + "name": "log-servers", + "data": "1.2.3.4" + } + ], + + "subnet4": [ + { + "id": 1, + "subnet": "10.0.0.0/8", + "pools": [ { "pool": "10.0.0.1 - 10.0.0.99" } ], + + # This particular subnet uses different values. + "valid-lifetime": 1200, + "option-data": [ + { + "name": "log-servers", + "data": "10.0.0.254" + }, + { + "name": "routers", + "data": "10.0.0.254" + } ] + }, + { + "id": 2, + "subnet": "192.0.2.0/24", + "pools": [ { "pool": "192.0.2.100 - 192.0.2.199" } ], + + # This subnet does not specify its own valid-lifetime value, + # so it is inherited from shared network scope. + "option-data": [ + { + "name": "routers", + "data": "192.0.2.1" + } ] + } + ] + } + ], + ... + } + +In this example, there is a ``log-servers`` option defined that is available +to clients in both subnets in this shared network. Also, the valid +lifetime is set to 10 minutes (600s). However, the first subnet +overrides some of the values (the valid lifetime is 20 minutes, there is a different IP +address for ``log-servers``), but also adds its own option (the router address). +Assuming a client asking for router and ``log-servers`` options is assigned +a lease from this subnet, it will get a lease for 20 minutes and a +``log-servers`` and routers value of 10.0.0.254. If the same client is +assigned to the second subnet, it will get a 10-minute lease, a +``log-servers`` value of 1.2.3.4, and routers set to 192.0.2.1. + +Local and Relayed Traffic in Shared Networks +-------------------------------------------- + +It is possible to specify an interface name at the shared-network level, +to tell the server that this specific shared network is reachable +directly (not via relays) using the local network interface. As all +subnets in a shared network are expected to be used on the same physical +link, it is a configuration error to attempt to define a shared network +using subnets that are reachable over different interfaces. In other +words, all subnets within the shared network must have the same value +for the ``interface`` parameter. The following configuration is an +example of what **NOT** to do: + +:: + + { + "shared-networks": [ + { + "name": "office-floor-2", + "subnet4": [ + { + "id": 1, + "subnet": "10.0.0.0/8", + "pools": [ { "pool": "10.0.0.1 - 10.0.0.99" } ], + "interface": "eth0" + }, + { + "id": 2, + "subnet": "192.0.2.0/24", + "pools": [ { "pool": "192.0.2.100 - 192.0.2.199" } ], + + # Specifying the different interface name is a configuration + # error. This value should rather be "eth0" or the interface + # name in the other subnet should be "eth1". + "interface": "eth1" + } + ] + } + ], + ... + } + +To minimize the chance of configuration errors, it is often more convenient +to simply specify the interface name once, at the shared-network level, as +shown in the example below. + +:: + + { + "shared-networks": [ + { + "name": "office-floor-2", + + # This tells Kea that the whole shared network is reachable over a + # local interface. This applies to all subnets in this network. + "interface": "eth0", + + "subnet4": [ + { + "id": 1, + "subnet": "10.0.0.0/8", + "pools": [ { "pool": "10.0.0.1 - 10.0.0.99" } ] + }, + { + "id": 2, + "subnet": "192.0.2.0/24", + "pools": [ { "pool": "192.0.2.100 - 192.0.2.199" } ] + } + ] + } + ], + ... + } + + +With relayed traffic, subnets are typically selected using +the relay agents' addresses. If the subnets are used independently (not +grouped within a shared network), a different relay +address can be specified for each of these subnets. When multiple subnets belong to a +shared network they must be selected via the same relay address and, +similarly to the case of the local traffic described above, it is a +configuration error to specify different relay addresses for the respective +subnets in the shared network. The following configuration is another example +of what **NOT** to do: + +:: + + { + "shared-networks": [ + { + "name": "kakapo", + "subnet4": [ + { + "id": 1, + "subnet": "192.0.2.0/26", + "relay": { + "ip-addresses": [ "192.1.1.1" ] + }, + "pools": [ { "pool": "192.0.2.63 - 192.0.2.63" } ] + }, + { + "id": 2, + "subnet": "10.0.0.0/24", + "relay": { + # Specifying a different relay address for this + # subnet is a configuration error. In this case + # it should be 192.1.1.1 or the relay address + # in the previous subnet should be 192.2.2.2. + "ip-addresses": [ "192.2.2.2" ] + }, + "pools": [ { "pool": "10.0.0.16 - 10.0.0.16" } ] + } + ] + } + ], + ... + } + +Again, it is better to specify the relay address at the shared-network +level; this value will be inherited by all subnets belonging to the +shared network. + +:: + + { + "shared-networks": [ + { + "name": "kakapo", + "relay": { + # This relay address is inherited by both subnets. + "ip-addresses": [ "192.1.1.1" ] + }, + "subnet4": [ + { + "id": 1, + "subnet": "192.0.2.0/26", + "pools": [ { "pool": "192.0.2.63 - 192.0.2.63" } ] + }, + { + "id": 2, + "subnet": "10.0.0.0/24", + "pools": [ { "pool": "10.0.0.16 - 10.0.0.16" } ] + } + ] + } + ], + ... + } + +Even though it is technically possible to configure two (or more) subnets +within the shared network to use different relay addresses, this will almost +always lead to a different behavior than what the user expects. In this +case, the Kea server will initially select one of the subnets by matching +the relay address in the client's packet with the subnet's configuration. +However, it MAY end up using the other subnet (even though it does not match +the relay address) if the client already has a lease in this subnet or has a +host reservation in this subnet, or simply if the initially selected subnet has no +more addresses available. Therefore, it is strongly recommended to always +specify subnet selectors (interface or relay address) at the shared-network +level if the subnets belong to a shared network, as it is rarely useful to +specify them at the subnet level and may lead to the configuration errors +described above. + +Client Classification in Shared Networks +---------------------------------------- + +Sometimes it is desirable to segregate clients into specific subnets +based on certain properties. This mechanism is called client +classification and is described in :ref:`classify`. Client +classification can be applied to subnets belonging to shared networks in +the same way as it is used for subnets specified outside of shared +networks. It is important to understand how the server selects subnets +for clients when client classification is in use, to ensure that the +appropriate subnet is selected for a given client type. + +If a subnet is associated with a class, only the clients belonging to +this class can use this subnet. If there are no classes specified for a +subnet, any client connected to a given shared network can use this +subnet. A common mistake is to assume that a subnet that includes a client +class is preferred over subnets without client classes. Consider the +following example: + +:: + + { + "client-classes": [ + { + "name": "b-devices", + "test": "option[93].hex == 0x0002" + } + ], + "shared-networks": [ + { + "name": "galah", + "interface": "eth0", + "subnet4": [ + { + "id": 1, + "subnet": "192.0.2.0/26", + "pools": [ { "pool": "192.0.2.1 - 192.0.2.63" } ] + }, + { + "id": 2, + "subnet": "10.0.0.0/24", + "pools": [ { "pool": "10.0.0.2 - 10.0.0.250" } ], + "client-class": "b-devices" + } + ] + } + ] + } + +If the client belongs to the "b-devices" class (because it includes +option 93 with a value of 0x0002), that does not guarantee that the +subnet 10.0.0.0/24 will be used (or preferred) for this client. The +server can use either of the two subnets, because the subnet 192.0.2.0/26 +is also allowed for this client. The client classification used in this +case should be perceived as a way to restrict access to certain subnets, +rather than as a way to express subnet preference. For example, if the +client does not belong to the "b-devices" class, it may only use the +subnet 192.0.2.0/26 and will never use the subnet 10.0.0.0/24. + +A typical use case for client classification is in a cable network, +where cable modems should use one subnet and other devices should use +another subnet within the same shared network. In this case it is +necessary to apply classification on all subnets. The following example +defines two classes of devices, and the subnet selection is made based +on option 93 values. + +:: + + { + "client-classes": [ + { + + "name": "a-devices", + "test": "option[93].hex == 0x0001" + }, + { + "name": "b-devices", + "test": "option[93].hex == 0x0002" + } + ], + "shared-networks": [ + { + "name": "galah", + "interface": "eth0", + "subnet4": [ + { + "id": 1, + "subnet": "192.0.2.0/26", + "pools": [ { "pool": "192.0.2.1 - 192.0.2.63" } ], + "client-class": "a-devices" + }, + { + "id": 2, + "subnet": "10.0.0.0/24", + "pools": [ { "pool": "10.0.0.2 - 10.0.0.250" } ], + "client-class": "b-devices" + } + ] + } + ] + } + +In this example each class has its own restriction. Only clients that +belong to class "a-devices" are able to use subnet 192.0.2.0/26 and +only clients belonging to "b-devices" are able to use subnet +10.0.0.0/24. Care should be taken not to define too-restrictive +classification rules, as clients that are unable to use any subnets will +be refused service. However, this may be a desired outcome if one wishes +to provide service only to clients with known properties (e.g. only VoIP +phones allowed on a given link). + +It is possible to achieve an effect similar to the one +presented in this section without the use of shared networks. If the +subnets are placed in the global subnets scope, rather than in the +shared network, the server will still use classification rules to pick +the right subnet for a given class of devices. The major benefit of +placing subnets within the shared network is that common parameters for +the logically grouped subnets can be specified once in the +shared-network scope, e.g. the ``interface`` or ``relay`` parameter. All subnets +belonging to this shared network will inherit those parameters. + +Host Reservations in Shared Networks +------------------------------------ + +Subnets that are part of a shared network allow host reservations, +similar to regular subnets: + +:: + + { + "shared-networks": [ + { + "name": "frog", + "interface": "eth0", + "subnet4": [ + { + "subnet": "192.0.2.0/26", + "id": 100, + "pools": [ { "pool": "192.0.2.1 - 192.0.2.63" } ], + "reservations": [ + { + "hw-address": "aa:bb:cc:dd:ee:ff", + "ip-address": "192.0.2.28" + } + ] + }, + { + "subnet": "10.0.0.0/24", + "id": 101, + "pools": [ { "pool": "10.0.0.1 - 10.0.0.254" } ], + "reservations": [ + { + "hw-address": "11:22:33:44:55:66", + "ip-address": "10.0.0.29" + } + ] + } + ] + } + ] + } + + +It is worth noting that Kea conducts additional checks when processing a +packet if shared networks are defined. First, instead of simply checking +whether there is a reservation for a given client in its initially +selected subnet, Kea looks through all subnets in a shared network for a +reservation. This is one of the reasons why defining a shared network +may impact performance. If there is a reservation for a client in any +subnet, that particular subnet is selected for the client. Although +it is technically not an error, it is considered bad practice to define +reservations for the same host in multiple subnets belonging to the same +shared network. + +While not strictly mandatory, it is strongly recommended to use explicit +"id" values for subnets if database storage will be used for host +reservations. If an ID is not specified, the values for it are +auto-generated, i.e. Kea assigns increasing integer values starting from +1. Thus, the auto-generated IDs are not stable across configuration +changes. + +.. _dhcp4-serverid: + +Server Identifier in DHCPv4 +=========================== + +The DHCPv4 protocol uses a "server identifier" to allow clients to +discriminate between several servers present on the same link; this +value is an IPv4 address of the server. The server chooses the IPv4 +address of the interface on which the message from the client (or relay) +has been received. A single server instance uses multiple server +identifiers if it is receiving queries on multiple interfaces. + +It is possible to override the default server identifier values by specifying +the ``dhcp-server-identifier`` option. This option configuration is only +supported at the subnet, shared network, client class, and global levels. It +must not be specified at the host-reservation level. +When configuring the ``dhcp-server-identifier`` option at client-class level, the +class must not set the ``only-if-required`` flag, because this class would not +be evaluated before the server determines if the received DHCP message should +be accepted for processing. Such classes are evaluated after subnet selection. +See :ref:`dhcp4-required-class` for details. + +The following example demonstrates how to override the server identifier +for a subnet: + +:: + + { + "subnet4": [ + { + "subnet": "192.0.2.0/24", + "option-data": [ + { + "name": "dhcp-server-identifier", + "data": "10.2.5.76" + } + ], + ... + } + ], + ... + } + +.. _dhcp4-subnet-selection: + +How the DHCPv4 Server Selects a Subnet for the Client +===================================================== + +The DHCPv4 server differentiates among directly connected clients, +clients trying to renew leases, and clients sending their messages +through relays. For directly connected clients, the server checks +the configuration for the interface on which the message has been +received and, if the server configuration does not match any configured +subnet, the message is discarded. + +An optional interface parameter is available within a subnet definition to +designate that a given subnet is local, i.e. reachable directly over the +specified interface. For example, a server that is intended to serve a local +subnet over eth0 may be configured as follows: + +:: + + "Dhcp4": { + "subnet4": [ + { + "id": 1, + "subnet": "192.0.2.0/24", + "pools": [ + { + "pool": "192.0.2.100 - 192.0.2.199" + } + ], + "interface": "eth0" + } + ], + ... + } + +Assuming that the server's interface is configured with the IPv4 address +192.0.2.3, the server only processes messages received through this +interface from a directly connected client if there is a subnet +configured to which this IPv4 address belongs, such as 192.0.2.0/24. The +server uses this subnet to assign an IPv4 address for the client. + +The rule above does not apply when the client unicasts its message, i.e. +is trying to renew its lease; such a message is accepted through any +interface. The renewing client sets ``ciaddr`` to the currently used IPv4 +address, and the server uses this address to select the subnet for the +client (in particular, to extend the lease using this address). + +If the message is relayed it is accepted through any interface. The +``giaddr`` set by the relay agent is used to select the subnet for the +client. + +It is also possible to specify a relay IPv4 address for a given subnet. +It can be used to match incoming packets into a subnet in uncommon +configurations, e.g. shared networks. See :ref:`dhcp4-relay-override` for details. + +.. note:: + + The subnet selection mechanism described in this section is based on + the assumption that client classification is not used. The + classification mechanism alters the way in which a subnet is selected + for the client, depending on the classes to which the client belongs. + +.. note:: + + When the selected subnet is a member of a shared network, the + whole shared network is selected. + +.. _dhcp4-relay-override: + +Using a Specific Relay Agent for a Subnet +----------------------------------------- + +A relay must have an interface connected to the link on which the +clients are being configured. Typically the relay has an IPv4 address +configured on that interface, which belongs to the subnet from which the +server assigns addresses. Normally, the server is able to use the +IPv4 address inserted by the relay (in the ``giaddr`` field of the DHCPv4 +packet) to select the appropriate subnet. + +However, that is not always the case. In certain uncommon — but valid — +deployments, the relay address may not match the subnet. This usually +means that there is more than one subnet allocated for a given link. The +two most common examples of this are long-lasting network +renumbering (where both old and new address spaces are still being used) +and a cable network. In a cable network, both cable modems and the +devices behind them are physically connected to the same link, yet they +use distinct addressing. In such a case, the DHCPv4 server needs +additional information (the IPv4 address of the relay) to properly +select an appropriate subnet. + +The following example assumes that there is a subnet 192.0.2.0/24 that +is accessible via a relay that uses 10.0.0.1 as its IPv4 address. The +server is able to select this subnet for any incoming packets that come +from a relay that has an address in the 192.0.2.0/24 subnet. It also +selects that subnet for a relay with address 10.0.0.1. + +.. code-block:: json + + { + "Dhcp4": { + "subnet4": [ + { + "id": 1, + "subnet": "192.0.2.0/24", + "pools": [ { "pool": "192.0.2.10 - 192.0.2.20" } ], + "relay": { + "ip-addresses": [ "10.0.0.1" ] + } + } + ] + } + } + +If ``relay`` is specified, the ``ip-addresses`` parameter within it is +mandatory. The ``ip-addresses`` parameter supports specifying a list of addresses. + +.. _dhcp4-srv-example-client-class-relay: + +Segregating IPv4 Clients in a Cable Network +------------------------------------------- + +In certain cases, it is useful to mix relay address information +(introduced in :ref:`dhcp4-relay-override`) with client classification (explained +in :ref:`classify`). One specific example is in a cable network, +where modems typically get addresses from a different subnet than all +the devices connected behind them. + +Let us assume that there is one Cable Modem Termination System (CMTS) +with one CM MAC (a physical link that modems are connected to). We want +the modems to get addresses from the 10.1.1.0/24 subnet, while +everything connected behind the modems should get addresses from the +192.0.2.0/24 subnet. The CMTS that acts as a relay uses address +10.1.1.1. The following configuration can serve that situation: + +:: + + "Dhcp4": { + "subnet4": [ + { + "id": 1, + "subnet": "10.1.1.0/24", + "pools": [ { "pool": "10.1.1.2 - 10.1.1.20" } ], + "client-class": "docsis3.0", + "relay": { + "ip-addresses": [ "10.1.1.1" ] + } + }, + { + "id": 2, + "subnet": "192.0.2.0/24", + "pools": [ { "pool": "192.0.2.10 - 192.0.2.20" } ], + "relay": { + "ip-addresses": [ "10.1.1.1" ] + } + } + ], + ... + } + +.. _dhcp4-decline: + +Duplicate Addresses (DHCPDECLINE Support) +========================================= + +The DHCPv4 server is configured with a certain pool of addresses that it +is expected to hand out to DHCPv4 clients. It is assumed that the server +is authoritative and has complete jurisdiction over those addresses. +However, for various reasons such as misconfiguration or a faulty +client implementation that retains its address beyond the valid +lifetime, there may be devices connected that use those addresses +without the server's approval or knowledge. + +Such an unwelcome event can be detected by legitimate clients (using ARP +or ICMP Echo Request mechanisms) and reported to the DHCPv4 server using +a DHCPDECLINE message. The server does a sanity check (to see whether +the client declining an address really was supposed to use it) and then +conducts a clean-up operation. Any DNS entries related to that +address are removed, the event is logged, and hooks are +triggered. After that is complete, the address is marked as +declined (which indicates that it is used by an unknown entity and thus +not available for assignment) and a probation time is set on it. +Unless otherwise configured, the probation period lasts 24 hours; after +that time, the server will recover the lease (i.e. put it back into +the available state) and the address will be available for assignment +again. It should be noted that if the underlying issue of a +misconfigured device is not resolved, the duplicate-address scenario +will repeat. If reconfigured correctly, this mechanism provides an +opportunity to recover from such an event automatically, without any +system administrator intervention. + +To configure the decline probation period to a value other than the +default, the following syntax can be used: + +:: + + "Dhcp4": { + "decline-probation-period": 3600, + "subnet4": [ + { + ... + }, + ... + ], + ... + } + +The parameter is expressed in seconds, so the example above +instructs the server to recycle declined leases after one hour. + +There are several statistics and hook points associated with the decline +handling procedure. The ``lease4_decline`` hook point is triggered after the +incoming DHCPDECLINE message has been sanitized and the server is about +to decline the lease. The ``declined-addresses`` statistic is increased +after the hook returns (both the global and subnet-specific variants). (See +:ref:`dhcp4-stats` and :ref:`hooks-libraries` +for more details on DHCPv4 statistics and Kea hook points.) + +Once the probation time elapses, the declined lease is recovered using +the standard expired-lease reclamation procedure, with several +additional steps. In particular, both ``declined-addresses`` statistics +(global and subnet-specific) are decreased. At the same time, +``reclaimed-declined-addresses`` statistics (again in two variants, global +and subnet-specific) are increased. + +A note about statistics: The Kea server does not decrease the +``assigned-addresses`` statistics when a DHCPDECLINE is received and +processed successfully. While technically a declined address is no +longer assigned, the primary usage of the ``assigned-addresses`` statistic +is to monitor pool utilization. Most people would forget to include +``declined-addresses`` in the calculation, and would simply use +``assigned-addresses``/``total-addresses``. This would cause a bias towards +under-representing pool utilization. As this has a potential to cause serious +confusion, ISC decided not to decrease ``assigned-addresses`` immediately after +receiving DHCPDECLINE, but to do it later when Kea recovers the address +back to the available pool. + +.. _dhcp4-stats: + +Statistics in the DHCPv4 Server +=============================== + +The DHCPv4 server supports the following statistics: + +.. tabularcolumns:: |p{0.2\linewidth}|p{0.1\linewidth}|p{0.7\linewidth}| + +.. table:: DHCPv4 statistics + :class: longtable + :widths: 20 10 70 + + + +----------------------------------------------------+----------------+------------------------------------+ + | Statistic | Data Type | Description | + +====================================================+================+====================================+ + | pkt4-received | integer | Number of DHCPv4 packets received. | + | | | This includes all packets: valid, | + | | | bogus, corrupted, rejected, etc. | + | | | This statistic is expected to grow | + | | | rapidly. | + +----------------------------------------------------+----------------+------------------------------------+ + | pkt4-discover-received | integer | Number of DHCPDISCOVER packets | + | | | received. This statistic is | + | | | expected to grow; its increase | + | | | means that clients that just | + | | | booted started their configuration | + | | | process and their initial packets | + | | | reached the Kea server. | + +----------------------------------------------------+----------------+------------------------------------+ + | pkt4-offer-received | integer | Number of DHCPOFFER packets | + | | | received. This statistic is | + | | | expected to remain zero at all | + | | | times, as DHCPOFFER packets are | + | | | sent by the server and the server | + | | | is never expected to receive them. | + | | | A non-zero value indicates an | + | | | error. One likely cause would be a | + | | | misbehaving relay agent that | + | | | incorrectly forwards DHCPOFFER | + | | | messages towards the server, | + | | | rather than back to the clients. | + +----------------------------------------------------+----------------+------------------------------------+ + | pkt4-request-received | integer | Number of DHCPREQUEST packets | + | | | received. This statistic is | + | | | expected to grow. Its increase | + | | | means that clients that just | + | | | booted received the server's | + | | | response (DHCPOFFER) and accepted | + | | | it, and are now requesting an | + | | | address (DHCPREQUEST). | + +----------------------------------------------------+----------------+------------------------------------+ + | pkt4-ack-received | integer | Number of DHCPACK packets | + | | | received. This statistic is | + | | | expected to remain zero at all | + | | | times, as DHCPACK packets are sent | + | | | by the server and the server is | + | | | never expected to receive them. A | + | | | non-zero value indicates an error. | + | | | One likely cause would be a | + | | | misbehaving relay agent that | + | | | incorrectly forwards DHCPACK | + | | | messages towards the server, | + | | | rather than back to the clients. | + +----------------------------------------------------+----------------+------------------------------------+ + | pkt4-nak-received | integer | Number of DHCPNAK packets | + | | | received. This statistic is | + | | | expected to remain zero at all | + | | | times, as DHCPNAK packets are sent | + | | | by the server and the server is | + | | | never expected to receive them. A | + | | | non-zero value indicates an error. | + | | | One likely cause would be a | + | | | misbehaving relay agent that | + | | | incorrectly forwards DHCPNAK | + | | | messages towards the server, | + | | | rather than back to the clients. | + +----------------------------------------------------+----------------+------------------------------------+ + | pkt4-release-received | integer | Number of DHCPRELEASE packets | + | | | received. This statistic is | + | | | expected to grow. Its increase | + | | | means that clients that had an | + | | | address are shutting down or | + | | | ceasing to use their addresses. | + +----------------------------------------------------+----------------+------------------------------------+ + | pkt4-decline-received | integer | Number of DHCPDECLINE packets | + | | | received. This statistic is | + | | | expected to remain close to zero. | + | | | Its increase means that a client | + | | | leased an address, but discovered | + | | | that the address is currently | + | | | used by an unknown device | + | | | elsewhere in the network. | + +----------------------------------------------------+----------------+------------------------------------+ + | pkt4-inform-received | integer | Number of DHCPINFORM packets | + | | | received. This statistic is | + | | | expected to grow. Its increase | + | | | means that there are clients | + | | | that either do not need an address | + | | | or already have an address and are | + | | | interested only in getting | + | | | additional configuration | + | | | parameters. | + +----------------------------------------------------+----------------+------------------------------------+ + | pkt4-unknown-received | integer | Number of packets received of an | + | | | unknown type. A non-zero value of | + | | | this statistic indicates that the | + | | | server received a packet that it | + | | | was not able to recognize, either | + | | | with an unsupported type or | + | | | possibly malformed (without a | + | | | message-type option). | + +----------------------------------------------------+----------------+------------------------------------+ + | pkt4-sent | integer | Number of DHCPv4 packets sent. | + | | | This statistic is expected to grow | + | | | every time the server transmits a | + | | | packet. In general, it should | + | | | roughly match pkt4-received, as | + | | | most incoming packets cause the | + | | | server to respond. There are | + | | | exceptions (e.g. DHCPRELEASE), so | + | | | do not worry if it is less than | + | | | pkt4-received. | + +----------------------------------------------------+----------------+------------------------------------+ + | pkt4-offer-sent | integer | Number of DHCPOFFER packets sent. | + | | | This statistic is expected to grow | + | | | in most cases after a DHCPDISCOVER | + | | | is processed. There are certain | + | | | uncommon, but valid, cases where | + | | | incoming DHCPDISCOVER packets are | + | | | dropped, but in general this | + | | | statistic is expected to be close | + | | | to pkt4-discover-received. | + +----------------------------------------------------+----------------+------------------------------------+ + | pkt4-ack-sent | integer | Number of DHCPACK packets sent. | + | | | This statistic is expected to grow | + | | | in most cases after a DHCPREQUEST | + | | | is processed. There are certain | + | | | cases where DHCPNAK is sent | + | | | instead. In general, the sum of | + | | | pkt4-ack-sent and pkt4-nak-sent | + | | | should be close to | + | | | pkt4-request-received. | + +----------------------------------------------------+----------------+------------------------------------+ + | pkt4-nak-sent | integer | Number of DHCPNAK packets sent. | + | | | This statistic is expected to grow | + | | | when the server chooses not to | + | | | honor the address requested by a | + | | | client. In general, the sum of | + | | | pkt4-ack-sent and pkt4-nak-sent | + | | | should be close to | + | | | pkt4-request-received. | + +----------------------------------------------------+----------------+------------------------------------+ + | pkt4-parse-failed | integer | Number of incoming packets that | + | | | could not be parsed. A non-zero | + | | | value of this statistic indicates | + | | | that the server received a | + | | | malformed or truncated packet. | + | | | This may indicate problems in the | + | | | network, faulty clients, or a bug | + | | | in the server. | + +----------------------------------------------------+----------------+------------------------------------+ + | pkt4-receive-drop | integer | Number of incoming packets that | + | | | were dropped. The exact reason for | + | | | dropping packets is logged, but | + | | | the most common reasons may be: an | + | | | unacceptable packet type was | + | | | received, direct responses are | + | | | forbidden, or the server-id sent | + | | | by the client does not match the | + | | | server's server-id. | + +----------------------------------------------------+----------------+------------------------------------+ + | subnet[id].total-addresses | integer | Total number of addresses | + | | | available for DHCPv4 management | + | | | for a given subnet; in other | + | | | words, this is the count of all | + | | | addresses in all configured pools. | + | | | This statistic changes only during | + | | | configuration updates. It does not | + | | | take into account any addresses | + | | | that may be reserved due to host | + | | | reservation. The *id* is the | + | | | the subnet-id of a given subnet. | + | | | This statistic is exposed for each | + | | | subnet separately, and is reset | + | | | during a reconfiguration event. | + +----------------------------------------------------+----------------+------------------------------------+ + | subnet[id].pool[pid].total-addresses | integer | Total number of addresses | + | | | available for DHCPv4 management | + | | | for a given subnet pool; in other | + | | | words, this is the count of all | + | | | addresses in configured subnet | + | | | pool. This statistic changes only | + | | | during configuration updates. It | + | | | does not take into account any | + | | | addresses that may be reserved due | + | | | to host reservation. The *id* is | + | | | the subnet-id of a given subnet. | + | | | The *pid* is the pool-id of a | + | | | given pool. This statistic is | + | | | exposed for each subnet pool | + | | | separately, and is reset during a | + | | | reconfiguration event. | + +----------------------------------------------------+----------------+------------------------------------+ + | cumulative-assigned-addresses | integer | Cumulative number of addresses | + | | | that have been assigned since | + | | | server startup. It is incremented | + | | | each time an address is assigned | + | | | and is not reset when the server | + | | | is reconfigured. | + +----------------------------------------------------+----------------+------------------------------------+ + | subnet[id].cumulative-assigned-addresses | integer | Cumulative number of assigned | + | | | addresses in a given subnet. It | + | | | increases every time a new lease | + | | | is allocated (as a result of | + | | | receiving a DHCPREQUEST message) | + | | | and never decreases. The *id* is | + | | | the subnet-id of the subnet. This | + | | | statistic is exposed for each | + | | | subnet separately, and is reset | + | | | during a reconfiguration event. | + +----------------------------------------------------+----------------+------------------------------------+ + | subnet[id].pool[pid].cumulative-assigned-addresses | integer | Cumulative number of assigned | + | | | addresses in a given subnet pool. | + | | | It increases every time a new | + | | | lease is allocated (as a result of | + | | | receiving a DHCPREQUEST message) | + | | | and never decreases. The *id* is | + | | | the subnet-id of the subnet. The | + | | | *pid* is the pool-id of the pool. | + | | | This statistic is exposed for each | + | | | subnet pool separately, and is | + | | | reset during a reconfiguration | + | | | event. | + +----------------------------------------------------+----------------+------------------------------------+ + | subnet[id].assigned-addresses | integer | Number of assigned addresses in a | + | | | given subnet. It increases every | + | | | time a new lease is allocated (as | + | | | a result of receiving a | + | | | DHCPREQUEST message) and decreases | + | | | every time a lease is released (a | + | | | DHCPRELEASE message is received) | + | | | or expires. The *id* is the | + | | | subnet-id of the subnet. This | + | | | statistic is exposed for each | + | | | subnet separately, and is reset | + | | | during a reconfiguration event. | + +----------------------------------------------------+----------------+------------------------------------+ + | subnet[id].pool[pid].assigned-addresses | integer | Number of assigned addresses in a | + | | | given subnet pool. It increases | + | | | every time a new lease is | + | | | allocated (as a result of | + | | | receiving a DHCPREQUEST message) | + | | | and decreases every time a lease | + | | | is released (a DHCPRELEASE message | + | | | is received) or expires. The *id* | + | | | is the subnet-id of the subnet. | + | | | The *pid* is the pool-id of the | + | | | pool. This statistic is exposed | + | | | for each subnet pool separately, | + | | | and is reset during a | + | | | reconfiguration event. | + +----------------------------------------------------+----------------+------------------------------------+ + | reclaimed-leases | integer | Number of expired leases that have | + | | | been reclaimed since server | + | | | startup. It is incremented each | + | | | time an expired lease is reclaimed | + | | | and never decreases. It can be | + | | | used as a long-term indicator of | + | | | how many actual leases have been | + | | | reclaimed. This is a global | + | | | statistic that covers all subnets. | + +----------------------------------------------------+----------------+------------------------------------+ + | subnet[id].reclaimed-leases | integer | Number of expired leases | + | | | associated with a given subnet | + | | | that have been reclaimed since | + | | | server startup. It is incremented | + | | | each time an expired lease is | + | | | reclaimed. The *id* is the | + | | | subnet-id of a given subnet. This | + | | | statistic is exposed for each | + | | | subnet separately. | + +----------------------------------------------------+----------------+------------------------------------+ + | subnet[id].pool[pid].reclaimed-leases | integer | Number of expired leases | + | | | associated with a given subnet | + | | | pool that have been reclaimed | + | | | since server startup. It is | + | | | incremented each time an expired | + | | | lease is reclaimed. The *id* is | + | | | the subnet-id of a given subnet. | + | | | The *pid* is the pool-id of the | + | | | pool. This statistic is exposed | + | | | for each subnet pool separately. | + +----------------------------------------------------+----------------+------------------------------------+ + | declined-addresses | integer | Number of IPv4 addresses that are | + | | | currently declined; a count of the | + | | | number of leases currently | + | | | unavailable. Once a lease is | + | | | recovered, this statistic is | + | | | decreased; ideally, this statistic | + | | | should be zero. If this statistic | + | | | is non-zero or increasing, a | + | | | network administrator should | + | | | investigate whether there is a | + | | | misbehaving device in the network. | + | | | This is a global statistic that | + | | | covers all subnets. | + +----------------------------------------------------+----------------+------------------------------------+ + | subnet[id].declined-addresses | integer | Number of IPv4 addresses that are | + | | | currently declined in a given | + | | | subnet; a count of the number of | + | | | leases currently unavailable. Once | + | | | a lease is recovered, this | + | | | statistic is decreased; ideally, | + | | | this statistic should be zero. If | + | | | this statistic is non-zero or | + | | | increasing, a network | + | | | administrator should investigate | + | | | whether there is a misbehaving | + | | | device in the network. The *id* is | + | | | the subnet-id of a given subnet. | + | | | This statistic is exposed for each | + | | | subnet separately. | + +----------------------------------------------------+----------------+------------------------------------+ + | subnet[id].pool[pid].declined-addresses | integer | Number of IPv4 addresses that are | + | | | currently declined in a given | + | | | subnet pool; a count of the number | + | | | of leases currently unavailable. | + | | | Once a lease is recovered, this | + | | | statistic is decreased; ideally, | + | | | this statistic should be zero. If | + | | | this statistic is non-zero or | + | | | increasing, a network | + | | | administrator should investigate | + | | | whether there is a misbehaving | + | | | device in the network. The *id* is | + | | | the subnet-id of a given subnet. | + | | | The *pid* is the pool-id of the | + | | | pool. This statistic is exposed | + | | | for each subnet pool separately. | + +----------------------------------------------------+----------------+------------------------------------+ + | reclaimed-declined-addresses | integer | Number of IPv4 addresses that were | + | | | declined, but have now been | + | | | recovered. Unlike | + | | | declined-addresses, this statistic | + | | | never decreases. It can be used as | + | | | a long-term indicator of how many | + | | | actual valid declines were | + | | | processed and recovered from. This | + | | | is a global statistic that covers | + | | | all subnets. | + +----------------------------------------------------+----------------+------------------------------------+ + | subnet[id].reclaimed-declined-addresses | integer | Number of IPv4 addresses that were | + | | | declined, but have now been | + | | | recovered. Unlike | + | | | declined-addresses, this statistic | + | | | never decreases. It can be used as | + | | | a long-term indicator of how many | + | | | actual valid declines were | + | | | processed and recovered from. The | + | | | *id* is the subnet-id of a given | + | | | subnet. This statistic is exposed | + | | | for each subnet separately. | + +----------------------------------------------------+----------------+------------------------------------+ + | subnet[id].pool[pid].reclaimed-declined-addresses | integer | Number of IPv4 addresses that were | + | | | declined, but have now been | + | | | recovered. Unlike | + | | | declined-addresses, this statistic | + | | | never decreases. It can be used as | + | | | a long-term indicator of how many | + | | | actual valid declines were | + | | | processed and recovered from. The | + | | | *id* is the subnet-id of a given | + | | | subnet. The *pid* is the pool-id | + | | | of the pool. This statistic is | + | | | exposed for each subnet pool | + | | | separately. | + +----------------------------------------------------+----------------+------------------------------------+ + | pkt4-lease-query-received | integer | Number of IPv4 DHCPLEASEQUERY | + | | | packets received. (Only exists if | + | | | Leasequery hook library is | + | | | loaded.) | + +----------------------------------------------------+----------------+------------------------------------+ + | pkt4-lease-query-response-unknown-sent | integer | Number of IPv4 DHCPLEASEUNKNOWN | + | | | responses sent. (Only exists if | + | | | Leasequery hook library is | + | | | loaded.) | + +----------------------------------------------------+----------------+------------------------------------+ + | pkt4-lease-query-response-unassigned-sent | integer | Number of IPv4 DHCPLEASEUNASSIGNED | + | | | responses sent. (Only exists if | + | | | Leasequery hook library is | + | | | loaded.) | + +----------------------------------------------------+----------------+------------------------------------+ + | pkt4-lease-query-response-active-sent | integer | Number of IPv4 DHCPLEASEACTIVE | + | | | responses sent. (Only exists if | + | | | Leasequery hook library is | + | | | loaded.) | + +----------------------------------------------------+----------------+------------------------------------+ + | v4-allocation-fail | integer | Number of total address allocation | + | | | failures for a particular client. | + | | | This consists in the number of | + | | | lease allocation attempts that the | + | | | server made before giving up and | + | | | was unable to use any of the | + | | | address pools. This is a global | + | | | statistic that covers all subnets. | + +----------------------------------------------------+----------------+------------------------------------+ + | subnet[id].v4-allocation-fail | integer | Number of total address allocation | + | | | failures for a particular client. | + | | | This consists in the number of | + | | | lease allocation attempts that the | + | | | server made before giving up and | + | | | was unable to use any of the | + | | | address pools. The *id* is the | + | | | subnet-id of a given subnet. This | + | | | statistic is exposed for each | + | | | subnet separately. | + +----------------------------------------------------+----------------+------------------------------------+ + | v4-allocation-fail-shared-network | integer | Number of address allocation | + | | | failures for a particular client | + | | | connected to a shared network. | + | | | This is a global statistic that | + | | | covers all subnets. | + +----------------------------------------------------+----------------+------------------------------------+ + | subnet[id].v4-allocation-fail-shared-network | integer | Number of address allocation | + | | | failures for a particular client | + | | | connected to a shared network. | + | | | The *id* is the subnet-id of a | + | | | given subnet. This statistic is | + | | | exposed for each subnet | + | | | separately. | + +----------------------------------------------------+----------------+------------------------------------+ + | v4-allocation-fail-subnet | integer | Number of address allocation | + | | | failures for a particular client | + | | | connected to a subnet that does | + | | | not belong to a shared network. | + | | | This is a global statistic that | + | | | covers all subnets. | + +----------------------------------------------------+----------------+------------------------------------+ + | subnet[id].v4-allocation-fail-subnet | integer | Number of address allocation | + | | | failures for a particular client | + | | | connected to a subnet that does | + | | | not belong to a shared network. | + | | | The *id* is the subnet-id of a | + | | | given subnet. This statistic is | + | | | exposed for each subnet | + | | | separately. | + +----------------------------------------------------+----------------+------------------------------------+ + | v4-allocation-fail-no-pools | integer | Number of address allocation | + | | | failures because the server could | + | | | not use any configured pools for | + | | | a particular client. It is also | + | | | possible that all of the subnets | + | | | from which the server attempted to | + | | | assign an address lack address | + | | | pools. In this case, it should be | + | | | considered misconfiguration if an | + | | | operator expects that some clients | + | | | should be assigned dynamic | + | | | addresses. This is a global | + | | | statistic that covers all subnets. | + +----------------------------------------------------+----------------+------------------------------------+ + | subnet[id].v4-allocation-fail-no-pools | integer | Number of address allocation | + | | | failures because the server could | + | | | not use any configured pools for | + | | | a particular client. It is also | + | | | possible that all of the subnets | + | | | from which the server attempted to | + | | | assign an address lack address | + | | | pools. In this case, it should be | + | | | considered misconfiguration if an | + | | | operator expects that some clients | + | | | should be assigned dynamic | + | | | addresses. The *id* is the | + | | | subnet-id of a given subnet. This | + | | | statistic is exposed for each | + | | | subnet separately. | + +----------------------------------------------------+----------------+------------------------------------+ + | v4-allocation-fail-classes | integer | Number of address allocation | + | | | failures when the client's packet | + | | | belongs to one or more classes. | + | | | There may be several reasons why a | + | | | lease was not assigned. One of | + | | | them may be a case when all pools | + | | | require packet to belong to | + | | | certain classes and the incoming | + | | | packet didn't belong to any of | + | | | them. Another case where this | + | | | information may be useful is to | + | | | point out that the pool reserved | + | | | to a given class has ran out of | + | | | addresses. This is a global | + | | | statistic that covers all subnets. | + +----------------------------------------------------+----------------+------------------------------------+ + | subnet[id].v4-allocation-fail-classes | integer | Number of address allocation | + | | | failures when the client's packet | + | | | belongs to one or more classes. | + | | | There may be several reasons why a | + | | | lease was not assigned. One of | + | | | them may be a case when all pools | + | | | require packet to belong to | + | | | certain classes and the incoming | + | | | packet didn't belong to any of | + | | | them. Another case where this | + | | | information may be useful is to | + | | | point out that the pool reserved | + | | | to a given class has ran out of | + | | | addresses. The *id* is the | + | | | subnet-id of a given subnet. This | + | | | statistic is exposed for each | + | | | subnet separately. | + +----------------------------------------------------+----------------+------------------------------------+ + | v4-lease-reuses | integer | Number of times an IPv4 lease had | + | | | its CLTT increased in memory and | + | | | its expiration time left unchanged | + | | | in persistent storage as part of | + | | | the lease caching feature. This is | + | | | referred to as a lease reuse. | + | | | This statistic is global. | + +----------------------------------------------------+----------------+------------------------------------+ + | subnet[id].v4-lease-reuses | integer | Number of times an IPv4 lease had | + | | | its CLTT increased in memory and | + | | | its expiration time left unchanged | + | | | in persistent storage as part of | + | | | the lease caching feature. This is | + | | | referred to as a lease reuse. | + | | | This statistic is on a per-subnet | + | | | basis. The *id* is the subnet-id | + | | | of a given subnet. | + +----------------------------------------------------+----------------+------------------------------------+ + | v4-reservation-conflicts | integer | Number of host reservation | + | | | allocation conflicts which have | + | | | occurred across every subnet. When | + | | | a client sends a DHCP Discover and | + | | | is matched to a host reservation | + | | | which is already leased to another | + | | | client, this counter is increased | + | | | by 1. | + +----------------------------------------------------+----------------+------------------------------------+ + | subnet[id].v4-reservation-conflicts | integer | Number of host reservation | + | | | allocation conflicts which have | + | | | occurred in a specific subnet. | + | | | When a client sends a DHCP | + | | | Discover and is matched to a host | + | | | reservation which is already | + | | | leased to another client, this | + | | | counter is increased by 1. | + +----------------------------------------------------+----------------+------------------------------------+ + +.. note:: + + The pool ID can be configured on each pool by explicitly setting the ``pool-id`` + parameter in the pool parameter map. If not configured, ``pool-id`` defaults to 0. + The statistics related to pool ID 0 refer to all the statistics of all the pools + that have unconfigured ``pool-id``. + The pool ID does not need to be unique within the subnet or across subnets. + The statistics regarding a specific pool ID within a subnet will be combined with the + other statistics of all other pools with the same pool ID in the respective subnet. + +.. note:: + + This section describes DHCPv4-specific statistics. For a general + overview and usage of statistics, see :ref:`stats`. + +The DHCPv4 server provides two global parameters to control the default sample +limits of statistics: + +- ``statistic-default-sample-count`` - determines the default maximum + number of samples which are kept. The special value of 0 + indicates that a default maximum age should be used. + +- ``statistic-default-sample-age`` - determines the default maximum + age in seconds of samples which are kept. + +For instance, to reduce the statistic-keeping overhead, set +the default maximum sample count to 1 so only one sample is kept: + +:: + + "Dhcp4": { + "statistic-default-sample-count": 1, + "subnet4": [ + { + ... + }, + ... + ], + ... + } + +Statistics can be retrieved periodically to gain more insight into Kea operations. One tool that +leverages that capability is ISC Stork. See :ref:`stork` for details. + + +.. _dhcp4-ctrl-channel: + +Management API for the DHCPv4 Server +==================================== + +The management API allows the issuing of specific management commands, +such as statistics retrieval, reconfiguration, or shutdown. For more +details, see :ref:`ctrl-channel`. Currently, the only supported +communication channel type is the UNIX stream socket. By default there are +no sockets open; to instruct Kea to open a socket, the following entry +in the configuration file can be used: + +:: + + "Dhcp4": { + "control-socket": { + "socket-type": "unix", + "socket-name": "/path/to/the/unix/socket" + }, + + "subnet4": [ + { + ... + }, + ... + ], + ... + } + +The length of the path specified by the ``socket-name`` parameter is +restricted by the maximum length for the UNIX socket name on the administrator's +operating system, i.e. the size of the ``sun_path`` field in the +``sockaddr_un`` structure, decreased by 1. This value varies on +different operating systems, between 91 and 107 characters. Typical +values are 107 on Linux and 103 on FreeBSD. + +Communication over the control channel is conducted using JSON +structures. See the +`Control Channel section in the Kea Developer's Guide +<https://reports.kea.isc.org/dev_guide/d2/d96/ctrlSocket.html>`__ +for more details. + +The DHCPv4 server supports the following operational commands: + +- :isccmd:`build-report` +- :isccmd:`config-get` +- :isccmd:`config-hash-get` +- :isccmd:`config-reload` +- :isccmd:`config-set` +- :isccmd:`config-test` +- :isccmd:`config-write` +- :isccmd:`dhcp-disable` +- :isccmd:`dhcp-enable` +- :isccmd:`leases-reclaim` +- :isccmd:`list-commands` +- :isccmd:`shutdown` +- :isccmd:`status-get` +- :isccmd:`version-get` + +as described in :ref:`commands-common`. In addition, it supports the +following statistics-related commands: + +- :isccmd:`statistic-get` +- :isccmd:`statistic-reset` +- :isccmd:`statistic-remove` +- :isccmd:`statistic-get`-all +- :isccmd:`statistic-reset`-all +- :isccmd:`statistic-remove`-all +- :isccmd:`statistic-sample-age-set` +- :isccmd:`statistic-sample-age-set`-all +- :isccmd:`statistic-sample-count-set` +- :isccmd:`statistic-sample-count-set`-all + +as described in :ref:`command-stats`. + +.. _dhcp4-user-contexts: + +User Contexts in IPv4 +===================== + +Kea allows the loading of hook libraries that can sometimes benefit from +additional parameters. If such a parameter is specific to the whole +library, it is typically defined as a parameter for the hook library. +However, sometimes there is a need to specify parameters that are +different for each pool. + +See :ref:`user-context` for additional background regarding the +user-context idea. See :ref:`user-context-hooks` for a discussion from the +hooks perspective. + +User contexts can be specified at global scope; at the shared-network, subnet, +pool, client-class, option-data, or definition level; and via host +reservation. One other useful feature is the ability to store comments or +descriptions. + +Let's consider an imaginary case of devices that have colored LED lights. +Depending on their location, they should glow red, blue, or green. It +would be easy to write a hook library that would send specific values, +maybe as a vendor option. However, the server has to have some way to +specify that value for each pool. This need is addressed by user +contexts. In essence, any user data can be specified in the user context +as long as it is a valid JSON map. For example, the aforementioned case +of LED devices could be configured in the following way: + +:: + + "Dhcp4": { + "subnet4": [ + { + "id": 1, + "subnet": "192.0.2.0/24", + "pools": [ + { + "pool": "192.0.2.10 - 192.0.2.20", + # This is pool specific user context + "user-context": { "color": "red" } + } + ], + + # This is a subnet-specific user context. Any type + # of information can be entered here as long as it is valid JSON. + "user-context": { + "comment": "network on the second floor", + "last-modified": "2017-09-04 13:32", + "description": "you can put anything you like here", + "phones": [ "x1234", "x2345" ], + "devices-registered": 42, + "billing": false + } + } + ] + } + +Kea does not interpret or use the user-context information; it simply +stores it and makes it available to the hook libraries. It is up to each +hook library to extract that information and use it. The parser +translates a ``comment`` entry into a user context with the entry, which +allows a comment to be attached inside the configuration itself. + + +.. _dhcp4-std: + +Supported DHCP Standards +======================== + +The following standards are currently supported in Kea: + +- *BOOTP Vendor Information Extensions*, `RFC 1497 + <https://tools.ietf.org/html/rfc1497>`__: This requires the open source + BOOTP hook to be loaded. See :ref:`hooks-bootp` for details. + +- *Dynamic Host Configuration Protocol*, `RFC 2131 + <https://tools.ietf.org/html/rfc2131>`__: Supported messages are + DHCPDISCOVER (1), DHCPOFFER (2), DHCPREQUEST (3), DHCPRELEASE (7), + DHCPINFORM (8), DHCPACK (5), and DHCPNAK(6). + +- *DHCP Options and BOOTP Vendor Extensions*, `RFC 2132 + <https://tools.ietf.org/html/rfc2132>`__: Supported options are PAD (0), + END(255), Message Type(53), DHCP Server Identifier (54), Domain Name (15), + DNS Servers (6), IP Address Lease Time (51), Subnet Mask (1), and Routers (3). + +- *The IPv4 Subnet Selection Option for DHCP*, `RFC 3011 + <https://tools.ietf.org/html/rfc3011>`__: The subnet-selection option is + supported; if received in a packet, it is used in the subnet-selection + process. + +- *DHCP Relay Agent Information Option*, `RFC 3046 + <https://tools.ietf.org/html/rfc3046>`__: Relay Agent Information, + Circuit ID, and Remote ID options are supported. + +- *Link Selection sub-option for the Relay Agent Option*, `RFC 3527 + <https://tools.ietf.org/html/rfc3527>`__: The link selection sub-option + is supported. + +- *Vendor-Identifying Vendor Options for Dynamic Host Configuration + Protocol version 4*, `RFC 3925 + <https://tools.ietf.org/html/rfc3925>`__: The Vendor-Identifying Vendor Class + and Vendor-Identifying Vendor-Specific Information options are supported. + +- *Subscriber-ID Suboption for the DHCP Relay Agent Option*, `RFC 3993 + <https://tools.ietf.org/html/rfc3993>`__: The Subscriber-ID option is + supported. + +- *The Dynamic Host Configuration Protocol (DHCP) Client Fully + Qualified Domain Name (FQDN) Option*, `RFC 4702 + <https://tools.ietf.org/html/rfc4702>`__: The Kea server is able to handle + the Client FQDN option. Also, it is able to use the :iscman:`kea-dhcp-ddns` + component to initiate appropriate DNS Update operations. + +- *Resolution of Fully Qualified Domain Name (FQDN) Conflicts among Dynamic + Host Configuration Protocol (DHCP) Clients*, `RFC 4703 + <https://tools.ietf.org/html/rfc4703>`__: The DHCPv6 server uses a DHCP-DDNS + server to resolve conflicts. + +- *Server Identifier Override sub-option for the Relay Agent Option*, `RFC 5107 + <https://tools.ietf.org/html/rfc5107>`__: The server identifier override + sub-option is supported. The implementation is not complete according to the + RFC, because the server does not store the RAI, but the functionality handles + expected use cases. + +- *Client Identifier Option in DHCP Server Replies*, `RFC 6842 + <https://tools.ietf.org/html/rfc6842>`__: The server by default sends back + the ``client-id`` option. That capability can be disabled. See + :ref:`dhcp4-echo-client-id` for details. + +- *Generalized UDP Source Port for the DHCP Relay Agent Option*, `RFC 8357 + <https://tools.ietf.org/html/rfc8357>`__: The Kea server handles the Relay + Agent Information Source Port sub-option in a received message, remembers the + UDP port, and sends back a reply to the same relay agent using this UDP port. + +- *Captive-Portal Identification in DHCP and Router Advertisements (RAs)*, `RFC + 8910 <https://tools.ietf.org/html/rfc8910>`__: The Kea server can configure + both v4 and v6 versions of the captive portal options. + +- *IPv6-Only Preferred Option for DHCPv4*, `RFC 8925 + <https://tools.ietf.org/html/rfc8925>`__: The Kea server is able to designate + its pools and subnets as IPv6-Only Preferred and send back the + ``v6-only-preferred`` option to clients that requested it. + +- *DHCP and Router Advertisement Options for the Discovery of Network-designated + Resolvers (DNR)*, `RFC 9463 <https://tools.ietf.org/html/rfc9463>`__. The Kea server + supports the DNR option. Part of its value (SvcParams) must be configured in + hex. + +Known RFC Violations +-------------------- + +In principle, Kea aspires to be a reference implementation and aims to implement 100% of the RFC standards. +However, in some cases there are practical aspects that prevent Kea from completely adhering to the text of the RFC documents. + +- `RFC 2131 <https://tools.ietf.org/html/rfc2131>`__, page 30, says that if the incoming DHCPREQUEST packet has no + "requested IP address" option and ``ciaddr`` is not set, the server is supposed to respond with NAK. However, + broken clients exist that will always send a DHCPREQUEST without those options indicated. In that event, Kea accepts the DHCPREQUEST, + assigns an address, and responds with an ACK. + +- `RFC 2131 <https://tools.ietf.org/html/rfc2131>`__, table 5, says that messages + of type DHCPDECLINE or DHCPRELEASE must have the server identifier set and + should be dropped if that option is missing. However, ISC DHCP does not enforce this, presumably as a compatibility + effort for broken clients, and the Kea team decided to follow suit. + +.. _dhcp4-limit: + +DHCPv4 Server Limitations +========================= + +These are the current known limitations of the Kea DHCPv4 server software. Most of +them are reflections of the current stage of development and should be +treated as “not implemented yet”, rather than as actual limitations. +However, some of them are implications of the design choices made. Those +are clearly marked as such. + +- On the Linux and BSD system families, DHCP messages are sent and + received over raw sockets (using LPF and BPF) and all packet + headers (including data link layer, IP, and UDP headers) are created + and parsed by Kea, rather than by the system kernel. Currently, Kea + can only parse the data-link layer headers with a format adhering to + the IEEE 802.3 standard, and assumes this data-link-layer header + format for all interfaces. Thus, Kea does not work on interfaces + which use different data-link-layer header formats (e.g. Infiniband). + +.. _dhcp4-srv-examples: + +Kea DHCPv4 Server Examples +========================== + +A collection of simple-to-use examples for the DHCPv4 component of Kea +is available with the source files, located in the ``doc/examples/kea4`` +directory. + +.. _dhcp4-cb: + +Configuration Backend in DHCPv4 +=============================== + +In the :ref:`config-backend` section we have described the Configuration +Backend (CB) feature, its applicability, and its limitations. This section focuses +on the usage of the CB with the Kea DHCPv4 server. It lists the supported +parameters, describes limitations, and gives examples of DHCPv4 +server configurations to take advantage of the CB. Please also refer to +the corresponding section :ref:`dhcp6-cb` for DHCPv6-specific usage of +the CB. + +.. _dhcp4-cb-parameters: + +Supported Parameters +-------------------- + +The ultimate goal for the CB is to serve as a central configuration +repository for one or multiple Kea servers connected to a database. +In currently supported Kea versions, only a subset of +the DHCPv4 server parameters can be configured in the database. All other +parameters must be specified in the JSON configuration file, if +required. + +All supported parameters can be configured via :ischooklib:`libdhcp_cb_cmds.so`. +The general rule is that +scalar global parameters are set using +:isccmd:`remote-global-parameter4-set`; shared-network-specific parameters +are set using :isccmd:`remote-network4-set`; and subnet-level and pool-level +parameters are set using :isccmd:`remote-subnet4-set`. Whenever +there is an exception to this general rule, it is highlighted in the +table. Non-scalar global parameters have dedicated commands; for example, +the global DHCPv4 options (``option-data``) are modified using +:isccmd:`remote-option4-global-set`. Client classes, together with class-specific +option definitions and DHCPv4 options, are configured using the +:isccmd:`remote-class4-set` command. + +The :ref:`cb-sharing` section explains the concept of shareable +and non-shareable configuration elements and the limitations for +sharing them between multiple servers. In the DHCP configuration (both DHCPv4 +and DHCPv6), the shareable configuration elements are subnets and shared +networks. Thus, they can be explicitly associated with multiple server tags. +The global parameters, option definitions, and global options are non-shareable +and can be associated with only one server tag. This rule does not apply +to the configuration elements associated with ``all`` servers. Any configuration +element associated with ``all`` servers (using the ``all`` keyword as a server tag) is +used by all servers connecting to the configuration database. + +The following table lists DHCPv4-specific parameters supported by the +Configuration Backend, with an indication of the level of the hierarchy +at which it is currently supported. + +.. table:: List of DHCPv4 parameters supported by the Configuration Backend + + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | Parameter | Global | Client | Shared | Subnet | Pool | + | | | Class | Network | | | + +=============================+============================+==============+=============+=============+=============+ + | 4o6-interface | n/a | n/a | n/a | yes | n/a | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | 4o6-interface-id | n/a | n/a | n/a | yes | n/a | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | 4o6-subnet | n/a | n/a | n/a | yes | n/a | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | allocator | yes | n/a | yes | yes | n/a | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | boot-file-name | yes | yes | yes | yes | n/a | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | cache-max-age | yes | n/a | no | no | n/a | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | cache-threshold | yes | n/a | no | no | n/a | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | calculate-tee-times | yes | n/a | yes | yes | n/a | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | client-class | n/a | n/a | yes | yes | yes | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | ddns-send-update | yes | n/a | yes | yes | n/a | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | ddns-override-no-update | yes | n/a | yes | yes | n/a | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | ddns-override-client-update | yes | n/a | yes | yes | n/a | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | ddns-replace-client-name | yes | n/a | yes | yes | n/a | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | ddns-generated-prefix | yes | n/a | yes | yes | n/a | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | ddns-qualifying-suffix | yes | n/a | yes | yes | n/a | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | decline-probation-period | yes | n/a | n/a | n/a | n/a | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | dhcp4o6-port | yes | n/a | n/a | n/a | n/a | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | echo-client-id | yes | n/a | n/a | n/a | n/a | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | hostname-char-set | yes | n/a | yes | yes | n/a | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | hostname-char-replacement | yes | n/a | yes | yes | n/a | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | interface | n/a | n/a | yes | yes | n/a | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | match-client-id | yes | n/a | yes | yes | n/a | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | min-valid-lifetime | yes | yes | yes | yes | n/a | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | max-valid-lifetime | yes | yes | yes | yes | n/a | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | next-server | yes | yes | yes | yes | n/a | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | option-data | yes (via | yes | yes | yes | yes | + | | remote-option4-global-set) | | | | | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | option-def | yes (via | yes | n/a | n/a | n/a | + | | remote-option-def4-set) | | | | | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | rebind-timer | yes | n/a | yes | yes | n/a | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | renew-timer | yes | n/a | yes | yes | n/a | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | server-hostname | yes | yes | yes | yes | n/a | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | valid-lifetime | yes | yes | yes | yes | n/a | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | relay | n/a | n/a | yes | yes | n/a | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | require-client-classes | no | n/a | yes | yes | yes | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | reservation-mode | yes | n/a | yes | yes | n/a | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | reservations-global | yes | n/a | yes | yes | n/a | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | reservations-in-subnet | yes | n/a | yes | yes | n/a | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | reservations-out-of-pool | yes | n/a | yes | yes | n/a | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | t1-percent | yes | n/a | yes | yes | n/a | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + | t2-percent | yes | n/a | yes | yes | n/a | + +-----------------------------+----------------------------+--------------+-------------+-------------+-------------+ + +- ``yes`` - indicates that the parameter is supported at the given + level of the hierarchy and can be configured via the Configuration Backend. + +- ``no`` - indicates that a parameter is supported at the given level + of the hierarchy but cannot be configured via the Configuration Backend. + +- ``n/a`` - indicates that a given parameter is not applicable + at the particular level of the hierarchy or that the + server does not support the parameter at that level. + +Some scalar parameters contained by top level global maps are supported by the Configuration Backend. + +.. table:: List of DHCPv4 map parameters supported by the Configuration Backend + + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | Parameter name (flat naming format) | Global map | Parameter name | + +==================================================================+==============================+==================================+ + | compatibility.ignore-dhcp-server-identifier | compatibility | ignore-dhcp-server-identifier | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | compatibility.ignore-rai-link-selection | compatibility | ignore-rai-link-selection | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | compatibility.lenient-option-parsing | compatibility | lenient-option-parsing | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | compatibility.exclude-first-last-24 | compatibility | exclude-first-last-24 | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | control-socket.socket-name | control-socket | socket-name | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | control-socket.socket-type | control-socket | socket-type | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | dhcp-ddns.enable-updates | dhcp-ddns | enable-updates | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | dhcp-ddns.max-queue-size | dhcp-ddns | max-queue-size | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | dhcp-ddns.ncr-format | dhcp-ddns | ncr-format | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | dhcp-ddns.ncr-protocol | dhcp-ddns | ncr-protocol | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | dhcp-ddns.sender-ip | dhcp-ddns | sender-ip | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | dhcp-ddns.sender-port | dhcp-ddns | sender-port | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | dhcp-ddns.server-ip | dhcp-ddns | server-ip | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | dhcp-ddns.server-port | dhcp-ddns | server-port | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | dhcp-ddns.generated-prefix | dhcp-ddns | generated-prefix | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | dhcp-ddns.hostname-char-replacement | dhcp-ddns | hostname-char-replacement | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | dhcp-ddns.hostname-char-set | dhcp-ddns | hostname-char-set | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | dhcp-ddns.override-client-update | dhcp-ddns | override-client-update | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | dhcp-ddns.override-no-update | dhcp-ddns | override-no-update | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | dhcp-ddns.qualifying-suffix | dhcp-ddns | qualifying-suffix | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | dhcp-ddns.replace-client-name | dhcp-ddns | replace-client-name | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | expired-leases-processing.flush-reclaimed-timer-wait-time | expired-leases-processing | flush-reclaimed-timer-wait-time | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | expired-leases-processing.hold-reclaimed-time | expired-leases-processing | hold-reclaimed-time | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | expired-leases-processing.max-reclaim-leases | expired-leases-processing | max-reclaim-leases | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | expired-leases-processing.max-reclaim-time | expired-leases-processing | max-reclaim-time | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | expired-leases-processing.reclaim-timer-wait-time | expired-leases-processing | reclaim-timer-wait-time | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | expired-leases-processing.unwarned-reclaim-cycles | expired-leases-processing | unwarned-reclaim-cycles | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | multi-threading.enable-multi-threading | multi-threading | enable-multi-threading | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | multi-threading.thread-pool-size | multi-threading | thread-pool-size | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | multi-threading.packet-queue-size | multi-threading | packet-queue-size | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | sanity-checks.lease-checks | sanity-checks | lease-checks | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | sanity-checks.extended-info-checks | sanity-checks | extended-info-checks | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | dhcp-queue-control.enable-queue | dhcp-queue-control | enable-queue | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | dhcp-queue-control.queue-type | dhcp-queue-control | queue-type | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | dhcp-queue-control.capacity | dhcp-queue-control | capacity | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + +.. _dhcp4-cb-json: + +Enabling the Configuration Backend +---------------------------------- + +Consider the following configuration snippet, which uses a MySQL configuration +database: + +.. code-block:: json + + { + "Dhcp4": { + "server-tag": "my DHCPv4 server", + "config-control": { + "config-databases": [ + { + "type": "mysql", + "name": "kea", + "user": "kea", + "password": "kea", + "host": "192.0.2.1", + "port": 3302 + } + ], + "config-fetch-wait-time": 20 + }, + "hooks-libraries": [ + { + "library": "/usr/local/lib/kea/hooks/libdhcp_mysql_cb.so" + }, { + "library": "/usr/local/lib/kea/hooks/libdhcp_cb_cmds.so" + } + ] + } + } + +The ``config-control`` map contains two parameters. ``config-databases`` +is a list that contains one element, which includes the database type, its location, +and the credentials to be used to connect to this database. (Note that +the parameters specified here correspond to the database specification +for the lease database backend and hosts database backend.) Currently +only one database connection can be specified on the +``config-databases`` list. The server connects to this database +during startup or reconfiguration, and fetches the configuration +available for this server from the database. This configuration is +merged into the configuration read from the configuration file. + +The following snippet illustrates the use of a PostgreSQL database: + +.. code-block:: json + + { + "Dhcp4": { + "server-tag": "my DHCPv4 server", + "config-control": { + "config-databases": [ + { + "type": "postgresql", + "name": "kea", + "user": "kea", + "password": "kea", + "host": "192.0.2.1", + "port": 5432 + } + ], + "config-fetch-wait-time": 20 + }, + "hooks-libraries": [ + { + "library": "/usr/local/lib/kea/hooks/libdhcp_pgsql_cb.so" + }, { + "library": "/usr/local/lib/kea/hooks/libdhcp_cb_cmds.so" + } + ] + } + } + +.. note:: + + Whenever there is a conflict between the parameters specified in the + configuration file and the database, the parameters from the database + take precedence. We strongly recommend avoiding the duplication of + parameters in the file and the database, but this recommendation is + not enforced by the Kea servers. In particular, if the subnets' + configuration is sourced from the database, we recommend that all + subnets be specified in the database and that no subnets be specified in + the configuration file. It is possible to specify the subnets in both + places, but the subnets in the + configuration file with overlapping IDs and/or prefixes with the + subnets from the database will be superseded by those from the + database. + +Once the Kea server is configured, it starts periodically polling +the database for configuration changes. The polling frequency is +controlled by the ``config-fetch-wait-time`` parameter, expressed +in seconds; it is the period between the time when the server +completed its last poll (and possibly the local configuration update) and +the time when it will begin polling again. In the example above, this period +is set to 20 seconds. This means that after adding a new configuration +into the database (e.g. adding a new subnet), it will take up to 20 seconds +(plus the time needed to fetch and apply the new configuration) before +the server starts using this subnet. The lower the +``config-fetch-wait-time`` value, the shorter the time for the server to +react to incremental configuration updates in the database. On the +other hand, polling the database too frequently may impact the DHCP +server's performance, because the server needs to make at least one query +to the database to discover any pending configuration updates. The +default value of ``config-fetch-wait-time`` is 30 seconds. + +The :isccmd:`config-backend-pull` command can be used to force the server to +immediately poll any configuration changes from the database and avoid +waiting for the next fetch cycle. + +In the configuration examples above, two hook libraries are loaded. The first +is a library which implements the Configuration Backend for a specific database +type: :ischooklib:`libdhcp_mysql_cb.so` provides support for MySQL and :ischooklib:`libdhcp_pgsql_cb.so` +provides support for PostgreSQL. The library loaded must match the database +``type`` specified within the ``config-control`` parameter or an will error be +logged when the server attempts to load its configuration and the load will +fail. + +The second hook library, :ischooklib:`libdhcp_cb_cmds.so`, is optional. It should +be loaded when the Kea server instance is to be used to manage the +configuration in the database. See the :ref:`hooks-cb-cmds` section for +details. This hook library is only available to ISC +customers with a paid support contract. + +.. _dhcp4-compatibility: + +Kea DHCPv4 Compatibility Configuration Parameters +================================================= + +ISC's intention is for Kea to follow the RFC documents to promote better standards +compliance. However, many buggy DHCP implementations already exist that cannot be +easily fixed or upgraded. Therefore, Kea provides an easy-to-use compatibility +mode for broken or non-compliant clients. For that purpose, the compatibility option must be +enabled to permit uncommon practices: + +.. code-block:: json + + { + "Dhcp4": { + "compatibility": { + } + } + } + + +Lenient Option Parsing +---------------------- + +By default, tuple fields defined in custom options are parsed as a set of +length-value pairs. + +With ``"lenient-option-parsing": true``, if a length ever exceeds the rest of +the option's buffer, previous versions of Kea returned a log message ``unable to +parse the opaque data tuple, the buffer length is x, but the tuple length is y`` +with ``x < y``; this no longer occurs. Instead, the value is considered to be the rest of the buffer, +or in terms of the log message above, the tuple length ``y`` becomes ``x``. + +.. code-block:: json + + { + "Dhcp4": { + "compatibility": { + "lenient-option-parsing": true + } + } + } + +Ignore DHCP Server Identifier +----------------------------- + +With ``"ignore-dhcp-server-identifier": true``, the server does not check the +address in the DHCP Server Identifier option, i.e. whether a query is sent +to this server or another one (and in the second case dropping the query). + +.. code-block:: json + + { + "Dhcp4": { + "compatibility": { + "ignore-dhcp-server-identifier": true + } + } + } + + +Ignore RAI Link Selection +------------------------- + +With ``"ignore-rai-link-selection": true``, Relay Agent Information Link +Selection sub-option data is not used for subnet selection. In this case, +normal logic drives the subnet selection, instead of attempting to use the subnet specified +by the sub-option. This option is not RFC-compliant and is set to ``false`` by +default. Setting this option to ``true`` can help with subnet selection in +certain scenarios; for example, when DHCP relays do not allow the administrator to +specify which sub-options are included in the Relay Agent Information option, +and include incorrect Link Selection information. + +.. code-block:: json + + { + "Dhcp4": { + "compatibility": { + "ignore-rai-link-selection": true + } + } + } + +Exclude First Last Addresses in /24 Subnets or Larger +----------------------------------------------------- + +The ``exclude-first-last-24`` compatibility flag is described in +:ref:`dhcp4-address-config` (when true .0 and .255 addresses are excluded +from subnets with prefix length less than or equal to 24). + +.. _dhcp4_allocation_strategies: + +Address Allocation Strategies in DHCPv4 +======================================= + +A DHCP server follows a complicated algorithm to select an IPv4 address for a client. +It prefers assigning specific addresses requested by the client and the addresses for +which the client has reservations. + +If the client requests no particular address and +has no reservations, or other clients are already using any requested addresses, the server must +find another available address within the configured pools. A server function called +an "allocator" is responsible in Kea for finding an available address in such a case. + +The Kea DHCPv4 server provides configuration parameters to select different allocators +at the global, shared-network, and subnet levels. +Consider the following example: + +.. code-block:: json + + { + "Dhcp4": { + "allocator": "random", + "subnet4": [ + { + "id": 1, + "subnet": "10.0.0.0/8", + "allocator": "iterative" + }, + { + "id": 2, + "subnet": "192.0.2.0/24" + } + ] + } + } + +This allocator overrides the default iterative allocation strategy at the global level and +selects the random allocation instead. The random allocation will be used +for the subnet with ID 2, while the iterative allocation will be used for the subnet +with ID 1. + +The following sections describe the supported allocators and their +recommended uses. + +Allocators Comparison +--------------------- + +In the table below, we briefly compare the supported allocators. The +detailed allocators' descriptions are in later sections. + +.. table:: Comparison of the lease allocators supported by Kea DHCPv4 + + +------------------+-----------------------------+------------------------------+-----------------------+------------------------------+----------------+ + | Allocator | Low Utilization Performance | High Utilization Performance | Lease Randomization | Startup/Configuration | Memory Usage | + +==================+=============================+==============================+=======================+==============================+================+ + | Iterative | very high | low | no | very fast | low | + +------------------+-----------------------------+------------------------------+-----------------------+------------------------------+----------------+ + | Random | high | low | yes | very fast | high (varying) | + +------------------+-----------------------------+------------------------------+-----------------------+------------------------------+----------------+ + | Free Lease Queue | high | high | yes | slow (depends on pool sizes) | high (varying) | + +------------------+-----------------------------+------------------------------+-----------------------+------------------------------+----------------+ + + +Iterative Allocator +------------------- +This is the default allocator used by the Kea DHCPv4 server. It remembers the +last offered address and offers this address, increased by one, to the next client. +For example, it may offer addresses in this order: ``192.0.2.10``, ``192.0.2.11``, +``192.0.2.12``, and so on. The time to find and offer the next address is very +short; thus, this is the most performant allocator when pool utilization +is low and there is a high probability that the next address is available. + +The iterative allocation underperforms when multiple DHCP servers share a lease +database or are connected to a cluster. The servers tend to offer and allocate +the same blocks of addresses to different clients independently, which causes many +allocation conflicts between the servers and retransmissions by clients. A random +allocation addresses this issue by dispersing the allocation order. + +Random Allocator +---------------- + +The random allocator uses a uniform randomization function to select offered +addresses from subnet pools. It is suitable in deployments where multiple servers +are connected to a shared +database or a database cluster. By dispersing the offered addresses, the servers +minimize the risk of allocating the same address to two different clients at +the same or nearly the same time. In addition, it improves the server's resilience against +attacks based on allocation predictability. + +The random allocator is, however, slightly slower than the iterative allocator. +Moreover, it increases the server's memory consumption because it must remember +randomized addresses to avoid offering them repeatedly. Memory consumption grows +with the number of offered addresses; in other words, larger pools and more +clients increase memory consumption by random allocation. + +The following configuration snippet shows how to select the random allocator +for a subnet: + +.. code-block:: json + + { + "Dhcp4": { + "allocator": "random", + "subnet4": [ + { + "id": 1, + "subnet": "10.0.0.0/8", + "allocator": "random" + } + ] + } + } + +Free Lease Queue Allocator +-------------------------- + +This is a sophisticated allocator whose use should be considered in subnets +with highly utilized address pools. In such cases, it can take a considerable +amount of time for the iterative or random allocator to find an available +address, because they must repeatedly check whether there is a valid lease for +an address they will offer. The number of checks can be as high as the number +of addresses in the subnet when the subnet pools are exhausted, which can have a +direct negative impact on the DHCP response time for each request. + +The Free Lease Queue (FLQ) allocator tracks lease allocations and de-allocations +and maintains a running list of available addresses for each address pool. +It allows an available lease to be selected within a constant time, regardless of +the subnet pools' utilization. The allocator continuously updates the list of +free leases by removing any allocated leases and adding released or +reclaimed ones. + +The following configuration snippet shows how to select the FLQ allocator +for a subnet: + +.. code-block:: json + + { + "Dhcp4": { + "subnet4": [ + { + "id": 1, + "subnet": "192.0.2.0/24", + "allocator": "flq" + } + ] + } + } + + +There are several considerations that the administrator should take into account +before using this allocator. The FLQ allocator can heavily impact the server's +startup and reconfiguration time, because the allocator has to populate the +list of free leases for each subnet where it is used. These delays can be +observed both during the configuration reload and when the subnets are +created using :ischooklib:`libdhcp_subnet_cmds.so`. The allocator increases the +memory consumption to hold the list of free leases, proportional +to the total size of the address pools for which this allocator is used. +Finally, lease reclamation must be enabled with a low value of the +``reclaim-timer-wait-time`` parameter, to ensure that the server frequently +collects expired leases and makes them available for allocation via the +free lease queue. Expired leases are not considered free by +the allocator until they are reclaimed by the server. See +:ref:`lease-reclamation` for more details about the lease reclamation process. + +We recommend that the FLQ allocator be selected +only after careful consideration. For example, using it for a subnet with a +``/8`` pool may delay the server's startup by 15 seconds or more. On the +other hand, the startup delay and the memory consumption increase should +be acceptable for subnets with a ``/16`` pool or smaller. We also recommend +specifying another allocator type in the global configuration settings +and overriding this selection at the subnet or shared-network level, to use +the FLQ allocator only for selected subnets. That way, when a new subnet is +added without an allocator specification, the global setting is used, thus +avoiding unnecessary impact on the server's startup time. + +Like the random allocator, the FLQ allocator offers leases in +random order, which makes it suitable for use with a shared lease database. diff --git a/doc/sphinx/arm/dhcp6-srv.rst b/doc/sphinx/arm/dhcp6-srv.rst new file mode 100644 index 0000000..f2f64de --- /dev/null +++ b/doc/sphinx/arm/dhcp6-srv.rst @@ -0,0 +1,8184 @@ +.. _dhcp6: + +***************** +The DHCPv6 Server +***************** + +.. _dhcp6-start-stop: + +Starting and Stopping the DHCPv6 Server +======================================= + +It is recommended that the Kea DHCPv6 server be started and stopped +using :iscman:`keactrl` (described in :ref:`keactrl`); however, it is also +possible to run the server directly via the :iscman:`kea-dhcp6` command, which accepts +the following command-line switches: + +- ``-c file`` - specifies the configuration file. This is the only + mandatory switch. + +- ``-d`` - specifies whether the server logging should be switched to + debug/verbose mode. In verbose mode, the logging severity and debuglevel + specified in the configuration file are ignored; "debug" severity + and the maximum debuglevel (99) are assumed. The flag is convenient + for temporarily switching the server into maximum verbosity, e.g. + when debugging. + +- ``-p server-port`` - specifies the local UDP port on which the server + listens. This is only useful during testing, as a DHCPv6 server + listening on ports other than the standard ones is not able to + handle regular DHCPv6 queries. + +- ``-P client-port`` - specifies the remote UDP port to which the + server sends all responses. This is only useful during testing, + as a DHCPv6 server sending responses to ports other than the standard + ones is not able to handle regular DHCPv6 queries. + +- ``-t file`` - specifies a configuration file to be tested. :iscman:`kea-dhcp6` + loads it, checks it, and exits. During the test, log messages are + printed to standard output and error messages to standard error. The + result of the test is reported through the exit code (0 = + configuration looks OK, 1 = error encountered). The check is not + comprehensive; certain checks are possible only when running the + server. + +- ``-T file`` - specifies a configuration file to be tested. :iscman:`kea-dhcp6` + loads it, checks it, and exits. It performs extra checks beyond what ``-t`` + offers, such as establishing database connections (for the lease backend, + host reservations backend, configuration backend, and forensic logging + backend), loading hook libraries, parsing hook-library configurations, etc. + It does not open UNIX or TCP/UDP sockets, nor does it open or rotate + files, as any of these actions could interfere with a running process on the + same machine. + +- ``-v`` - displays the Kea version and exits. + +- ``-V`` - displays the Kea extended version with additional parameters + and exits. The listing includes the versions of the libraries + dynamically linked to Kea. + +- ``-W`` - displays the Kea configuration report and exits. The report + is a copy of the ``config.report`` file produced by ``./configure``; + it is embedded in the executable binary. + + The contents of the ``config.report`` file may also be accessed by examining + certain libraries in the installation tree or in the source tree. + + .. code-block:: shell + + # from installation using libkea-process.so + $ strings ${prefix}/lib/libkea-process.so | sed -n 's/;;;; //p' + + # from sources using libkea-process.so + $ strings src/lib/process/.libs/libkea-process.so | sed -n 's/;;;; //p' + + # from sources using libkea-process.a + $ strings src/lib/process/.libs/libkea-process.a | sed -n 's/;;;; //p' + + # from sources using libcfgrpt.a + $ strings src/lib/process/cfgrpt/.libs/libcfgrpt.a | sed -n 's/;;;; //p' + +On startup, the server detects available network interfaces and +attempts to open UDP sockets on all interfaces listed in the +configuration file. Since the DHCPv6 server opens privileged ports, it +requires root access; this daemon must be run as root. + +During startup, the server attempts to create a PID file of the +form: ``[runstatedir]/kea/[conf name].kea-dhcp6.pid``, where: + +- ``runstatedir``: The value as passed into the build configure + script; it defaults to ``/usr/local/var/run``. Note that this value may be + overridden at runtime by setting the environment variable + ``KEA_PIDFILE_DIR``, although this is intended primarily for testing + purposes. + +- ``conf name``: The configuration file name used to start the server, + minus all preceding paths and the file extension. For example, given + a pathname of ``/usr/local/etc/kea/myconf.txt``, the portion used would + be ``myconf``. + +If the file already exists and contains the PID of a live process, the +server issues a ``DHCP6_ALREADY_RUNNING`` log message and exits. It is +possible, though unlikely, that the file is a remnant of a system crash +and the process to which the PID belongs is unrelated to Kea. In such a +case, it would be necessary to manually delete the PID file. + +The server can be stopped using the ``kill`` command. When running in a +console, the server can also be shut down by pressing Ctrl-c. Kea detects +the key combination and shuts down gracefully. + +The reconfiguration of each Kea server is triggered by the SIGHUP signal. +When a server receives the SIGHUP signal it rereads its configuration file and, +if the new configuration is valid, uses the new configuration. +If the new configuration proves to be invalid, the server retains its +current configuration; however, in some cases a fatal error message is logged +indicating that the server is no longer providing any service: a working +configuration must be loaded as soon as possible. + +.. _dhcp6-configuration: + +DHCPv6 Server Configuration +=========================== + +Introduction +------------ + +This section explains how to configure the Kea DHCPv6 server using a +configuration file. + +Before DHCPv6 is started, its configuration file must +be created. The basic configuration is as follows: + +:: + + { + # DHCPv6 configuration starts on the next line + "Dhcp6": { + + # First we set up global values + "valid-lifetime": 4000, + "renew-timer": 1000, + "rebind-timer": 2000, + "preferred-lifetime": 3000, + + # Next we set up the interfaces to be used by the server. + "interfaces-config": { + "interfaces": [ "eth0" ] + }, + + # And we specify the type of lease database + "lease-database": { + "type": "memfile", + "persist": true, + "name": "/var/lib/kea/dhcp6.leases" + }, + + # Finally, we list the subnets from which we will be leasing addresses. + "subnet6": [ + { + "id": 1, + "subnet": "2001:db8:1::/64", + "pools": [ + { + "pool": "2001:db8:1::1-2001:db8:1::ffff" + } + ] + } + ] + # DHCPv6 configuration ends with the next line + } + + } + +The following paragraphs provide a brief overview of the parameters in +the above example, along with their format. Subsequent sections of this +chapter go into much greater detail for these and other parameters. + +The lines starting with a hash (#) are comments and are ignored by the +server; they do not impact its operation in any way. + +The configuration starts in the first line with the initial opening +curly bracket (or brace). Each configuration must contain an object +specifying the configuration of the Kea module using it. In the example +above, this object is called ``Dhcp6``. + +The ``Dhcp6`` configuration starts with the ``"Dhcp6": {`` line and ends +with the corresponding closing brace (in the above example, the brace +after the last comment). Everything defined between those lines is +considered to be the ``Dhcp6`` configuration. + +In general, the order in which those parameters appear does not +matter, but there are two caveats. The first one is that the +configuration file must be well-formed JSON, meaning that the +parameters for any given scope must be separated by a comma, and there +must not be a comma after the last parameter. When reordering a +configuration file, moving a parameter to or from the +last position in a given scope may also require moving the comma. The +second caveat is that it is uncommon — although legal JSON — to repeat +the same parameter multiple times. If that happens, the last occurrence +of a given parameter in a given scope is used, while all previous +instances are ignored. This is unlikely to cause any confusion as there +are no real-life reasons to keep multiple copies of the same parameter +in the configuration file. + +The first few DHCPv6 configuration elements +define some global parameters. ``valid-lifetime`` defines how long the +addresses (leases) given out by the server are valid; the default +is for a client to be allowed to use a given address for 4000 +seconds. (Note that integer numbers are specified as is, without any +quotes around them.) The address will become deprecated in 3000 seconds, +i.e. clients are allowed to keep old connections, but cannot use this +address to create new connections. ``renew-timer`` and +``rebind-timer`` are values (also in seconds) that define T1 and T2 timers, which govern +when the client begins the renewal and rebind procedures. + +The ``interfaces-config`` map specifies the network interfaces on which the +server should listen to DHCP messages. The ``interfaces`` parameter specifies +a list of network interfaces on which the server should listen. Lists are +opened and closed with square brackets, with elements separated by commas. To +listen on two interfaces, the ``interfaces-config`` element should look like +this: + +:: + + { + "interfaces-config": { + "interfaces": [ "eth0", "eth1" ] + }, + ... + } + +The next lines define the lease database, the place where the +server stores its lease information. This particular example tells the +server to use memfile, which is the simplest and fastest database +backend. It uses an in-memory database and stores leases on disk in a +CSV (comma-separated values) file. This is a very simple configuration example; +usually the lease database configuration is more extensive and contains +additional parameters. Note that ``lease-database`` is an object and opens up a +new scope, using an opening brace. Its parameters (just one in this example: +``type``) follow. If there were more than one, they would be separated +by commas. This scope is closed with a closing brace. As more parameters +for the ``Dhcp6`` definition follow, a trailing comma is present. + +Finally, we need to define a list of IPv6 subnets. This is the most +important DHCPv6 configuration structure, as the server uses that +information to process clients' requests. It defines all subnets from +which the server is expected to receive DHCP requests. The subnets are +specified with the ``subnet6`` parameter. It is a list, so it starts and +ends with square brackets. Each subnet definition in the list has +several attributes associated with it, so it is a structure and is +opened and closed with braces. At a minimum, a subnet definition must +have at least two parameters: ``subnet``, which defines the whole +subnet; and ``pools``, which is a list of dynamically allocated pools +that are governed by the DHCP server. + +The example contains a single subnet. If more than one were defined, +additional elements in the ``subnet6`` parameter would be specified and +separated by commas. For example, to define two subnets, the following +syntax would be used: + +:: + + { + "subnet6": [ + { + "id": 1, + "pools": [ { "pool": "2001:db8:1::/112" } ], + "subnet": "2001:db8:1::/64" + }, + { + "id": 2, + "pools": [ { "pool": "2001:db8:2::1-2001:db8:2::ffff" } ], + "subnet": "2001:db8:2::/64" + } + ], + ... + } + +Note that indentation is optional and is used for aesthetic purposes +only. In some cases it may be preferable to use more compact notation. + +After all the parameters have been specified, there are two contexts open: +``global`` and ``Dhcp6``; thus, two closing curly brackets must be used to close +them. + +Lease Storage +------------- + +All leases issued by the server are stored in the lease database. +There are three database backends available: memfile +(the default), MySQL, PostgreSQL. + +Memfile - Basic Storage for Leases +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The server is able to store lease data in different repositories. Larger +deployments may elect to store leases in a database; +:ref:`database-configuration6` describes this option. In +typical smaller deployments, though, the server stores lease +information in a CSV file rather than a database. As well as requiring +less administration, an advantage of using a file for storage is that it +eliminates a dependency on third-party database software. + +The configuration of the memfile backend is controlled through +the ``Dhcp6``/``lease-database`` parameters. The ``type`` parameter is mandatory +and specifies which storage for leases the server should use, through +the ``"memfile"`` value. The following list gives additional optional parameters +that can be used to configure the memfile backend. + +- ``persist``: controls whether the new leases and updates to existing + leases are written to the file. It is strongly recommended that the + value of this parameter be set to ``true`` at all times during the + server's normal operation. Not writing leases to disk means that if a + server is restarted (e.g. after a power failure), it will not know + which addresses have been assigned. As a result, it may assign new clients + addresses that are already in use. The value of + ``false`` is mostly useful for performance-testing purposes. The + default value of the ``persist`` parameter is ``true``, which enables + writing lease updates to the lease file. + +- ``name``: specifies an absolute location of the lease file in which + new leases and lease updates are recorded. The default value for + this parameter is ``"[kea-install-dir]/var/lib/kea/kea-leases6.csv"``. + +- ``lfc-interval``: specifies the interval, in seconds, at which the + server will perform a lease file cleanup (LFC). This removes + redundant (historical) information from the lease file and + effectively reduces the lease file size. The cleanup process is + described in more detail later in this section. The default + value of the ``lfc-interval`` is ``3600``. A value of ``0`` disables the LFC. + +- ``max-row-errors``: specifies the number of row errors before the server + stops attempting to load a lease file. When the server loads a lease file, it is processed + row by row, each row containing a single lease. If a row is flawed and + cannot be processed correctly the server logs it, discards the row, + and goes on to the next row. This parameter can be used to set a limit on + the number of such discards that can occur, after which the server + abandons the effort and exits. The default value of ``0`` disables the limit + and allows the server to process the entire file, regardless of how many + rows are discarded. + +An example configuration of the memfile backend is presented below: + +:: + + "Dhcp6": { + "lease-database": { + "type": "memfile", + "persist": true, + "name": "/tmp/kea-leases6.csv", + "lfc-interval": 1800, + "max-row-errors": 100 + } + } + +This configuration selects ``/tmp/kea-leases6.csv`` as the storage file +for lease information and enables persistence (writing lease updates to +this file). It also configures the backend to perform a periodic cleanup +of the lease file every 1800 seconds (30 minutes) and sets the maximum number of +row errors to 100. + +Why Is Lease File Cleanup Necessary? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +It is important to know how the lease file contents are organized to +understand why the periodic lease file cleanup is needed. Every time the +server updates a lease or creates a new lease for a client, the new +lease information must be recorded in the lease file. For performance +reasons, the server does not update the existing client's lease in the +file, as this would potentially require rewriting the entire file. +Instead, it simply appends the new lease information to the end of the +file; the previous lease entries for the client are not removed. When +the server loads leases from the lease file, e.g. at server startup, +it assumes that the latest lease entry for the client is the valid one. +Previous entries are discarded, meaning that the server can +reconstruct accurate information about the leases even though there +may be many lease entries for each client. However, storing many entries +for each client results in a bloated lease file and impairs the +performance of the server's startup and reconfiguration, as it needs to +process a larger number of lease entries. + +Lease file cleanup (LFC) removes all previous entries for each client +and leaves only the latest ones. The interval at which the cleanup is +performed is configurable, and it should be selected according to the +frequency of lease renewals initiated by the clients. The more frequent +the renewals, the smaller the value of ``lfc-interval`` should be. Note, +however, that the LFC takes time and thus it is possible (although +unlikely) that, if the ``lfc-interval`` is too short, a new cleanup may +be started while the previous one is still running. The server would +recover from this by skipping the new cleanup when it detected that the +previous cleanup was still in progress, but it implies that the actual +cleanups will be triggered more rarely than the configured interval. Moreover, +triggering a new cleanup adds overhead to the server, which is not +able to respond to new requests for a short period of time when the new +cleanup process is spawned. Therefore, it is recommended that the +``lfc-interval`` value be selected in a way that allows the LFC +to complete the cleanup before a new cleanup is triggered. + +Lease file cleanup is performed by a separate process (in the +background) to avoid a performance impact on the server process. To +avoid conflicts between two processes using the same lease +files, the LFC process starts with Kea opening a new lease file; the +actual LFC process operates on the lease file that is no longer used by +the server. There are also other files created as a side effect of the +lease file cleanup. The detailed description of the LFC process is located later +in this Kea Administrator's Reference Manual: :ref:`kea-lfc`. + +.. _database-configuration6: + +Lease Database Configuration +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + + Lease database access information must be configured for the DHCPv6 + server, even if it has already been configured for the DHCPv4 server. + The servers store their information independently, so each server can + use a separate database or both servers can use the same database. + +.. note:: + + Kea requires the database timezone to match the system timezone. + For more details, see :ref:`mysql-database-create` and + :ref:`pgsql-database-create`. + +Lease database configuration is controlled through the +``Dhcp6``/``lease-database`` parameters. The database type must be set to +``memfile``, ``mysql`` or ``postgresql``, e.g.: + +:: + + "Dhcp6": { "lease-database": { "type": "mysql", ... }, ... } + +Next, the name of the database to hold the leases must be set; this is +the name used when the database was created (see +:ref:`mysql-database-create` or :ref:`pgsql-database-create`). + +For MySQL or PostgreSQL: + +:: + + "Dhcp6": { "lease-database": { "name": "database-name" , ... }, ... } + +If the database is located on a different system from the DHCPv6 server, +the database host name must also be specified: + +:: + + "Dhcp6": { "lease-database": { "host": "remote-host-name", ... }, ... } + +Normally, the database is on the same machine as the DHCPv6 server. +In this case, set the value to the empty string: + +:: + + "Dhcp6": { "lease-database": { "host" : "", ... }, ... } + +Should the database use a port other than the default, it may be +specified as well: + +:: + + "Dhcp6": { "lease-database": { "port" : 12345, ... }, ... } + +Should the database be located on a different system, the administrator may need to +specify a longer interval for the connection timeout: + +:: + + "Dhcp6": { "lease-database": { "connect-timeout" : timeout-in-seconds, ... }, ... } + +The default value of five seconds should be more than adequate for local +connections. If a timeout is given, though, it should be an integer +greater than zero. + +The maximum number of times the server automatically attempts to +reconnect to the lease database after connectivity has been lost may be +specified: + +:: + + "Dhcp6": { "lease-database": { "max-reconnect-tries" : number-of-tries, ... }, ... } + +If the server is unable to reconnect to the database after making the +maximum number of attempts, the server will exit. A value of 0 (the +default) disables automatic recovery and the server will exit +immediately upon detecting a loss of connectivity (MySQL and PostgreSQL +only). + +The number of milliseconds the server waits between attempts to +reconnect to the lease database after connectivity has been lost may +also be specified: + +:: + + "Dhcp6": { "lease-database": { "reconnect-wait-time" : number-of-milliseconds, ... }, ... } + +The default value for MySQL and PostgreSQL is 0, which disables automatic +recovery and causes the server to exit immediately upon detecting the +loss of connectivity. + +:: + + "Dhcp6": { "lease-database": { "on-fail" : "stop-retry-exit", ... }, ... } + +The possible values are: + +- ``stop-retry-exit`` - disables the DHCP service while trying to automatically + recover lost connections. Shuts down the server on failure after exhausting + ``max-reconnect-tries``. This is the default value for the lease backend, + the host backend, and the configuration backend. + +- ``serve-retry-exit`` - continues the DHCP service while trying to + automatically recover lost connections. Shuts down the server on failure + after exhausting ``max-reconnect-tries``. + +- ``serve-retry-continue`` - continues the DHCP service and does not shut down + the server even if the recovery fails. This is the default value for forensic + logging. + +.. note:: + + Automatic reconnection to database backends is configured individually per + backend; this allows users to tailor the recovery parameters to each backend + they use. We suggest that users enable it either for all backends or none, + so behavior is consistent. + + Losing connectivity to a backend for which reconnection is disabled results + (if configured) in the server shutting itself down. This includes cases when + the lease database backend and the hosts database backend are connected to + the same database instance. + + It is highly recommended not to change the ``stop-retry-exit`` default + setting for the lease manager, as it is critical for the connection to be + active while processing DHCP traffic. Change this only if the server is used + exclusively as a configuration tool. + +:: + + "Dhcp6": { "lease-database": { "retry-on-startup" : true, ... }, ... } + +During server startup, the inability to connect to any of the configured +backends is considered fatal only if ``retry-on-startup`` is set to ``false`` +(the default). A fatal error is logged and the server exits, based on the idea +that the configuration should be valid at startup. Exiting to the operating +system allows nanny scripts to detect the problem. +If ``retry-on-startup`` is set to ``true``, the server will start reconnection +attempts even at server startup or on reconfigure events, and will honor the +action specified in the ``on-fail`` parameter. + +The host parameter is used by the MySQL and PostgreSQL backends. + +Finally, the credentials of the account under which the server will +access the database should be set: + +:: + + "Dhcp6": { + "lease-database": { + "user": "user-name", + "password": "password", + ... + }, + ... + } + +If there is no password to the account, set the password to the empty +string ``""``. (This is the default.) + +.. _tuning-database-timeouts6: + +Tuning Database Timeouts +~~~~~~~~~~~~~~~~~~~~~~~~ + +In rare cases, reading or writing to the database may hang. This can be +caused by a temporary network issue, or by misconfiguration of the proxy +server switching the connection between different database instances. +These situations are rare, but users have reported +that Kea sometimes hangs while performing database IO operations. +Setting appropriate timeout values can mitigate such issues. + +MySQL exposes two distinct connection options to configure the read and +write timeouts. Kea's corresponding ``read-timeout`` and ``write-timeout`` +configuration parameters specify the timeouts in seconds. For example: + +:: + + "Dhcp6": { "lease-database": { "read-timeout" : 10, "write-timeout": 20, ... }, ... } + + +Setting these parameters to 0 is equivalent to not specifying them, and +causes the Kea server to establish a connection to the database with the +MySQL defaults. In this case, Kea waits indefinitely for the completion of +the read and write operations. + +MySQL versions earlier than 5.6 do not support setting timeouts for +read and write operations. Moreover, the ``read-timeout`` and ``write-timeout`` +parameters can only be specified for the MySQL backend; setting them for +any other backend database type causes a configuration error. + +To set a timeout in seconds for PostgreSQL, use the ``tcp-user-timeout`` +parameter. For example: + +:: + + "Dhcp6": { "lease-database": { "tcp-user-timeout" : 10, ... }, ... } + + +Specifying this parameter for other backend types causes a configuration +error. + +.. note:: + + The timeouts described here are only effective for TCP connections. + Please note that the MySQL client library used by the Kea servers + typically connects to the database via a UNIX domain socket when the + ``host`` parameter is ``localhost``, but establishes a TCP connection + for ``127.0.0.1``. + + +.. _hosts6-storage: + +Hosts Storage +------------- + +Kea is also able to store information about host reservations in the +database. The hosts database configuration uses the same syntax as the +lease database. In fact, the Kea server opens independent connections for +each purpose, be it lease or hosts information, which gives +the most flexibility. Kea can keep leases and host reservations +separately, but can also point to the same database. Currently the +supported hosts database types are MySQL and PostgreSQL. + +The following configuration can be used to configure a +connection to MySQL: + +:: + + "Dhcp6": { + "hosts-database": { + "type": "mysql", + "name": "kea", + "user": "kea", + "password": "secret123", + "host": "localhost", + "port": 3306 + } + } + +Depending on the database configuration, many of the +parameters may be optional. + +Please note that usage of hosts storage is optional. A user can define +all host reservations in the configuration file, and that is the +recommended way if the number of reservations is small. However, when +the number of reservations grows, it is more convenient to use host +storage. Please note that both storage methods (the configuration file and +one of the supported databases) can be used together. If hosts are +defined in both places, the definitions from the configuration file are +checked first and external storage is checked later, if necessary. + +Host information can be placed in multiple stores. Operations +are performed on the stores in the order they are defined in the +configuration file, although this leads to a restriction in ordering +in the case of a host reservation addition; read-only stores must be +configured after a (required) read-write store, or the addition will +fail. + +.. note:: + + Kea requires the database timezone to match the system timezone. + For more details, see :ref:`mysql-database-create` and + :ref:`pgsql-database-create`. + +.. _hosts-databases-configuration6: + +DHCPv6 Hosts Database Configuration +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Hosts database configuration is controlled through the +``Dhcp6``/``hosts-database`` parameters. If enabled, the type of database must +be set to ``mysql`` or ``postgresql``. + +:: + + "Dhcp6": { "hosts-database": { "type": "mysql", ... }, ... } + +Next, the name of the database to hold the reservations must be set; +this is the name used when the lease database was created (see +:ref:`supported-databases` for instructions on how to set up the +desired database type): + +:: + + "Dhcp6": { "hosts-database": { "name": "database-name" , ... }, ... } + +If the database is located on a different system than the DHCPv6 server, +the database host name must also be specified: + +:: + + "Dhcp6": { "hosts-database": { "host": remote-host-name, ... }, ... } + +Normally, the database is on the same machine as the DHCPv6 server. +In this case, set the value to the empty string: + +:: + + "Dhcp6": { "hosts-database": { "host" : "", ... }, ... } + +Should the database use a port different than the default, it may be +specified as well: + +:: + + "Dhcp6": { "hosts-database": { "port" : 12345, ... }, ... } + +The maximum number of times the server automatically attempts to +reconnect to the host database after connectivity has been lost may be +specified: + +:: + + "Dhcp6": { "hosts-database": { "max-reconnect-tries" : number-of-tries, ... }, ... } + +If the server is unable to reconnect to the database after making the +maximum number of attempts, the server will exit. A value of 0 (the +default) disables automatic recovery and the server will exit +immediately upon detecting a loss of connectivity (MySQL and PostgreSQL +only). + +The number of milliseconds the server waits between attempts to +reconnect to the host database after connectivity has been lost may also +be specified: + +:: + + "Dhcp6": { "hosts-database": { "reconnect-wait-time" : number-of-milliseconds, ... }, ... } + +The default value for MySQL and PostgreSQL is 0, which disables automatic +recovery and causes the server to exit immediately upon detecting the +loss of connectivity. + +:: + + "Dhcp6": { "hosts-database": { "on-fail" : "stop-retry-exit", ... }, ... } + +The possible values are: + +- ``stop-retry-exit`` - disables the DHCP service while trying to automatically + recover lost connections. Shuts down the server on failure after exhausting + ``max-reconnect-tries``. This is the default value for MySQL and PostgreSQL. + +- ``serve-retry-exit`` - continues the DHCP service while trying to automatically + recover lost connections. Shuts down the server on failure after exhausting + ``max-reconnect-tries``. + +- ``serve-retry-continue`` - continues the DHCP service and does not shut down the + server even if the recovery fails. + +.. note:: + + Automatic reconnection to database backends is configured individually per + backend. This allows users to tailor the recovery parameters to each backend + they use. We suggest that users enable it either for all backends or none, + so behavior is consistent. + + Losing connectivity to a backend for which reconnection is disabled results + (if configured) in the server shutting itself down. This includes cases when + the lease database backend and the hosts database backend are connected to + the same database instance. + +:: + + "Dhcp6": { "hosts-database": { "retry-on-startup" : true, ... }, ... } + +During server startup, the inability to connect to any of the configured +backends is considered fatal only if ``retry-on-startup`` is set to ``false`` +(the default). A fatal error is logged and the server exits, based on the idea +that the configuration should be valid at startup. Exiting to the operating +system allows nanny scripts to detect the problem. +If ``retry-on-startup`` is set to ``true``, the server will start reconnection +attempts even at server startup or on reconfigure events, and will honor the +action specified in the ``on-fail`` parameter. +Database connection retries are not attempted on startup if the +:ischooklib:`libdhcp_limits.so` is loaded because the hook library requires a +valid connection to the database to check if JSON format is supported and to +recount class limits. + +Finally, the credentials of the account under which the server will +access the database should be set: + +:: + + "Dhcp6": { + "hosts-database": { + "user": "user-name", + "password": "password", + ... + }, + ... + } + +If there is no password to the account, set the password to the empty +string ``""``. (This is the default.) + +The multiple-storage extension uses a similar syntax; a configuration is +placed into a ``hosts-databases`` list instead of into a ``hosts-database`` +entry, as in: + +:: + + "Dhcp6": { "hosts-databases": [ { "type": "mysql", ... }, ... ], ... } + +If the same host is configured both in-file and in-database, Kea does not issue a warning, +as it would if both were specified in the same data source. +Instead, the host configured in-file has priority over the one configured +in-database. + +.. _read-only-database-configuration6: + +Using Read-Only Databases for Host Reservations with DHCPv6 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In some deployments, the user whose name is specified in the +database backend configuration may not have write privileges to the +database. This is often required by the policy within a given network to +secure the data from being unintentionally modified. In many cases +administrators have deployed inventory databases, which contain +substantially more information about the hosts than just the static +reservations assigned to them. The inventory database can be used to +create a view of a Kea hosts database and such a view is often +read-only. + +Kea host-database backends operate with an implicit configuration to +both read from and write to the database. If the user does not +have write access to the host database, the backend will fail to start +and the server will refuse to start (or reconfigure). However, if access +to a read-only host database is required for retrieving reservations +for clients and/or assigning specific addresses and options, it is +possible to explicitly configure Kea to start in "read-only" mode. This +is controlled by the ``readonly`` boolean parameter as follows: + +:: + + "Dhcp6": { "hosts-database": { "readonly": true, ... }, ... } + +Setting this parameter to ``false`` configures the database backend to +operate in "read-write" mode, which is also the default configuration if +the parameter is not specified. + +.. note:: + + The ``readonly`` parameter is only supported for MySQL and + PostgreSQL databases. + + +Tuning Database Timeouts for Hosts Storage +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +See :ref:`tuning-database-timeouts6`. + +.. _dhcp6-interface-configuration: + +Interface Configuration +----------------------- + +The DHCPv6 server must be configured to listen on specific network +interfaces. The simplest network interface configuration tells the +server to listen on all available interfaces: + +:: + + "Dhcp6": { + "interfaces-config": { + "interfaces": [ "*" ] + }, + ... + } + +The asterisk plays the role of a wildcard and means "listen on all +interfaces." However, it is usually a good idea to explicitly specify +interface names: + +:: + + "Dhcp6": { + "interfaces-config": { + "interfaces": [ "eth1", "eth3" ] + }, + ... + } + + +It is possible to use an interface wildcard (*) concurrently +with explicit interface names: + +:: + + "Dhcp6": { + "interfaces-config": { + "interfaces": [ "eth1", "eth3", "*" ] + }, + ... + } + +This format should only be used when it is +desired to temporarily override a list of interface names and listen on +all interfaces. + +As with the DHCPv4 server, binding to specific addresses and disabling +re-detection of interfaces are supported. But ``dhcp-socket-type`` is +not supported, because DHCPv6 uses only UDP/IPv6 sockets. The following example +shows how to disable interface detection: + +:: + + "Dhcp6": { + "interfaces-config": { + "interfaces": [ "eth1", "eth3" ], + "re-detect": false + }, + ... + } + + +The loopback interfaces (i.e. the ``lo`` or ``lo0`` interface) are not +configured by default, unless explicitly mentioned in the +configuration. Note that Kea requires a link-local address (which does +not exist on all systems) or a specified unicast address, as in: + +:: + + "Dhcp6": { + "interfaces-config": { + "interfaces": [ "enp0s2/2001:db8::1234:abcd" ] + }, + ... + } + +Kea binds the service sockets for each interface on startup. If another +process is already using a port, then Kea logs the message and suppresses an +error. DHCP service runs, but it is unavailable on some interfaces. + +The "service-sockets-require-all" option makes Kea require all sockets to +be successfully bound. If any opening fails, Kea interrupts the +initialization and exits with a non-zero status. (Default is false). + +:: + + "Dhcp6": { + "interfaces-config": { + "interfaces": [ "eth1", "eth3" ], + "service-sockets-require-all": true + }, + ... + } + +Sometimes, immediate interruption isn't a good choice. The port can be +unavailable only temporary. In this case, retrying the opening may resolve +the problem. Kea provides two options to specify the retrying: +``service-sockets-max-retries`` and ``service-sockets-retry-wait-time``. + +The first defines a maximal number of retries that Kea makes to open a socket. +The zero value (default) means that the Kea doesn't retry the process. + +The second defines a wait time (in milliseconds) between attempts. The default +value is 5000 (5 seconds). + +:: + + "Dhcp6": { + "interfaces-config": { + "interfaces": [ "eth1", "eth3" ], + "service-sockets-max-retries": 5, + "service-sockets-retry-wait-time": 5000 + }, + ... + } + +If "service-sockets-max-retries" is non-zero and "service-sockets-require-all" +is false, then Kea retries the opening (if needed) but does not fail if any +socket is still not opened. + +.. _ipv6-subnet-id: + +IPv6 Subnet Identifier +---------------------- + +The subnet identifier (subnet ID) is a unique number associated with a particular +subnet. In principle, it is used to associate clients' leases with their +respective subnets. The server configuration should contain unique and stable +identifiers for all subnets. When a subnet identifier is not specified for a +subnet, it is automatically assigned by the configuration mechanism. The identifiers +are assigned starting at 1 and are monotonically increased for each subsequent +subnet: 1, 2, 3, .... + +If there are multiple subnets configured with auto-generated identifiers +and one of them is removed, the subnet identifiers may be renumbered. +For example: if there are four subnets and the third is removed, the +last subnet will be assigned the identifier that the third subnet had +before removal. As a result, the leases stored in the lease database for +subnet 3 are now associated with subnet 4, something that may have +unexpected consequences. It is one of the reasons why auto-generated subnet +identifiers are deprecated starting from Kea version 2.4.0. + +.. note:: + + The auto-generation of the subnet identifiers will be removed in a future + release. Starting from Kea 2.4.0, a subnet without an ``id`` entry + or with the zero value raises a warning at the configuration time. + +.. note:: + + Subnet IDs must be greater than zero and less than 4294967295. + +The following configuration assigns the specified subnet identifier +to a newly configured subnet: + +:: + + "Dhcp6": { + "subnet6": [ + { + "subnet": "2001:db8:1::/64", + "id": 1024, + ... + } + ] + } + +This identifier will not change for this subnet unless the ``id`` +parameter is removed or set to 0. The value of 0 forces auto-generation +of the subnet identifier. + +.. _ipv6-subnet-prefix: + +IPv6 Subnet Prefix +------------------ + +The subnet prefix is the second way to identify a subnet. Kea can +accept non-canonical subnet addresses; for instance, +this configuration is accepted: + +:: + + "Dhcp6": { + "subnet6": [ + { + "subnet": "2001:db8:1::1/64", + ... + } + ] + } + +This works even if there is another subnet with the "2001:db8:1::/64" prefix; +only the textual form of subnets are compared to avoid duplicates. + +.. note:: + + Abuse of this feature can lead to incorrect subnet selection + (see :ref:`dhcp6-config-subnets`). + +.. _dhcp6-unicast: + +Unicast Traffic Support +----------------------- + +When the DHCPv6 server starts, by default it listens to the DHCP traffic +sent to multicast address ff02::1:2 on each interface that it is +configured to listen on (see :ref:`dhcp6-interface-configuration`). In some cases it is +useful to configure a server to handle incoming traffic sent to global +unicast addresses as well; the most common reason for this is to have +relays send their traffic to the server directly. To configure the +server to listen on a specific unicast address, add a slash (/) after the interface name, +followed by the global unicast +address on which the server should listen. The server will listen to this +address in addition to normal link-local binding and listening on the +ff02::1:2 address. The sample configuration below shows how to listen on +2001:db8::1 (a global address) configured on the ``eth1`` interface. + +:: + + "Dhcp6": { + "interfaces-config": { + "interfaces": [ "eth1/2001:db8::1" ] + }, + "option-data": [ + { + "name": "unicast", + "data": "2001:db8::1" + } ], + ... + } + + +This configuration will cause the server to listen on ``eth1`` on the +link-local address, the multicast group (ff02::1:2), and 2001:db8::1. + +Usually, unicast support is associated with a server unicast option which +allows clients to send unicast messages to the server. The example above +includes a server unicast option specification which causes the +client to send messages to the specified unicast address. + +It is possible to mix interface names, wildcards, and interface +names/addresses in the list of interfaces. It is not possible, however, +to specify more than one unicast address on a given interface. + +Care should be taken to specify proper unicast addresses, as the server +will attempt to bind to the addresses specified without any additional +checks. This approach was selected intentionally, to allow the software to +communicate over uncommon addresses if so desired. + +.. _dhcp6-address-config: + +Configuration of IPv6 Address Pools +----------------------------------- + +The main role of a DHCPv6 server is address assignment. For this, the +server must be configured with at least one subnet and one pool of +dynamic addresses to be managed. For example, assume that the server is +connected to a network segment that uses the 2001:db8:1::/64 prefix. The +administrator of that network decides that addresses from the range +2001:db8:1::1 to 2001:db8:1::ffff are going to be managed by the DHCPv6 +server. Such a configuration can be achieved in the following way: + +:: + + "Dhcp6": { + "subnet6": [ + { + "subnet": "2001:db8:1::/64", + "pools": [ + { + "pool": "2001:db8:1::1-2001:db8:1::ffff" + } + ], + ... + } + ] + } + +Note that ``subnet`` is defined as a simple string, but the ``pools`` +parameter is actually a list of pools; for this reason, the pool +definition is enclosed in square brackets, even though only one range of +addresses is specified. + +Each ``pool`` is a structure that contains the parameters that describe +a single pool. Currently there is only one parameter, ``pool``, which +gives the range of addresses in the pool. + +It is possible to define more than one pool in a subnet; continuing the +previous example, further assume that 2001:db8:1:0:5::/80 should also be +managed by the server. It could be written as 2001:db8:1:0:5:: to +2001:db8:1::5:ffff:ffff:ffff, but typing so many ``f`` characters is cumbersome. +The pool can be expressed more simply as 2001:db8:1:0:5::/80. Both formats are +supported by ``Dhcp6`` and they can be mixed in the pool list. For example, +the following pools could be defined: + +:: + + "Dhcp6": { + "subnet6": [ + { + "subnet": "2001:db8:1::/64", + "pools": [ + { "pool": "2001:db8:1::1-2001:db8:1::ffff" }, + { "pool": "2001:db8:1:05::/80" } + ], + ... + } + ] + } + +White space in pool definitions is ignored, so spaces before and after +the hyphen are optional. They can be used to improve readability. + +The number of pools is not limited, but for performance reasons it is +recommended to use as few as possible. + +The server may be configured to serve more than one subnet. To add a +second subnet, use a command similar to the following: + +:: + + "Dhcp6": { + "subnet6": [ + { + "id": 1, + "subnet": "2001:db8:1::/64", + "pools": [ + { "pool": "2001:db8:1::1-2001:db8:1::ffff" } + ] + }, + { + "id": 2, + "subnet": "2001:db8:2::/64", + "pools": [ + { "pool": "2001:db8:2::/64" } + ] + }, + ... + ] + } + +In this example, we allow the server to dynamically assign all addresses +available in the whole subnet. Although rather wasteful, it is certainly +a valid configuration to dedicate the whole /64 subnet for that purpose. +Note that the Kea server does not preallocate the leases, so there is no +danger in using gigantic address pools. + +When configuring a DHCPv6 server using prefix/length notation, please +pay attention to the boundary values. When specifying that the server +can use a given pool, it is also able to allocate the first +(typically a network address) address from that pool. For example, for +pool 2001:db8:2::/64, the 2001:db8:2:: address may be assigned as well. +To avoid this, use the ``min-max`` notation. + +.. _dhcp6-prefix-config: + +Subnet and Prefix Delegation Pools +---------------------------------- + +Subnets may also be configured to delegate prefixes, as defined in `RFC +8415 <https://tools.ietf.org/html/rfc8415>`__, section 6.3. A subnet may +have one or more prefix delegation pools. Each pool has a prefixed +address, which is specified as a prefix (``prefix``) and a prefix length +(``prefix-len``), as well as a delegated prefix length +(``delegated-len``). The delegated length must not be shorter than +(i.e. it must be numerically greater than or equal to) the prefix length. +If both the delegated and prefix lengths are equal, the server will be +able to delegate only one prefix. The delegated prefix does not have to +match the subnet prefix. + +Below is a sample subnet configuration which enables prefix delegation +for the subnet: + +:: + + "Dhcp6": { + "subnet6": [ + { + "id": 1, + "subnet": "2001:d8b:1::/64", + "pd-pools": [ + { + "prefix": "3000:1::", + "prefix-len": 64, + "delegated-len": 96 + } + ] + } + ], + ... + } + +.. _pd-exclude-option: + +Prefix Exclude Option +--------------------- + +For each delegated prefix, the delegating router may choose to exclude a +single prefix out of the delegated prefix as specified in `RFC +6603 <https://tools.ietf.org/html/rfc6603>`__. The requesting router must +not assign the excluded prefix to any of its downstream interfaces. +The excluded prefix is intended to be used on a link through which the delegating router +exchanges DHCPv6 messages with the requesting router. The configuration +example below demonstrates how to specify an excluded prefix within a +prefix pool definition. The excluded prefix +``2001:db8:1:8000:cafe:80::/72`` will be sent to a requesting router which +includes the Prefix Exclude option in the Option Request option (ORO), +and which is delegated a prefix from this pool. + +:: + + "Dhcp6": { + "subnet6": [ + { + "id": 1, + "subnet": "2001:db8:1::/48", + "pd-pools": [ + { + "prefix": "2001:db8:1:8000::", + "prefix-len": 56, + "delegated-len": 64, + "excluded-prefix": "2001:db8:1:8000:cafe:80::", + "excluded-prefix-len": 72 + } + ] + } + ] + } + +.. note:: + + Here are some liberties and limits to the values that subnets and pools can + take in Kea configurations that are out of the ordinary: + + +-------------------------------------------------------------------------------+---------+------------------------------------------------------------------------------------+ + | Kea configuration case | Allowed | Comment | + +===============================================================================+=========+====================================================================================+ + | Overlapping subnets | Yes | Administrator consideration needs to be given to how clients are matched to | + | | | these subnets. | + +-------------------------------------------------------------------------------+---------+------------------------------------------------------------------------------------+ + | Overlapping address pools in one subnet | No | Startup error: DHCP6_PARSER_FAIL | + +-------------------------------------------------------------------------------+---------+------------------------------------------------------------------------------------+ + | Overlapping address pools in different subnets | Yes | Specifying the same address pool in different subnets can be used as an equivalent | + | | | of the global address pool. In that case, the server can assign addresses from the | + | | | same range regardless of the client's subnet. If an address from such a pool is | + | | | assigned to a client in one subnet, the same address will be renewed for this | + | | | client if it moves to another subnet. Another client in a different subnet will | + | | | not be assigned an address already assigned to the client in any of the subnets. | + +-------------------------------------------------------------------------------+---------+------------------------------------------------------------------------------------+ + | Address pools that are outside the subnet they are configured under | No | Startup error: DHCP6_PARSER_FAIL | + +-------------------------------------------------------------------------------+---------+------------------------------------------------------------------------------------+ + | Overlapping prefix delegation pools in one subnet | No | Startup error: DHCP6_PARSER_FAIL | + +-------------------------------------------------------------------------------+---------+------------------------------------------------------------------------------------+ + | Overlapping prefix delegation pools in different subnets | Yes | Specifying the same prefix delegation pool in different subnets can be used as an | + | | | equivalent of the global pool. In that case, the server can delegate the same | + | | | prefixes regardless of the client's subnet. If a prefix from such a pool is | + | | | delegated to a client in one subnet, the same prefix will be renewed for this | + | | | client if it moves to another subnet. Another client in a different subnet will | + | | | not be delegated a prefix already delegated to the client in any of the subnets. | + +-------------------------------------------------------------------------------+---------+------------------------------------------------------------------------------------+ + | Prefix delegation pools not matching the subnet prefix | Yes | It is common in many deployments to configure the prefix delegation pools not | + | | | matching the subnet prefix, e.g. a prefix pool of 3000::/96 within the | + | | | 2001:db8:1::/64 subnet. Such use cases are supported by the Kea DHCPv6 server. | + +-------------------------------------------------------------------------------+---------+------------------------------------------------------------------------------------+ + +.. _dhcp6-std-options: + +Standard DHCPv6 Options +----------------------- + +One of the major features of the DHCPv6 server is the ability to provide +configuration options to clients. Although there are several options +that require special behavior, most options are sent by the server only +if the client explicitly requests them. The following example shows how +to configure the addresses of DNS servers, one of the most frequently used options. +Options specified in this way are considered global and apply to all configured subnets. + +:: + + "Dhcp6": { + "option-data": [ + { + "name": "dns-servers", + "code": 23, + "space": "dhcp6", + "csv-format": true, + "data": "2001:db8::cafe, 2001:db8::babe" + }, + ... + ] + } + +The ``option-data`` line creates a new entry in the option-data table. +This table contains information on all global options that the server is +supposed to configure in all subnets. The ``name`` line specifies the +option name. (For a complete list of currently supported names, see +:ref:`dhcp6-std-options-list`.) The next line specifies the +option code, which must match one of the values from that list. The line +beginning with ``space`` specifies the option space, which must always +be set to ``dhcp6`` as these are standard DHCPv6 options. For other name +spaces, including custom option spaces, see :ref:`dhcp6-option-spaces`. The following line +specifies the format in which the data will be entered; use of CSV +(comma-separated values) is recommended. Finally, the ``data`` line +gives the actual value to be sent to clients. The data parameter is specified as +normal text, with values separated by commas if more than one value is +allowed. + +Options can also be configured as hexadecimal values. If ``csv-format`` is +set to ``false``, the option data must be specified as a hexadecimal string. +The following commands configure the ``dns-servers`` option for all subnets +with the addresses 2001:db8:1::cafe and 2001:db8:1::babe. + +:: + + "Dhcp6": { + "option-data": [ + { + "name": "dns-servers", + "code": 23, + "space": "dhcp6", + "csv-format": false, + "data": "20 01 0D B8 00 01 00 00 00 00 00 00 00 00 CA FE \ + 20 01 0D B8 00 01 00 00 00 00 00 00 00 00 BA BE" + }, + ... + ] + } + +.. note:: + + The value for the setting of the ``data`` element is split across two + lines in this example for clarity; when entering the command, the + whole string should be entered on the same line. + +Kea supports the following formats when specifying hexadecimal data: + +- ``Delimited octets`` - one or more octets separated by either colons or + spaces (":" or " "). While each octet may contain one or two digits, + we strongly recommend always using two digits. Valid examples are + "ab:cd:ef" and "ab cd ef". + +- ``String of digits`` - a continuous string of hexadecimal digits with + or without a "0x" prefix. Valid examples are "0xabcdef" and "abcdef". + +Care should be taken to use proper encoding when using hexadecimal +format; Kea's ability to validate data correctness in hexadecimal is +limited. + +It is also possible to specify data for binary options as +a single-quoted text string within double quotes, as shown (note that +``csv-format`` must be set to ``false``): + +:: + + "Dhcp6": { + "option-data": [ + { + "name": "subscriber-id", + "code": 38, + "space": "dhcp6", + "csv-format": false, + "data": "'convert this text to binary'" + }, + ... + ], + ... + } + +Most of the parameters in the ``option-data`` structure are optional and +can be omitted in some circumstances, as discussed in :ref:`dhcp6-option-data-defaults`. +Only one of ``name`` or ``code`` +is required; it is not necessary to specify both. Space has a default value +of ``dhcp6``, so this can be skipped as well if a regular (not +encapsulated) DHCPv6 option is defined. Finally, ``csv-format`` defaults to ``true``, so it +too can be skipped, unless the option value is specified as +hexstring. Therefore, the above example can be simplified to: + +:: + + "Dhcp6": { + "option-data": [ + { + "name": "dns-servers", + "data": "2001:db8::cafe, 2001:db8::babe" + }, + ... + ] + } + + +Defined options are added to the response when the client requests them, +as well as any options required by a protocol. An administrator can also +specify that an option is always sent, even if a client did not +specifically request it. To enforce the addition of a particular option, +set the ``always-send`` flag to ``true``, as in: + +:: + + "Dhcp6": { + "option-data": [ + { + "name": "dns-servers", + "data": "2001:db8::cafe, 2001:db8::babe", + "always-send": true + }, + ... + ] + } + + +The effect is the same as if the client added the option code in the +Option Request Option (or its equivalent for vendor options), as in: + +:: + + "Dhcp6": { + "option-data": [ + { + "name": "dns-servers", + "data": "2001:db8::cafe, 2001:db8::babe", + "always-send": true + }, + ... + ], + "subnet6": [ + { + "subnet": "2001:db8:1::/64", + "option-data": [ + { + "name": "dns-servers", + "data": "2001:db8:1::cafe, 2001:db8:1::babe" + }, + ... + ], + ... + }, + ... + ], + ... + } + + +In the example above, the ``dns-servers`` option respects the global +``always-send`` flag and is always added to responses, but for subnet +``2001:db8:1::/64``, the value is taken from the subnet-level option data +specification. + +Contrary to ``always-send``, if the ``never-send`` flag is set to +``true`` for a particular option, the server does not add it to the response. +The effect is the same as if the client removed the option code in the +Option Request Option (or its equivalent for vendor options): + +:: + + "Dhcp6": { + "option-data": [ + { + "name": "dns-servers", + "data": "2001:db8::cafe, 2001:db8::babe" + }, + ... + ], + "subnet6": [ + { + "subnet": "2001:db8:1::/64", + "option-data": [ + { + "name": "dns-servers", + "never-send": true + }, + ... + ], + ... + }, + ... + ], + ... + } + +In the example above, the ``dns-server`` option is never added to responses +on subnet ``2001:db8:1::/64``. ``never-send`` has precedence over +``always-send``, so if both are ``true`` the option is not added. + +.. note:: + + The ``always-send`` and ``never-send`` flags are sticky, meaning + they do not follow the usual configuration inheritance rules. + Instead, if they are enabled at least once along the configuration + inheritance chain, they are applied - even if they are + disabled in other places which would normally receive a higher priority. + For instance, if one of the flags is enabled in the global scope, + but disabled at the subnet level, it is enabled, + disregarding the subnet-level setting. + +.. note:: + + The ``never-send`` flag is less powerful than :ischooklib:`libdhcp_flex_option.so`; + for instance, it has no effect on options managed by the server itself. + Both ``always-send`` and ``never-send`` have no effect on options + which cannot be requested, for instance from a custom space. + +It is possible to override options on a per-subnet basis. If clients +connected to most subnets are expected to get the same values of +a given option, administrators should use global options; it is possible to override +specific values for a small number of subnets. On the other hand, if +different values are used in each subnet, it does not make sense to specify +global option values; rather, only subnet-specific ones should be set. + +The following commands override the global ``dns-servers`` option for a +particular subnet, setting a single DNS server with address +2001:db8:1::3. + +:: + + "Dhcp6": { + "subnet6": [ + { + "option-data": [ + { + "name": "dns-servers", + "code": 23, + "space": "dhcp6", + "csv-format": true, + "data": "2001:db8:1::3" + }, + ... + ], + ... + }, + ... + ], + ... + } + +In some cases it is useful to associate some options with an address or +prefix pool from which a client is assigned a lease. Pool-specific +option values override subnet-specific and global option values. If the +client is assigned multiple leases from different pools, the server +assigns options from all pools from which the leases have been obtained. +However, if the particular option is specified in multiple pools from +which the client obtains the leases, only one instance of this option +is handed out to the client. The server's administrator must not +try to prioritize assignment of pool-specific options by trying to order +pool declarations in the server configuration. + +The following configuration snippet demonstrates how to specify the +``dns-servers`` option, which will be assigned to a client only if the client +obtains an address from the given pool: + +:: + + "Dhcp6": { + "subnet6": [ + { + "pools": [ + { + "pool": "2001:db8:1::100-2001:db8:1::300", + "option-data": [ + { + "name": "dns-servers", + "data": "2001:db8:1::10" + } + ] + } + ] + }, + ... + ], + ... + } + +Options can also be specified in class or host-reservation scope. The +current Kea options precedence order is (from most important to least): host +reservation, pool, subnet, shared network, class, global. + +When a data field is a string and that string contains the comma (``,``; +U+002C) character, the comma must be escaped with two backslashes (``\\,``; +U+005C). This double escape is required because both the routine +splitting of CSV data into fields and JSON use the same escape character; a +single escape (``\,``) would make the JSON invalid. For example, the string +"EST5EDT4,M3.2.0/02:00,M11.1.0/02:00" must be represented as: + +:: + + "Dhcp6": { + "subnet6": [ + { + "pools": [ + { + "option-data": [ + { + "name": "new-posix-timezone", + "data": "EST5EDT4\\,M3.2.0/02:00\\,M11.1.0/02:00" + } + ] + }, + ... + ], + ... + }, + ... + ], + ... + } + +Some options are designated as arrays, which means that more than one +value is allowed. For example, the option ``dns-servers`` +allows the specification of more than one IPv6 address, enabling clients +to obtain the addresses of multiple DNS servers. + +:ref:`dhcp6-custom-options` describes the +configuration syntax to create custom option definitions (formats). +Creation of custom definitions for standard options is generally not +permitted, even if the definition being created matches the actual +option format defined in the RFCs. However, there is an exception to this rule +for standard options for which Kea currently does not provide a +definition. To use such options, a server administrator must +create a definition as described in :ref:`dhcp6-custom-options` in the ``dhcp6`` option space. This +definition should match the option format described in the relevant RFC, +but the configuration mechanism allows any option format as there is +currently no way to validate it. + +The currently supported standard DHCPv6 options are listed in +the table below. "Name" and "Code" are the +values that should be used as a name/code in the option-data structures. +"Type" designates the format of the data; the meanings of the various +types are given in :ref:`dhcp-types`. + +.. _dhcp6-std-options-list: + +.. table:: List of standard DHCPv6 options configurable by an administrator + + +--------------------------+-----------------+-----------------+-----------------+ + | Name | Code | Type | Array? | + +==========================+=================+=================+=================+ + | preference | 7 | uint8 | false | + +--------------------------+-----------------+-----------------+-----------------+ + | unicast | 12 | ipv6-address | false | + +--------------------------+-----------------+-----------------+-----------------+ + | sip-server-dns | 21 | fqdn | true | + +--------------------------+-----------------+-----------------+-----------------+ + | sip-server-addr | 22 | ipv6-address | true | + +--------------------------+-----------------+-----------------+-----------------+ + | dns-servers | 23 | ipv6-address | true | + +--------------------------+-----------------+-----------------+-----------------+ + | domain-search | 24 | fqdn | true | + +--------------------------+-----------------+-----------------+-----------------+ + | nis-servers | 27 | ipv6-address | true | + +--------------------------+-----------------+-----------------+-----------------+ + | nisp-servers | 28 | ipv6-address | true | + +--------------------------+-----------------+-----------------+-----------------+ + | nis-domain-name | 29 | fqdn | true | + +--------------------------+-----------------+-----------------+-----------------+ + | nisp-domain-name | 30 | fqdn | true | + +--------------------------+-----------------+-----------------+-----------------+ + | sntp-servers | 31 | ipv6-address | true | + +--------------------------+-----------------+-----------------+-----------------+ + | information-refresh-time | 32 | uint32 | false | + +--------------------------+-----------------+-----------------+-----------------+ + | bcmcs-server-dns | 33 | fqdn | true | + +--------------------------+-----------------+-----------------+-----------------+ + | bcmcs-server-addr | 34 | ipv6-address | true | + +--------------------------+-----------------+-----------------+-----------------+ + | geoconf-civic | 36 | record (uint8, | false | + | | | uint16, binary) | | + +--------------------------+-----------------+-----------------+-----------------+ + | remote-id | 37 | record (uint32, | false | + | | | binary) | | + +--------------------------+-----------------+-----------------+-----------------+ + | subscriber-id | 38 | binary | false | + +--------------------------+-----------------+-----------------+-----------------+ + | client-fqdn | 39 | record (uint8, | false | + | | | fqdn) | | + +--------------------------+-----------------+-----------------+-----------------+ + | pana-agent | 40 | ipv6-address | true | + +--------------------------+-----------------+-----------------+-----------------+ + | new-posix-timezone | 41 | string | false | + +--------------------------+-----------------+-----------------+-----------------+ + | new-tzdb-timezone | 42 | string | false | + +--------------------------+-----------------+-----------------+-----------------+ + | ero | 43 | uint16 | true | + +--------------------------+-----------------+-----------------+-----------------+ + | lq-query (1) | 44 | record (uint8, | false | + | | | ipv6-address) | | + +--------------------------+-----------------+-----------------+-----------------+ + | client-data (1) | 45 | empty | false | + +--------------------------+-----------------+-----------------+-----------------+ + | clt-time (1) | 46 | uint32 | false | + +--------------------------+-----------------+-----------------+-----------------+ + | lq-relay-data (1) | 47 | record | false | + | | | (ipv6-address, | | + | | | binary) | | + +--------------------------+-----------------+-----------------+-----------------+ + | lq-client-link (1) | 48 | ipv6-address | true | + +--------------------------+-----------------+-----------------+-----------------+ + | v6-lost | 51 | fqdn | false | + +--------------------------+-----------------+-----------------+-----------------+ + | capwap-ac-v6 | 52 | ipv6-address | true | + +--------------------------+-----------------+-----------------+-----------------+ + | relay-id | 53 | binary | false | + +--------------------------+-----------------+-----------------+-----------------+ + | v6-access-domain | 57 | fqdn | false | + +--------------------------+-----------------+-----------------+-----------------+ + | sip-ua-cs-list | 58 | fqdn | true | + +--------------------------+-----------------+-----------------+-----------------+ + | bootfile-url | 59 | string | false | + +--------------------------+-----------------+-----------------+-----------------+ + | bootfile-param | 60 | tuple | true | + +--------------------------+-----------------+-----------------+-----------------+ + | client-arch-type | 61 | uint16 | true | + +--------------------------+-----------------+-----------------+-----------------+ + | nii | 62 | record (uint8, | false | + | | | uint8, uint8) | | + +--------------------------+-----------------+-----------------+-----------------+ + | aftr-name | 64 | fqdn | false | + +--------------------------+-----------------+-----------------+-----------------+ + | erp-local-domain-name | 65 | fqdn | false | + +--------------------------+-----------------+-----------------+-----------------+ + | rsoo | 66 | empty | false | + +--------------------------+-----------------+-----------------+-----------------+ + | pd-exclude | 67 | binary | false | + +--------------------------+-----------------+-----------------+-----------------+ + | rdnss-selection | 74 | record | true | + | | | (ipv6-address, | | + | | | uint8, fqdn) | | + +--------------------------+-----------------+-----------------+-----------------+ + | client-linklayer-addr | 79 | binary | false | + +--------------------------+-----------------+-----------------+-----------------+ + | link-address | 80 | ipv6-address | false | + +--------------------------+-----------------+-----------------+-----------------+ + | solmax-rt | 82 | uint32 | false | + +--------------------------+-----------------+-----------------+-----------------+ + | inf-max-rt | 83 | uint32 | false | + +--------------------------+-----------------+-----------------+-----------------+ + | dhcp4o6-server-addr | 88 | ipv6-address | true | + +--------------------------+-----------------+-----------------+-----------------+ + | s46-rule | 89 | record (uint8, | false | + | | | uint8, uint8, | | + | | | ipv4-address, | | + | | | ipv6-prefix) | | + +--------------------------+-----------------+-----------------+-----------------+ + | s46-br | 90 | ipv6-address | false | + +--------------------------+-----------------+-----------------+-----------------+ + | s46-dmr | 91 | ipv6-prefix | false | + +--------------------------+-----------------+-----------------+-----------------+ + | s46-v4v6bind | 92 | record | false | + | | | (ipv4-address, | | + | | | ipv6-prefix) | | + +--------------------------+-----------------+-----------------+-----------------+ + | s46-portparams | 93 | record(uint8, | false | + | | | psid) | | + +--------------------------+-----------------+-----------------+-----------------+ + | s46-cont-mape | 94 | empty | false | + +--------------------------+-----------------+-----------------+-----------------+ + | s46-cont-mapt | 95 | empty | false | + +--------------------------+-----------------+-----------------+-----------------+ + | s46-cont-lw | 96 | empty | false | + +--------------------------+-----------------+-----------------+-----------------+ + | v6-captive-portal | 103 | string | false | + +--------------------------+-----------------+-----------------+-----------------+ + | v6-sztp-redirect | 136 | tuple | true | + +--------------------------+-----------------+-----------------+-----------------+ + | ipv6-address-andsf | 143 | ipv6-address | true | + +--------------------------+-----------------+-----------------+-----------------+ + | v6-dnr | 144 | record (uint16, | false | + | | | uint16, fqdn, | | + | | | binary) | | + +--------------------------+-----------------+-----------------+-----------------+ + +Options marked with (1) have option definitions, but the logic behind +them is not implemented. That means that, technically, Kea knows how to +parse them in incoming messages or how to send them if configured to do +so, but not what to do with them. Since the related RFCs require certain +processing, the support for those options is non-functional. However, it +may be useful in some limited lab testing; hence the definition formats +are listed here. + +Some options are more complex to configure than others. In particular, the Softwire46 family of options +and DNR are discussed in separate sections below. + +Kea supports more options than those listed above. The following list is mostly useful for readers who +want to understand whether Kea is able to support certain options. The following options are +returned by the Kea engine itself and in general should not be configured manually. + +.. table:: List of standard DHCPv6 options managed by Kea on its own and not directly configurable by an administrator + + +--------------+------+------------------------------------------------------------------------+ + | Name | Code | Description | + +==============+======+========================================================================+ + | client-id | 1 | Sent by the client; Kea uses it to distinguish between clients. | + +--------------+------+------------------------------------------------------------------------+ + | server-id | 2 | Sent by clients to request action from a specific server and by the | + | | | server to identify itself. See :ref:`dhcp6-serverid` for details. | + +--------------+------+------------------------------------------------------------------------+ + | ia-na | 3 | A container option that conveys IPv6 addresses (``iaddr`` options). Kea| + | | | receives and sends those options using its allocation engine. | + +--------------+------+------------------------------------------------------------------------+ + | ia-ta | 4 | Conveys temporary addresses. Deprecated feature, not supported. | + +--------------+------+------------------------------------------------------------------------+ + | iaaddr | 5 | Conveys addresses with lifetimes in ``ia-na`` and ``ia-ta`` options. | + +--------------+------+------------------------------------------------------------------------+ + | oro | 6 | ORO (or Option Request Option) is used by clients to request a list | + | | | of options they are interested in. Kea supports it and sends the | + | | | requested options back if configured with required options. | + +--------------+------+------------------------------------------------------------------------+ + | elapsed-time | 8 | Sent by clients to identify how long they have been trying to obtain a | + | | | configuration. Kea uses high values sent by clients as an indicator | + | | | that something is wrong; this is one of the aspects used in HA to | + | | | determine if the partner is healthy or not. | + +--------------+------+------------------------------------------------------------------------+ + | relay-msg | 9 | Used by relays to encapsulate the original client message. Kea uses it | + | | | when sending back relayed responses to the relay agent. | + +--------------+------+------------------------------------------------------------------------+ + | auth | 11 | Used to pass authentication information between clients and server. The| + | | | support for this option is very limited. | + +--------------+------+------------------------------------------------------------------------+ + | status-code | 13 | An option that the server can attach in case of various failures, such | + | | | as running out of addresses or not being configured to assign prefixes.| + +--------------+------+------------------------------------------------------------------------+ + | rapid-commit | 14 | Used to signal the client's willingness to support ``rapid-commit`` and| + | | | the server's acceptance for this configuration. See | + | | | :ref:`dhcp6-rapid-commit` for details. | + +--------------+------+------------------------------------------------------------------------+ + | user-class | 15 | Sent by the client to self-identify the device type. Kea | + | | | can use this for client classification. | + +--------------+------+------------------------------------------------------------------------+ + | vendor-class | 16 | Similar to ``user-class``, but vendor-specific. | + +--------------+------+------------------------------------------------------------------------+ + | vendor-opts | 17 | A vendor-specific container that is used by both the client and the | + | | | server to exchange vendor-specific options. The logic behind those | + | | | options varies between vendors. Vendor options are explained in | + | | | :ref:`dhcp6-vendor-opts`. | + +--------------+------+------------------------------------------------------------------------+ + | interface-id | 18 | May be inserted by the relay agent to identify the interface that the | + | | | original client message was received on. Kea may be told to use this | + | | | information to select specific subnets. Also, if specified, Kea | + | | | echoes this option back, so the relay will know which interface to use | + | | | to reach the client. | + +--------------+------+------------------------------------------------------------------------+ + | ia-pd | 25 | A container for conveying Prefix Delegations (PDs)) that are being | + | | | delegated to clients. See :ref:`dhcp6-prefix-config` for details. | + +--------------+------+------------------------------------------------------------------------+ + | iaprefix | 26 | Conveys the IPv6 prefix in the ``ia-pd`` option. See | + | | | :ref:`dhcp6-prefix-config` for details. | + +--------------+------+------------------------------------------------------------------------+ + +.. _s46-options: + +Common Softwire46 Options +------------------------- + +Softwire46 options are involved in IPv4-over-IPv6 provisioning by means +of tunneling or translation, as specified in `RFC +7598 <https://tools.ietf.org/html/rfc7598>`__. The following sections +provide configuration examples of these options. + +.. _s46-containers: + +Softwire46 Container Options +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Softwire46 (S46) container options group rules and optional port parameters for a +specified domain. There are three container options specified in the +"dhcp6" (top-level) option space: the MAP-E Container option, the MAP-T +Container option, and the S46 Lightweight 4over6 Container option. These +options only contain the encapsulated options specified below; they do not +include any data fields. + +To configure the server to send a specific container option along with +all encapsulated options, the container option must be included in the +server configuration as shown below: + +:: + + "Dhcp6": { + "option-data": [ + { + "name": "s46-cont-mape" + } ], + ... + } + +This configuration will cause the server to include the MAP-E Container +option to the client. Use ``s46-cont-mapt`` or ``s46-cont-lw`` for the MAP-T +Container and S46 Lightweight 4over6 Container options, respectively. + +All remaining Softwire46 options described below are included in one of +the container options. Thus, they must be included in appropriate +option spaces by selecting a ``space`` name, which specifies the +option where they are supposed to be included. + +S46 Rule Option +~~~~~~~~~~~~~~~ + +The S46 Rule option is used to convey the Basic Mapping Rule (BMR) +and Forwarding Mapping Rule (FMR). + +:: + + { + "space": "s46-cont-mape-options", + "name": "s46-rule", + "data": "128, 0, 24, 192.0.2.0, 2001:db8:1::/64" + } + +Another possible ``space`` value is ``s46-cont-mapt-options``. + +The S46 Rule option conveys a number of parameters: + +- ``flags`` - an unsigned 8-bit integer, with currently only the + most-significant bit specified. It denotes whether the rule can be + used for forwarding (128) or not (0). + +- ``ea-len`` - an 8-bit-long Embedded Address length. Allowed values + range from 0 to 48. + +- ``IPv4 prefix length`` - an 8-bit-long expression of the prefix length of + the Rule IPv4 prefix specified in the ``ipv4-prefix`` field. Allowed + values range from 0 to 32. + +- ``IPv4 prefix`` - a fixed-length 32-bit field that specifies the IPv4 + prefix for the S46 rule. The bits in the prefix after + a specific number of bits (defined in ``prefix4-len``) are reserved, and MUST + be initialized to zero by the sender and ignored by the receiver. + +- ``IPv6 prefix`` - a field in prefix/length notation that specifies the IPv6 + domain prefix for the S46 rule. The field is padded on the right with + zero bits up to the nearest octet boundary, when ``prefix6-len`` is not + evenly divisible by 8. + +S46 BR Option +~~~~~~~~~~~~~ + +The S46 BR option is used to convey the IPv6 address of the Border +Relay. This option is mandatory in the MAP-E Container option and is not +permitted in the MAP-T and S46 Lightweight 4over6 Container options. + +.. code-block:: json + + { + "space": "s46-cont-mape-options", + "name": "s46-br", + "data": "2001:db8:cafe::1" + } + +Another possible ``space`` value is ``s46-cont-lw-options``. + +S46 DMR Option +~~~~~~~~~~~~~~ + +The S46 DMR option is used to convey values for the Default Mapping Rule +(DMR). This option is mandatory in the MAP-T container option and is not +permitted in the MAP-E and S46 Lightweight 4over6 Container options. + +.. code-block:: json + + { + "space": "s46-cont-mapt-options", + "name": "s46-dmr", + "data": "2001:db8:cafe::/64" + } + +This option must not be included in other containers. + +S46 IPv4/IPv6 Address Binding Option +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The S46 IPv4/IPv6 Address Binding option may be used to specify the full +or shared IPv4 address of the Customer Edge (CE). The IPv6 prefix field +is used by the CE to identify the correct prefix to use for the tunnel +source. + +:: + + { + "space": "s46-cont-lw", + "name": "s46-v4v6bind", + "data": "192.0.2.3, 2001:db8:1:cafe::/64" + } + +This option must not be included in other containers. + +S46 Port Parameters +~~~~~~~~~~~~~~~~~~~ + +The S46 Port Parameters option specifies optional port-set information +that may be provided to CEs. + +.. code-block:: json + + { + "space": "s46-rule-options", + "name": "s46-portparams", + "data": "2, 3/4" + } + +Another possible ``space`` value is ``s46-v4v6bind``, to include this option +in the S46 IPv4/IPv6 Address Binding option. + +Note that the second value in the example above specifies the PSID and +PSID-length fields in the format of PSID/PSID length. This is equivalent +to the values of ``PSID-len=4`` and ``PSID=12288`` conveyed in the S46 Port +Parameters option. + +.. _dnr6-options: + +DNR (Discovery of Network-designated Resolvers) Options for DHCPv6 +------------------------------------------------------------------ + +One of the more recently added options is the Discovery of +Network-designated Resolvers or DNR option, +introduced in `RFC 9463 <https://www.rfc-editor.org/rfc/rfc9463>`__. The goal of that RFC is +to provide a way to communicate location of DNS resolvers available over means other than +the classic DNS over UDP port 53. At the time of this writing, the supported technologies +are DoT (DNS-over-TLS), DoH (DNS-over-HTTPS), and DoQ (DNS-over-QUIC), but the option was +designed to be extensible to accommodate other protocols in the future. + +DNR option may be configured using convenient notation. Comma delimited fields must be provided in the following order: + +- Service Priority (mandatory), +- ADN FQDN (mandatory), +- IP address(es) (optional - if more than one - they must be space-separated) +- SvcParams as a set of key=value pairs (optional - if more than one - they must be space-separated; + to provide more than one alpn-id separate them with double backslash escaped comma like in the + example below). + +Let's imagine an example that we want to convey a DoT server operating at ``dot1.example.org`` +(which resolves to two IPv6 addresses: ``2001:db8::1`` and ``2001:db8::2``) on a non-standard port 8530. +An example option that would convey this information looks as follows: + +:: + + { + "name": "v6-dnr", // name of the option + + // The following fields should be specified: + // - service priority (unsigned 16 bit integer) + // - authentication-domain-name (fqdn of the encrypted resolver) + // - a list of one or more IPv6 addresses + // - list of parameters in key=value format, space separated; any comma + // characters in this field must be escaped with double backslash + "data": "100, dot1.example.org., 2001:db8::1 2001:db8::2, alpn=dot port=8530" + } + +The above option will be encoded on-wire as follows: + +:: + + 00 64 - service priority (100 in hex as unsigned 16 bit integer) + 00 12 - length of the Authentication Domain Name (name of the resolver) FQDN (18 in hex as unsigned 16 bit integer) + 04 64 6f 74 31 07 65 78 61 6d 70 6c 65 03 6f 72 67 00 - 18 octets of the ADN FQDN + 00 20 - 32 octets is the length of the following two IPv6 addresses + 20 01 0d b8 00 00 00 00 00 00 00 00 00 00 00 01 - 2001:db8::1 + 20 01 0d b8 00 00 00 00 00 00 00 00 00 00 00 02 - 2001:db8::2 + 00 01 - SvsParams begin - this is alpn SvcParamKey + 00 04 - length of the alpn SvcParamValue field (4 octets) + 03 - length of the following alpn-id coded on one octet + 64 6f 74 - "dot" - value of the alpn + 00 03 - this is port SvcParamKey + 00 02 - length of the SvcParamValue field is 2 octets + 21 52 - the actual value is 0x2152 or 8530 in decimal + +The following example shows how to configure more than one ``ALPN`` protocol in Service Parameters. +The example specifies a resolver known as ``resolver.example`` that supports: + +- DoT on default port 853 +- DoQ on default port 853 +- DoH at ``https://resolver.example/q{?dns}`` + +:: + + { + "name": "v6-dnr", // name of the option + + // Note the double backslash escaped commas in alpn-id list. + "data": "150, resolver.example., 2001:db8::1 2001:db8::2, alpn=dot\\,doq\\,h2\\,h3 dohpath=/q{?dns}" + } + +The above option will be encoded on-wire as follows: + +:: + + 00 96 - service priority (150 in hex as unsigned 16 bit integer) + 00 12 - length of the Authentication Domain Name (name of the resolver) FQDN (18 in hex as unsigned 16 bit integer) + 08 72 65 73 6f 6c 76 65 72 07 65 78 61 6d 70 6c 65 00 - 18 octets of the ADN FQDN + 00 20 - 32 octets is the length of the following two IPv6 addresses + 20 01 0d b8 00 00 00 00 00 00 00 00 00 00 00 01 - 2001:db8::1 + 20 01 0d b8 00 00 00 00 00 00 00 00 00 00 00 02 - 2001:db8::2 + 00 01 - SvsParams begin - this is alpn SvcParamKey + 00 0e - length of the alpn SvcParamValue field (14 octets) + 03 - length of the following alpn-id coded on one octet + 64 6f 74 - "dot" - value of the alpn + 03 - length of the following alpn-id coded on one octet + 64 6f 71 - "doq" - value of the alpn + 02 - length of the following alpn-id coded on one octet + 68 32 - "h2" - value of the alpn "HTTP/2 over TLS" + 02 - length of the following alpn-id coded on one octet + 68 33 - "h3" - value of the alpn "HTTP/3" + 00 07 - this is dohpath SvcParamKey + 00 08 - length of the SvcParamValue field is 8 octets + 2f 71 7b 3f 64 6e 73 7d - "/q{?dns}" dohpath + + +.. note:: + + Note that whenever "comma" characters need to be used not as the delimiters, they must be escaped with + double backslash (``\\,``). E.g. one must use escaped commas when configuring more than one ``ALPN`` + protocol to separate them. + +The `RFC 9463 <https://www.rfc-editor.org/rfc/rfc9463#name-option-format>`__ Section 4.1 is encouraging to include +at least the ``ALPN`` (Application-Layer Protocol Negotiation) SvcParam, as it will be required in most cases. +It defines the protocol how the encrypted resolver could be reached. The most common values are +``dot``, ``doq``, ``h2`` (meaning HTTP/2.0 over TLS, used in DoH). + +As per `RFC 9461 <https://www.rfc-editor.org/rfc/rfc9461.html#name-new-svcparamkey-dohpath>`__ Section 5: + +If the ``alpn`` SvcParam indicates support for HTTP, ``dohpath`` MUST be present. The URI Template MUST contain +a "dns" variable. For example, when advertising DoH resolver available at +``https://doh1.example.org/query{?dns}``, the ``dohpath`` should be set to relative URI ``/query{?dns}``. + +A reader interested in configuring this option is encouraged to read the following materials: + +- A very nice set of examples is available in Section 7 of `RFC 9461 + <https://www.rfc-editor.org/rfc/rfc9461#name-examples>`__. +- List of all currently defined service parameters is maintained on `IANA registry + <https://www.iana.org/assignments/dns-svcb/dns-svcb.xhtml>`__. This specifies records that can be + stored in the svcParams field of the DNR option. +- List of currently allowed protocols in the ALPN parameter is maintained on `another IANA registry + <https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids>`__. + +- `RFC 9463 <https://www.rfc-editor.org/rfc/rfc9463>`__ which provides option definitions. In terms of SvcParams, it states + that at `alpn` and `port` must be supported, and `dohpath` (used for DoH) is recommended to be supported. +- Section 2.2 of `RFC 9460 <https://www.rfc-editor.org/rfc/rfc9460>`__, which defines the on-wire format for SvcParams. +- Sections 7.1, 7.2 of `RFC 9460 <https://www.rfc-editor.org/rfc/rfc9460>`__, which defines the on-wire format for alpn and port. +- Section 5 of `RFC 9461 <https://www.rfc-editor.org/rfc/rfc9461#name-new-svcparamkey-dohpath>`__, which defines + on-wire format for `dohpath`. + +Kea currently supports the following service parameters: + + +-----------------+------+------------------------------------------------------------------------+ + | Name | Code | Description | + +=================+======+========================================================================+ + | alpn | 1 | Specifies comma separated protocol types (DoT, DoH, etc.) | + +-----------------+------+------------------------------------------------------------------------+ + | port | 3 | Unsigned 16 bit integer. Indicated non-standard TCP or UDP port. | + +-----------------+------+------------------------------------------------------------------------+ + | dohpath | 7 | Mandatory for DoH. Contains URL path for the DoT resolver. | + +-----------------+------+------------------------------------------------------------------------+ + +Other currently defined service parameters: mandatory (0), no-default-alpn (2), ipv4hint (4), ech (5), +ipv6hint (6), and ohttp (8) are not usable in the DNR option. + +Further examples are provided in Kea sources in ``all-options.json`` file +in the ``doc/examples/kea6`` directory. The DHCPv4 option is almost equivalent, and is described +in :ref:`dnr4-options`. + + +.. _dhcp6-custom-options: + +Custom DHCPv6 Options +--------------------- + +Kea supports custom (non-standard) DHCPv6 options. +Let's say that we want to define a new DHCPv6 option called ``foo``, which +will have code 100 and will convey a single, unsigned, 32-bit +integer value. Such an option can be defined by putting the following entry +in the configuration file: + +:: + + "Dhcp6": { + "option-def": [ + { + "name": "foo", + "code": 100, + "type": "uint32", + "array": false, + "record-types": "", + "space": "dhcp6", + "encapsulate": "" + }, + ... + ], + ... + } + +The ``false`` value of the ``array`` parameter determines that the option +does NOT comprise an array of ``uint32`` values but is, instead, a single +value. Two other parameters have been left blank: ``record-types`` and +``encapsulate``. The former specifies the comma-separated list of option +data fields, if the option comprises a record of data fields. The +``record-types`` value should be non-empty if ``type`` is set to +``record``; otherwise it must be left blank. The latter parameter +specifies the name of the option space being encapsulated by the +particular option. If the particular option does not encapsulate any +option space, the parameter should be left blank. Note that the ``option-def`` +configuration statement only defines the format of an option and does +not set its value(s). + +The ``name``, ``code``, and ``type`` parameters are required; all others +are optional. The ``array`` parameter default value is ``false``. The +``record-types`` and ``encapsulate`` parameters default values are blank +(``""``). The default ``space`` is ``dhcp6``. + +Once the new option format is defined, its value is set in the same way +as for a standard option. For example, the following commands set a +global value that applies to all subnets. + +:: + + "Dhcp6": { + "option-data": [ + { + "name": "foo", + "code": 100, + "space": "dhcp6", + "csv-format": true, + "data": "12345" + }, + ... + ], + ... + } + +New options can take more complex forms than the simple use of primitives +(uint8, string, ipv6-address, etc.); it is possible to define an option +comprising a number of existing primitives. + +For example, say we want to define a new option that will consist of +an IPv6 address, followed by an unsigned 16-bit integer, followed by a +boolean value, followed by a text string. Such an option could be +defined in the following way: + +:: + + "Dhcp6": { + "option-def": [ + { + "name": "bar", + "code": 101, + "space": "dhcp6", + "type": "record", + "array": false, + "record-types": "ipv6-address, uint16, boolean, string", + "encapsulate": "" + }, + ... + ], + ... + } + +The ``type`` parameter is set to ``"record"`` to indicate that the option +contains multiple values of different types. These types are given as a +comma-separated list in the ``record-types`` field and should be ones +from those listed in :ref:`dhcp-types`. + +The values of the options are set in an ``option-data`` statement as +follows: + +:: + + "Dhcp6": { + "option-data": [ + { + "name": "bar", + "space": "dhcp6", + "code": 101, + "csv-format": true, + "data": "2001:db8:1::10, 123, false, Hello World" + } + ], + ... + } + +The ``csv-format`` parameter is set to ``true`` to indicate that the ``data`` +field comprises a comma-separated list of values. The values in ``data`` must +correspond to the types set in the ``record-types`` field of the option +definition. + +When ``array`` is set to ``true`` and ``type`` is set to ``"record"``, the +last field is an array, i.e. it can contain more than one value, as in: + +:: + + "Dhcp6": { + "option-def": [ + { + "name": "bar", + "code": 101, + "space": "dhcp6", + "type": "record", + "array": true, + "record-types": "ipv6-address, uint16", + "encapsulate": "" + }, + ... + ], + ... + } + +The new option content is one IPv6 address followed by one or more 16-bit +unsigned integers. + +.. note:: + + In general, boolean values are specified as ``true`` or ``false``, + without quotes. Some specific boolean parameters may also accept + ``"true"``, ``"false"``, ``0``, ``1``, ``"0"``, and ``"1"``. + +.. _dhcp6-vendor-opts: + +DHCPv6 Vendor-Specific Options +------------------------------ + +Vendor options in DHCPv6 are carried in the Vendor-Specific +Information option (code 17). The idea behind option 17 +is that each vendor has its own unique set of options with their own custom +formats. The vendor is identified by a 32-bit unsigned integer called +``enterprise-number`` or ``vendor-id``. + +The standard spaces defined in Kea and their options are: + +- ``vendor-2495``: Internet Systems Consortium, Inc. for 4o6 options: + ++-------------+--------------------+------------------------------------------------------------------------+ +| option code | option name | option description | ++=============+====================+========================================================================+ +| 60000 | 4o6-interface | the name of the 4o6 server's client-facing interface | ++-------------+--------------------+------------------------------------------------------------------------+ +| 60001 | 4o6-source-address | the address that the 4o6 server uses to send packets to the client | ++-------------+--------------------+------------------------------------------------------------------------+ +| 60002 | 4o6-source-port | the port that the 4o6 server opens to send packets to the client | ++-------------+--------------------+------------------------------------------------------------------------+ + +- ``vendor-4491``: Cable Television Laboratories, Inc. for DOCSIS3 options: + ++-------------+--------------------+------------------------------------------------------------------------+ +| option code | option name | option description | ++=============+====================+========================================================================+ +| 1 | oro | ORO (or Option Request Option) is used by clients to request a list of | +| | | options they are interested in. | ++-------------+--------------------+------------------------------------------------------------------------+ +| 2 | tftp-servers | a list of IPv4 addresses of TFTP servers to be used by the cable modem | ++-------------+--------------------+------------------------------------------------------------------------+ + +The following examples show how to +define an option ``"foo"`` with code 1 that consists of an IPv6 address, +an unsigned 16-bit integer, and a string. The ``"foo"`` option is +conveyed in a Vendor-Specific Information option, which comprises a +single uint32 value that is set to ``12345``. The sub-option ``"foo"`` +follows the data field holding this value. + +The first step is to define the format of the option: + +:: + + "Dhcp6": { + "option-def": [ + { + "name": "foo", + "code": 1, + "space": "vendor-12345", + "type": "record", + "array": false, + "record-types": "ipv6-address, uint16, string", + "encapsulate": "" + } + ], + ... + } + +Note that the option space is set to ``"vendor-12345"``. +Once the option format is defined, the next step is to define actual values +for that option: + +:: + + "Dhcp6": { + "option-data": [ + { + "name": "foo", + "space": "vendor-12345", + "data": "2001:db8:1::10, 123, Hello World" + }, + ... + ], + ... + } + +We should also define a value (``"enterprise-number"``) for the +Vendor-Specific Information option, to convey the option ``foo``. + +:: + + "Dhcp6": { + "option-data": [ + { + "name": "vendor-opts", + "data": "12345" + }, + ... + ], + ... + } + +Alternatively, the option can be specified using its code. + +:: + + "Dhcp6": { + "option-data": [ + { + "code": 17, + "data": "12345" + }, + ... + ], + ... + } + +A common configuration is to set the ``always-send`` flag to ``true``, so the +vendor option is sent even when the client did not specify it in the query. + +This is also how :iscman:`kea-dhcp6` can be configured to send multiple vendor options +from different vendors, along with each of their specific enterprise number. +If these options need to be sent by the server regardless of whether the client +specified any enterprise number, ``"always-send": true`` must be configured +for the suboptions that will be included in the Vendor-Specific Information option (code 17). + +.. code-block:: json + + { + "Dhcp6": { + "option-data": [ + { + "always-send": true, + "data": "tagged", + "name": "tag", + "space": "vendor-2234" + }, + { + "always-send": true, + "data": "https://example.com:1234/path", + "name": "url", + "space": "vendor-3561" + } + ], + "option-def": [ + { + "code": 22, + "name": "tag", + "space": "vendor-2234", + "type": "string" + }, + { + "code": 11, + "name": "url", + "space": "vendor-3561", + "type": "string" + } + ] + } + } + +.. note:: + + The :iscman:`kea-dhcp6` server is able to recognize multiple Vendor Class + options (code 16) with different enterprise numbers in the client requests + and to send multiple Vendor-Specific Information options (code 17) in the + responses, one for each vendor. + +.. _dhcp6-option-spaces: + +Nested DHCPv6 Options (Custom Option Spaces) +-------------------------------------------- + +It is sometimes useful to define a completely new option space, such as +when a user creates a new option to convey sub-options that +use a separate numbering scheme, such as sub-options with codes 1 +and 2. Those option codes conflict with standard DHCPv6 options, so a +separate option space must be defined. + +Note that the creation of a new option space is not required when +defining sub-options for a standard option, because one is created by +default if the standard option is meant to convey any sub-options (see +:ref:`dhcp6-vendor-opts`). + +If we want a DHCPv6 option called ``container`` with code 102, +that conveys two sub-options with codes 1 and 2, we first need to +define the new sub-options: + +:: + + "Dhcp6": { + "option-def": [ + { + "name": "subopt1", + "code": 1, + "space": "isc", + "type": "ipv6-address", + "record-types": "", + "array": false, + "encapsulate": "" + }, + { + "name": "subopt2", + "code": 2, + "space": "isc", + "type": "string", + "record-types": "", + "array": false, + "encapsulate": "" + } + ], + ... + } + +Note that we have defined the options to belong to a new option space +(in this case, ``"isc"``). + +The next step is to define a regular DHCPv6 option with the desired code +and specify that it should include options from the new option space: + +:: + + "Dhcp6": { + "option-def": [ + { + "name": "container", + "code": 102, + "space": "dhcp6", + "type": "empty", + "array": false, + "record-types": "", + "encapsulate": "isc" + }, + ... + ], + ... + } + +The name of the option space in which the sub-options are defined is set +in the ``encapsulate`` field. The ``type`` field is set to ``"empty"``, to +indicate that this option does not carry any data other than +sub-options. + +Finally, we can set values for the new options: + +.. code-block:: json + + { + "Dhcp6": { + "option-data": [ + { + "name": "subopt1", + "code": 1, + "space": "isc", + "data": "2001:db8::abcd" + }, + { + "name": "subopt2", + "code": 2, + "space": "isc", + "data": "Hello world" + }, + { + "name": "container", + "code": 102, + "space": "dhcp6" + } + ] + } + } + +It is possible to create an option which carries some data in +addition to the sub-options defined in the encapsulated option space. +For example, if the ``container`` option from the previous example were +required to carry a uint16 value as well as the sub-options, the +``type`` value would have to be set to ``"uint16"`` in the option +definition. (Such an option would then have the following data +structure: DHCP header, uint16 value, sub-options.) The value specified +with the ``data`` parameter — which should be a valid integer enclosed +in quotes, e.g. ``"123"`` — would then be assigned to the ``uint16`` field in +the ``container`` option. + +.. _dhcp6-option-data-defaults: + +Unspecified Parameters for DHCPv6 Option Configuration +------------------------------------------------------ + +In many cases it is not required to specify all parameters for an option +configuration, and the default values can be used. However, it is +important to understand the implications of not specifying some of them, +as it may result in configuration errors. The list below explains the +behavior of the server when a particular parameter is not explicitly +specified: + +- ``name`` - the server requires either an option name or an option code to + identify an option. If this parameter is unspecified, the option code + must be specified. + +- ``code`` - the server requires either an option name or an option code to + identify an option; this parameter may be left unspecified if the + ``name`` parameter is specified. However, this also requires that the + particular option have a definition (either as a standard option or + an administrator-created definition for the option using an + ``option-def`` structure), as the option definition associates an + option with a particular name. It is possible to configure an option + for which there is no definition (unspecified option format). + Configuration of such options requires the use of the option code. + +- ``space`` - if the option space is unspecified it defaults to + ``dhcp6``, which is an option space holding standard DHCPv6 options. + +- ``data`` - if the option data is unspecified it defaults to an empty + value. The empty value is mostly used for the options which have no + payload (boolean options), but it is legal to specify empty values + for some options which carry variable-length data and for which the + specification allows a length of 0. For such options, the data + parameter may be omitted in the configuration. + +- ``csv-format`` - if this value is not specified, the server + assumes that the option data is specified as a list of comma-separated + values to be assigned to individual fields of the DHCP option. + +.. _dhcp6-t1-t2-times: + +Controlling the Values Sent for T1 and T2 Times +----------------------------------------------- + +According to RFC 8415, section 21.4, the recommended T1 and T2 values +are 50% and 80% of the preferred +lease time, respectively. Kea can be configured to send values that are +specified explicitly or that are calculated as percentages of the +preferred lease time. The server's behavior is determined by a combination +of configuration parameters, of which T1 and T2 are only two. + +The lease's preferred and valid lifetimes are expressed as triplets with +minimum, default, and maximum values using configuration entries: + +- ``min-preferred-lifetime`` - specifies the minimum preferred lifetime (optional). + +- ``preferred-lifetime`` - specifies the default preferred lifetime. + +- ``max-preferred-lifetime`` - specifies the maximum preferred lifetime (optional). + +- ``min-valid-lifetime`` - specifies the minimum valid lifetime (optional). + +- ``valid-lifetime`` - specifies the default valid lifetime. + +- ``max-valid-lifetime`` - specifies the maximum valid lifetime (optional). + +Since Kea 1.9.11, these values may be specified within client classes. + +When the client does not specify lifetimes, the default is used. +A specified lifetime - using the IAADDR or IAPREFIX sub-option with +non-zero values - uses these values when they are between the configured +minimum and maximum bounds. Values outside the bounds are rounded up or down as +needed. + +.. note:: + + As of Kea 2.3.8, if the preferred-lifetime has not been explicitly specified + or the specified value is larger than the value of valid-lifetime, the server + will use the value given by 0.625 * valid-lifetime. + +To send specific fixed values, use the following two parameters: + +- ``renew-timer`` - specifies the value of T1 in seconds. + +- ``rebind-timer`` - specifies the value of T2 in seconds. + +Any value greater than or equal to zero may be specified for T2. +T1, if specified, must be less than T2. This flexibility allows +a use case where administrators want to suppress client renewals and +rebinds by deferring them beyond the lifespan of the lease. This should +cause the lease to expire, rather than get renewed by clients. If T1 is +specified as larger than T2, T1 is silently set to zero in the outbound IA. + +In the great majority of cases, the values should follow this rule: T1 < T2 < +preferred lifetime < valid lifetime. Alternatively, both T1 and T2 +values can be configured to 0, which is a signal to DHCPv6 clients that +they may renew at their own discretion. However, there are known broken +client implementations in use that will start renewing immediately. +Administrators who plan to use T1=T2=0 values should test first and make sure +their clients behave rationally. + +In some rare cases there may be a need to disable a client's ability to +renew addresses. This is undesired from a protocol perspective and should +be avoided if possible. However, if necessary, administrators can +configure the T1 and T2 values to be equal or greater to the valid +lifetime. Be advised that this will cause clients to occasionally +lose their addresses, which is generally perceived as poor service. +However, there may be some rare business cases when this is desired +(e.g. when it is desirable to intentionally break long-lasting connections). + +Calculation of the values is controlled by the following three parameters: + +- ``calculate-tee-times`` - when ``true``, T1 and T2 are calculated as + percentages of the valid lease time. It defaults to ``true``. + +- ``t1-percent`` - the percentage of the valid lease time to use for + T1. It is expressed as a real number between 0.0 and 1.0 and must be + less than ``t2-percent``. The default value is 0.5, per RFC 8415. + +- ``t2-percent`` - the percentage of the valid lease time to use for + T2. It is expressed as a real number between 0.0 and 1.0 and must be + greater than ``t1-percent``. The default value is 0.8 per RFC 8415. + +.. note:: + + If both explicit values are specified and + ``calculate-tee-times`` is ``true``, the server will use the explicit values. + Administrators with a setup where some subnets or shared-networks + use explicit values and some use calculated values must + not define the explicit values at any level higher than where they + will be used. Inheriting them from too high a scope, such as + global, will cause them to have values at every level underneath + (both shared-networks and subnets), effectively disabling calculated + values. + +.. _dhcp6-config-subnets: + +IPv6 Subnet Selection +--------------------- + +The DHCPv6 server may receive requests from local (connected to the same +subnet as the server) and remote (connected via relays) clients. As the +server may have many subnet configurations defined, it must select an +appropriate subnet for a given request. + +In IPv4, the server can determine which of the configured subnets are +local, as there is a reasonable expectation that the server will have a +(global) IPv4 address configured on the interface. That assumption is not +true in IPv6; the DHCPv6 server must be able to operate while only using +link-local addresses. Therefore, an optional ``interface`` parameter is +available within a subnet definition to designate that a given subnet is +local, i.e. reachable directly over the specified interface. For +example, a server that is intended to serve a local subnet over eth0 +may be configured as follows: + +:: + + "Dhcp6": { + "subnet6": [ + { + "id": 1, + "subnet": "2001:db8:beef::/48", + "pools": [ + { + "pool": "2001:db8:beef::/48" + } + ], + "interface": "eth0" + } + ], + ... + } + +.. _dhcp6-rapid-commit: + +Rapid Commit +------------ + +The Rapid Commit option, described in `RFC +8415 <https://tools.ietf.org/html/rfc8415>`__, is supported by the Kea +DHCPv6 server. However, support is disabled by default. It can be +enabled on a per-subnet basis using the ``rapid-commit`` parameter as +shown below: + +.. code-block:: json + + { + "Dhcp6": { + "subnet6": [ + { + "id": 1, + "subnet": "2001:db8:beef::/48", + "rapid-commit": true, + "pools": [ + { + "pool": "2001:db8:beef::1-2001:db8:beef::10" + } + ] + } + ] + } + } + +This setting only affects the subnet for which ``rapid-commit`` is +set to ``true``. For clients connected to other subnets, the server +ignores the Rapid Commit option sent by the client and follows the +4-way exchange procedure, i.e. responds with an Advertise for a Solicit +containing a Rapid Commit option. + +.. _dhcp6-relays: + +DHCPv6 Relays +------------- + +A DHCPv6 server with multiple subnets defined must select the +appropriate subnet when it receives a request from a client. For clients +connected via relays, two mechanisms are used: + +The first uses the ``linkaddr`` field in the ``RELAY_FORW`` message. The name of +this field is somewhat misleading in that it does not contain a +link-layer address; instead, it holds an address (typically a global +address) that is used to identify a link. The DHCPv6 server checks to +see whether the address belongs to a defined subnet and, if it does, +that subnet is selected for the client's request. + +The second mechanism is based on ``interface-id`` options. While forwarding +a client's message, relays may insert an ``interface-id`` option into the +message that identifies the interface on the relay that received the +message. (Some relays allow configuration of that parameter, but it is +sometimes hard-coded and may range from the very simple [e.g. "vlan100"] +to the very cryptic; one example seen on real hardware was +"ISAM144|299|ipv6|nt:vp:1:110".) The server can use this information to +select the appropriate subnet. The information is also returned to the +relay, which then knows the interface to use to transmit the response to +the client. For this to work successfully, the relay interface IDs must +be unique within the network and the server configuration must match +those values. + +When configuring the DHCPv6 server, two +similarly named parameters can be configured for a subnet: + +- ``interface`` - defines which local network interface can be used to + access a given subnet. + +- ``interface-id`` - specifies the content of the ``interface-id`` option + used by relays to identify the interface on the relay to which the + response packet is sent. + +The two are mutually exclusive; a subnet cannot be reachable both +locally (direct traffic) and via relays (remote traffic). Specifying +both is a configuration error and the DHCPv6 server will refuse such a +configuration. + +The following example configuration shows how to specify an ``interface-id`` +with a value of "vlan123": + +:: + + "Dhcp6": { + "subnet6": [ + { + "id": 1, + "subnet": "2001:db8:beef::/48", + "pools": [ + { + "pool": "2001:db8:beef::/48" + } + ], + "interface-id": "vlan123" + } + ], + ... + } + +.. _dhcp6-rsoo: + +Relay-Supplied Options +---------------------- + +`RFC 6422 <https://tools.ietf.org/html/rfc6422>`__ defines a mechanism +called Relay-Supplied DHCP Options. In certain cases relay agents are +the only entities that may have specific information, and they can +insert options when relaying messages from the client to the server. The +server then does certain checks and copies those options to the +response sent to the client. + +There are certain conditions that must be met for the option to be +included. First, the server must not provide the option itself; in other +words, if both relay and server provide an option, the server always +takes precedence. Second, the option must be RSOO-enabled. (RSOO is the +"Relay Supplied Options option.") IANA maintains a list of RSOO-enabled +options +`here <https://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml#options-relay-supplied>`__. +However, there may be cases when system administrators want to echo +other options. Kea can be instructed to treat other options as +RSOO-enabled; for example, to mark options 110, 120, and 130 as +RSOO-enabled, the following syntax should be used: + +:: + + "Dhcp6": { + "relay-supplied-options": [ "110", "120", "130" ], + ... + } + +At this time, only option 65 is RSOO-enabled by IANA. This option +will always be treated as RSOO-enabled, so there is no need to explicitly mark +it. When enabling standard options, it is also possible to use their +names rather than their option code, e.g. use ``dns-servers`` instead of +``23``. See ref:`dhcp6-std-options-list` for the names. In +certain cases this may also work for custom options, but due to the +nature of the parser code this may be unreliable and should be avoided. + +.. _dhcp6-client-classifier: + +Client Classification in DHCPv6 +------------------------------- + +The DHCPv6 server includes support for client classification. For a +deeper discussion of the classification process, see :ref:`classify`. + +In certain cases it is useful to configure the server to differentiate +between DHCP client types and treat them accordingly. Client +classification can be used to modify the behavior of almost any part of +DHCP message processing. Kea currently offers +three mechanisms that take advantage of client classification in DHCPv6: +subnet selection, address pool selection, and DHCP options assignment. + +Kea can be instructed to limit access to given subnets based on class +information. This is particularly useful for cases where two types of +devices share the same link and are expected to be served from two +different subnets. The primary use case for such a scenario is cable +networks, where there are two classes of devices: the cable modem +itself, which should be handed a lease from subnet A; and all other +devices behind the modem, which should get leases from subnet B. That +segregation is essential to prevent overly curious end-users from playing +with their cable modems. For details on how to set up class restrictions +on subnets, see :ref:`classification-subnets`. + +When subnets belong to a shared network, the classification applies to +subnet selection but not to pools; that is, a pool in a subnet limited to a +particular class can still be used by clients which do not belong to the +class, if the pool they are expected to use is exhausted. The limit +on access based on class information is also available at the +address/prefix pool level within a subnet: see :ref:`classification-pools`. +This is useful when segregating clients belonging to the same +subnet into different address ranges. + +In a similar way, a pool can be constrained to serve only known clients, +i.e. clients which have a reservation, using the built-in ``KNOWN`` or +``UNKNOWN`` classes. Addresses can be assigned to registered clients +without giving a different address per reservation: for instance, when +there are not enough available addresses. The determination whether +there is a reservation for a given client is made after a subnet is +selected, so it is not possible to use ``KNOWN``/``UNKNOWN`` classes to select a +shared network or a subnet. + +The process of classification is conducted in five steps. The first step +is to assess an incoming packet and assign it to zero or more classes. +The second step is to choose a subnet, possibly based on the class +information. When the incoming packet is in the special class ``DROP``, +it is dropped and a debug message logged. +The next step is to evaluate class expressions depending on the built-in +``KNOWN``/``UNKNOWN`` classes after host reservation lookup, using them for +pool/pd-pool selection and assigning classes from host reservations. The +list of required classes is then built and each class of the list has +its expression evaluated; when it returns ``true``, the packet is added as +a member of the class. The last step is to assign options, again possibly +based on the class information. More complete and detailed information +is available in :ref:`classify`. + +There are two main methods of classification. The first is automatic and +relies on examining the values in the vendor class options or the +existence of a host reservation. Information from these options is +extracted, and a class name is constructed from it and added to the +class list for the packet. The second method specifies an expression that is +evaluated for each packet. If the result is ``true``, the packet is a +member of the class. + +.. note:: + + The new ``early-global-reservations-lookup`` global parameter flag + enables a lookup for global reservations before the subnet selection + phase. This lookup is similar to the general lookup described above + with two differences: + + - the lookup is limited to global host reservations + + - the ``UNKNOWN`` class is never set + +.. note:: + + Care should be taken with client classification, as it is easy for + clients that do not meet class criteria to be denied all service. + +Defining and Using Custom Classes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following example shows how to configure a class using an expression +and a subnet using that class. This configuration defines the class +named ``Client_enterprise``. It is comprised of all clients whose client +identifiers start with the given hex string (which would indicate a DUID +based on an enterprise id of 0xAABBCCDD). Members of this class will be given an address +from 2001:db8:1::0 to 2001:db8:1::FFFF and the addresses of their DNS +servers set to 2001:db8:0::1 and 2001:db8:2::1. + +:: + + "Dhcp6": { + "client-classes": [ + { + "name": "Client_enterprise", + "test": "substring(option[1].hex,0,6) == 0x0002AABBCCDD", + "option-data": [ + { + "name": "dns-servers", + "code": 23, + "space": "dhcp6", + "csv-format": true, + "data": "2001:db8:0::1, 2001:db8:2::1" + } + ] + }, + ... + ], + "subnet6": [ + { + "id": 1, + "subnet": "2001:db8:1::/64", + "pools": [ { "pool": "2001:db8:1::-2001:db8:1::ffff" } ], + "client-class": "Client_enterprise" + } + ], + ... + } + +This example shows a configuration using an automatically generated +``VENDOR_CLASS_`` class. The administrator of the network has decided that +addresses in the range 2001:db8:1::1 to 2001:db8:1::ffff are to be +managed by the DHCPv6 server and that only clients belonging to the +eRouter1.0 client class are allowed to use that pool. + +:: + + "Dhcp6": { + "subnet6": [ + { + "id": 1, + "subnet": "2001:db8:1::/64", + "pools": [ + { + "pool": "2001:db8:1::-2001:db8:1::ffff" + } + ], + "client-class": "VENDOR_CLASS_eRouter1.0" + } + ], + ... + } + +.. _dhcp6-required-class: + +Required Classification +~~~~~~~~~~~~~~~~~~~~~~~ + +In some cases it is useful to limit the scope of a class to a +shared network, subnet, or pool. There are two parameters which are used +to limit the scope of the class by instructing the server to evaluate test +expressions when required. + +The first one is the per-class ``only-if-required`` flag, which is ``false`` +by default. When it is set to ``true``, the test expression of the class +is not evaluated at the reception of the incoming packet but later, and +only if the class evaluation is required. + +The second is ``require-client-classes``, which takes a list of class +names and is valid in shared-network, subnet, and pool scope. Classes in +these lists are marked as required and evaluated after selection of this +specific shared network/subnet/pool and before output-option processing. + +In this example, a class is assigned to the incoming packet when the +specified subnet is used: + +:: + + "Dhcp6": { + "client-classes": [ + { + "name": "Client_foo", + "test": "member('ALL')", + "only-if-required": true + }, + ... + ], + "subnet6": [ + { + "subnet": "2001:db8:1::/64", + "pools": [ + { + "pool": "2001:db8:1::-2001:db8:1::ffff" + } + ], + "require-client-classes": [ "Client_foo" ], + ... + }, + ... + ], + ... + } + +Required evaluation can be used to express complex dependencies like +subnet membership. It can also be used to reverse the +precedence; if ``option-data`` is set in a subnet, it takes precedence +over ``option-data`` in a class. If ``option-data`` is moved to a +required class and required in the subnet, a class evaluated earlier +may take precedence. + +Required evaluation is also available at shared-network and pool/pd-pool +levels. The order in which required classes are considered is: +shared-network, subnet, and (pd-)pool, i.e. in the reverse order from the +way in which ``option-data`` is processed. + +.. _dhcp6-ddns-config: + +DDNS for DHCPv6 +--------------- + +As mentioned earlier, :iscman:`kea-dhcp6` can be configured to generate requests +to the DHCP-DDNS server, :iscman:`kea-dhcp-ddns`, (referred to herein as "D2") to +update DNS entries. These requests are known as NameChangeRequests or +NCRs. Each NCR contains the following information: + +1. Whether it is a request to add (update) or remove DNS entries. + +2. Whether the change requests forward DNS updates (AAAA records), reverse + DNS updates (PTR records), or both. + +3. The Fully Qualified Domain Name (FQDN), lease address, and DHCID + (information identifying the client associated with the FQDN). + +DDNS-related parameters are split into two groups: + +1. Connectivity Parameters + + These are parameters which specify where and how :iscman:`kea-dhcp6` connects to + and communicates with D2. These parameters can only be specified + within the top-level ``dhcp-ddns`` section in the :iscman:`kea-dhcp6` + configuration. The connectivity parameters are listed below: + + - ``enable-updates`` + - ``server-ip`` + - ``server-port`` + - ``sender-ip`` + - ``sender-port`` + - ``max-queue-size`` + - ``ncr-protocol`` + - ``ncr-format"`` + +2. Behavioral Parameters + + These parameters influence behavior such as how client host names and + FQDN options are handled. They have been moved out of the ``dhcp-ddns`` + section so that they may be specified at the global, shared-network, + and/or subnet levels. Furthermore, they are inherited downward from global to + shared-network to subnet. In other words, if a parameter is not specified at + a given level, the value for that level comes from the level above it. + The behavioral parameters are as follows: + + - ``ddns-send-updates`` + - ``ddns-override-no-update`` + - ``ddns-override-client-update`` + - ``ddns-replace-client-name"`` + - ``ddns-generated-prefix`` + - ``ddns-qualifying-suffix`` + - ``ddns-update-on-renew`` + - ``ddns-conflict-resolution-mode`` + - ``ddns-ttl-percent`` + - ``hostname-char-set`` + - ``hostname-char-replacement`` + +.. note:: + + For backward compatibility, configuration parsing still recognizes + the original behavioral parameters specified in ``dhcp-ddns``, + by translating the parameter into its global equivalent. If a + parameter is specified both globally and in ``dhcp-ddns``, the latter + value is ignored. In either case, a log is emitted explaining + what has occurred. Specifying these values within ``dhcp-ddns`` is + deprecated and support for it will be removed. + +The default configuration and values would appear as follows: + +:: + + "Dhcp6": { + "dhcp-ddns": { + // Connectivity parameters + "enable-updates": false, + "server-ip": "127.0.0.1", + "server-port":53001, + "sender-ip":"", + "sender-port":0, + "max-queue-size":1024, + "ncr-protocol":"UDP", + "ncr-format":"JSON" + }, + + // Behavioral parameters (global) + "ddns-send-updates": true, + "ddns-override-no-update": false, + "ddns-override-client-update": false, + "ddns-replace-client-name": "never", + "ddns-generated-prefix": "myhost", + "ddns-qualifying-suffix": "", + "ddns-update-on-renew": false, + "ddns-conflict-resolution-mode": "check-with-dhcid", + "hostname-char-set": "", + "hostname-char-replacement": "", + ... + } + +There are two parameters which determine if :iscman:`kea-dhcp6` +can generate DDNS requests to D2: the existing ``dhcp-ddns:enable-updates`` +parameter, which now only controls whether :iscman:`kea-dhcp6` connects to D2; +and the new behavioral parameter, ``ddns-send-updates``, which determines +whether DDNS updates are enabled at a given level (i.e. global, shared-network, +or subnet). The following table shows how the two parameters function +together: + +.. table:: Enabling and disabling DDNS updates + + +-----------------+--------------------+-------------------------------------+ + | dhcp-ddns: | Global | Outcome | + | enable-updates | ddns-send-updates | | + +=================+====================+=====================================+ + | false (default) | false | no updates at any scope | + +-----------------+--------------------+-------------------------------------+ + | false | true (default) | no updates at any scope | + +-----------------+--------------------+-------------------------------------+ + | true | false | updates only at scopes with | + | | | a local value of ``true`` for | + | | | ``ddns-enable-updates`` | + +-----------------+--------------------+-------------------------------------+ + | true | true | updates at all scopes except those | + | | | with a local value of ``false`` | + | | | for ``ddns-enable-updates`` | + +-----------------+--------------------+-------------------------------------+ + +Kea 1.9.1 added two new parameters; the first is ``ddns-update-on-renew``. +Normally, when leases are renewed, the server only updates DNS if the DNS +information for the lease (e.g. FQDN, DNS update direction flags) has changed. +Setting ``ddns-update-on-renew`` to ``true`` instructs the server to always update +the DNS information when a lease is renewed, even if its DNS information has not +changed. This allows Kea to "self-heal" if it was previously unable +to add DNS entries or they were somehow lost by the DNS server. + +.. note:: + + Setting ``ddns-update-on-renew`` to ``true`` may impact performance, especially + for servers with numerous clients that renew often. + +The second parameter added in Kea 1.9.1 is ``ddns-use-conflict-resolution``. This +boolean parameter was passed through to D2 and enabled or disabled conflict resolution +as described in `RFC 4703 <https://tools.ietf.org/html/rfc4703>`__. Beginning with +Kea 2.5.0, it is deprecated and replaced by ``ddns-conflict-resolution-mode`` which +offers four modes of conflict resolution-related behavior: + + - ``check-with-dhcid`` - The default mode, it instructs D2 to carry out RFC + 4703-compliant conflict resolution. Existing DNS entries may only be + overwritten if they have a DHCID record and it matches the client's DHCID. + This is equivalent to ``ddns-use-conflict-resolution``: true; + + - ``no-check-with-dhcid`` - Existing DNS entries may be overwritten by any + client, whether or not those entries include a DHCID record. The new entries + will include a DHCID record for the client to whom they belong. + This is equivalent to ``ddns-use-conflict-resolution``: false; + + - ``check-exists-with-dhcid`` - Existing DNS entries may only be overwritten + if they have a DHCID record. The DHCID record need not match the client's DHCID. + This mode provides a way to protect static DNS entries (those that do not have + a DHCID record) while allowing dynamic entries (those that do have a DHCID + record) to be overwritten by any client. This behavior was not supported + prior to Kea 2.4.0. + + - ``no-check-without-dhcid`` - Existing DNS entries may be overwritten by + any client. New entries will not include DHCID records. This behavior was + not supported prior to Kea 2.4.0. + +.. note:: + + For backward compatibility, ddns-use-conflict-resolution is still accepted in + JSON configuration. The server will replace the value internally, with the + ``ddns-conflict-resolution-mode`` and an appropriate value: ` + `check-with-dhcid`` for ``true`` and ``no-check-with-dhcid`` for ``false``. + +.. note:: + + Setting ``ddns-conflict-resolution-mode`` to any value other than + ``check-with-dhcid`` disables the one or more overwrite safeguards + that the rules of conflict resolution (from + `RFC 4703 <https://tools.ietf.org/html/rfc4703>`__) are intended to + prevent. This means that existing entries for an FQDN or an + IP address made for Client-A can be deleted or replaced by entries + for Client-B. Furthermore, there are two scenarios by which entries + for multiple clients for the same key (e.g. FQDN or IP) can be created. + + 1. Client-B uses the same FQDN as Client-A but a different IP address. + In this case, the forward DNS entries (AAAA and DHCID RRs) for + Client-A will be deleted as they match the FQDN and new entries for + Client-B will be added. The reverse DNS entries (PTR and DHCID RRs) + for Client-A, however, will not be deleted as they belong to a different + IP address, while new entries for Client-B will still be added. + + 2. Client-B uses the same IP address as Client-A but a different FQDN. + In this case the reverse DNS entries (PTR and DHCID RRs) for Client-A + will be deleted as they match the IP address, and new entries for + Client-B will be added. The forward DNS entries (AAAA and DHCID RRs) + for Client-A, however, will not be deleted, as they belong to a different + FQDN, while new entries for Client-B will still be added. + + Disabling conflict resolution should be done only after careful review of + specific use cases. The best way to avoid unwanted DNS entries is to + always ensure lease changes are processed through Kea, whether they are + released, expire, or are deleted via the :isccmd:`lease6-del` command, prior to + reassigning either FQDNs or IP addresses. Doing so causes :iscman:`kea-dhcp6` + to generate DNS removal requests to D2. + +The DNS entries Kea creates contain a value for TTL (time to live). +The :iscman:`kea-dhcp6` server calculates that value based on +`RFC 4702, Section 5 <https://tools.ietf.org/html/rfc4702#section-5>`__, +which suggests that the TTL value be 1/3 of the lease's lifetime, with +a minimum value of 10 minutes. + +The parameter ``ddns-ttl-percent``, when specified, +causes the TTL to be calculated as a simple percentage of the lease's +lifetime, using the parameter's value as the percentage. It is specified +as a decimal percent (e.g. .25, .75, 1.00) and may be specified at the +global, shared-network, and subnet levels. By default it is unspecified. + +.. _dhcpv6-d2-io-config: + +DHCP-DDNS Server Connectivity +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For NCRs to reach the D2 server, :iscman:`kea-dhcp6` must be able to communicate +with it. :iscman:`kea-dhcp6` uses the following configuration parameters to +control this communication: + +- ``enable-updates`` - Enables connectivity to :iscman:`kea-dhcp-ddns` such that DDNS + updates can be constructed and sent. + It must be ``true`` for NCRs to be generated and sent to D2. + It defaults to ``false``. + +- ``server-ip`` - This is the IP address on which D2 listens for requests. The + default is the local loopback interface at address 127.0.0.1. + Either an IPv4 or IPv6 address may be specified. + +- ``server-port`` - This is the port on which D2 listens for requests. The default + value is ``53001``. + +- ``sender-ip`` - This is the IP address which :iscman:`kea-dhcp6` uses to send requests to + D2. The default value is blank, which instructs :iscman:`kea-dhcp6` to select a + suitable address. + +- ``sender-port`` - This is the port which :iscman:`kea-dhcp6` uses to send requests to D2. + The default value of ``0`` instructs :iscman:`kea-dhcp6` to select a suitable port. + +- ``max-queue-size`` - This is the maximum number of requests allowed to queue + while waiting to be sent to D2. This value guards against requests + accumulating uncontrollably if they are being generated faster than + they can be delivered. If the number of requests queued for + transmission reaches this value, DDNS updating is turned off + until the queue backlog has been sufficiently reduced. The intent is + to allow the :iscman:`kea-dhcp4` server to continue lease operations without + running the risk that its memory usage grows without limit. The + default value is ``1024``. + +- ``ncr-protocol`` - This specifies the socket protocol to use when sending requests to + D2. Currently only UDP is supported. + +- ``ncr-format`` - This specifies the packet format to use when sending requests to D2. + Currently only JSON format is supported. + +By default, :iscman:`kea-dhcp-ddns` is assumed to be running on the same machine +as :iscman:`kea-dhcp6`, and all of the default values mentioned above should be +sufficient. If, however, D2 has been configured to listen on a different +address or port, these values must be altered accordingly. For example, if +D2 has been configured to listen on 2001:db8::5 port 900, the following +configuration is required: + +:: + + "Dhcp6": { + "dhcp-ddns": { + "server-ip": "2001:db8::5", + "server-port": 900, + ... + }, + ... + } + +.. _dhcpv6-d2-rules-config: + +When Does the :iscman:`kea-dhcp6` Server Generate a DDNS Request? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The :iscman:`kea-dhcp6` server follows the behavior prescribed for DHCP servers in +`RFC 4704 <https://tools.ietf.org/html/rfc4704>`__. It is important to keep +in mind that :iscman:`kea-dhcp6` makes the initial decision of when and what to +update and forwards that information to D2 in the form of NCRs. Carrying +out the actual DNS updates and dealing with such things as conflict +resolution are within the purview of D2 itself +(see :ref:`dhcp-ddns-server`). This section describes when :iscman:`kea-dhcp6` +generates NCRs and the configuration parameters that can be used to +influence this decision. It assumes that both the connectivity parameter +``enable-updates`` and the behavioral parameter ``ddns-send-updates``, +are ``true``. + +.. note:: + + Currently the interface between :iscman:`kea-dhcp6` and D2 only supports + requests which update DNS entries for a single IP address. If a lease + grants more than one address, :iscman:`kea-dhcp6` creates the DDNS update + request for only the first of these addresses. + +In general, :iscman:`kea-dhcp6` generates DDNS update requests when: + +1. A new lease is granted in response to a DHCPREQUEST; + +2. An existing lease is renewed but the FQDN associated with it has + changed; or + +3. An existing lease is released in response to a DHCPRELEASE. + +In the second case, lease renewal, two DDNS requests are issued: one +request to remove entries for the previous FQDN, and a second request to +add entries for the new FQDN. In the third case, a lease release - a +single DDNS request - to remove its entries will be made. + +As for the first case, the decisions involved when granting a new lease are +more complex. When a new lease is granted, :iscman:`kea-dhcp6` generates a +DDNS update request only if the DHCPREQUEST contains the FQDN option +(code 39). +By default, :iscman:`kea-dhcp6` respects the FQDN N and S flags +specified by the client as shown in the following table: + +.. table:: Default FQDN flag behavior + + +------------+-----------------+-----------------+-------------+ + | Client | Client Intent | Server Response | Server | + | Flags:N-S | | | Flags:N-S-O | + +============+=================+=================+=============+ + | 0-0 | Client wants to | Server | 1-0-0 | + | | do forward | generates | | + | | updates, server | reverse-only | | + | | should do | request | | + | | reverse updates | | | + +------------+-----------------+-----------------+-------------+ + | 0-1 | Server should | Server | 0-1-0 | + | | do both forward | generates | | + | | and reverse | request to | | + | | updates | update both | | + | | | directions | | + +------------+-----------------+-----------------+-------------+ + | 1-0 | Client wants no | Server does not | 1-0-0 | + | | updates done | generate a | | + | | | request | | + +------------+-----------------+-----------------+-------------+ + +The first row in the table above represents "client delegation." Here +the DHCP client states that it intends to do the forward DNS updates and +the server should do the reverse updates. By default, :iscman:`kea-dhcp6` +honors the client's wishes and generates a DDNS request to the D2 server +to update only reverse DNS data. The parameter +``ddns-override-client-update`` can be used to instruct the server to +override client delegation requests. When this parameter is ``true``, +:iscman:`kea-dhcp6` disregards requests for client delegation and generates a +DDNS request to update both forward and reverse DNS data. In this case, +the N-S-O flags in the server's response to the client will be 0-1-1 +respectively. + +(Note that the flag combination N=1, S=1 is prohibited according to `RFC +4702 <https://tools.ietf.org/html/rfc4702>`__. If such a combination is +received from the client, the packet will be dropped by :iscman:`kea-dhcp6`.) + +To override client delegation, set the following values in the +configuration file: + +:: + + "Dhcp6": { + "ddns-override-client-update": true, + ... + } + +The third row in the table above describes the case in which the client +requests that no DNS updates be done. The parameter +``ddns-override-no-update`` can be used to instruct the server to disregard +the client's wishes. When this parameter is ``true``, :iscman:`kea-dhcp6` +generates DDNS update requests to :iscman:`kea-dhcp-ddns` even if the client +requests that no updates be done. The N-S-O flags in the server's response to +the client will be 0-1-1. + +To override client delegation, issue the following commands: + +:: + + "Dhcp6": { + "ddns-override-no-update": true, + ... + } + +The :iscman:`kea-dhcp6` server always generates DDNS update requests if the +client request only contains the Host Name option. In addition, it includes +an FQDN option in the response to the client with the FQDN N-S-O flags +set to 0-1-0, respectively. The domain name portion of the FQDN option +is the name submitted to D2 in the DDNS update request. + +.. _dhcpv6-fqdn-name-generation: + +:iscman:`kea-dhcp6` Name Generation for DDNS Update Requests +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Each NameChangeRequest must of course include the fully qualified domain +name whose DNS entries are to be affected. :iscman:`kea-dhcp6` can be configured +to supply a portion or all of that name, based on what it receives +from the client in the DHCPREQUEST. + +The default rules for constructing the FQDN that will be used for DNS +entries are: + +1. If the DHCPREQUEST contains the client FQDN option, take the + candidate name from there. + +2. If the candidate name is a partial (i.e. unqualified) name, then add + a configurable suffix to the name and use the result as the FQDN. + +3. If the candidate name provided is empty, generate an FQDN using a + configurable prefix and suffix. + +4. If the client provides neither option, then take no DNS action. + +These rules can be amended by setting the ``ddns-replace-client-name`` +parameter, which provides the following modes of behavior: + +- ``never`` - use the name the client sent. If the client sent no name, + do not generate one. This is the default mode. + +- ``always`` - replace the name the client sent. If the client sent no + name, generate one for the client. + +- ``when-present`` - replace the name the client sent. If the client + sent no name, do not generate one. + +- ``when-not-present`` - use the name the client sent. If the client + sent no name, generate one for the client. + +.. note:: + + In early versions of Kea, this parameter was a boolean and permitted only + values of ``true`` and ``false``. Boolean values have been deprecated + and are no longer accepted. Administrators currently using booleans + must replace them with the desired mode name. A value of ``true`` + maps to ``when-present``, while ``false`` maps to ``never``. + +For example, to instruct :iscman:`kea-dhcp6` to always generate the FQDN for a +client, set the parameter ``ddns-replace-client-name`` to ``always`` as +follows: + +:: + + "Dhcp6": { + "ddns-replace-client-name": "always", + ... + } + +The prefix used in the generation of an FQDN is specified by the +``ddns-generated-prefix`` parameter. The default value is "myhost". To alter +its value, simply set it to the desired string: + +:: + + "Dhcp6": { + "ddns-generated-prefix": "another.host", + ... + } + +The suffix used when generating an FQDN, or when qualifying a partial +name, is specified by the ``ddns-qualifying-suffix`` parameter. It is +strongly recommended that the user supply a value for the qualifying +suffix when DDNS updates are enabled. For obvious reasons, we cannot +supply a meaningful default. + +:: + + "Dhcp6": { + "ddns-qualifying-suffix": "foo.example.org", + ... + } + +When qualifying a partial name, :iscman:`kea-dhcp6` constructs the name in the +format: + +``[candidate-name].[ddns-qualifying-suffix].`` + +where ``candidate-name`` is the partial name supplied in the DHCPREQUEST. +For example, if the FQDN domain name value is "some-computer" and the +``ddns-qualifying-suffix`` is "example.com", the generated FQDN is: + +``some-computer.example.com.`` + +When generating the entire name, :iscman:`kea-dhcp6` constructs the name in +the format: + +``[ddns-generated-prefix]-[address-text].[ddns-qualifying-suffix].`` + +where ``address-text`` is simply the lease IP address converted to a +hyphenated string. For example, if the lease address is 3001:1::70E, the +qualifying suffix is "example.com", and the default value is used for +``ddns-generated-prefix``, the generated FQDN is: + +``myhost-3001-1--70E.example.com.`` + +.. _dhcp6-host-name-sanitization: + +Sanitizing Client FQDN Names +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Some DHCP clients may provide values in the name component of the FQDN +option (option code 39) that contain undesirable +characters. It is possible to configure :iscman:`kea-dhcp6` to sanitize these +values. The most typical use case is ensuring that only characters that +are permitted by RFC 1035 be included: A-Z, a-z, 0-9, and "-". This may be +accomplished with the following two parameters: + +- ``hostname-char-set`` - a regular expression describing the invalid + character set. This can be any valid, regular expression using POSIX + extended expression syntax. Embedded nulls (0x00) are always + considered an invalid character to be replaced (or omitted). + The default is ``"[^A-Za-z0-9.-]"``. This matches any character that is not + a letter, digit, dot, hyphen, or null. + +- ``hostname-char-replacement`` - a string of zero or more characters + with which to replace each invalid character in the host name. An empty + string causes invalid characters to be OMITTED rather than replaced. + The default is ``""``. + +The following configuration replaces anything other than a letter, +digit, dot, or hyphen with the letter "x": +:: + + "Dhcp6": { + "hostname-char-set": "[^A-Za-z0-9.-]", + "hostname-char-replacement": "x", + ... + } + +Thus, a client-supplied value of "myhost-$[123.org" would become +"myhost-xx123.org". Sanitizing is performed only on the portion of the +name supplied by the client, and it is performed before applying a +qualifying suffix (if one is defined and needed). + +.. note:: + + Name sanitizing is meant to catch the more common cases of invalid + characters through a relatively simple character-replacement scheme. + It is difficult to devise a scheme that works well in all cases. + Administrators who find they have clients with odd corner cases of + character combinations that cannot be readily handled with this + mechanism should consider writing a hook that can carry out + sufficiently complex logic to address their needs. + + Make sure that the dot, "." is considered a valid character by the + ``hostname-char-set`` expression, such as this: ``"[^A-Za-z0-9.-]"``. + When scrubbing FQDNs, dots are treated as delimiters and used to separate + the option value into individual domain labels that are scrubbed and + then re-assembled. + + If clients are sending values that differ only by characters + considered as invalid by the ``hostname-char-set``, be aware that + scrubbing them will yield identical values. In such cases, DDNS + conflict rules will permit only one of them to register the name. + + Finally, given the latitude clients have in the values they send, it + is virtually impossible to guarantee that a combination of these two + parameters will always yield a name that is valid for use in DNS. For + example, using an empty value for ``hostname-char-replacement`` could + yield an empty domain label within a name, if that label consists + only of invalid characters. + +.. note:: + + It is possible to specify ``hostname-char-set`` + and/or ``hostname-char-replacement`` at the global scope. This allows + host names to be sanitized without requiring a ``dhcp-ddns`` entry. When + a ``hostname-char`` parameter is defined at both the global scope and + in a ``dhcp-ddns`` entry, the second (local) value is used. + + For the ability to generate host names procedurally, based on an expression, and + for the ability to skip DDNS updates on a per-client basis, or fine-tuning various + DNS update aspects, the :iscman:`kea-dhcp6` can load the premium hook library + `libdhcp_ddns_tuning.so` which is available from ISC. Please refer to + :ref:`hooks-ddns-tuning` documentation for the configuration options. + +.. _dhcp6-dhcp4o6-config: + +DHCPv4-over-DHCPv6: DHCPv6 Side +------------------------------- + +The support of DHCPv4-over-DHCPv6 transport is described in `RFC +7341 <https://tools.ietf.org/html/rfc7341>`__ and is implemented using +cooperating DHCPv4 and DHCPv6 servers. This section is about the +configuration of the DHCPv6 side (the DHCPv4 side is described in +:ref:`dhcp4-dhcp4o6-config`). + +.. note:: + + DHCPv4-over-DHCPv6 support is experimental and the details of the + inter-process communication may change; for instance, the + support of port relay (RFC 8357) introduced an incompatible change. + Both the DHCPv4 and DHCPv6 sides should be running the same version of Kea. + +There is only one specific parameter for the DHCPv6 side: +``dhcp4o6-port``, which specifies the first of the two consecutive ports +of the UDP sockets used for the communication between the DHCPv6 and +DHCPv4 servers. The DHCPv6 server is bound to ::1 on ``port`` and +connected to ::1 on ``port`` + 1. + +Two other configuration entries are generally required: unicast traffic +support (see :ref:`dhcp6-unicast`) and the DHCP 4o6 +server address option (name "dhcp4o6-server-addr", code 88). + +ISC tested the following configuration: + +:: + + { + + # DHCPv6 conf + "Dhcp6": { + + "interfaces-config": { + "interfaces": [ "eno33554984/2001:db8:1:1::1" ] + }, + + "lease-database": { + "type": "memfile", + "name": "leases6" + }, + + "preferred-lifetime": 3000, + "valid-lifetime": 4000, + "renew-timer": 1000, + "rebind-timer": 2000, + + "subnet6": [ { + "id": 1, + "subnet": "2001:db8:1:1::/64", + "interface": "eno33554984", + "pools": [ { "pool": "2001:db8:1:1::1:0/112" } ] + } ], + + "dhcp4o6-port": 6767, + + "option-data": [ { + "name": "dhcp4o6-server-addr", + "code": 88, + "space": "dhcp6", + "csv-format": true, + "data": "2001:db8:1:1::1" + } ], + + + "loggers": [ { + "name": "kea-dhcp6", + "output-options": [ { + "output": "/tmp/kea-dhcp6.log" + } ], + "severity": "DEBUG", + "debuglevel": 0 + } ] + } + + } + +.. note:: + + Relayed DHCPv4-QUERY DHCPv6 messages are not supported. + +.. _sanity-checks6: + +Sanity Checks in DHCPv6 +----------------------- + +An important aspect of a well-running DHCP system is an assurance that +the data remains consistent; however, in some cases it may be convenient +to tolerate certain inconsistent data. For example, a network +administrator who temporarily removes a subnet from a configuration +would not want all the leases associated with it to disappear from the +lease database. Kea has a mechanism to implement sanity checks for situations +like this. + +Kea supports a configuration scope called ``sanity-checks``. +A parameter, called ``lease-checks``, +governs the verification carried out when a new lease is loaded from a +lease file. This mechanism permits Kea to attempt to correct inconsistent data. + +Every subnet has a ``subnet-id`` value; this is how Kea internally +identifies subnets. Each lease has a ``subnet-id`` parameter as well, which +identifies the subnet it belongs to. However, if the configuration has +changed, it is possible that a lease could exist with a ``subnet-id`` but +without any subnet that matches it. Also, it is possible that the +subnet's configuration has changed and the ``subnet-id`` now belongs to a +subnet that does not match the lease. + +Kea's corrective algorithm first +checks to see if there is a subnet with the ``subnet-id`` specified by the +lease. If there is, it verifies whether the lease belongs to that +subnet. If not, depending on the ``lease-checks`` setting, the lease is +discarded, a warning is displayed, or a new subnet is selected for the +lease that matches it topologically. + +Since delegated prefixes do not have to belong to a subnet in which +they are offered, there is no way to implement such a mechanism for IPv6 +prefixes. As such, the mechanism works for IPv6 addresses only. + +There are five levels which are supported: + +- ``none`` - do no special checks; accept the lease as is. + +- ``warn`` - if problems are detected display a warning, but + accept the lease data anyway. This is the default value. + +- ``fix`` - if a data inconsistency is discovered, try to + correct it. If the correction is not successful, insert the incorrect data + anyway. + +- ``fix-del`` - if a data inconsistency is discovered, try to + correct it. If the correction is not successful, reject the lease. + This setting ensures the data's correctness, but some + incorrect data may be lost. Use with care. + +- ``del`` - if any inconsistency is + detected, reject the lease. This is the strictest mode; use with care. + +This feature is currently implemented for the memfile backend. The +sanity check applies to the lease database in memory, not to the lease file, +i.e. inconsistent leases will stay in the lease file. + +An example configuration that sets this parameter looks as follows: + +:: + + "Dhcp6": { + "sanity-checks": { + "lease-checks": "fix-del" + }, + ... + } + +.. _store-extended-info-v6: + +Storing Extended Lease Information +---------------------------------- +To support such features as DHCPv6 Reconfigure +(`RFC 3315 <https://tools.ietf.org/html/rfc3315>`__) and Leasequery +(`RFC 5007 <https://tools.ietf.org/html/rfc5007>`__), +additional information must be stored with each lease. Because the amount +of information stored for each lease has ramifications in terms of +performance and system resource consumption, storage of this additional +information is configurable through the ``store-extended-info`` parameter. +It defaults to ``false`` and may be set at the global, shared-network, and +subnet levels. + +:: + + "Dhcp6": { + "store-extended-info": true, + ... + } + +When set to ``true``, information relevant to the DHCPv6 query (e.g. REQUEST, RENEW, +or REBIND) asking for the lease is added into the lease's ``user-context`` as a +map element labeled "ISC". Currently, the information contained in the map +is a list of relays, one for each relay message layer that encloses the +client query. The lease's +``user-context`` for a two-hop query might look something like this (shown +pretty-printed for clarity): + +:: + + { + "ISC": { + "relay-info": [ + { + "hop": 3, + "link": "2001:db8::1", + "peer": "2001:db8::2" + }, + { + "hop": 2, + "link": "2001:db8::3", + "options": "0x00C800080102030405060708", + "peer": "2001:db8::4" + }, + { + "hop": 1, + "link": "2001:db8::5", + "options": "0x00250006010203040506003500086464646464646464", + "remote-id": "010203040506", + "relay-id": "6464646464646464" + } + ] + } + } + +.. note:: + + Prior to Kea version 2.3.2, this entry was named ``relays``; remote and relay + identifier options were not decoded. + +.. note:: + + It is possible that other hook libraries are already using + ``user-context``. Enabling ``store-extended-info`` should not interfere with + any other ``user-context`` content, as long as it does not also use an element + labeled "ISC". In other words, ``user-context`` is intended to be a flexible + container serving multiple purposes. As long as no other purpose also + writes an "ISC" element to ``user-context`` there should not be a conflict. + +Extended lease information is also subject to configurable sanity checking. +The parameter in the ``sanity-checks`` scope is named ``extended-info-checks`` +and supports these levels: + +- ``none`` - do no check nor upgrade. This level should be used only when + extended info is not used at all or when no badly formatted extended + info, including using the old format, is expected. + +- ``fix`` - fix some common inconsistencies and upgrade extended info + using the old format to the new one. It is the default level and is + convenient when the Leasequery hook library is not loaded. + +- ``strict`` - fix all inconsistencies which have an impact on the (Bulk) + Leasequery hook library. + +- ``pedantic`` - enforce full conformance to the format produced by the + Kea code; for instance, no extra entries are allowed with the exception + of ``comment``. + +.. note:: + + This feature is currently implemented only for the memfile + backend. The sanity check applies to the lease database in memory, + not to the lease file, i.e. inconsistent leases stay in the lease + file. + +.. _dhcp6-multi-threading-settings: + +Multi-Threading Settings +------------------------ + +The Kea server can be configured to process packets in parallel using multiple +threads. These settings can be found under the ``multi-threading`` structure and are +represented by: + +- ``enable-multi-threading`` - use multiple threads to process packets in + parallel. The default is ``true``. + +- ``thread-pool-size`` - specify the number of threads to process packets in + parallel. It may be set to ``0`` (auto-detect), or any positive number that + explicitly sets the thread count. The default is ``0``. + +- ``packet-queue-size`` - specify the size of the queue used by the thread + pool to process packets. It may be set to ``0`` (unlimited), or any positive + number that explicitly sets the queue size. The default is ``64``. + +An example configuration that sets these parameters looks as follows: + +:: + + "Dhcp6": { + "multi-threading": { + "enable-multi-threading": true, + "thread-pool-size": 4, + "packet-queue-size": 16 + }, + ... + } + +Multi-Threading Settings With Different Database Backends +--------------------------------------------------------- + +The Kea DHCPv6 server is benchmarked by ISC to determine which settings +give the best performance. Although this section describes our results, they are merely +recommendations and are very dependent on the particular hardware used +for benchmarking. We strongly advise that administrators run their own performance benchmarks. + +A full report of performance results for the latest stable Kea version can be found +`here <https://reports.kea.isc.org/>`_. +This includes hardware and benchmark scenario descriptions, as well as +current results. + +After enabling multi-threading, the number of threads is set by the ``thread-pool-size`` +parameter. Results from our experiments show that the best settings for +:iscman:`kea-dhcp6` are: + +- ``thread-pool-size``: 4 when using ``memfile`` for storing leases. + +- ``thread-pool-size``: 12 or more when using ``mysql`` for storing leases. + +- ``thread-pool-size``: 6 when using ``postgresql``. + +Another very important parameter is ``packet-queue-size``; in our benchmarks we +used it as a multiplier of ``thread-pool-size``. The actual setting strongly depends +on ``thread-pool-size``. + +We saw the best results in our benchmarks with the following settings: + +- ``packet-queue-size``: 150 * ``thread-pool-size`` when using ``memfile`` for + storing leases; in our case it was 150 * 4 = 600. This means that at any given + time, up to 600 packets could be queued. + +- ``packet-queue-size``: 200 * ``thread-pool-size`` when using ``mysql`` for + storing leases; in our case it was 200 * 12 = 2400. This means that up to + 2400 packets could be queued. + +- ``packet-queue-size``: 11 * ``thread-pool-size`` when using ``postgresql`` for + storing leases; in our case it was 11 * 6 = 66. + +Lease Caching +------------- + +Clients that attempt multiple renewals in a short period can cause the server to update +and write to the database frequently, resulting in a performance impact +on the server. The cache parameters instruct the DHCP server to avoid +updating leases too frequently, thus avoiding this behavior. Instead, +the server assigns the same lease (i.e. reuses it) with no +modifications except for CLTT (Client Last Transmission Time), which +does not require disk operations. + +The two parameters are the ``cache-threshold`` double and the +``cache-max-age`` integer; they have no default setting, i.e. the lease caching +feature must be explicitly enabled. These parameters can be configured +at the global, shared-network, and subnet levels. The subnet level has +the precedence over the shared-network level, while the global level is used +as a last resort. For example: + +:: + + { + "subnet6": [ + { + "subnet": "2001:db8:1:1::/64", + "pools": [ { "pool": "2001:db8:1:1::1:0/112" } ], + "cache-threshold": .25, + "cache-max-age": 600, + "valid-lifetime": 2000, + ... + } + ], + ... + } + +When an already-assigned lease can fulfill a client query: + + - any important change, e.g. for DDNS parameter, hostname, or + preferred or valid lifetime reduction, makes the lease not reusable. + + - lease age, i.e. the difference between the creation or last modification + time and the current time, is computed (elapsed duration). + + - if ``cache-max-age`` is explicitly configured, it is compared with the lease age; + leases that are too old are not reusable. This means that the value 0 + for ``cache-max-age`` disables the lease cache feature. + + - if ``cache-threshold`` is explicitly configured and is between 0.0 and 1.0, + it expresses the percentage of the lease valid lifetime which is + allowed for the lease age. Values below and including 0.0 and + values greater than 1.0 disable the lease cache feature. + +In our example, a lease with a valid lifetime of 2000 seconds can be +reused if it was committed less than 500 seconds ago. With a lifetime +of 3000 seconds, a maximum age of 600 seconds applies. + +In outbound client responses (e.g. DHCPV6_REPLY messages), the used +preferred and valid lifetimes are the reusable values, i.e. the +expiration dates do not change. + +.. _host-reservation-v6: + +Host Reservations in DHCPv6 +=========================== + +There are many cases where it is useful to provide a configuration on a +per-host basis. The most obvious one is to reserve a specific, static +IPv6 address or/and prefix for exclusive use by a given client (host); +the returning client receives the same address and/or prefix every time, +and other clients will never get that address. Host +reservations are also convenient when a host has specific requirements, +e.g. a printer that needs additional DHCP options or a cable modem that +needs specific parameters. Yet another possible use case is to define +unique names for hosts. + +There may be cases when a new reservation has been made for a +client for an address or prefix currently in use by another client. We +call this situation a "conflict." These conflicts get resolved +automatically over time, as described in subsequent sections. Once a +conflict is resolved, the correct client will receive the reserved +configuration when it renews. + +Host reservations are defined as parameters for each subnet. Each host +must be identified by either DUID or its hardware/MAC address; see +:ref:`mac-in-dhcpv6` for details. There +is an optional ``reservations`` array in the ``subnet6`` structure; each +element in that array is a structure that holds information about reservations for a +single host. In particular, the structure has an identifier that +uniquely identifies a host. In the DHCPv6 context, the identifier is +usually a DUID, but it can also be a hardware or MAC address. One or more +addresses or prefixes may also be specified, and it is possible to +specify a hostname and DHCPv6 options for a given host. + +.. note:: + + The reserved address must be within the subnet. + This does not apply to reserved prefixes. + +The following example shows how to reserve addresses and prefixes for +specific hosts: + +:: + + { + "subnet6": [ + { + "id": 1, + "subnet": "2001:db8:1::/48", + "pools": [ { "pool": "2001:db8:1::/80" } ], + "pd-pools": [ + { + "prefix": "2001:db8:1:8000::", + "prefix-len": 56, + "delegated-len": 64 + } + ], + "reservations": [ + { + "duid": "01:02:03:04:05:0A:0B:0C:0D:0E", + "ip-addresses": [ "2001:db8:1::100" ] + }, + { + "hw-address": "00:01:02:03:04:05", + "ip-addresses": [ "2001:db8:1::101", "2001:db8:1::102" ] + }, + { + "duid": "01:02:03:04:05:06:07:08:09:0A", + "ip-addresses": [ "2001:db8:1::103" ], + "prefixes": [ "2001:db8:2:abcd::/64" ], + "hostname": "foo.example.com" + } + ] + } + ], + ... + } + +This example includes reservations for three different clients. The +first reservation is for the address 2001:db8:1::100, for a client using +DUID 01:02:03:04:05:0A:0B:0C:0D:0E. The second reservation is for two +addresses, 2001:db8:1::101 and 2001:db8:1::102, for a client using MAC +address 00:01:02:03:04:05. Lastly, address 2001:db8:1::103 and prefix +2001:db8:2:abcd::/64 are reserved for a client using DUID +01:02:03:04:05:06:07:08:09:0A. The last reservation also assigns a +hostname to this client. + +DHCPv6 allows a single client to lease multiple addresses and +multiple prefixes at the same time. Therefore ``ip-addresses`` and +``prefixes`` are plural and are actually arrays. When the client sends +multiple IA options (IA_NA or IA_PD), each reserved address or prefix is +assigned to an individual IA of the appropriate type. If the number of +IAs of a specific type is lower than the number of reservations of that +type, the number of reserved addresses or prefixes assigned to the +client is equal to the number of IA_NAs or IA_PDs sent by the client; +that is, some reserved addresses or prefixes are not assigned. However, +they still remain reserved for this client and the server will not +assign them to any other client. If the number of IAs of a specific type +sent by the client is greater than the number of reserved addresses or +prefixes, the server will try to assign all reserved addresses or +prefixes to the individual IAs and dynamically allocate addresses or +prefixes to the remaining IAs. If the server cannot assign a reserved +address or prefix because it is in use, the server will select the next +reserved address or prefix and try to assign it to the client. If the +server subsequently finds that there are no more reservations that can +be assigned to the client at that moment, the server will try to assign +leases dynamically. + +Making a reservation for a mobile host that may visit multiple subnets +requires a separate host definition in each subnet that host is expected to +visit. It is not possible to define multiple host definitions with the +same hardware address in a single subnet. Multiple host definitions with +the same hardware address are valid if each is in a different subnet. +The reservation for a given host should include only one identifier, +either DUID or hardware address; defining both for the same host is +considered a configuration error. + +Adding host reservations incurs a performance penalty. In principle, +when a server that does not support host reservation responds to a +query, it needs to check whether there is a lease for a given address +being considered for allocation or renewal. The server that does +support host reservation has to perform additional checks: not only +whether the address is currently used (i.e., if there is a lease for +it), but also whether the address could be used by someone else (i.e., +if there is a reservation for it). That additional check incurs extra +overhead. + +.. _reservation6-types: + +Address/Prefix Reservation Types +-------------------------------- + +In a typical Kea scenario there is an IPv6 subnet defined, with a certain +part of it dedicated for dynamic address allocation by the DHCPv6 +server. There may be an additional address space defined for prefix +delegation. Those dynamic parts are referred to as dynamic pools, +address and prefix pools, or simply pools. In principle, a host +reservation can reserve any address or prefix that belongs to the +subnet. The reservations that specify addresses that belong to +configured pools are called "in-pool reservations." In contrast, those +that do not belong to dynamic pools are called "out-of-pool +reservations." There is no formal difference in the reservation syntax +and both reservation types are handled uniformly. + +Kea supports global host reservations. These are reservations that are +specified at the global level within the configuration and that do not +belong to any specific subnet. Kea still matches inbound client +packets to a subnet as before, but when the subnet's reservation mode is +set to "global", Kea looks for host reservations only among the +global reservations defined. Typically, such reservations would be used +to reserve hostnames for clients which may move from one subnet to +another. + +.. note:: + + Global reservations, while useful in certain circumstances, have aspects + that must be given due consideration when using them. Please see + :ref:`reservation6-conflict` for more details. + +.. note:: + + Since Kea 1.9.1, reservation mode has been replaced by three + boolean flags, ``reservations-global``, ``reservations-in-subnet`` + and ``reservations-out-of-pool``, which allow the configuration of + host reservations both globally and in a subnet. In such cases a subnet + host reservation has preference over a global reservation + when both exist for the same client. + +.. _reservation6-conflict: + +Conflicts in DHCPv6 Reservations +-------------------------------- + +As reservations and lease information are stored separately, conflicts +may arise. Consider the following series of events: the server has +configured the dynamic pool of addresses from the range of 2001:db8::10 +to 2001:db8::20. Host A requests an address and gets 2001:db8::10. Now +the system administrator decides to reserve address 2001:db8::10 for +Host B. In general, reserving an address that is currently assigned to +someone else is not recommended, but there are valid use cases where +such an operation is warranted. + +The server now has a conflict to resolve. If Host B boots up and +requests an address, the server cannot immediately assign the reserved +address 2001:db8::10. A naive approach would to be immediately remove +the lease for Host A and create a new one for Host B. That would not +solve the problem, though, because as soon as Host B gets the address, +it will detect that the address is already in use (by Host +A) and will send a DHCPDECLINE message. Therefore, in this situation, +the server has to temporarily assign a different address from the +dynamic pool (not matching what has been reserved) to Host B. + +When Host A renews its address, the server will discover that the +address being renewed is now reserved for someone else - Host B. +The server will remove the lease for 2001:db8::10, select a +new address, and create a new lease for it. It will send two addresses +in its response: the old address, with the lifetime set to 0 to explicitly +indicate that it is no longer valid; and the new address, with a +non-zero lifetime. When Host B tries to renew its temporarily assigned address, +the server will detect that the existing lease does not match the +reservation, so it will release the current address Host B has and will +create a new lease matching the reservation. As before, the server will +send two addresses: the temporarily assigned one with a zero lifetime, +and the new one that matches the reservation with the proper lifetime set. + +This recovery will succeed, even if other hosts attempt to get the +reserved address. If Host C requests the address 2001:db8::10 after the +reservation is made, the server will propose a different address. + +This recovery mechanism allows the server to fully recover from a case +where reservations conflict with existing leases; however, this procedure +takes roughly as long as the value set for ``renew-timer``. The +best way to avoid such a recovery is not to define new reservations that +conflict with existing leases. Another recommendation is to use +out-of-pool reservations; if the reserved address does not belong to a +pool, there is no way that other clients can get it. + +.. note:: + + The conflict-resolution mechanism does not work for global + reservations. Although the global address reservations feature may be useful + in certain settings, it is generally recommended not to use + global reservations for addresses. Administrators who do choose + to use global reservations must manually ensure that the reserved + addresses are not in dynamic pools. + +.. _reservation6-hostname: + +Reserving a Hostname +-------------------- + +When the reservation for a client includes the ``hostname``, the server +assigns this hostname to the client and sends it back in the Client +FQDN option, if the client included the Client FQDN option in its message +to the server. The reserved hostname always takes precedence over the +hostname supplied by the client (via the FQDN option) or the autogenerated +(from the IPv6 address) hostname. + +The server qualifies the reserved hostname with the value of the +``ddns-qualifying-suffix`` parameter. For example, the following subnet +configuration: + +:: + + { + "subnet6": [ + { + "id": 1, + "subnet": "2001:db8:1::/48", + "pools": [ { "pool": "2001:db8:1::/80" } ], + "ddns-qualifying-suffix": "example.isc.org.", + "reservations": [ + { + "duid": "01:02:03:04:05:0A:0B:0C:0D:0E", + "ip-addresses": [ "2001:db8:1::100" ], + "hostname": "alice-laptop" + } + ] + } + ], + "dhcp-ddns": { + "enable-updates": true + }, + ... + } + +will result the "alice-laptop.example.isc.org." hostname being assigned to +the client using the DUID "01:02:03:04:05:0A:0B:0C:0D:0E". If the +``ddns-qualifying-suffix`` is not specified, the default (empty) value will +be used, and in this case the value specified as a ``hostname`` will be +treated as a fully qualified name. Thus, by leaving the +``ddns-qualifying-suffix`` empty it is possible to qualify hostnames for +different clients with different domain names: + +.. code-block:: json + + { + "subnet6": [ + { + "id": 1, + "subnet": "2001:db8:1::/48", + "pools": [ { "pool": "2001:db8:1::/80" } ], + "reservations": [ + { + "duid": "01:02:03:04:05:0A:0B:0C:0D:0E", + "ip-addresses": [ "2001:db8:1::100" ], + "hostname": "mark-desktop.example.org." + } + ] + } + ], + "dhcp-ddns": { + "enable-updates": true + } + } + +The above example results in the assignment of the +"mark-desktop.example.org." hostname to the client using the DUID +"01:02:03:04:05:0A:0B:0C:0D:0E". + +.. _reservation6-options: + +Including Specific DHCPv6 Options in Reservations +------------------------------------------------- + +Kea offers the ability to specify options on a per-host basis. These +options follow the same rules as any other options. These can be +standard options (see :ref:`dhcp6-std-options`), +custom options (see :ref:`dhcp6-custom-options`), +or vendor-specific options (see :ref:`dhcp6-vendor-opts`). The following +example demonstrates how standard options can be defined. + +:: + + { + "reservations": [ + { + "duid": "01:02:03:05:06:07:08", + "ip-addresses": [ "2001:db8:1::2" ], + "option-data": [ + { + "name": "dns-servers", + "data": "3000:1::234" + }, + { + "name": "nis-servers", + "data": "3000:1::234" + }, + ... + ], + ... + }, + ... + ], + ... + } + +Vendor-specific options can be reserved in a similar manner: + +:: + + { + "reservations": [ + { + "duid": "aa:bb:cc:dd:ee:ff", + "ip-addresses": [ "2001:db8::1" ], + "option-data": [ + { + "name": "vendor-opts", + "data": 4491 + }, + { + "name": "tftp-servers", + "space": "vendor-4491", + "data": "3000:1::234" + }, + ... + ], + ... + }, + ... + ], + ... + } + +Options defined at the host level have the highest priority. In other words, +if there are options defined with the same type on global, subnet, +class, and host levels, the host-specific values are used. + +.. _reservation6-client-classes: + +Reserving Client Classes in DHCPv6 +---------------------------------- + +:ref:`classification-using-expressions` explains how to configure +the server to assign classes to a client, based on the content of the +options that this client sends to the server. Host reservation +mechanisms also allow for the static assignment of classes to clients. +The definitions of these classes are placed in the Kea configuration file or +a database. The following configuration snippet shows how to specify that +a client belongs to the classes ``reserved-class1`` and ``reserved-class2``. Those +classes are associated with specific options sent to the clients which belong +to them. + +:: + + { + "client-classes": [ + { + "name": "reserved-class1", + "option-data": [ + { + "name": "dns-servers", + "data": "2001:db8:1::50" + } + ] + }, + { + "name": "reserved-class2", + "option-data": [ + { + "name": "nis-servers", + "data": "2001:db8:1::100" + } + ] + } + ], + "subnet6": [ + { + "id": 1, + "pools": [ { "pool": "2001:db8:1::/64" } ], + "subnet": "2001:db8:1::/48", + "reservations": [ + { + "duid": "01:02:03:04:05:06:07:08", + + "client-classes": [ "reserved-class1", "reserved-class2" ] + + } + ] + } ] + } + +In some cases the host reservations can be used in conjunction with client +classes specified within the Kea configuration. In particular, when a +host reservation exists for a client within a given subnet, the "KNOWN" +built-in class is assigned to the client. Conversely, when there is no +static assignment for the client, the "UNKNOWN" class is assigned to the +client. Class expressions within the Kea configuration file can +refer to "KNOWN" or "UNKNOWN" classes using the "member" operator. +For example: + +:: + + { + "client-classes": [ + { + "name": "dependent-class", + "test": "member('KNOWN')", + "only-if-required": true + } + ] + } + +The ``only-if-required`` parameter is needed here to force +evaluation of the class after the lease has been allocated and thus the +reserved class has been also assigned. + +.. note:: + + The classes specified in non-global host reservations + are assigned to the processed packet after all classes with the + ``only-if-required`` parameter set to ``false`` have been evaluated. + This means that these classes must not depend on the + statically assigned classes from the host reservations. If + such a dependency is needed, the ``only-if-required`` must + be set to ``true`` for the dependent classes. Such classes are + evaluated after the static classes have been assigned to the packet. + This, however, imposes additional configuration overhead, because + all classes marked as ``only-if-required`` must be listed in the + ``require-client-classes`` list for every subnet where they are used. + +.. note:: + + Client classes specified within the Kea configuration file may + depend on the classes specified within the global host reservations. + In such a case the ``only-if-required`` parameter is not needed. + Refer to the :ref:`pool-selection-with-class-reservations6` and + :ref:`subnet-selection-with-class-reservations6` + for specific use cases. + +.. _reservations6-mysql-pgsql: + +Storing Host Reservations in MySQL or PostgreSQL +------------------------------------------------ + +Kea can store host reservations in MySQL or PostgreSQL. +See :ref:`hosts6-storage` for information on how to +configure Kea to use reservations stored in MySQL or PostgreSQL. +Kea provides a dedicated hook for managing reservations in a +database; section :ref:`hooks-host-cmds` provides detailed information. +The `Kea wiki +<https://gitlab.isc.org/isc-projects/kea/wikis/designs/commands#23-host-reservations-hr-management>`__ +provides some examples of how to conduct common host reservation +operations. + +.. note:: + + In Kea, the maximum length of an option specified per-host is + arbitrarily set to 4096 bytes. + +.. _reservations6-tuning: + +Fine-Tuning DHCPv6 Host Reservation +----------------------------------- + +The host reservation capability introduces additional restrictions for +the allocation engine (the component of Kea that selects an address for +a client) during lease selection and renewal. In particular, three major +checks are necessary. First, when selecting a new lease, it is not +sufficient for a candidate lease to simply not be in use by another DHCP +client; it also must not be reserved for another client. Similarly, when +renewing a lease, an additional check must be performed to see whether +the address being renewed is reserved for another client. Finally, when +a host renews an address or a prefix, the server must check whether +there is a reservation for this host, which would mean the existing (dynamically +allocated) address should be revoked and the reserved one be used +instead. + +Some of those checks may be unnecessary in certain deployments, and not +performing them may improve performance. The Kea server provides the +``reservation-mode`` configuration parameter to select the types of +reservations allowed for a particular subnet. Each reservation type has +different constraints for the checks to be performed by the server when +allocating or renewing a lease for the client. Allowed values are: + +- ``all`` - enables both in-pool and out-of-pool host reservation + types. This setting is the default value, and is the safest and most + flexible. However, as all checks are conducted, it is also the slowest. + It does not check against global reservations. + +- ``out-of-pool`` - allows only out-of-pool host reservations. With + this setting in place, the server assumes that all host + reservations are for addresses that do not belong to the dynamic + pool. Therefore, it can skip the reservation checks when dealing with + in-pool addresses, thus improving performance. Do not use this mode + if any reservations use in-pool addresses. Caution is advised + when using this setting; Kea does not sanity-check the reservations + against ``reservation-mode`` and misconfiguration may cause problems. + +- ``global`` - allows only global host reservations. With this setting + in place, the server searches for reservations for a client only + among the defined global reservations. If an address is specified, + the server skips the reservation checks carried out in + other modes, thus improving performance. Caution is advised when + using this setting; Kea does not sanity-check the reservations when + ``global`` is set, and misconfiguration may cause problems. + +- ``disabled`` - host reservation support is disabled. As there are no + reservations, the server skips all checks. Any reservations + defined are completely ignored. As checks are skipped, the + server may operate faster in this mode. + +Since Kea 1.9.1, the ``reservation-mode`` parameter is replaced by the +``reservations-global``, ``reservations-in-subnet`` and +``reservations-out-of-pool`` flags. +The flags can be activated independently and can produce various combinations, +some of them being unsupported by the deprecated ``reservation-mode``. + +The ``reservation-mode`` parameter can be specified at: + +- global level: ``.Dhcp6["reservation-mode"]`` (lowest priority: gets overridden + by all others) + +- subnet level: ``.Dhcp6.subnet6[]["reservation-mode"]`` (low priority) + +- shared-network level: ``.Dhcp6["shared-networks"][]["reservation-mode"]`` + (high priority) + +- shared-network subnet-level: + ``.Dhcp6["shared-networks"][].subnet6[]["reservation-mode"]`` (highest + priority: overrides all others) + +To decide which ``"reservation-mode"`` to choose, the +following decision diagram may be useful: + +:: + + O + | + v + +-----------------------------+------------------------------+ + | Is per-host configuration needed, such as | + | reserving specific addresses, | + | assigning specific options or | + | assigning packets to specific classes on per-device basis? | + +-+-----------------+----------------------------------------+ + | | + no| yes| + | | +--------------------------------------+ + | | | For all given hosts, | + +--> "disabled" +-->+ can the reserved resources | + | be used in all configured subnets? | + +--------+---------------------------+-+ + | | + +----------------------------+ |no |yes + | Is | | | + | at least one reservation +<--+ "global" <--+ + | used to reserve addresses | + | or prefixes? | + +-+------------------------+-+ + | | + no| yes| +---------------------------+ + | | | Is high leases-per-second | + +--> "out-of-pool" +-->+ performance or efficient | + ^ | resource usage | + | | (CPU ticks, RAM usage, | + | | database roundtrips) | + | | important to your setup? | + | +-+----------------+--------+ + | | | + | yes| no| + | | | + | +-------------+ | + | | | + | | +----------------------+ | + | | | Can it be guaranteed | | + | +-->+ that the reserved | | + | | addresses/prefixes | | + | | aren't part of the | | + | | pools configured | | + | | in the respective | | + | | subnet? | | + | +-+------------------+-+ | + | | | | + | yes| no| | + | | | V + +----------------+ +--> "all" + +An example configuration that disables reservations looks as follows: + +.. code-block:: json + + { + "Dhcp6": { + "subnet6": [ + { + "id": 1, + "pools": [ + { + "pool": "2001:db8:1::-2001:db8:1::100" + } + ], + "reservation-mode": "disabled", + "subnet": "2001:db8:1::/64" + } + ] + } + } + +An example configuration using global reservations is shown below: + +.. code-block:: json + + { + "Dhcp6": { + "reservation-mode": "global", + "reservations": [ + { + "duid": "00:03:00:01:11:22:33:44:55:66", + "hostname": "host-one" + }, + { + "duid": "00:03:00:01:99:88:77:66:55:44", + "hostname": "host-two" + } + ], + "subnet6": [ + { + "id": 1, + "pools": [ + { + "pool": "2001:db8:1::-2001:db8:1::100" + } + ], + "subnet": "2001:db8:1::/64" + } + ] + } + } + +The meaning of the reservation flags are: + +- ``reservations-global``: fetch global reservations. + +- ``reservations-in-subnet``: fetch subnet reservations. For a shared network + this includes all subnet members of the shared network. + +- ``reservations-out-of-pool``: this makes sense only when the + ``reservations-in-subnet`` flag is ``true``. When ``reservations-out-of-pool`` + is ``true``, the server assumes that all host reservations are for addresses + that do not belong to the dynamic pool. Therefore, it can skip the reservation + checks when dealing with in-pool addresses, thus improving performance. + The server will not assign reserved addresses that are inside the dynamic + pools to the respective clients. This also means that the addresses matching + the respective reservations from inside the dynamic pools (if any) can be + dynamically assigned to any client. + +The ``disabled`` value from the deprecated ``reservation-mode`` corresponds to: + +.. code-block:: json + + { + "Dhcp6": { + "reservations-global": false, + "reservations-in-subnet": false + } + } + +The ``global`` value from the deprecated ``reservation-mode`` corresponds to: + +.. code-block:: json + + { + "Dhcp6": { + "reservations-global": true, + "reservations-in-subnet": false + } + } + +The ``out-of-pool`` value from the deprecated ``reservation-mode`` corresponds to: + +.. code-block:: json + + { + "Dhcp6": { + "reservations-global": false, + "reservations-in-subnet": true, + "reservations-out-of-pool": true + } + } + +And the ``all`` value from the deprecated ``reservation-mode`` corresponds to: + +.. code-block:: json + + { + "Dhcp6": { + "reservations-global": false, + "reservations-in-subnet": true, + "reservations-out-of-pool": false + } + } + +To activate both ``global`` and ``all``, the following combination can be used: + +.. code-block:: json + + { + "Dhcp6": { + "reservations-global": true, + "reservations-in-subnet": true, + "reservations-out-of-pool": false + } + } + +To activate both ``global`` and ``out-of-pool``, the following combination can +be used: + +.. code-block:: json + + { + "Dhcp6": { + "reservations-global": true, + "reservations-in-subnet": true, + "reservations-out-of-pool": true + } + } + +Enabling ``out-of-pool`` and disabling ``in-subnet`` at the same time +is not recommended because ``out-of-pool`` applies to host reservations in a +subnet, which are fetched only when the ``in-subnet`` flag is ``true``. + +The parameter can be specified at the global, subnet, and shared-network +levels. + +An example configuration that disables reservations looks as follows: + +.. code-block:: json + + { + "Dhcp6": { + "subnet6": [ + { + "reservations-global": false, + "reservations-in-subnet": false, + "subnet": "2001:db8:1::/64", + "id": 1 + } + ] + } + } + +An example configuration using global reservations is shown below: + +.. code-block:: json + + { + "Dhcp6": { + "reservations": [ + { + "duid": "00:03:00:01:11:22:33:44:55:66", + "hostname": "host-one" + }, + { + "duid": "00:03:00:01:99:88:77:66:55:44", + "hostname": "host-two" + } + ], + "reservations-global": true, + "reservations-in-subnet": false, + "subnet6": [ + { + "pools": [ + { + "pool": "2001:db8:1::-2001:db8:1::100" + } + ], + "subnet": "2001:db8:1::/64", + "id": 1 + } + ] + } + } + +For more details regarding global reservations, see :ref:`global-reservations6`. + +Another aspect of host reservations is the different types of +identifiers. Kea currently supports two types of identifiers in DHCPv6: +hardware address and DUID. This is beneficial from a usability +perspective; however, there is one drawback. For each incoming packet +Kea has to extract each identifier type and then query the database +to see if there is a reservation by this particular identifier. If +nothing is found, the next identifier is extracted and the next query is +issued. This process continues until either a reservation is found or +all identifier types have been checked. Over time, with an increasing +number of supported identifier types, Kea would become slower and +slower. + +To address this problem, a parameter called +``host-reservation-identifiers`` is available. It takes a list of +identifier types as a parameter. Kea checks only those identifier +types enumerated in ``host-reservation-identifiers``. From a performance +perspective, the number of identifier types should be kept to a minimum, +ideally one. If the deployment uses several reservation types, please +enumerate them from most- to least-frequently used, as this increases +the chances of Kea finding the reservation using the fewest queries. An +example of a ``host-reservation-identifiers`` configuration looks as follows: + +:: + + { + "host-reservation-identifiers": [ "duid", "hw-address" ], + "subnet6": [ + { + "subnet": "2001:db8:1::/64", + ... + } + ], + ... + } + +If not specified, the default value is: + +:: + + "host-reservation-identifiers": [ "hw-address", "duid" ] + +.. note:: + + As soon as a host reservation is found the search is stopped so + when a client has two host reservations using different enabled + identifier types the first is always returned and the second + ignored. In other words, this is usually a configuration mistake. + In rare cases when having two reservations for the same host makes sense, + you can control which of those will be used by ordering the list of + identifier types in `host-reservation-identifiers`. + + +.. _global-reservations6: + +Global Reservations in DHCPv6 +----------------------------- + +In some deployments, such as mobile, clients can roam within the network +and certain parameters must be specified regardless of the client's +current location. To meet such a need, Kea offers a global reservation +mechanism. The idea behind it is that regular host +reservations are tied to specific subnets, by using a specific +subnet ID. Kea can specify a global reservation that can be used in +every subnet that has global reservations enabled. + +This feature can be used to assign certain parameters, such as hostname +or other dedicated, host-specific options. It can also be used to assign +addresses or prefixes. + +An address assigned via global host reservation must be feasible for the +subnet the server selects for the client. In other words, the address must +lie within the subnet; otherwise, it is ignored and the server will +attempt to dynamically allocate an address. If the selected subnet +belongs to a shared network, the server checks for feasibility against +the subnet's siblings, selecting the first in-range subnet. If no such +subnet exists, the server falls back to dynamically allocating the address. +This does not apply to globally reserved prefixes. + +.. note:: + + Prior to release 2.3.5, the server did not perform feasibility checks on + globally reserved addresses, which allowed the server to be configured to + hand out nonsensical leases for arbitrary address values. Later versions + of Kea perform these checks. + +To use global host reservations, a configuration similar to the +following can be used: + +:: + + "Dhcp6": { + # This specifies global reservations. + # They will apply to all subnets that + # have global reservations enabled. + + "reservations": [ + { + "hw-address": "aa:bb:cc:dd:ee:ff", + "hostname": "hw-host-dynamic" + }, + { + "hw-address": "01:02:03:04:05:06", + "hostname": "hw-host-fixed", + + # Use of IP addresses in global reservations is risky. + # If used outside of matching subnet, such as 3001::/64, + # it will result in a broken configuration being handed + # to the client. + "ip-address": "2001:db8:ff::77" + }, + { + "duid": "01:02:03:04:05", + "hostname": "duid-host" + } + ], + "valid-lifetime": 600, + "subnet4": [ { + "subnet": "2001:db8:1::/64", + # It is replaced by the "reservations-global", + # "reservations-in-subnet", and "reservations-out-of-pool" + # parameters. + # "reservation-mode": "global", + # Specify if the server should look up global reservations. + "reservations-global": true, + # Specify if the server should look up in-subnet reservations. + "reservations-in-subnet": false, + # Specify if the server can assume that all reserved addresses + # are out-of-pool. It can be ignored because "reservations-in-subnet" + # is false. + # "reservations-out-of-pool": false, + "pools": [ { "pool": "2001:db8:1::-2001:db8:1::100" } ] + } ] + } + +When using database backends, the global host reservations are +distinguished from regular reservations by using a ``subnet-id`` value of +0. + +.. _pool-selection-with-class-reservations6: + +Pool Selection with Client Class Reservations +--------------------------------------------- + +Client classes can be specified both in the Kea configuration file and/or +via host reservations. The classes specified in the Kea configuration file are +evaluated immediately after receiving the DHCP packet and therefore can be +used to influence subnet selection using the ``client-class`` parameter +specified in the subnet scope. The classes specified within the host +reservations are fetched and assigned to the packet after the server has +already selected a subnet for the client. This means that the client +class specified within a host reservation cannot be used to influence +subnet assignment for this client, unless the subnet belongs to a +shared network. If the subnet belongs to a shared network, the server may +dynamically change the subnet assignment while trying to allocate a lease. +If the subnet does not belong to a shared network, once selected, the subnet +is not changed once selected. + +If the subnet does not belong to a shared network, it is possible to +use host reservation-based client classification to select an address pool +within the subnet as follows: + +:: + + "Dhcp6": { + "client-classes": [ + { + "name": "reserved_class" + }, + { + "name": "unreserved_class", + "test": "not member('reserved_class')" + } + ], + "subnet6": [ + { + "id": 1, + "subnet": "2001:db8:1::/64", + "reservations": [ + { + "hw-address": "aa:bb:cc:dd:ee:fe", + "client-classes": [ "reserved_class" ] + } + ], + "pools": [ + { + "pool": "2001:db8:1::10-2001:db8:1::20", + "client-class": "reserved_class" + }, + { + "pool": "2001:db8:1::30-2001:db8:1::40", + "client-class": "unreserved_class" + } + ] + } + ] + } + +The ``reserved_class`` is declared without the ``test`` parameter because +it may be only assigned to the client via host reservation mechanism. The +second class, ``unreserved_class``, is assigned to clients which do not +belong to the ``reserved_class``. The first pool within the subnet is only +used for clients having a reservation for the ``reserved_class``. The +second pool is used for clients not having such a reservation. The +configuration snippet includes one host reservation which causes the client +with the MAC address aa:bb:cc:dd:ee:fe to be assigned to the +``reserved_class``. Thus, this client will be given an IP address from the +first address pool. + +.. _subnet-selection-with-class-reservations6: + +Subnet Selection with Client Class Reservations +----------------------------------------------- + +There is one specific use case when subnet selection may be influenced by +client classes specified within host reservations: when the +client belongs to a shared network. In such a case it is possible to use +classification to select a subnet within this shared network. Consider the +following example: + +:: + + "Dhcp6": { + "client-classes": [ + { + "name": "reserved_class" + }, + { + "name": "unreserved_class", + "test": "not member('reserved_class')" + } + ], + "reservations": [ + { + "hw-address": "aa:bb:cc:dd:ee:fe", + "client-classes": [ "reserved_class" ] + } + ], + # It is replaced by the "reservations-global", + # "reservations-in-subnet", and "reservations-out-of-pool" parameters. + # Specify if the server should look up global reservations. + "reservations-global": true, + # Specify if the server should look up in-subnet reservations. + "reservations-in-subnet": false, + # Specify if the server can assume that all reserved addresses + # are out-of-pool. It can be ignored because "reservations-in-subnet" + # is false, but if specified, it is inherited by "shared-networks" + # and "subnet6" levels. + # "reservations-out-of-pool": false, + "shared-networks": [ + { + "subnet6": [ + { + "id": 1, + "subnet": "2001:db8:1::/64", + "pools": [ + { + "pool": "2001:db8:1::10-2001:db8:1::20", + "client-class": "reserved_class" + } + ] + }, + { + "id": 2, + "subnet": "2001:db8:2::/64", + "pools": [ + { + "pool": "2001:db8:2::10-2001:db8:2::20", + "client-class": "unreserved_class" + } + ] + } + ] + } + ] + } + +This is similar to the example described in the +:ref:`pool-selection-with-class-reservations6`. This time, however, there +are two subnets, each of which has a pool associated with a different +class. The clients that do not have a reservation for the ``reserved_class`` +are assigned an address from the subnet 2001:db8:2::/64. Clients with +a reservation for the ``reserved_class`` are assigned an address from +the subnet 2001:db8:1::/64. The subnets must belong to the same shared network. +In addition, the reservation for the client class must be specified at the +global scope (global reservation) and ``reservations-global`` must be +set to ``true``. + +In the example above, the ``client-class`` could also be specified at the +subnet level rather than the pool level, and would yield the same effect. + +.. _multiple-reservations-same-ip6: + +Multiple Reservations for the Same IP +------------------------------------- + +Host reservations were designed to preclude the creation of multiple +reservations for the same IP address or delegated prefix within a +particular subnet, to avoid having two different clients +compete for the same lease. When using the default settings, the server +returns a configuration error when it finds two or more reservations for +the same lease within a subnet in the Kea configuration file. +:ischooklib:`libdhcp_host_cmds.so` returns an error in response to the +:isccmd:`reservation-add` command when it detects that the reservation exists +in the database for the lease for which the new reservation is being added. + +Similar to DHCPv4 (see :ref:`multiple-reservations-same-ip4`), the DHCPv6 +server can also be configured to allow the creation of multiple reservations +for the same IPv6 address and/or delegated prefix in a given subnet. This +is supported since Kea release 1.9.1 as an optional mode of operation +enabled with the ``ip-reservations-unique`` global parameter. + +The ``ip-reservations-unique`` is a boolean parameter that defaults to +``true``, which forbids the specification of more than one reservation +for the same lease in a given subnet. Setting this parameter to ``false`` +allows such reservations to be created both in the Kea configuration +file and in the host database backend, via :ischooklib:`libdhcp_host_cmds.so`. + +Setting ``ip-reservations-unique`` to ``false`` when using memfile, MySQL or PostgreSQL is supported. +This setting is not supported when using Host Cache (see :ref:`hooks-host-cache`), and the RADIUS backend +(see :ref:`hooks-radius`). These reservation backends simply do not support multiple reservations for the +same IP. If either of these hooks are loaded and ``ip-reservations-unique`` is set to ``false``, then a +configuration error will be emitted and the server will fail to start. + +.. note:: + + When ``ip-reservations-unique`` is set to ``true`` (the default value), + the server ensures that IP reservations are unique for a subnet within + a single host backend and/or Kea configuration file. It does not + guarantee that the reservations are unique across multiple backends. + On server startup, only IP reservations defined in the Kea configuration + file are checked for uniqueness. + + +The following is an example configuration with two reservations for +the same IPv6 address but different MAC addresses: + +:: + + "Dhcp6": { + "ip-reservations-unique": false, + "subnet6": [ + { + "id": 1, + "subnet": "2001:db8:1::/64", + "reservations": [ + { + "hw-address": "1a:1b:1c:1d:1e:1f", + "ip-address": "2001:db8:1::11" + }, + { + "hw-address": "2a:2b:2c:2d:2e:2f", + "ip-address": "2001:db8:1::11" + } + ] + } + ] + } + +It is possible to control the ``ip-reservations-unique`` parameter via the +:ref:`dhcp6-cb`. If the new setting of this parameter conflicts with +the currently used backends (i.e. backends do not support the new setting), +the new setting is ignored and a warning log message is generated. +The backends continue to use the default setting, expecting that +IP reservations are unique within each subnet. To allow the +creation of non-unique IP reservations, the administrator must remove +the backends which lack support for them from the configuration file. + +Administrators must be careful when they have been using multiple +reservations for the same IP address and/or delegated prefix and later +decide to return to the default mode in which this is no longer allowed. +They must make sure that at most one reservation for +a given IP address or delegated prefix exists within a subnet, prior +to switching back to the default mode. If such duplicates are left in +the configuration file, the server reports a configuration error. +Leaving such reservations in the host databases does not cause +configuration errors but may lead to lease allocation errors during +the server's operation, when it unexpectedly finds multiple reservations +for the same IP address or delegated prefix. + +.. note:: + + Currently the Kea server does not verify whether multiple reservations for + the same IP address and/or delegated prefix exist in + MySQL and/or PostgreSQL) host databases when ``ip-reservations-unique`` + is updated from ``false`` to ``true``. This may cause issues with + lease allocations. The administrator must ensure that there is at + most one reservation for each IP address and/or delegated prefix + within each subnet, prior to the configuration update. + +The ``reservations-lookup-first`` is a boolean parameter which controls whether +host reservations lookup should be performed before lease lookup. This parameter +has effect only when multi-threading is disabled. When multi-threading is +enabled, host reservations lookup is always performed first to avoid lease-lookup +resource locking. The ``reservations-lookup-first`` parameter defaults to ``false`` +when multi-threading is disabled. + +.. _host_reservations_as_basic_access_control6: + +Host Reservations as Basic Access Control +----------------------------------------- + +Starting with Kea 2.3.5, it is possible to define a host reservation that +contains just an identifier, without any address, options, or values. In some +deployments this is useful, as the hosts that have a reservation belong to +the KNOWN class while others do not. This can be used as a basic access control +mechanism. + +The following example demonstrates this concept. It indicates a single IPv6 subnet +and all clients will get an address from it. However, only known clients (those that +have reservations) will get their default DNS server configured. Empty reservations +i.e. reservations that only have the identification criterion, can be +specifically useful in this regard of making the clients known. + +:: + + "Dhcp6": { + "client-classes": [ + { + "name": "KNOWN", + "option-data": [ + { + "name": "dns-servers", + "data": "2001:db8::1" + } + ] + } + ], + "reservations": [ + // Clients on this list will be added to the KNOWN class. + { "duid": "01:02:03:04:05:0A:0B:0C:0D:0E" }, + { "duid": "02:03:04:05:0A:0B:0C:0D:0E:0F" } + ], + "reservations-in-subnet": true, + + "subnet6": [ + { + "id": 1, + "subnet": "2001:db8:1::/48", + "pools": [ + { + "pool": "2001:db8:1:1::/64" + } + ] + } + ] + } + +This concept can be extended further. A good real-life scenario might be a +situation where some customers of an ISP have not paid their bills. A new class can be +defined to use an alternative default DNS server that, instead of giving access +to the Internet, redirects those customers to a captive portal urging them to bring +their accounts up to date. + +:: + + "Dhcp6": { + "client-classes": [ + { + "name": "blocked", + "option-data": [ + { + "name": "dns-servers", + "data": "2001:db8::2" + } + ] + } + ], + "reservations": [ + // Clients on this list will be added to the KNOWN class. Some + // will also be added to the blocked class. + { "duid": "01:02:03:04:05:0A:0B:0C:0D:0E", + "client-classes": [ "blocked" ] }, + { "duid": "02:03:04:05:0A:0B:0C:0D:0E:0F" } + ], + "reservations-in-subnet": true, + + "subnet6": [ + { + "id": 1, + "subnet": "2001:db8:1::/48", + "pools": [ + { + "pool": "2001:db8:1:1::/64" + } + ], + "option-data": [ + { + "name": "dns-servers", + "data": "2001:db8::1" + } + ] + } + ] + } + +.. _shared-network6: + +Shared Networks in DHCPv6 +========================= + +DHCP servers use subnet information in two ways. It is used to +both determine the point of attachment, i.e. where the client is +connected to the network, and to +group information pertaining to a specific location in the network. +Sometimes it is useful to have more than one +logical IP subnet being deployed on the same physical link. +Understanding that two or more subnets are used on the same link requires +additional logic in the DHCP server. This capability is called "shared +networks" in Kea, and sometimes also +"shared subnets"; in Microsoft's nomenclature it is called +"multinet." + +There are many cases where the shared networks feature is useful; here we explain +just a handful of the most common ones. The first and by far most common +use case is an existing IPv4 network that has grown and +is running out of available +address space. This is less common in IPv6, but shared networks +are still useful: for example, with the exhaustion of IPv6- +delegated prefixes within a subnet, or the desire to +experiment with an addressing scheme. With the advent of IPv6 deployment +and a vast address space, many organizations split the address space +into subnets, deploy it, and then after a while discover that they want +to split it differently. In the transition period, they want both the old +and new addressing to be available: thus the need for more than one +subnet on the same physical link. + +Finally, the case of cable networks is directly applicable in IPv6. +There are two types of devices in cable networks: cable modems and the +end-user devices behind them. It is a common practice to use different +subnets for cable modems to prevent users from tinkering with them. In +this case, the distinction is based on the type of device, rather than +on address-space exhaustion. + +A client connected to a shared network may be assigned a lease (address +or prefix) from any of the pools defined within the subnets belonging to +the shared network. Internally, the server selects one of the subnets +belonging to a shared network and tries to allocate a lease from this +subnet. If the server is unable to allocate a lease from the selected +subnet (e.g., due to pool exhaustion), it uses another subnet from +the same shared network and tries to allocate a lease from this subnet. +The server typically allocates all leases +available in a given subnet before it starts allocating leases from +other subnets belonging to the same shared network. However, in certain +situations the client can be allocated a lease from another subnet +before the pools in the first subnet get exhausted; this sometimes occurs +when the client provides a hint that belongs to another subnet, or the client has +reservations in a subnet other than the default. + +.. note:: + + Deployments should not assume that Kea waits until it has allocated + all the addresses from the first subnet in a shared network before + allocating addresses from other subnets. + +To define a shared network, an additional configuration scope is +introduced: + +:: + + { + "Dhcp6": { + "shared-networks": [ + { + # Name of the shared network. It may be an arbitrary string + # and it must be unique among all shared networks. + "name": "ipv6-lab-1", + + # The subnet selector can be specified on the shared network + # level. Subnets from this shared network will be selected + # for clients communicating via relay agent having + # the specified IP address. + "relay": { + "ip-addresses": [ "2001:db8:2:34::1" ] + }, + + # This starts a list of subnets in this shared network. + # There are two subnets in this example. + "subnet6": [ + { + "id": 1, + "subnet": "2001:db8::/48", + "pools": [ { "pool": "2001:db8::1 - 2001:db8::ffff" } ] + }, + { + "id": 2, + "subnet": "3ffe:ffe::/64", + "pools": [ { "pool": "3ffe:ffe::/64" } ] + } + ] + } + ], + # end of shared-networks + + # It is likely that in the network there will be a mix of regular, + # "plain" subnets and shared networks. It is perfectly valid + # to mix them in the same configuration file. + # + # This is a regular subnet. It is not part of any shared-network. + "subnet6": [ + { + "id": 3, + "subnet": "2001:db9::/48", + "pools": [ { "pool": "2001:db9::/64" } ], + "relay": { + "ip-addresses": [ "2001:db8:1:2::1" ] + } + } + ] + } + } + +As demonstrated in the example, it is possible to mix shared and regular +("plain") subnets. Each shared network must have a unique name. This is +similar to the ID for subnets, but gives administrators more +flexibility. It is used for logging, but also internally for +identifying shared networks. + +In principle it makes sense to define only shared networks that consist +of two or more subnets. However, for testing purposes, an empty subnet +or a network with just a single subnet is allowed. This +is not a recommended practice in production networks, as the shared +network logic requires additional processing and thus lowers the +server's performance. To avoid unnecessary performance degradation, +shared subnets should only be defined when required by the deployment. + +Shared networks provide an ability to specify many parameters in the +shared network scope that apply to all subnets within it. If +necessary, it is possible to specify a parameter in the shared-network scope and +then override its value in the subnet scope. For example: + +:: + + { + "shared-networks": [ + { + "name": "lab-network3", + "relay": { + "ip-addresses": [ "2001:db8:2:34::1" ] + }, + + # This applies to all subnets in this shared network, unless + # values are overridden on subnet scope. + "valid-lifetime": 600, + + # This option is made available to all subnets in this shared + # network. + "option-data": [ { + "name": "dns-servers", + "data": "2001:db8::8888" + } ], + + "subnet6": [ + { + "id": 1, + "subnet": "2001:db8:1::/48", + "pools": [ { "pool": "2001:db8:1::1 - 2001:db8:1::ffff" } ], + + # This particular subnet uses different values. + "valid-lifetime": 1200, + "option-data": [ + { + "name": "dns-servers", + "data": "2001:db8::1:2" + }, + { + "name": "unicast", + "data": "2001:abcd::1" + } ] + }, + { + "id": 2, + "subnet": "2001:db8:2::/48", + "pools": [ { "pool": "2001:db8:2::1 - 2001:db8:2::ffff" } ], + + # This subnet does not specify its own valid-lifetime value, + # so it is inherited from shared network scope. + "option-data": [ + { + "name": "dns-servers", + "data": "2001:db8:cafe::1" + } ] + } + ] + } + ], + ... + } + +In this example, there is a ``dns-servers`` option defined that is available +to clients in both subnets in this shared network. Also, the valid +lifetime is set to 10 minutes (600s). However, the first subnet +overrides some of the values (the valid lifetime is 20 minutes, there is a different IP +address for ``dns-servers``), but also adds its own option (the unicast +address). Assuming a client asking for server unicast and ``dns-servers`` +options is assigned a lease from this subnet, it will get a lease for 20 +minutes and ``dns-servers``, and be allowed to use server unicast at address +2001:abcd::1. If the same client is assigned to the second subnet, it +will get a 10-minute lease, a ``dns-servers`` value of 2001:db8:cafe::1, and +no server unicast. + +Some parameters must be the same in all subnets in the same shared +network. This restriction applies to the ``interface`` and +``rapid-commit`` settings. The most convenient way is to define them on +the shared-network scope, but they can be specified for each subnet. +However, each subnet must have the same value. + +.. note:: + + There is an inherent ambiguity when using clients that send multiple IA + options in a single request, and shared-networks whose subnets have + different values for options and configuration parameters. The server + sequentially processes IA options in the order that they occur in the + client's query; if the leases requested in the IA options end up being + fulfilled from different subnets, which parameters and options should + apply? Currently, the code uses the values from the last subnet of + the last IA option fulfilled. + + We view this largely as a site configuration issue. A shared network + generally means the same physical link, so services configured by options + from subnet A should be as easily reachable from subnet B and vice versa. + There are a number of ways to avoid this situation: + + - Use the same values for options and parameters for subnets within the shared network. + - Use subnet selectors or client class guards that ensure that for a single client's query, the same subnet is used for all IA options in that query. + - Avoid using shared networks with clients that send multiple IA options per query. + +Local and Relayed Traffic in Shared Networks +-------------------------------------------- + +It is possible to specify an interface name at the shared-network level, +to tell the server that this specific shared network is reachable +directly (not via relays) using the local network interface. As all +subnets in a shared network are expected to be used on the same physical +link, it is a configuration error to attempt to define a shared network +using subnets that are reachable over different interfaces. In other +words, all subnets within the shared network must have the same value +for the ``interface`` parameter. The following configuration is an example +of what **NOT** to do: + +:: + + { + "shared-networks": [ + { + "name": "office-floor-2", + "subnet6": [ + { + "id": 1, + "subnet": "2001:db8::/64", + "pools": [ { "pool": "2001:db8::1 - 2001:db8::ffff" } ], + "interface": "eth0" + }, + { + "id": 2, + "subnet": "3ffe:abcd::/64", + "pools": [ { "pool": "3ffe:abcd::1 - 3ffe:abcd::ffff" } ], + ... + # Specifying a different interface name is a configuration + # error. This value should rather be "eth0" or the interface + # name in the other subnet should be "eth1". + # "interface": "eth1" + } + ] + } + ], + ... + } + +To minimize the chance of configuration errors, it is often more convenient +to simply specify the interface name once, at the shared-network level, as +shown in the example below. + +:: + + { + "shared-networks": [ + { + "name": "office-floor-2", + + # This tells Kea that the whole shared network is reachable over a + # local interface. This applies to all subnets in this network. + "interface": "eth0", + + "subnet6": [ + { + "id": 1, + "subnet": "2001:db8::/64", + "pools": [ { "pool": "2001:db8::1 - 2001:db8::ffff" } ] + }, + { + "id": 2, + "subnet": "3ffe:abcd::/64", + "pools": [ { "pool": "3ffe:abcd::1 - 3ffe:abcd::ffff" } ] + } + ] + } + ], + ... + } + + +With relayed traffic, subnets are typically selected using +the relay agents' addresses. If the subnets are used independently (not +grouped within a shared network), a different relay +address can be specified for each of these subnets. When multiple subnets belong to a +shared network they must be selected via the same relay address and, +similarly to the case of the local traffic described above, it is a +configuration error to specify different relay addresses for the respective +subnets in the shared network. The following configuration is another example +of what **NOT** to do: + +:: + + { + "shared-networks": [ + { + "name": "kakapo", + "subnet6": [ + { + "id": 1, + "subnet": "2001:db8::/64", + "relay": { + "ip-addresses": [ "2001:db8::1234" ] + }, + "pools": [ { "pool": "2001:db8::1 - 2001:db8::ffff" } ] + }, + { + "id": 2, + "subnet": "3ffe:abcd::/64", + "pools": [ { "pool": "3ffe:abcd::1 - 3ffe:abcd::ffff" } ], + "relay": { + # Specifying a different relay address for this + # subnet is a configuration error. In this case + # it should be 2001:db8::1234 or the relay address + # in the previous subnet should be 3ffe:abcd::cafe. + "ip-addresses": [ "3ffe:abcd::cafe" ] + } + } + ] + } + ], + ... + } + +Again, it is better to specify the relay address at the shared-network +level; this value will be inherited by all subnets belonging to the +shared network. + +:: + + { + "shared-networks": [ + { + "name": "kakapo", + "relay": { + # This relay address is inherited by both subnets. + "ip-addresses": [ "2001:db8::1234" ] + }, + "subnet6": [ + { + "id": 1, + "subnet": "2001:db8::/64", + "pools": [ { "pool": "2001:db8::1 - 2001:db8::ffff" } ] + }, + { + "id": 2, + "subnet": "3ffe:abcd::/64", + "pools": [ { "pool": "3ffe:abcd::1 - 3ffe:abcd::ffff" } ] + } + ] + } + ], + ... + } + +Even though it is technically possible to configure two (or more) subnets +within the shared network to use different relay addresses, this will almost +always lead to a different behavior than what the user would expect. In this +case, the Kea server will initially select one of the subnets by matching +the relay address in the client's packet with the subnet's configuration. +However, it MAY end up using the other subnet (even though it does not match +the relay address) if the client already has a lease in this subnet or has a +host reservation in this subnet, or simply if the initially selected subnet has no +more addresses available. Therefore, it is strongly recommended to always +specify subnet selectors (interface or relay address) at the shared-network +level if the subnets belong to a shared network, as it is rarely useful to +specify them at the subnet level and may lead to the configuration errors +described above. + +Client Classification in Shared Networks +---------------------------------------- + +Sometimes it is desirable to segregate clients into specific subnets +based on certain properties. This mechanism is called client +classification and is described in :ref:`classify`. Client +classification can be applied to subnets belonging to shared networks in +the same way as it is used for subnets specified outside of shared +networks. It is important to understand how the server selects subnets +for clients when client classification is in use, to ensure that the +appropriate subnet is selected for a given client type. + +If a subnet is associated with a class, only the clients belonging to +this class can use this subnet. If there are no classes specified for a +subnet, any client connected to a given shared network can use this +subnet. A common mistake is to assume that the subnet that includes a client +class is preferred over subnets without client classes. Consider the +following example: + +.. code-block:: json + + { + "client-classes": [ + { + "name": "b-devices", + "test": "option[1234].hex == 0x0002" + } + ], + "shared-networks": [ + { + "name": "galah", + "relay": { + "ip-address": [ "2001:db8:2:34::1" ] + }, + "subnet6": [ + { + "id": 1, + "subnet": "2001:db8:1::/64", + "pools": [ { "pool": "2001:db8:1::20 - 2001:db8:1::ff" } ] + }, + { + "id": 2, + "subnet": "2001:db8:3::/64", + "pools": [ { "pool": "2001:db8:3::20 - 2001:db8:3::ff" } ], + "client-class": "b-devices" + } + ] + } + ] + } + +If the client belongs to the "b-devices" class (because it includes +option 1234 with a value of 0x0002), that does not guarantee that the +subnet 2001:db8:3::/64 will be used (or preferred) for this client. The +server can use either of the two subnets, because the subnet +2001:db8:1::/64 is also allowed for this client. The client +classification used in this case should be perceived as a way to +restrict access to certain subnets, rather than as a way to express subnet +preference. For example, if the client does not belong to the "b-devices" +class, it may only use the subnet 2001:db8:1::/64 and will never use the +subnet 2001:db8:3::/64. + +A typical use case for client classification is in a cable network, +where cable modems should use one subnet and other devices should use +another subnet within the same shared network. In this case it is +necessary to apply classification on all subnets. The following example +defines two classes of devices, and the subnet selection is made based +on option 1234 values. + +:: + + { + "client-classes": [ + { + + "name": "a-devices", + "test": "option[1234].hex == 0x0001" + }, + { + "name": "b-devices", + "test": "option[1234].hex == 0x0002" + } + ], + "shared-networks": [ + { + "name": "galah", + "relay": { + "ip-addresses": [ "2001:db8:2:34::1" ] + }, + "subnet6": [ + { + "id": 1, + "subnet": "2001:db8:1::/64", + "pools": [ { "pool": "2001:db8:1::20 - 2001:db8:1::ff" } ], + "client-class": "a-devices" + }, + { + "id": 2, + "subnet": "2001:db8:3::/64", + "pools": [ { "pool": "2001:db8:3::20 - 2001:db8:3::ff" } ], + "client-class": "b-devices" + } + ] + } + ] + } + +In this example each class has its own restriction. Only clients that +belong to class "a-devices" are able to use subnet 2001:db8:1::/64 +and only clients belonging to "b-devices" are able to use subnet +2001:db8:3::/64. Care should be taken not to define too-restrictive +classification rules, as clients that are unable to use any subnets will +be refused service. However, this may be a desired outcome if one wishes +to provide service only to clients with known properties (e.g. only VoIP +phones allowed on a given link). + +It is possible to achieve an effect similar to the one +presented in this section without the use of shared networks. If the +subnets are placed in the global subnets scope, rather than in the +shared network, the server will still use classification rules to pick +the right subnet for a given class of devices. The major benefit of +placing subnets within the shared network is that common parameters for +the logically grouped subnets can be specified once, in the shared +network scope, e.g. the ``interface`` or ``relay`` parameter. All subnets +belonging to this shared network will inherit those parameters. + +Host Reservations in Shared Networks +------------------------------------ + +Subnets that are part of a shared network allow host reservations, +similar to regular subnets: + +:: + + { + "shared-networks": [ + { + "name": "frog", + "relay": { + "ip-addresses": [ "2001:db8:2:34::1" ] + }, + "subnet6": [ + { + "subnet": "2001:db8:1::/64", + "id": 100, + "pools": [ { "pool": "2001:db8:1::1 - 2001:db8:1::64" } ], + "reservations": [ + { + "duid": "00:03:00:01:11:22:33:44:55:66", + "ip-addresses": [ "2001:db8:1::28" ] + } + ] + }, + { + "subnet": "2001:db8:3::/64", + "id": 101, + "pools": [ { "pool": "2001:db8:3::1 - 2001:db8:3::64" } ], + "reservations": [ + { + "duid": "00:03:00:01:aa:bb:cc:dd:ee:ff", + "ip-addresses": [ "2001:db8:2::28" ] + } + ] + } + ] + } + ] + } + + +It is worth noting that Kea conducts additional checks when processing a +packet if shared networks are defined. First, instead of simply checking +whether there is a reservation for a given client in its initially +selected subnet, Kea looks through all subnets in a shared network for a +reservation. This is one of the reasons why defining a shared network +may impact performance. If there is a reservation for a client in any +subnet, that particular subnet is picked for the client. Although +it is technically not an error, it is considered bad practice to define +reservations for the same host in multiple subnets belonging to the same +shared network. + +While not strictly mandatory, it is strongly recommended to use explicit +"id" values for subnets if database storage will be used for host +reservations. If an ID is not specified, the values for it are +auto generated, i.e. Kea assigns increasing integer values starting from +1. Thus, the auto-generated IDs are not stable across configuration +changes. + +.. _dhcp6-serverid: + +Server Identifier in DHCPv6 +=========================== + +The DHCPv6 protocol uses a "server identifier" (also known as a DUID) to +allow clients to discriminate between several servers present on the +same link. `RFC 8415 <https://tools.ietf.org/html/rfc8415>`__ currently +defines four DUID types: DUID-LLT, DUID-EN, DUID-LL, and DUID-UUID. + +The Kea DHCPv6 server generates a server identifier once, upon the first +startup, and stores it in a file. This identifier is not modified across +restarts of the server and so is a stable identifier. + +Kea follows the recommendation from `RFC +8415 <https://tools.ietf.org/html/rfc8415>`__ to use DUID-LLT as the +default server identifier. However, ISC has received reports that some +deployments require different DUID types, and that there is a need to +administratively select both the DUID type and/or its contents. + +The server identifier can be configured using parameters within the +``server-id`` map element in the global scope of the Kea configuration +file. The following example demonstrates how to select DUID-EN as a +server identifier: + +:: + + "Dhcp6": { + "server-id": { + "type": "EN" + }, + ... + } + +Currently supported values for the ``type`` parameter are: "LLT", "EN", and +"LL", for DUID-LLT, DUID-EN, and DUID-LL respectively. + +When a new DUID type is selected, the server generates its value and +replaces any existing DUID in the file. The server then uses the new +server identifier in all future interactions with clients. + +.. note:: + + If the new server identifier is created after some clients have + obtained their leases, the clients using the old identifier are not + able to renew their leases; the server will ignore messages containing + the old server identifier. Clients will continue sending RENEW until + they transition to the rebinding state. In this state, they will + start sending REBIND messages to the multicast address without a + server identifier. The server will respond to the REBIND messages + with a new server identifier, and the clients will associate the new + server identifier with their leases. Although the clients will be + able to keep their leases and will eventually learn the new server + identifier, this will be at the cost of an increased number of + renewals and multicast traffic due to a need to rebind. Therefore, it + is recommended that modification of the server-identifier type and + value be avoided if the server has already assigned leases and these + leases are still valid. + +There are cases when an administrator needs to explicitly specify a DUID +value rather than allow the server to generate it. The following example +demonstrates how to explicitly set all components of a DUID-LLT. + +:: + + "Dhcp6": { + "server-id": { + "type": "LLT", + "htype": 8, + "identifier": "A65DC7410F05", + "time": 2518920166 + }, + ... + } + +where: + +- ``htype`` is a 16-bit unsigned value specifying hardware type, + +- ``identifier`` is a link-layer address, specified as a string of + hexadecimal digits, and + +- ``time`` is a 32-bit unsigned time value. + +The hexadecimal representation of the DUID generated as a result of the +configuration specified above is: + +:: + + 00:01:00:08:96:23:AB:E6:A6:5D:C7:41:0F:05 + |type |htype| time | identifier | + +A special value of "0" for ``htype`` and ``time`` is allowed, which indicates +that the server should use ANY value for these components. If the server +already uses a DUID-LLT, it will use the values from this DUID; if the +server uses a DUID of a different type or does not yet use any DUID, it +will generate these values. Similarly, if the ``identifier`` is assigned +an empty string, the value of the ``identifier`` will be generated. Omitting +any of these parameters is equivalent to setting them to those special +values. + +For example, the following configuration: + +:: + + "Dhcp6": { + "server-id": { + "type": "LLT", + "htype": 0, + "identifier": "", + "time": 2518920166 + }, + ... + } + +indicates that the server should use ANY link-layer address and hardware +type. If the server is already using DUID-LLT, it will use the +link-layer address and hardware type from the existing DUID. If the +server is not yet using any DUID, it will use the link-layer address and +hardware type from one of the available network interfaces. The server +will use an explicit value of time; if it is different than a time value +present in the currently used DUID, that value will be replaced, +effectively modifying the current server identifier. + +The following example demonstrates an explicit configuration of a +DUID-EN: + +:: + + "Dhcp6": { + "server-id": { + "type": "EN", + "enterprise-id": 2495, + "identifier": "87ABEF7A5BB545" + }, + ... + } + +where: + +- ``enterprise-id`` is a 32-bit unsigned value holding an enterprise + number, and + +- ``identifier`` is a variable- length identifier within DUID-EN. + +The hexadecimal representation of the DUID-EN created according to the +configuration above is: + +:: + + 00:02:00:00:09:BF:87:AB:EF:7A:5B:B5:45 + |type | ent-id | identifier | + +As in the case of the DUID-LLT, special values can be used for the +configuration of the DUID-EN. If the ``enterprise-id`` is "0", the server +will use a value from the existing DUID-EN. If the server is not using +any DUID or the existing DUID has a different type, the ISC enterprise +ID will be used. When an empty string is entered for ``identifier``, the +identifier from the existing DUID-EN will be used. If the server is not +using any DUID-EN, a new 6-byte-long ``identifier`` will be generated. + +DUID-LL is configured in the same way as DUID-LLT except that the +``time`` parameter has no effect for DUID-LL, because this DUID type +only comprises a hardware type and link-layer address. The following +example demonstrates how to configure DUID-LL: + +:: + + "Dhcp6": { + "server-id": { + "type": "LL", + "htype": 8, + "identifier": "A65DC7410F05" + }, + ... + } + +which will result in the following server identifier: + +:: + + 00:03:00:08:A6:5D:C7:41:0F:05 + |type |htype| identifier | + +The server stores the generated server identifier in the following +location: ``[kea-install-dir]/var/lib/kea/kea-dhcp6-serverid``. + +In some uncommon deployments where no stable storage is available, the +server should be configured not to try to store the server identifier. +This choice is controlled by the value of the ``persist`` boolean +parameter: + +:: + + "Dhcp6": { + "server-id": { + "type": "EN", + "enterprise-id": 2495, + "identifier": "87ABEF7A5BB545", + "persist": false + }, + ... + } + +The default value of the ``persist`` parameter is ``true``, which +configures the server to store the server identifier on a disk. + +In the example above, the server is configured not to store the +generated server identifier on a disk. But if the server identifier is +not modified in the configuration, the same value is used after +server restart, because the entire server identifier is explicitly +specified in the configuration. + +.. _data-directory: + +DHCPv6 Data Directory +===================== + +The Kea DHCPv6 server puts the server identifier file and the default +memory lease file into its data directory. By default this directory is +``prefix/var/lib/kea`` but this location can be changed using the +``data-directory`` global parameter, as in: + +:: + + "Dhcp6": { + "data-directory": "/var/tmp/kea-server6", + ... + } + +.. _stateless-dhcp6: + +Stateless DHCPv6 (INFORMATION-REQUEST Message) +============================================== + +Typically DHCPv6 is used to assign both addresses and options. These +assignments (leases) have a state that changes over time, hence their +description as "stateful." DHCPv6 also supports a "stateless" mode, where clients +request only configuration options. This mode is considered lightweight +from the server perspective, as it does not require any state tracking. + +The Kea server supports stateless mode. When clients send +INFORMATION-REQUEST messages, the server sends back answers with the +requested options, if they are available in the server +configuration. The server attempts to use per-subnet options first; if +that fails, it then tries to provide options +defined in the global scope. + +Stateless and stateful mode can be used together. No special +configuration directives are required to handle this; simply use the +configuration for stateful clients and the stateless clients will get +only the options they requested. + +It is possible to run a server that provides only options and no addresses or +prefixes. If the options have the same value in each subnet, the +configuration can define the required options in the global scope and skip +subnet definitions altogether. Here's a simple example of such a +configuration: + +:: + + "Dhcp6": { + "interfaces-config": { + "interfaces": [ "ethX" ] + }, + "option-data": [ { + "name": "dns-servers", + "data": "2001:db8::1, 2001:db8::2" + } ], + "lease-database": { + "type": "memfile" + } + } + +This very simple configuration provides DNS server information to +all clients in the network, regardless of their location. The +memfile lease database must be specified, as Kea +requires a lease database to be specified even if it is not used. + +.. _dhcp6-rfc7550: + +Support for RFC 7550 (now part of RFC 8415) +=========================================== + +`RFC 7550 <https://tools.ietf.org/html/rfc7550>`__ introduced some +changes to the previous DHCPv6 specifications, `RFC +3315 <https://tools.ietf.org/html/rfc3315>`__ and `RFC +3633 <https://tools.ietf.org/html/rfc3633>`__, to resolve issues +with the coexistence of multiple stateful options in the messages sent +between clients and servers. Those changes were later included in +the most recent DHCPv6 protocol specification, `RFC +8415 <https://tools.ietf.org/html/rfc8415>`__, which obsoleted `RFC +7550 <https://tools.ietf.org/html/rfc7550>`__. Kea supports `RFC +8415 <https://tools.ietf.org/html/rfc8415>`__ along with these protocol +changes, which are briefly described below. + +When a client, such as a requesting router, requests an allocation of +both addresses and prefixes during the 4-way (SARR) exchange with the +server, and the server is not configured to allocate any prefixes but +can allocate some addresses, it will respond with the IA_NA(s) +containing allocated addresses and the IA_PD(s) containing the +NoPrefixAvail status code. According to the updated specifications, if +the client can operate without prefixes it should accept allocated +addresses and transition to the "bound" state. When the client +subsequently sends RENEW/REBIND messages to the server to extend the +lifetimes of the allocated addresses, according to the T1 and T2 times, and +if the client is still interested in obtaining prefixes from the server, +it may also include an IA_PD in the RENEW/REBIND to request allocation +of the prefixes. If the server still cannot allocate the prefixes, it +will respond with the IA_PD(s) containing the NoPrefixAvail status code. +However, if the server can allocate the prefixes, it allocates and +sends them in the IA_PD(s) to the client. A similar situation occurs when +the server is unable to allocate addresses for the client but can +delegate prefixes: the client may request allocation of the addresses +while renewing the delegated prefixes. Allocating leases for other IA +types while renewing existing leases is by default supported by the Kea +DHCPv6 server, and the server provides no configuration mechanisms to +disable this behavior. + +The following are the other behaviors first introduced in `RFC +7550 <https://tools.ietf.org/html/rfc7550>`__ (now part of `RFC +8415 <https://tools.ietf.org/html/rfc8415>`__) and supported by the Kea +DHCPv6 server: + +- Set T1/T2 timers to the same value for all stateful (IA_NA and IA_PD) + options to facilitate renewal of all of a client's leases at the same + time (in a single message exchange). + +- Place NoAddrsAvail and NoPrefixAvail status codes in the IA_NA and + IA_PD options in the ADVERTISE message, rather than as the top-level + options. + +.. _dhcp6-relay-override: + +Using a Specific Relay Agent for a Subnet +========================================= + +The DHCPv6 server follows the same principles as the DHCPv4 server to +select a subnet for the client, with noticeable differences mainly for +relays. + +.. note:: + + When the selected subnet is a member of a shared network, the + whole shared network is selected. + +A relay must have an interface connected to the link on which the +clients are being configured. Typically the relay has a global IPv6 +address configured on that interface, which belongs to the subnet from +which the server assigns addresses. Normally, the server is able to +use the IPv6 address inserted by the relay (in the ``link-addr`` field in +the RELAY-FORW message) to select the appropriate subnet. + +However, that is not always the case; the relay address may not match +the subnet in certain deployments. This usually means that there is more +than one subnet allocated for a given link. The two most common examples +of this are long-lasting network renumbering (where both the +old and new address spaces are still being used) and a cable network. In a +cable network, both cable modems and the devices behind them are +physically connected to the same link, yet they use distinct addressing. +In such a case, the DHCPv6 server needs additional information (the +value of the ``interface-id`` option or the IPv6 address inserted in the +``link-addr`` field in the RELAY-FORW message) to properly select an +appropriate subnet. + +The following example assumes that there is a subnet 2001:db8:1::/64 +that is accessible via a relay that uses 3000::1 as its IPv6 address. +The server is able to select this subnet for any incoming packets that +come from a relay that has an address in the 2001:db8:1::/64 subnet. It also +selects that subnet for a relay with address 3000::1. + +:: + + "Dhcp6": { + "subnet6": [ + { + "id": 1, + "subnet": "2001:db8:1::/64", + "pools": [ + { + "pool": "2001:db8:1::1-2001:db8:1::ffff" + } + ], + "relay": { + "ip-addresses": [ "3000::1" ] + } + } + ] + } + +If ``relay`` is specified, the ``ip-addresses`` parameter within it is +mandatory. The ``ip-addresses`` parameter supports specifying a list of addresses. + +.. _dhcp6-client-class-relay: + +Segregating IPv6 Clients in a Cable Network +=========================================== + +In certain cases, it is useful to mix relay address information +(introduced in :ref:`dhcp6-relay-override`) with client classification (explained +in :ref:`classify`). One specific example is in a cable network, +where modems typically get addresses from a different subnet than all +the devices connected behind them. + +Let us assume that there is one Cable Modem Termination System (CMTS) +with one CM MAC (a physical link that modems are connected to). We want +the modems to get addresses from the 3000::/64 subnet, while everything +connected behind the modems should get addresses from the 2001:db8:1::/64 +subnet. The CMTS that acts as a relay uses address 3000::1. +The following configuration can serve that situation: + +:: + + "Dhcp6": { + "subnet6": [ + { + "id": 1, + "subnet": "3000::/64", + "pools": [ + { "pool": "3000::2 - 3000::ffff" } + ], + "client-class": "VENDOR_CLASS_docsis3.0", + "relay": { + "ip-addresses": [ "3000::1" ] + } + }, + { + "id": 2, + "subnet": "2001:db8:1::/64", + "pools": [ + { + "pool": "2001:db8:1::1-2001:db8:1::ffff" + } + ], + "relay": { + "ip-addresses": [ "3000::1" ] + } + } + ] + } + +.. _mac-in-dhcpv6: + +MAC/Hardware Addresses in DHCPv6 +================================ + +MAC/hardware addresses are available in DHCPv4 messages from +clients, and administrators frequently use that information to perform +certain tasks like per-host configuration and address reservation for +specific MAC addresses. Unfortunately, the DHCPv6 protocol does not +provide any completely reliable way to retrieve that information. To +mitigate that issue, a number of mechanisms have been implemented in +Kea. Each of these mechanisms works in certain cases, but may not in +others. Whether the mechanism works in a particular deployment is +somewhat dependent on the network topology and the technologies used. + +Kea allows specification of which of the supported methods should be +used and in what order, via the ``mac-sources`` parameter. This configuration +may be considered a fine +tuning of the DHCP deployment. + +Here is an example: + +:: + + "Dhcp6": { + "mac-sources": [ + "method1", + "method2", + "method3", + ... + ], + + "subnet6": [ + { + ... + }, + ... + ], + ... + } + +When not specified, a value of "any" is used, which instructs +the server to attempt to try all the methods in sequence and use the +value returned by the first one that succeeds. In a typical deployment the default value +of "any" is sufficient and there is no need to select specific +methods. Changing the value of this parameter is most useful in +cases when an administrator wants to disable certain methods; for +example, if the administrator trusts the network infrastructure more +than the information provided by the clients themselves, they may prefer +information provided by the relays over that provided by clients. + +If specified, ``mac-sources`` must have at least one value. + +Supported methods are: + +- ``any`` - this is not an actual method, just a keyword that instructs Kea to + try all other methods and use the first one that succeeds. This is + the default operation if no ``mac-sources`` are defined. + +- ``raw`` - in principle, a DHCPv6 server could use raw sockets to + receive incoming traffic and extract MAC/hardware address + information. This is currently not implemented for DHCPv6 and this + value has no effect. + +- ``duid`` - DHCPv6 uses DUID identifiers instead of MAC addresses. + There are currently four DUID types defined, and two of them + (DUID-LLT, which is the default, and DUID-LL) convey MAC address + information. Although `RFC 8415 <https://tools.ietf.org/html/rfc8415>`__ + forbids it, it is possible to + parse those DUIDs and extract necessary information from them. This + method is not completely reliable, as clients may use other DUID + types, namely DUID-EN or DUID-UUID. + +- ``ipv6-link-local`` - another possible acquisition method comes from + the source IPv6 address. In typical usage, clients are sending their + packets from IPv6 link-local addresses. There is a good chance that + those addresses are based on EUI-64, which contains a MAC address. + This method is not completely reliable, as clients may use other + link-local address types. In particular, privacy extensions, defined + in `RFC 4941 <https://tools.ietf.org/html/rfc4941>`__, do not use MAC + addresses. Also note that successful extraction requires that the + address's u-bit must be set to "1" and its g-bit set to "0", indicating + that it is an interface identifier as per `RFC 2373, section + 2.5.1 <https://tools.ietf.org/html/rfc2373#section-2.5.1>`__. + +- ``client-link-addr-option`` - one extension defined to alleviate + missing MAC issues is the client link-layer address option, defined + in `RFC 6939 <https://tools.ietf.org/html/rfc6939>`__. This is an + option that is inserted by a relay and contains information about a + client's MAC address. This method requires a relay agent that + supports the option and is configured to insert it. This method is + useless for directly connected clients. The value ``rfc6939`` is an alias for + ``client-link-addr-option``. + +- ``remote-id`` - `RFC 4649 <https://tools.ietf.org/html/rfc4649>`__ + defines a ``remote-id`` option that is inserted by a relay agent. + Depending on the relay agent configuration, the inserted option may + convey the client's MAC address information. The value ``rfc4649`` + is an alias for ``remote-id``. + +- ``subscriber-id`` - Defined in `RFC 4580 <https://tools.ietf.org/html/rfc4580>`__, + ``subscriber-id`` is somewhat similar to ``remote-id``; it is also inserted + by a relay agent. The value ``rfc4580`` is an alias for + ``subscriber-id``. This method is currently not implemented. + +- ``docsis-cmts`` - Yet another possible source of MAC address + information are the DOCSIS options inserted by a CMTS that acts as a + DHCPv6 relay agent in cable networks. This method attempts to extract + MAC address information from sub-option 1026 (cm mac) of the + vendor-specific option with ``vendor-id=4491``. This vendor option is + extracted from the Relay-forward message, not the original client's + message. + +- ``docsis-modem`` - The final possible source of MAC address + information are the DOCSIS options inserted by the cable modem + itself. This method attempts to extract MAC address information from + sub-option 36 (``device-id``) of the vendor-specific option with + ``vendor-id=4491``. This vendor option is extracted from the original + client's message, not from any relay options. + +An empty ``mac-sources`` parameter is not allowed. Administrators who do not want to specify it +should either simply omit the ``mac-sources`` definition or specify it with the +"any" value, which is the default. + +.. _dhcp6-decline: + +Duplicate Addresses (DHCPDECLINE Support) +========================================= + +The DHCPv6 server is configured with a certain pool of addresses that it +is expected to hand out to DHCPv6 clients. It is assumed that the server +is authoritative and has complete jurisdiction over those addresses. +However, for various reasons such as misconfiguration or a faulty +client implementation that retains its address beyond the valid +lifetime, there may be devices connected that use those addresses +without the server's approval or knowledge. + +Such an unwelcome event can be detected by legitimate clients (using +Duplicate Address Detection) and reported to the DHCPv6 server using a +DHCPDECLINE message. The server does a sanity check (to see whether +the client declining an address really was supposed to use it), then +conducts a clean-up operation, and confirms the DHCPDECLINE by sending back a REPLY +message. Any DNS entries related to that address are removed, the +event is logged, and hooks are triggered. After that is +complete, the address is marked as declined (which indicates that +it is used by an unknown entity and thus not available for assignment) +and a probation time is set on it. Unless otherwise configured, the +probation period lasts 24 hours; after that time, the server will +recover the lease (i.e. put it back into the available state) and the +address will be available for assignment again. It should be noted that +if the underlying issue of a misconfigured device is not resolved, the +duplicate-address scenario will repeat. If reconfigured correctly, this +mechanism provides an opportunity to recover from such an event +automatically, without any system administrator intervention. + +To configure the decline probation period to a value other than the +default, the following syntax can be used: + +:: + + "Dhcp6": { + "decline-probation-period": 3600, + "subnet6": [ + { + ... + }, + ... + ], + ... + } + +The parameter is expressed in seconds, so the example above +instructs the server to recycle declined leases after one hour. + +There are several statistics and hook points associated with the decline +handling procedure. The ``lease6_decline`` hook point is triggered after the +incoming DHCPDECLINE message has been sanitized and the server is about +to decline the lease. The ``declined-addresses`` statistic is increased +after the hook returns (both the global and subnet-specific variants). (See +:ref:`dhcp6-stats` and :ref:`hooks-libraries` +for more details on DHCPv6 statistics and Kea hook points.) + +Once the probation time elapses, the declined lease is recovered using +the standard expired-lease reclamation procedure, with several +additional steps. In particular, both ``declined-addresses`` statistics +(global and subnet-specific) are decreased. At the same time, +``reclaimed-declined-addresses`` statistics (again in two variants, global +and subnet-specific) are increased. + +A note about statistics: The Kea server does not decrease the +``assigned-nas`` statistics when a DHCPDECLINE message is received and +processed successfully. While technically a declined address is no +longer assigned, the primary usage of the ``assigned-nas`` statistic +is to monitor pool utilization. Most people would forget to include +``declined-addresses`` in the calculation, and would simply use +``assigned-nas``/``total-nas``. This would cause a bias towards +under-representing pool utilization. As this has a potential to cause serious +confusion, ISC decided not to decrease ``assigned-nas`` immediately after +receiving DHCPDECLINE, but to do it later when Kea recovers the address +back to the available pool. + +.. _dhcp6-stats: + +Statistics in the DHCPv6 Server +=============================== + +The DHCPv6 server supports the following statistics: + +.. tabularcolumns:: |p{0.2\linewidth}|p{0.1\linewidth}|p{0.7\linewidth}| + +.. table:: DHCPv6 statistics + :class: longtable + :widths: 20 10 70 + + + +---------------------------------------------------+----------------+------------------------------------+ + | Statistic | Data Type | Description | + +===================================================+================+====================================+ + | pkt6-received | integer | Number of DHCPv6 packets received. | + | | | This includes all packets: valid, | + | | | bogus, corrupted, rejected, etc. | + | | | This statistic is expected to grow | + | | | rapidly. | + +---------------------------------------------------+----------------+------------------------------------+ + | pkt6-receive-drop | integer | Number of incoming packets that | + | | | were dropped. The exact reason for | + | | | dropping packets is logged, but | + | | | the most common reasons may be: an | + | | | unacceptable or not supported | + | | | packet type is received, direct | + | | | responses are forbidden, the | + | | | server-id sent by the client does | + | | | not match the server's server-id, | + | | | or the packet is malformed. | + +---------------------------------------------------+----------------+------------------------------------+ + | pkt6-parse-failed | integer | Number of incoming packets that | + | | | could not be parsed. A non-zero | + | | | value of this statistic indicates | + | | | that the server received a | + | | | malformed or truncated packet. | + | | | This may indicate problems in the | + | | | network, faulty clients, faulty | + | | | relay agents, or a bug in the | + | | | server. | + +---------------------------------------------------+----------------+------------------------------------+ + | pkt6-solicit-received | integer | Number of SOLICIT packets | + | | | received. This statistic is | + | | | expected to grow; its increase | + | | | means that clients that just | + | | | booted started their configuration | + | | | process and their initial packets | + | | | reached the Kea server. | + +---------------------------------------------------+----------------+------------------------------------+ + | pkt6-advertise-received | integer | Number of ADVERTISE packets | + | | | received. ADVERTISE packets are | + | | | sent by the server and the server | + | | | is never expected to receive them. | + | | | A non-zero value of this statistic | + | | | indicates an error occurring in | + | | | the network. One likely cause | + | | | would be a misbehaving relay | + | | | agent that incorrectly forwards | + | | | ADVERTISE messages towards the | + | | | server, rather than back to the | + | | | clients. | + +---------------------------------------------------+----------------+------------------------------------+ + | pkt6-request-received | integer | Number of DHCPREQUEST packets | + | | | received. This statistic is | + | | | expected to grow. Its increase | + | | | means that clients that just | + | | | booted received the server's | + | | | response (DHCPADVERTISE) and | + | | | accepted it, and are now | + | | | requesting an address | + | | | (DHCPREQUEST). | + +---------------------------------------------------+----------------+------------------------------------+ + | pkt6-reply-received | integer | Number of REPLY packets received. | + | | | This statistic is expected to | + | | | remain zero at all times, as REPLY | + | | | packets are sent by the server and | + | | | the server is never expected to | + | | | receive them. A non-zero value | + | | | indicates an error. One likely | + | | | cause would be a misbehaving relay | + | | | agent that incorrectly forwards | + | | | REPLY messages towards the server, | + | | | rather than back to the clients. | + +---------------------------------------------------+----------------+------------------------------------+ + | pkt6-renew-received | integer | Number of RENEW packets received. | + | | | This statistic is expected to | + | | | grow; its increase means that | + | | | clients received their addresses | + | | | and prefixes and are trying to | + | | | renew them. | + +---------------------------------------------------+----------------+------------------------------------+ + | pkt6-rebind-received | integer | Number of REBIND packets received. | + | | | A non-zero value indicates that | + | | | clients did not receive responses | + | | | to their RENEW messages (through | + | | | the regular lease-renewal | + | | | mechanism) and are attempting to | + | | | find any server that is able to | + | | | take over their leases. It may | + | | | mean that some servers' REPLY | + | | | messages never reached the | + | | | clients. | + +---------------------------------------------------+----------------+------------------------------------+ + | pkt6-release-received | integer | Number of RELEASE packets | + | | | received. This statistic is | + | | | expected to grow when a device is | + | | | being shut down in the network; it | + | | | indicates that the address or | + | | | prefix assigned is reported as no | + | | | longer needed. Note that many | + | | | devices, especially wireless, do | + | | | not send RELEASE packets either | + | | | because of design choice or due to | + | | | the client moving out of range. | + +---------------------------------------------------+----------------+------------------------------------+ + | pkt6-decline-received | integer | Number of DECLINE packets | + | | | received. This statistic is | + | | | expected to remain close to zero. | + | | | Its increase means that a client | + | | | leased an address, but discovered | + | | | that the address is currently used | + | | | by an unknown device in the | + | | | network. If this statistic is | + | | | growing, it may indicate a | + | | | misconfigured server or devices | + | | | that have statically assigned | + | | | conflicting addresses. | + +---------------------------------------------------+----------------+------------------------------------+ + | pkt6-infrequest-received | integer | Number of INFORMATION-REQUEST | + | | | packets received. This statistic | + | | | is expected to grow if there are | + | | | devices that are using stateless | + | | | DHCPv6. INFORMATION-REQUEST | + | | | messages are used by clients that | + | | | request stateless configuration, | + | | | i.e. options and parameters other | + | | | than addresses or prefixes. | + +---------------------------------------------------+----------------+------------------------------------+ + | pkt6-dhcpv4-query-received | integer | Number of DHCPv4-QUERY packets | + | | | received. This statistic is | + | | | expected to grow if there are | + | | | devices that are using | + | | | DHCPv4-over-DHCPv6. DHCPv4-QUERY | + | | | messages are used by DHCPv4 | + | | | clients on an IPv6-only line which | + | | | encapsulates the requests over | + | | | DHCPv6. | + +---------------------------------------------------+----------------+------------------------------------+ + | pkt6-dhcpv4-response-received | integer | Number of DHCPv4-RESPONSE packets | + | | | received. This statistic is | + | | | expected to remain zero at all | + | | | times, as DHCPv4-RESPONSE packets | + | | | are sent by the server and the | + | | | server is never expected to | + | | | receive them. A non-zero value | + | | | indicates an error. One likely | + | | | cause would be a misbehaving relay | + | | | agent that incorrectly forwards | + | | | DHCPv4-RESPONSE message towards | + | | | the server rather than back to the | + | | | clients. | + +---------------------------------------------------+----------------+------------------------------------+ + | pkt6-unknown-received | integer | Number of packets received of an | + | | | unknown type. A non-zero value of | + | | | this statistic indicates that the | + | | | server received a packet that it | + | | | was unable to recognize; either it | + | | | had an unsupported type or was | + | | | possibly malformed. | + +---------------------------------------------------+----------------+------------------------------------+ + | pkt6-sent | integer | Number of DHCPv6 packets sent. | + | | | This statistic is expected to grow | + | | | every time the server transmits a | + | | | packet. In general, it should | + | | | roughly match pkt6-received, as | + | | | most incoming packets cause the | + | | | server to respond. There are | + | | | exceptions (e.g. server receiving | + | | | a REQUEST with server-id matching | + | | | another server), so do not worry | + | | | if it is less than pkt6-received. | + +---------------------------------------------------+----------------+------------------------------------+ + | pkt6-advertise-sent | integer | Number of ADVERTISE packets sent. | + | | | This statistic is expected to grow | + | | | in most cases after a SOLICIT is | + | | | processed. There are certain | + | | | uncommon, but valid, cases where | + | | | incoming SOLICIT packets are | + | | | dropped, but in general this | + | | | statistic is expected to be close | + | | | to pkt6-solicit-received. | + +---------------------------------------------------+----------------+------------------------------------+ + | pkt6-reply-sent | integer | Number of REPLY packets sent. This | + | | | statistic is expected to grow in | + | | | most cases after a SOLICIT (with | + | | | rapid-commit), REQUEST, RENEW, | + | | | REBIND, RELEASE, DECLINE, or | + | | | INFORMATION-REQUEST is processed. | + | | | There are certain cases where | + | | | there is no response. | + +---------------------------------------------------+----------------+------------------------------------+ + | pkt6-dhcpv4-response-sent | integer | Number of DHCPv4-RESPONSE packets | + | | | sent. This statistic is expected | + | | | to grow in most cases after a | + | | | DHCPv4-QUERY is processed. There | + | | | are certain cases where there is | + | | | no response. | + +---------------------------------------------------+----------------+------------------------------------+ + | subnet[id].total-nas | big integer | Total number of NA addresses | + | | | available for DHCPv6 management | + | | | for a given subnet; in other | + | | | words, this is the count of all | + | | | addresses in all configured pools. | + | | | This statistic changes only during | + | | | configuration changes. It does not | + | | | take into account any addresses | + | | | that may be reserved due to host | + | | | reservation. The *id* is the | + | | | subnet-id of a given subnet. This | + | | | statistic is exposed for each | + | | | subnet separately, and is reset | + | | | during a reconfiguration event. | + +---------------------------------------------------+----------------+------------------------------------+ + | subnet[id].pool[pid].total-nas | big integer | Total number of NA addresses | + | | | available for DHCPv6 management | + | | | for a given subnet pool; in other | + | | | words, this is the count of all | + | | | addresses in configured subnet | + | | | pool. This statistic changes only | + | | | during configuration changes. It | + | | | does not take into account any | + | | | addresses that may be reserved due | + | | | to host reservation. The *id* is | + | | | the subnet-id of a given subnet. | + | | | The *pid* is the pool-id of a | + | | | given pool. This statistic is | + | | | exposed for each subnet pool | + | | | separately, and is reset during a | + | | | reconfiguration event. | + +---------------------------------------------------+----------------+------------------------------------+ + | cumulative-assigned-nas | integer | Cumulative number of NA addresses | + | | | that have been assigned since | + | | | server startup. It is incremented | + | | | each time a NA address is assigned | + | | | and is not reset when the server | + | | | is reconfigured. | + +---------------------------------------------------+----------------+------------------------------------+ + | subnet[id].cumulative-assigned-nas | integer | Cumulative number of NA addresses | + | | | in a given subnet that were | + | | | assigned. It increases every time | + | | | a new lease is allocated (as a | + | | | result of receiving a REQUEST | + | | | message) and is never decreased. | + | | | The *id* is the subnet-id of a | + | | | given subnet. This statistic is | + | | | exposed for each subnet | + | | | separately, and is reset during a | + | | | reconfiguration event. | + +---------------------------------------------------+----------------+------------------------------------+ + | subnet[id].pool[pid].cumulative-assigned-nas | integer | Cumulative number of NA addresses | + | | | in a given subnet pool that were | + | | | assigned. It increases every time | + | | | a new lease is allocated (as a | + | | | result of receiving a REQUEST | + | | | message) and is never decreased. | + | | | The *id* is the subnet-id of a | + | | | given subnet. The *pid* is the | + | | | pool-id of a given pool. This | + | | | statistic is exposed for each | + | | | subnet pool separately, and is | + | | | reset during a reconfiguration | + | | | event. | + +---------------------------------------------------+----------------+------------------------------------+ + | subnet[id].assigned-nas | integer | Number of NA addresses in a given | + | | | subnet that are assigned. It | + | | | increases every time a new lease | + | | | is allocated (as a result of | + | | | receiving a REQUEST message) and | + | | | is decreased every time a lease is | + | | | released (a RELEASE message is | + | | | received) or expires. The *id* is | + | | | the subnet-id of a given subnet. | + | | | This statistic is exposed for each | + | | | subnet separately, and is reset | + | | | during a reconfiguration event. | + +---------------------------------------------------+----------------+------------------------------------+ + | subnet[id].pool[pid].assigned-nas | integer | Number of NA addresses in a given | + | | | subnet pool that are assigned. It | + | | | increases every time a new lease | + | | | is allocated (as a result of | + | | | receiving a REQUEST message) and | + | | | is decreased every time a lease is | + | | | released (a RELEASE message is | + | | | received) or expires. The *id* is | + | | | the subnet-id of a given subnet. | + | | | The *pid* is the pool-id of the | + | | | pool. This statistic is exposed | + | | | for each subnet pool separately, | + | | | and is reset during a | + | | | reconfiguration event. | + +---------------------------------------------------+----------------+------------------------------------+ + | subnet[id].total-pds | big integer | Total number of PD prefixes | + | | | available for DHCPv6 management | + | | | for a given subnet; in other | + | | | words, this is the count of all | + | | | prefixes in all configured pools. | + | | | This statistic changes only during | + | | | configuration changes. Note it | + | | | does not take into account any | + | | | prefixes that may be reserved due | + | | | to host reservation. The *id* is | + | | | the subnet-id of a given subnet. | + | | | This statistic is exposed for each | + | | | subnet separately, and is reset | + | | | during a reconfiguration event. | + +---------------------------------------------------+----------------+------------------------------------+ + | subnet[id].pd-pool[pid].total-pds | big integer | Total number of PD prefixes | + | | | available for DHCPv6 management | + | | | for a given subnet pool; in other | + | | | words, this is the count of all | + | | | prefixes in configured subnet | + | | | pd-pool. This statistic changes | + | | | only during configuration changes. | + | | | It does not take into account any | + | | | prefixes that may be reserved due | + | | | to host reservation. The *id* is | + | | | the subnet-id of a given subnet. | + | | | The *pid* is the pool-id of a | + | | | given pool. This statistic is | + | | | exposed for each subnet pd-pool | + | | | separately, and is reset during a | + | | | reconfiguration event. | + +---------------------------------------------------+----------------+------------------------------------+ + | cumulative-assigned-pds | integer | Cumulative number of PD prefixes | + | | | that have been assigned since | + | | | server startup. It is incremented | + | | | each time a PD prefix is assigned | + | | | and is not reset when the server | + | | | is reconfigured. | + +---------------------------------------------------+----------------+------------------------------------+ + | subnet[id].cumulative-assigned-pds | integer | Cumulative number of PD prefixes | + | | | in a given subnet that were | + | | | assigned. It increases every time | + | | | a new lease is allocated (as a | + | | | result of receiving a REQUEST | + | | | message) and is never decreased. | + | | | The *id* is the subnet-id of a | + | | | given subnet. This statistic is | + | | | exposed for each subnet | + | | | separately, and is reset during a | + | | | reconfiguration event. | + +---------------------------------------------------+----------------+------------------------------------+ + | subnet[id].pd-pool[pid].cumulative-assigned-pds | integer | Cumulative number of PD prefixes | + | | | in a given subnet pd-pool that | + | | | were assigned. It increases every | + | | | time a new lease is allocated (as | + | | | a result of receiving a REQUEST | + | | | message) and is never decreased. | + | | | The *id* is the subnet-id of a | + | | | given subnet. The *pid* is the | + | | | pool-id of a given pd-pool. This | + | | | statistic is exposed for each | + | | | subnet pd-pool separately, and is | + | | | reset during a reconfiguration | + | | | event. | + +---------------------------------------------------+----------------+------------------------------------+ + | subnet[id].assigned-pds | integer | Number of PD prefixes in a given | + | | | subnet that are assigned. It | + | | | increases every time a new lease | + | | | is allocated (as a result of | + | | | receiving a REQUEST message) and | + | | | is decreased every time a lease is | + | | | released (a RELEASE message is | + | | | received) or expires. The *id* is | + | | | the subnet-id of a given subnet. | + | | | This statistic is exposed for each | + | | | subnet separately, and is reset | + | | | during a reconfiguration event. | + +---------------------------------------------------+----------------+------------------------------------+ + | subnet[id].pd-pool[pid].assigned-pds | integer | Number of PD prefixes in a given | + | | | subnet pd-pool that are assigned. | + | | | It increases every time a new | + | | | lease is allocated (as a result of | + | | | receiving a REQUEST message) and | + | | | is decreased every time a lease is | + | | | released (a RELEASE message is | + | | | received) or expires. The *id* is | + | | | the subnet-id of a given subnet. | + | | | The *pid* is the pool-id of the | + | | | pd-pool. This statistic is exposed | + | | | for each subnet pd-pool | + | | | separately, and is reset during a | + | | | reconfiguration event. | + +---------------------------------------------------+----------------+------------------------------------+ + | reclaimed-leases | integer | Number of expired leases that have | + | | | been reclaimed since server | + | | | startup. It is incremented each | + | | | time an expired lease is reclaimed | + | | | (counting both NA and PD | + | | | reclamations). This statistic | + | | | never decreases. It can be used as | + | | | a long-term indicator of how many | + | | | actual leases have been reclaimed. | + | | | This is a global statistic that | + | | | covers all subnets. | + +---------------------------------------------------+----------------+------------------------------------+ + | subnet[id].reclaimed-leases | integer | Number of expired leases | + | | | associated with a given subnet | + | | | that have been reclaimed since | + | | | server startup. It is incremented | + | | | each time an expired lease is | + | | | reclaimed (counting both NA and PD | + | | | reclamations). The *id* is the | + | | | subnet-id of a given subnet. This | + | | | statistic is exposed for each | + | | | subnet separately. | + +---------------------------------------------------+----------------+------------------------------------+ + | subnet[id].pool[pid].reclaimed-leases | integer | Number of expired NA addresses | + | | | associated with a given subnet | + | | | pool that have been reclaimed | + | | | since server startup. It is | + | | | incremented each time an expired | + | | | lease is reclaimed. The *id* is | + | | | the subnet-id of a given subnet. | + | | | The *pid* is the pool-id of the | + | | | pool. This statistic is exposed | + | | | for each subnet pool separately, | + | | | and is reset during a | + | | | reconfiguration event. | + +---------------------------------------------------+----------------+------------------------------------+ + | subnet[id].pd-pool[pid].reclaimed-leases | integer | Number of expired PD prefixes | + | | | associated with a given subnet | + | | | pd-pool that have been reclaimed | + | | | since server startup. It is | + | | | incremented each time an expired | + | | | lease is reclaimed. The *id* is | + | | | the subnet-id of a given subnet. | + | | | The *pid* is the pool-id of the | + | | | pd-pool. This statistic is exposed | + | | | for each subnet pd-pool | + | | | separately, and is reset during a | + | | | reconfiguration event. | + +---------------------------------------------------+----------------+------------------------------------+ + | declined-addresses | integer | Number of IPv6 addresses that are | + | | | currently declined; a count of the | + | | | number of leases currently | + | | | unavailable. Once a lease is | + | | | recovered, this statistic will be | + | | | decreased; ideally, this statistic | + | | | should be zero. If this statistic | + | | | is non-zero or increasing, a | + | | | network administrator should | + | | | investigate whether there is a | + | | | misbehaving device in the network. | + | | | This is a global statistic that | + | | | covers all subnets. | + +---------------------------------------------------+----------------+------------------------------------+ + | subnet[id].declined-addresses | integer | Number of IPv6 addresses that are | + | | | currently declined in a given | + | | | subnet; a count of the number of | + | | | leases currently unavailable. Once | + | | | a lease is recovered, this | + | | | statistic will be decreased; | + | | | ideally, this statistic should be | + | | | zero. If this statistic is | + | | | non-zero or increasing, a network | + | | | administrator should investigate | + | | | whether there is a misbehaving | + | | | device in the network. The *id* is | + | | | the subnet-id of a given subnet. | + | | | This statistic is exposed for each | + | | | subnet separately. | + +---------------------------------------------------+----------------+------------------------------------+ + | subnet[id].pool[pid].declined-addresses | integer | Number of IPv6 addresses that are | + | | | currently declined in a given | + | | | subnet pool; a count of the number | + | | | of leases currently unavailable. | + | | | Once a lease is recovered, this | + | | | statistic will be decreased; | + | | | ideally, this statistic should be | + | | | zero. If this statistic is | + | | | non-zero or increasing, a network | + | | | administrator should investigate | + | | | whether there is a misbehaving | + | | | device in the network. The *id* is | + | | | the subnet-id of a given subnet. | + | | | The *pid* is the pool-id of the | + | | | pool. This statistic is exposed | + | | | for each subnet pool separately. | + +---------------------------------------------------+----------------+------------------------------------+ + | reclaimed-declined-addresses | integer | Number of IPv6 addresses that were | + | | | declined, but have now been | + | | | recovered. Unlike | + | | | declined-addresses, this statistic | + | | | never decreases. It can be used as | + | | | a long-term indicator of how many | + | | | actual valid declines were | + | | | processed and recovered from. This | + | | | is a global statistic that covers | + | | | all subnets. | + +---------------------------------------------------+----------------+------------------------------------+ + | subnet[id].reclaimed-declined-addresses | integer | Number of IPv6 addresses that were | + | | | declined, but have now been | + | | | recovered. Unlike | + | | | declined-addresses, this statistic | + | | | never decreases. It can be used as | + | | | a long-term indicator of how many | + | | | actual valid declines were | + | | | processed and recovered from. The | + | | | *id* is the subnet-id of a given | + | | | subnet. This statistic is exposed | + | | | for each subnet separately. | + +---------------------------------------------------+----------------+------------------------------------+ + | subnet[id].pool[pid].reclaimed-declined-addresses | integer | Number of IPv6 addresses that were | + | | | declined, but have now been | + | | | recovered. Unlike | + | | | declined-addresses, this statistic | + | | | never decreases. It can be used as | + | | | a long-term indicator of how many | + | | | actual valid declines were | + | | | processed and recovered from. The | + | | | *id* is the subnet-id of a given | + | | | subnet. The *pid* is the pool-id | + | | | of the pool. This statistic is | + | | | exposed for each subnet pool | + | | | separately. | + +---------------------------------------------------+----------------+------------------------------------+ + | v6-allocation-fail | integer | Number of total address allocation | + | | | failures for a particular client. | + | | | This consists in the number of | + | | | lease allocation attempts that the | + | | | server made before giving up and | + | | | was unable to use any of the | + | | | address pools. This is a global | + | | | statistic that covers all subnets. | + +---------------------------------------------------+----------------+------------------------------------+ + | subnet[id].v6-allocation-fail | integer | Number of total address allocation | + | | | failures for a particular client. | + | | | This consists in the number of | + | | | lease allocation attempts that the | + | | | server made before giving up and | + | | | was unable to use any of the | + | | | address pools. The *id* is the | + | | | subnet-id of a given subnet. This | + | | | statistic is exposed for each | + | | | subnet separately. | + +---------------------------------------------------+----------------+------------------------------------+ + | v6-allocation-fail-shared-network | integer | Number of address allocation | + | | | failures for a particular client | + | | | connected to a shared network. | + | | | This is a global statistic that | + | | | covers all subnets. | + +---------------------------------------------------+----------------+------------------------------------+ + | subnet[id].v6-allocation-fail-shared-network | integer | Number of address allocation | + | | | failures for a particular client | + | | | connected to a shared network. | + | | | The *id* is the subnet-id of a | + | | | given subnet. This statistic is | + | | | exposed for each subnet | + | | | separately. | + +---------------------------------------------------+----------------+------------------------------------+ + | v6-allocation-fail-subnet | integer | Number of address allocation | + | | | failures for a particular client | + | | | connected to a subnet that does | + | | | not belong to a shared network. | + | | | This is a global statistic that | + | | | covers all subnets. | + +---------------------------------------------------+----------------+------------------------------------+ + | subnet[id].v6-allocation-fail-subnet | integer | Number of address allocation | + | | | failures for a particular client | + | | | connected to a subnet that does | + | | | not belong to a shared network. | + | | | The *id* is the subnet-id of a | + | | | given subnet. This statistic is | + | | | exposed for each subnet | + | | | separately. | + +---------------------------------------------------+----------------+------------------------------------+ + | v6-allocation-fail-no-pools | integer | Number of address allocation | + | | | failures because the server could | + | | | not use any configured pools for | + | | | a particular client. It is also | + | | | possible that all of the subnets | + | | | from which the server attempted to | + | | | assign an address lack address | + | | | pools. In this case, it should be | + | | | considered misconfiguration if an | + | | | operator expects that some clients | + | | | should be assigned dynamic | + | | | addresses. This is a global | + | | | statistic that covers all subnets. | + +---------------------------------------------------+----------------+------------------------------------+ + | subnet[id].v6-allocation-fail-no-pools | integer | Number of address allocation | + | | | failures because the server could | + | | | not use any configured pools for | + | | | a particular client. It is also | + | | | possible that all of the subnets | + | | | from which the server attempted to | + | | | assign an address lack address | + | | | pools. In this case, it should be | + | | | considered misconfiguration if an | + | | | operator expects that some clients | + | | | should be assigned dynamic | + | | | addresses. The *id* is the | + | | | subnet-id of a given subnet. This | + | | | statistic is exposed for each | + | | | subnet separately. | + +---------------------------------------------------+----------------+------------------------------------+ + | v6-allocation-fail-classes | integer | Number of address allocation | + | | | failures when the client's packet | + | | | belongs to one or more classes. | + | | | There may be several reasons why a | + | | | lease was not assigned. One of | + | | | them may be a case when all pools | + | | | require packet to belong to | + | | | certain classes and the incoming | + | | | packet didn't belong to any of | + | | | them. Another case where this | + | | | information may be useful is to | + | | | point out that the pool reserved | + | | | to a given class has ran out of | + | | | addresses. This is a global | + | | | statistic that covers all subnets. | + +---------------------------------------------------+----------------+------------------------------------+ + | subnet[id].v6-allocation-fail-classes | integer | Number of address allocation | + | | | failures when the client's packet | + | | | belongs to one or more classes. | + | | | There may be several reasons why a | + | | | lease was not assigned. One of | + | | | them may be a case when all pools | + | | | require packet to belong to | + | | | certain classes and the incoming | + | | | packet didn't belong to any of | + | | | them. Another case where this | + | | | information may be useful is to | + | | | point out that the pool reserved | + | | | to a given class has ran out of | + | | | addresses. The *id* is the | + | | | subnet-id of a given subnet. This | + | | | statistic is exposed for each | + | | | subnet separately. | + +---------------------------------------------------+----------------+------------------------------------+ + | v6-ia-na-lease-reuses | integer | Number of times an IA_NA lease had | + | | | its CLTT increased in memory and | + | | | its expiration time left unchanged | + | | | in persistent storage as part of | + | | | the lease caching feature. This is | + | | | referred to as a lease reuse. | + | | | This statistic is global. | + +---------------------------------------------------+----------------+------------------------------------+ + | subnet[id].v6-ia-na-lease-reuses | integer | Number of times an IA_NA lease had | + | | | its CLTT increased in memory and | + | | | its expiration time left unchanged | + | | | in persistent storage as part of | + | | | the lease caching feature. This is | + | | | referred to as a lease reuse. | + | | | This statistic is on a per-subnet | + | | | basis. The *id* is the subnet-id | + | | | of a given subnet. | + +---------------------------------------------------+----------------+------------------------------------+ + | v6-ia-pd-lease-reuses | integer | Number of times an IA_PD lease had | + | | | its CLTT increased in memory and | + | | | its expiration time left unchanged | + | | | in persistent storage as part of | + | | | the lease caching feature. This is | + | | | referred to as a lease reuse. | + | | | This statistic is global. | + +---------------------------------------------------+----------------+------------------------------------+ + | subnet[id].v6-ia-pd-lease-reuses | integer | Number of times an IA_PD lease had | + | | | its CLTT increased in memory and | + | | | its expiration time left unchanged | + | | | in persistent storage as part of | + | | | the lease caching feature. This is | + | | | referred to as a lease reuse. | + | | | This statistic is on a per-subnet | + | | | basis. The *id* is the subnet-id | + | | | of a given subnet. | + +---------------------------------------------------+----------------+------------------------------------+ + +.. note:: + + The pool ID can be configured on each pool by explicitly setting the ``pool-id`` + parameter in the pool parameter map. If not configured, ``pool-id`` defaults to 0. + The statistics related to pool ID 0 refer to all the statistics of all the pools + that have unconfigured ``pool-id``. + The pool ID does not need to be unique within the subnet or across subnets. + The statistics regarding a specific pool ID within a subnet will be combined with the + other statistics of all other pools with the same pool ID in the respective subnet. + +.. note:: + + This section describes DHCPv6-specific statistics. For a general + overview and usage of statistics, see :ref:`stats`. + +The DHCPv6 server provides two global parameters to control the default sample +limits of statistics: + +- ``statistic-default-sample-count`` - determines the default maximum + number of samples which are kept. The special value of 0 + indicates that a default maximum age should be used. + +- ``statistic-default-sample-age`` - determines the default maximum + age in seconds of samples which are kept. + +For instance, to reduce the statistic-keeping overhead, set +the default maximum sample count to 1 so only one sample is kept: + +:: + + "Dhcp6": { + "statistic-default-sample-count": 1, + "subnet6": [ + { + ... + }, + ... + ], + ... + } + +Statistics can be retrieved periodically to gain more insight into Kea operations. One tool that +leverages that capability is ISC Stork. See :ref:`stork` for details. + + +.. _dhcp6-ctrl-channel: + +Management API for the DHCPv6 Server +==================================== + +The management API allows the issuing of specific management commands, +such as statistics retrieval, reconfiguration, or shutdown. For more +details, see :ref:`ctrl-channel`. Currently, the only supported +communication channel type is the UNIX stream socket. By default there are +no sockets open; to instruct Kea to open a socket, the following entry +in the configuration file can be used: + +:: + + "Dhcp6": { + "control-socket": { + "socket-type": "unix", + "socket-name": "/path/to/the/unix/socket" + }, + + "subnet6": [ + { + ... + }, + ... + ], + ... + } + +The length of the path specified by the ``socket-name`` parameter is +restricted by the maximum length for the UNIX socket name on the administrator's +operating system, i.e. the size of the ``sun_path`` field in the +``sockaddr_un`` structure, decreased by 1. This value varies on +different operating systems, between 91 and 107 characters. Typical +values are 107 on Linux and 103 on FreeBSD. + +Communication over the control channel is conducted using JSON +structures. See the +`Control Channel section in the Kea Developer's Guide +<https://reports.kea.isc.org/dev_guide/d2/d96/ctrlSocket.html>`__ +for more details. + +The DHCPv6 server supports the following operational commands: + +- :isccmd:`build-report` +- :isccmd:`config-get` +- :isccmd:`config-hash-get` +- :isccmd:`config-reload` +- :isccmd:`config-set` +- :isccmd:`config-test` +- :isccmd:`config-write` +- :isccmd:`dhcp-disable` +- :isccmd:`dhcp-enable` +- :isccmd:`leases-reclaim` +- :isccmd:`list-commands` +- :isccmd:`shutdown` +- :isccmd:`status-get` +- :isccmd:`version-get` + +as described in :ref:`commands-common`. In addition, it supports the +following statistics-related commands: + +- :isccmd:`statistic-get` +- :isccmd:`statistic-reset` +- :isccmd:`statistic-remove` +- :isccmd:`statistic-get`-all +- :isccmd:`statistic-reset`-all +- :isccmd:`statistic-remove`-all +- :isccmd:`statistic-sample-age-set` +- :isccmd:`statistic-sample-age-set`-all +- :isccmd:`statistic-sample-count-set` +- :isccmd:`statistic-sample-count-set`-all + +as described in :ref:`command-stats`. + +.. _dhcp6-user-contexts: + +User Contexts in IPv6 +===================== + +Kea allows the loading of hook libraries that can sometimes benefit from +additional parameters. If such a parameter is specific to the whole +library, it is typically defined as a parameter for the hook library. +However, sometimes there is a need to specify parameters that are +different for each pool. + +See :ref:`user-context` for additional background regarding the +user-context idea. See :ref:`user-context-hooks` for a discussion from the +hooks perspective. + +User contexts can be specified at global scope; at the shared-network, subnet, +pool, client-class, option-data, or definition level; and via host +reservation. One other useful feature is the ability to store comments or +descriptions. + +Let's consider an example deployment of lightweight 4over6, an +IPv6 transition technology that allows mapping IPv6 prefixes into full +or partial IPv4 addresses. In the DHCP context, these are specific +parameters that are supposed to be delivered to clients in the form of +additional options. Values of these options are correlated to delegated +prefixes, so it is reasonable to keep these parameters together with the +prefix delegation (PD) pool. On the other hand, lightweight 4over6 is not a commonly used +feature, so it is not a part of the base Kea code. The solution to this +problem is to specify a user context. For each PD pool that is expected to be +used for lightweight 4over6, a user context with extra parameters is +defined. Those extra parameters will be used by a hook library +and loaded only when dynamic calculation of the lightweight 4over6 +option is actually needed. An example configuration looks as follows: + +:: + + "Dhcp6": { + "subnet6": [ { + "pd-pools": [ + { + "prefix": "2001:db8::", + "prefix-len": 56, + "delegated-len": 64, + + # This is a pool specific context. + "user-context": { + "threshold-percent": 85, + "v4-network": "192.168.0.0/16", + "v4-overflow": "10.0.0.0/16", + "lw4over6-sharing-ratio": 64, + "lw4over6-v4-pool": "192.0.2.0/24", + "lw4over6-sysports-exclude": true, + "lw4over6-bind-prefix-len": 56 + } + } ], + "id": 1, + "subnet": "2001:db8::/32", + + # This is a subnet-specific context. Any type of + # information can be entered here as long as it is valid JSON. + "user-context": { + "comment": "Those v4-v6 migration technologies are tricky.", + "experimental": true, + "billing-department": 42, + "contacts": [ "Alice", "Bob" ] + } + } ] + } + +Kea does not interpret or use the user-context information; it simply +stores it and makes it available to the hook libraries. It is up to each +hook library to extract that information and use it. The parser +translates a ``comment`` entry into a user context with the entry, which +allows a comment to be attached inside the configuration itself. + +.. _dhcp6-std: + +Supported DHCPv6 Standards +========================== + +The following standards are currently supported in Kea: + +- *Dynamic Host Configuration Protocol for IPv6*, `RFC + 3315 <https://tools.ietf.org/html/rfc3315>`__: Supported messages are + SOLICIT, ADVERTISE, REQUEST, RELEASE, RENEW, REBIND, + INFORMATION-REQUEST, CONFIRM, DECLINE and REPLY. The only + unsupported message is RECONFIGURE. + +- *Dynamic Host Configuration Protocol (DHCPv6) Options for + Session Initiation Protocol (SIP) Servers*, `RFC 3319 + <https://tools.ietf.org/html/rfc3319>`__: All defined options are supported. + +- *IPv6 Prefix Options for Dynamic Host Configuration Protocol (DHCP) + version 6*, `RFC 3633 <https://tools.ietf.org/html/rfc3633>`__: + Supported options are IA_PD and IA_PREFIX. Also supported is the + status code NoPrefixAvail. + +- *DNS Configuration options for Dynamic Host Configuration Protocol for IPv6 + (DHCPv6)*, `RFC 3646 <https://tools.ietf.org/html/rfc3646>`__: All defined + options are supported. + +- *Stateless Dynamic Host Configuration Protocol (DHCP) Service for IPv6*, `RFC + 3736 <https://tools.ietf.org/html/rfc3736>`__: Server operation in + stateless mode is supported. Kea is currently server-only, so the client side + is not implemented. + +- *Information Refresh Time Option for Dynamic Host Configuration Protocol for + IPv6 (DHCPv6)*, `RFC 4242 <https://tools.ietf.org/html/rfc4242>`__: The + sole defined option (``information-refresh-time``) is supported. + +- *The Dynamic Host Configuration Protocol for IPv6 (DHCPv6) Relay + Agent Remote-ID Option*, `RFC + 4649 <https://tools.ietf.org/html/rfc4649>`__: The REMOTE-ID option is + supported. + +- *Resolution of Fully Qualified Domain Name (FQDN) Conflicts among Dynamic Host + Configuration Protocol (DHCP) Clients*, `RFC 4703 + <https://tools.ietf.org/html/rfc4703>`__: The DHCPv6 server uses the DHCP-DDNS + server to resolve conflicts. + +- *The Dynamic Host Configuration Protocol for IPv6 (DHCPv6) Client + Fully Qualified Domain Name (FQDN) Option*, `RFC + 4704 <https://tools.ietf.org/html/rfc4704>`__: The supported option is + CLIENT_FQDN. + +- *Dynamic Host Configuration Protocol for IPv6 (DHCPv6) Option for + Dual-Stack Lite*, `RFC 6334 <https://tools.ietf.org/html/rfc6334>`__: + The AFTR-Name DHCPv6 Option is supported. + +- *Relay-Supplied DHCP Options*, `RFC + 6422 <https://tools.ietf.org/html/rfc6422>`__: The full functionality is + supported: OPTION_RSOO; the ability of the server to echo back the + options; verification of whether an option is RSOO-enabled; the ability to mark + additional options as RSOO-enabled. + +- *Prefix Exclude Option for DHCPv6-based Prefix Delegation*, `RFC + 6603 <https://tools.ietf.org/html/rfc6603>`__: The Prefix Exclude option + is supported. + +- *Client Link-Layer Address Option in DHCPv6*, `RFC + 6939 <https://tools.ietf.org/html/rfc6939>`__: The supported option is + the client link-layer address option. + +- *Issues and Recommendations with Multiple Stateful DHCPv6 Options*, + `RFC 7550 <https://tools.ietf.org/html/rfc7550>`__: All + recommendations related to the DHCPv6 server operation are supported. + +- *DHCPv6 Options for Configuration of Softwire Address and Port-Mapped + Clients*, `RFC 7598 <https://tools.ietf.org/html/rfc7598>`__: All + options indicated in this specification are supported by the DHCPv6 + server. + +- *Generalized UDP Source Port for DHCP Relay*, `RFC 8357 + <https://tools.ietf.org/html/rfc8357>`__: The Kea server is able + to handle Relay Source Port option in a received Relay-forward + message, remembers the UDP port and sends back Relay-reply with a + copy of the option to the relay agent using this UDP port. + +- *Dynamic Host Configuration Protocol for IPv6 (DHCPv6)*, `RFC 8415 + <https://tools.ietf.org/html/rfc8415>`__: This new DHCPv6 protocol specification + obsoletes RFC 3315, RFC 3633, RFC 3736, RFC 4242, RFC 7083, RFC 7283, + and RFC 7550. All features, with the exception of the RECONFIGURE mechanism and + the now-deprecated temporary addresses (IA_TA) mechanism, are supported. + +- *Captive-Portal Identification in DHCP and Router Advertisements (RAs)*, `RFC 8910 + <https://tools.ietf.org/html/rfc8910>`__: The Kea server can configure both v4 + and v6 versions of the captive portal options. + +- *DHCP and Router Advertisement Options for the Discovery of Network-designated + Resolvers (DNR)*, `RFC 9463 <https://tools.ietf.org/html/rfc9463>`__. The Kea server + supports the DNR option. Part of its value (SvcParams) must be configured in + hex. + +.. _dhcp6-limit: + +DHCPv6 Server Limitations +========================= + +These are the current known limitations of the Kea DHCPv6 server software. Most of +them are reflections of the current stage of development and should be +treated as “not implemented yet”, rather than actual limitations. + +- The server will allocate, renew, or rebind a maximum of one lease for + a particular IA option (IA_NA or IA_PD) sent by a client. `RFC + 8415 <https://tools.ietf.org/html/rfc8415>`__ allows for multiple + addresses or prefixes to be allocated for a single IA. + +- Temporary addresses are not supported. There is no intention to ever + implement this feature, as it is deprecated in `RFC 8415 + <https://tools.ietf.org/html/rfc8415>`__. + +- Client reconfiguration (RECONFIGURE) is not yet supported. + +.. _dhcp6-srv-examples: + +Kea DHCPv6 Server Examples +========================== + +A collection of simple-to-use examples for the DHCPv6 component of Kea +is available with the source files, located in the ``doc/examples/kea6`` +directory. + +.. _dhcp6-cb: + +Configuration Backend in DHCPv6 +=============================== + +In the :ref:`config-backend` section we have described the Configuration +Backend (CB) feature, its applicability, and its limitations. This section focuses +on the usage of the CB with the DHCPv6 server. It lists the supported +parameters, describes limitations, and gives examples of DHCPv6 +server configurations to take advantage of the CB. Please also refer to +the corresponding section :ref:`dhcp4-cb` for DHCPv4-specific usage of +the CB. + +.. _dhcp6-cb-parameters: + +Supported Parameters +-------------------- + +The ultimate goal for the CB is to serve as a central configuration +repository for one or multiple Kea servers connected to a database. +In currently supported Kea versions, only a subset of +the DHCPv6 server parameters can be configured in the database. All other +parameters must be specified in the JSON configuration file, if +required. + +All supported parameters can be configured via :ischooklib:`libdhcp_cb_cmds.so`. +The general rule is that +scalar global parameters are set using +:isccmd:`remote-global-parameter6-set`; shared-network-specific parameters +are set using :isccmd:`remote-network6-set`; and subnet-level and pool-level +parameters are set using :isccmd:`remote-subnet6-set`. Whenever +there is an exception to this general rule, it is highlighted in the +table. Non-scalar global parameters have dedicated commands; for example, +the global DHCPv6 options (``option-data``) are modified using +:isccmd:`remote-option6-global-set`. Client classes, together with class-specific +option definitions and DHCPv6 options, are configured using the +:isccmd:`remote-class6-set` command. + +The :ref:`cb-sharing` section explains the concept of shareable +and non-shareable configuration elements and the limitations for +sharing them between multiple servers. In the DHCP configuration (both DHCPv4 +and DHCPv6), the shareable configuration elements are subnets and shared +networks. Thus, they can be explicitly associated with multiple server tags. +The global parameters, option definitions, and global options are non-shareable +and can be associated with only one server tag. This rule does not apply +to the configuration elements associated with ``all`` servers. Any configuration +element associated with ``all`` servers (using the ``all`` keyword as a server tag) is +used by all servers connecting to the configuration database. + +The following table lists DHCPv6-specific parameters supported by the +Configuration Backend, with an indication of the level of the hierarchy +at which it is currently supported. + +.. table:: List of DHCPv6 parameters supported by the Configuration Backend + + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | Parameter | Global | Client | Shared | Subnet | Pool | Prefix | + | | | Class | Network | | | Delegation | + | | | | | | | Pool | + +=============================+============================+===========+===========+===========+===========+============+ + | allocator | yes | n/a | yes | yes | n/a | n/a | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | cache-max-age | yes | n/a | no | no | n/a | n/a | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | cache-threshold | yes | n/a | no | no | n/a | n/a | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | calculate-tee-times | yes | n/a | yes | yes | n/a | n/a | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | client-class | n/a | n/a | yes | yes | yes | yes | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | ddns-send-update | yes | n/a | yes | yes | n/a | n/a | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | ddns-override-no-update | yes | n/a | yes | yes | n/a | n/a | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | ddns-override-client-update | yes | n/a | yes | yes | n/a | n/a | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | ddns-replace-client-name | yes | n/a | yes | yes | n/a | n/a | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | ddns-generated-prefix | yes | n/a | yes | yes | n/a | n/a | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | ddns-qualifying-suffix | yes | n/a | yes | yes | n/a | n/a | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | decline-probation-period | yes | n/a | n/a | n/a | n/a | n/a | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | delegated-len | n/a | n/a | n/a | n/a | n/a | yes | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | dhcp4o6-port | yes | n/a | n/a | n/a | n/a | n/a | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | excluded-prefix | n/a | n/a | n/a | n/a | n/a | yes | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | excluded-prefix-len | n/a | n/a | n/a | n/a | n/a | yes | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | hostname-char-set | yes | n/a | yes | yes | n/a | n/a | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | hostname-char-replacement | yes | n/a | yes | yes | n/a | n/a | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | interface | n/a | n/a | yes | yes | n/a | n/a | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | interface-id | n/a | n/a | yes | yes | n/a | n/a | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | max-preferred-lifetime | yes | yes | yes | yes | n/a | n/a | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | max-valid-lifetime | yes | yes | yes | yes | n/a | n/a | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | min-preferred-lifetime | yes | yes | yes | yes | n/a | n/a | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | min-valid-lifetime | yes | yes | yes | yes | n/a | n/a | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | option-data | yes (via | yes | yes | yes | yes | yes | + | | remote-option6-global-set) | | | | | | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | option-def | yes (via | yes | n/a | n/a | n/a | n/a | + | | remote-option-def6-set) | | | | | | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | pd-allocator | yes | n/a | yes | yes | n/a | n/a | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | preferred-lifetime | yes | yes | yes | yes | n/a | n/a | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | prefix | n/a | n/a | n/a | n/a | n/a | yes | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | prefix-len | n/a | n/a | n/a | n/a | n/a | yes | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | rapid-commit | yes | n/a | yes | yes | n/a | n/a | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | rebind-timer | yes | n/a | yes | yes | n/a | n/a | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | relay | n/a | n/a | yes | yes | n/a | n/a | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | renew-timer | yes | n/a | yes | yes | n/a | n/a | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | require-client-classes | n/a | n/a | yes | yes | yes | yes | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | reservation-mode | yes | n/a | yes | yes | n/a | n/a | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | reservations-global | yes | n/a | yes | yes | n/a | n/a | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | reservations-in-subnet | yes | n/a | yes | yes | n/a | n/a | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | reservations-out-of-pool | yes | n/a | yes | yes | n/a | n/a | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | t1-percent | yes | n/a | yes | yes | n/a | n/a | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | t2-percent | yes | n/a | yes | yes | n/a | n/a | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + | valid-lifetime | yes | yes | yes | yes | n/a | n/a | + +-----------------------------+----------------------------+-----------+-----------+-----------+-----------+------------+ + +- ``yes`` - indicates that the parameter is supported at the given + level of the hierarchy and can be configured via the Configuration Backend. + +- ``no`` - indicates that a parameter is supported at the given level + of the hierarchy but cannot be configured via the Configuration Backend. + +- ``n/a`` - indicates that a given parameter is not applicable + at the particular level of the hierarchy or that the + server does not support the parameter at that level. + +Some scalar parameters contained by top level global maps are supported by the Configuration Backend. + +.. table:: List of DHCPv6 map parameters supported by the Configuration Backend + + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | Parameter name (flat naming format) | Global map | Parameter name | + +==================================================================+==============================+==================================+ + | compatibility.lenient-option-parsing | compatibility | lenient-option-parsing | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | control-socket.socket-name | control-socket | socket-name | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | control-socket.socket-type | control-socket | socket-type | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | dhcp-ddns.enable-updates | dhcp-ddns | enable-updates | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | dhcp-ddns.max-queue-size | dhcp-ddns | max-queue-size | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | dhcp-ddns.ncr-format | dhcp-ddns | ncr-format | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | dhcp-ddns.ncr-protocol | dhcp-ddns | ncr-protocol | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | dhcp-ddns.sender-ip | dhcp-ddns | sender-ip | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | dhcp-ddns.sender-port | dhcp-ddns | sender-port | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | dhcp-ddns.server-ip | dhcp-ddns | server-ip | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | dhcp-ddns.server-port | dhcp-ddns | server-port | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | dhcp-ddns.generated-prefix | dhcp-ddns | generated-prefix | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | dhcp-ddns.hostname-char-replacement | dhcp-ddns | hostname-char-replacement | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | dhcp-ddns.hostname-char-set | dhcp-ddns | hostname-char-set | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | dhcp-ddns.override-client-update | dhcp-ddns | override-client-update | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | dhcp-ddns.override-no-update | dhcp-ddns | override-no-update | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | dhcp-ddns.qualifying-suffix | dhcp-ddns | qualifying-suffix | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | dhcp-ddns.replace-client-name | dhcp-ddns | replace-client-name | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | expired-leases-processing.flush-reclaimed-timer-wait-time | expired-leases-processing | flush-reclaimed-timer-wait-time | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | expired-leases-processing.hold-reclaimed-time | expired-leases-processing | hold-reclaimed-time | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | expired-leases-processing.max-reclaim-leases | expired-leases-processing | max-reclaim-leases | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | expired-leases-processing.max-reclaim-time | expired-leases-processing | max-reclaim-time | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | expired-leases-processing.reclaim-timer-wait-time | expired-leases-processing | reclaim-timer-wait-time | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | expired-leases-processing.unwarned-reclaim-cycles | expired-leases-processing | unwarned-reclaim-cycles | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | multi-threading.enable-multi-threading | multi-threading | enable-multi-threading | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | multi-threading.thread-pool-size | multi-threading | thread-pool-size | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | multi-threading.packet-queue-size | multi-threading | packet-queue-size | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | sanity-checks.lease-checks | sanity-checks | lease-checks | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | sanity-checks.extended-info-checks | sanity-checks | extended-info-checks | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | server-id.type | server-id | type | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | server-id.enterprise-id | server-id | enterprise-id | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | server-id.identifier | server-id | identifier | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | server-id.persist | server-id | persist | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | dhcp-queue-control.enable-queue | dhcp-queue-control | enable-queue | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | dhcp-queue-control.queue-type | dhcp-queue-control | queue-type | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + | dhcp-queue-control.capacity | dhcp-queue-control | capacity | + +------------------------------------------------------------------+------------------------------+----------------------------------+ + +.. _dhcp6-cb-json: + +Enabling the Configuration Backend +---------------------------------- + +Consider the following configuration snippet, which uses a MySQL configuration +database: + +.. code-block:: json + + { + "Dhcp6": { + "server-tag": "my DHCPv6 server", + "config-control": { + "config-databases": [ + { + "type": "mysql", + "name": "kea", + "user": "kea", + "password": "kea", + "host": "2001:db8:1::1", + "port": 3302 + } + ], + "config-fetch-wait-time": 20 + }, + "hooks-libraries": [ + { + "library": "/usr/local/lib/kea/hooks/libdhcp_mysql_cb.so" + }, + { + "library": "/usr/local/lib/kea/hooks/libdhcp_cb_cmds.so" + } + ] + } + } + +The configuration structure is almost identical to that of the DHCPv4 server +(see :ref:`dhcp4-cb-json` for the detailed description). + +.. _dhcp6-compatibility: + +Kea DHCPv6 Compatibility Configuration Parameters +================================================= + +ISC's intention is for Kea to follow the RFC documents to promote better standards +compliance. However, many buggy DHCP implementations already exist that cannot be +easily fixed or upgraded. Therefore, Kea provides an easy-to-use compatibility +mode for broken or non-compliant clients. For that purpose, the compatibility option must be +enabled to permit uncommon practices: + +.. code-block:: json + + { + "Dhcp6": { + "compatibility": { + } + } + } + + +Lenient Option Parsing +---------------------- + +By default, DHCPv6 option 16's ``vendor-class-data`` field is parsed as a set of +length-value pairs. Same for tuple fields defined in custom options. + +With ``"lenient-option-parsing": true``, if a length ever exceeds the rest of +the option's buffer, previous versions of Kea returned a log message ``unable to +parse the opaque data tuple, the buffer length is x, but the tuple length is y`` +with ``x < y``; this no longer occurs. Instead, the value is considered to be the rest of the buffer, +or in terms of the log message above, the tuple length ``y`` becomes ``x``. + +Enabling this flag is expected to improve compatibility with devices such as RAD +MiNID. + +.. code-block:: json + + { + "Dhcp6": { + "compatibility": { + "lenient-option-parsing": true + } + } + } + +.. _dhcp6_allocation_strategies: + +Allocation Strategies in DHCPv6 +=============================== + +A DHCP server follows a complicated algorithm to select a DHCPv6 lease for a client. +It prefers assigning specific addresses or delegated prefixes requested by the client +and the ones for which the client has reservations. + +When the client requests a specific delegated prefix, there are a few steps that +:iscman:`kea-dhcp6` goes through to try to satisfy the request, in the following +order: + +1. It searches for a lease that matches the requested prefix and prefix length. +2. It searches for a lease that matches the prefix length. +3. It searches for a lease with a larger address space (smaller prefix length). +4. It searches for a lease with a smaller address space (larger prefix length). + +If the client requests no particular +lease and has no reservations, or other clients are already using any requested leases, the server must +find another available lease within the configured pools. A server function called +an "allocator" is responsible in Kea for finding an available lease in such a case. + +The Kea DHCPv6 server provides configuration parameters to select different allocators +at the global, shared-network, and subnet levels. It also +allows for selecting different allocation strategies for address assignments and +prefix delegation. + +Consider the following example: + +.. code-block:: json + + { + "Dhcp6": { + "allocator": "iterative", + "pd-allocator": "random", + "subnet6": [ + { + "id": 1, + "subnet": "2001:db8:1::/64", + "allocator": "random" + }, + { + "id": 2, + "subnet": "2001:db8:2::/64", + "pd-allocator": "iterative" + } + ] + } + } + +The iterative allocator is globally selected for address assignments, while the +random allocator is globally selected for prefix delegation. These settings +are selectively overridden at the subnet level. + +The following sections describe the supported allocators and their +recommended uses. + + +Allocators Comparison +--------------------- + +In the table below, we briefly compare the supported allocators. The +detailed allocators' descriptions are in later sections. + +.. table:: Comparison of the lease allocators supported by Kea DHCPv6 + + +------------------+-----------------------------+------------------------------+-----------------------+------------------------------+----------------+ + | Allocator | Low Utilization Performance | High Utilization Performance | Lease Randomization | Startup/Configuration | Memory Usage | + +==================+=============================+==============================+=======================+==============================+================+ + | Iterative | very high | low | no | very fast | low | + +------------------+-----------------------------+------------------------------+-----------------------+------------------------------+----------------+ + | Random | high | low | yes | very fast | high (varying) | + +------------------+-----------------------------+------------------------------+-----------------------+------------------------------+----------------+ + | Free Lease Queue | high | high | yes | slow (depends on pool sizes) | high (varying) | + +------------------+-----------------------------+------------------------------+-----------------------+------------------------------+----------------+ + + +Iterative Allocator +------------------- +This is the default allocator used by the Kea DHCPv6 server. It remembers the +last offered lease and offers the following sequential lease to the next client. +For example, it may offer addresses in this order: ``2001:db8:1::10``, +``2001:db8:1::11``, ``2001:db8:1::12``, and so on. Similarly, it offers the +next sequential delegated prefix after the previous one to the next client. The time to +find and offer the next lease is very short; thus, this is the most performant +allocator when pool utilization is low and there is a high probability +that the next selected lease is available. + +The iterative allocation underperforms when multiple DHCP servers share a lease +database or are connected to a cluster. The servers tend to offer and allocate +the same blocks of addresses to different clients independently, which causes many +allocation conflicts between the servers and retransmissions by clients. A random +allocation addresses this issue by dispersing the allocation order. + +Random Allocator +---------------- + +The random allocator uses a uniform randomization function to select offered +addresses and delegated prefixes from subnet pools. It is suitable in deployments +where multiple servers are connected +to a shared database or a database cluster. By dispersing the offered leases, the +servers minimize the risk of allocating the same lease to two different clients at +the same or nearly the same time. In addition, it improves the server's +resilience against attacks based on allocation predictability. + +The random allocator is, however, slightly slower than the iterative allocator. +Moreover, it increases the server's memory consumption because it must remember +randomized leases to avoid offering them repeatedly. Memory consumption grows +with the number of offered leases; in other words, larger pools and more +clients increase memory consumption by random allocation. + +Free Lease Queue Allocator (Prefix Delegation Only) +--------------------------------------------------- + +This is a sophisticated allocator whose use should be considered in subnets +with highly utilized delegated prefix pools. In such cases, it can take a +considerable amount of time for the iterative or random allocator to find +an available prefix, because they must repeatedly check whether there is a +valid lease for a prefix they will offer. The number of checks can be as +high as the number of delegated prefixes in the subnet when the subnet pools +are exhausted, which can have a direct negative impact on the DHCP response time for +each request. + +The Free Lease Queue (FLQ) allocator tracks lease allocations and de-allocations +and maintains a running list of available delegated prefixes for each pool. +It allows an available lease to be selected within a constant time, regardless of +the subnet pools' utilization. The allocator continuously updates the list of +free leases by removing any allocated leases and adding released or +reclaimed ones. + +The following configuration snippet shows how to select the FLQ allocator +for prefix delegation in a subnet: + +.. code-block:: json + + { + "Dhcp6": { + "subnet6": [ + { + "id": 1, + "subnet": "2001:db8:1::/64", + "pd-allocator": "flq" + } + ] + } + } + +.. note:: + + The Free Lease Queue allocator can only be used for DHCPv6 prefix delegation. + An attempt to use this allocator for address assignment (with the ``allocator`` + parameter) will cause a configuration error. DHCPv6 address pools are + typically very large and their utilization is low; in these situation, the benefits + of using the FLQ allocator diminish. The amount of time required for the + allocator to populate the free lease queue would cause the server to freeze + upon startup. + +There are several considerations that the administrator should take into account +before using this allocator for prefix delegation. The FLQ allocator can heavily +impact the server's startup and reconfiguration time, because the allocator +has to populate the list of free leases for each subnet where it is used. +These delays can be observed both during the configuration reload and when +the subnets are created using :ischooklib:`libdhcp_subnet_cmds.so`. The allocator +increases the memory consumption to hold the list of free leases, +proportional to the total size of the pools for which this allocator is used. +Finally, lease reclamation must be enabled with a low value of the +``reclaim-timer-wait-time`` parameter, to ensure that the server frequently +collects expired leases and makes them available for allocation via the +free lease queue. Expired leases are not considered free by +the allocator until they are reclaimed by the server. See +:ref:`lease-reclamation` for more details about the lease reclamation process. + +We recommend that the FLQ allocator be selected +only after careful consideration. The server puts no restrictions on the +delegated prefix pool sizes used with the FLQ allocator, so we advise users to +test how long it takes for the server to load the pools before deploying the +configuration using the FLQ allocator in production. We also recommend +specifying another allocator type in the global configuration settings +and overriding this selection at the subnet or shared-network level, to use +the FLQ allocator only for selected subnets. That way, when a new subnet is +added without an allocator specification, the global setting is used, thus +avoiding unnecessary impact on the server's startup time. + +Like the random allocator, the FLQ allocator offers leases in +random order, which makes it suitable for use with a shared lease database. diff --git a/doc/sphinx/arm/ext-gss-tsig.rst b/doc/sphinx/arm/ext-gss-tsig.rst new file mode 100644 index 0000000..404a15e --- /dev/null +++ b/doc/sphinx/arm/ext-gss-tsig.rst @@ -0,0 +1,1303 @@ +.. _gss-tsig: + +GSS-TSIG +======== + +.. _gss-tsig-overview: + +GSS-TSIG Overview +----------------- + +Kea provides 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 servers, have chosen to adopt a more complex GSS-TSIG approach that offers +additional capabilities, such as using negotiated dynamic keys. + +Kea supports GSS-TSIG to protect DNS updates sent by +the Kea DHCP-DDNS (D2) server in a premium hook, called :ischooklib:`libddns_gss_tsig.so`. + +GSS-TSIG is defined in `RFC 3645 <https://tools.ietf.org/html/rfc3645>`__. +The GSS-TSIG protocol itself is an implementation of generic GSS-API v2 +services, defined in `RFC 2743 <https://tools.ietf.org/html/rfc2743>`__. + +Many protocols are involved in this mechanism: + + - Kerberos 5 - `RFC 4120 <https://tools.ietf.org/html/rfc4120>`__, which + provides the security framework; + - GSS-API (Generic Security Services Application Program Interface) - + `RFC 2743 <https://tools.ietf.org/html/rfc2743>`__ for the API, + `RFC 2744 <https://tools.ietf.org/html/rfc2743>`__ for the C bindings, and + `RFC 4121 <https://tools.ietf.org/html/rfc4121>`__ for the application + to Kerberos 5; + - SPNEGO (Simple and Protected GSS-API Negotiation Mechanism) - + `RFC 4178 <https://tools.ietf.org/html/rfc4178>`__ for the negotiation; + - DNS update `RFC 2136 <https://tools.ietf.org/html/rfc2136>`__; + - TSIG (Secret Key Transaction Authentication for DNS) - + `RFC 8945 <https://tools.ietf.org/html/rfc8945>`__, which + protects DNS exchanges; + - Secure Domain Name System (DNS) Dynamic Update - + `RFC 3007 <https://tools.ietf.org/html/rfc3007>`__, which is the + application of TSIG to DNS update protection; + - TKEY (Secret Key Establishment for DNS) - + `RFC 2930 <https://tools.ietf.org/html/rfc2930>`__, which establishes + secret keys for TSIG by transmitting crypto payloads between DNS + parties; and + - GSS-TSIG - `RFC 3645 <https://tools.ietf.org/html/rfc3645>`__, which + is the application of GSS-API to TSIG. + +To summarize, GSS-API for Kerberos 5 with SPNEGO and TKEY are used to +negotiate a security context between the Kea D2 server and a DNS server: + +.. figure:: ../uml/tkey.* + +The security context is then used by GSS-TSIG to protect updates: + +.. figure:: ../uml/update.* + +The Kea implementation of GSS-TSIG uses a GSS-API for Kerberos 5 with +the SPNEGO library. Two implementations meet this criteria: MIT Kerberos +5 and Heimdal. + +.. _gss-tsig-install: + +GSS-TSIG Compilation +-------------------- + +The following procedure was tested on Ubuntu 20.10 and 21.04. A similar +approach can be applied to other systems. + +1. Obtain the Kea sources and premium packages, extract the Kea sources, + and then extract the premium packages into the ``premium/`` directory within the Kea + source tree. + +2. Run autoreconf: + +.. code-block:: console + + autoreconf -i + +3. Make sure ``./configure --help`` shows the ``--with-gssapi`` option. + +4. Install either the MIT (``libkrb5-dev``) or the Heimdal (``heimdal-dev``) library, + for instance: + +.. code-block:: console + + sudo apt install libkrb5-dev + +5. Run ``configure`` with the ``--with-gssapi`` option: + +.. code-block:: console + + ./configure --with-gssapi + +.. note: + + It is ``--with-gssapi`` (with no dash between "gss" and "api"), to maintain + consistency with the BIND 9 option. + +The ``--with-gssapi`` parameter requires the ``krb5-config`` tool to be present. This +tool is provided by both MIT Kerberos 5 and Heimdal; however, on some systems +where both Kerberos 5 and Heimdal are installed, it is a symbolic link +to one of them. If the tool is not in the standard location, it can be specified +with ``--with-gssapi=/path/to/krb5-config``. It is strongly recommended +to use the default installation locations provided by the packages. + +The ``./configure`` script should complete with a successful GSS-API +detection, similar to this: + +:: + + GSS-API support: + GSSAPI_CFLAGS: -isystem /usr/include/mit-krb5 + GSSAPI_LIBS: -L/usr/lib/x86_64-linux-gnu/mit-krb5 -Wl,-Bsymbolic-functions -Wl,-z,relro -lgssapi_krb5 -lkrb5 -lk5crypto -lcom_err + +6. Compile ``make -jX``, where X is the number of CPU cores + available. + +7. After compilation, :ischooklib:`libddns_gss_tsig.so` is available in the + ``premium/src/hooks/d2/gss_tsig`` directory. It can be loaded by :iscman:`kea-dhcp-ddns`. + +:ischooklib:`libddns_gss_tsig.so` was developed using the MIT Kerberos 5 implementation, but +Heimdal is also supported. Note that Heimdal is picky about +security-sensitive file permissions and is known to emit an unclear error message. +It is a good idea to keep these files plain, with one link and no +access for the group or other users. + +The ``krb5-config`` script should provide an ``--all`` option which +identifies the implementation. + +.. _gss-tsig-deployment: + +GSS-TSIG Deployment +------------------- + +Before using GSS-TSIG, a GSS-TSIG capable DNS server, such as BIND 9 +or Microsoft Active Directory (AD), must be deployed. Other +GSS-TSIG capable implementations may work, but have not been tested. + +Kerberos 5 Setup +~~~~~~~~~~~~~~~~ + +There are two kinds of key tables (keytab files): the system one used +by servers, and client tables used by clients. For Kerberos 5, Kea is a +**client**. + +Install the Kerberos 5 client library and ``kadmin`` tool: + +.. code-block:: console + + sudo apt install krb5-kdc krb5-admin-server + +The following examples use the ``EXAMPLE.ORG`` realm to demonstrate required +configuration steps and settings. + +The Kerberos 5 client library must be configured to accept incoming requests +for the realm ``EXAMPLE.ORG`` by updating the ``krb5.conf`` file +(e.g. on Linux: /etc/krb5.conf): + +.. 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 + } + +In addition to the ``krb5.conf`` file, the ``kdc.conf`` file can be used +(e.g. on Linux: /etc/krb5kdc/kdc.conf): + +.. code-block:: ini + + [kdcdefaults] + kdc_ports = 750,88 + + [realms] + EXAMPLE.ORG = { + database_name = /var/lib/krb5kdc/principal + admin_keytab = FILE:/etc/krb5kdc/kadm5.keytab + acl_file = /etc/krb5kdc/kadm5.acl + key_stash_file = /etc/krb5kdc/stash + kdc_ports = 750,88 + max_life = 10h 0m 0s + max_renewable_life = 7d 0h 0m 0s + master_key_type = des3-hmac-sha1 + #supported_enctypes = aes256-cts:normal aes128-cts:normal + default_principal_flags = +preauth + } + +The ``kadmind`` daemon Access Control List (ACL) must be configured to give +permissions to the DNS client principal to access the Kerberos 5 database +(e.g. on Linux: /etc/krb5kdc/kadm5.acl): + +.. code-block:: ini + + DHCP/admin.example.org@EXAMPLE.ORG * + +The administrator password for the default realm must be set: + +.. code-block:: console + + krb5_newrealm + +After the following message is displayed, enter +the password for the default realm: + +.. code-block:: console + + This script should be run on the master KDC/admin server to initialize + a Kerberos realm. It will ask you to type in a master key password. + This password will be used to generate a key that is stored in + /etc/krb5kdc/stash. You should try to remember this password, but it + is much more important that it be a strong password than that it be + remembered. However, if you lose the password and /etc/krb5kdc/stash, + you cannot decrypt your Kerberos database. + Loading random data + Initializing database '/var/lib/krb5kdc/principal' for realm 'EXAMPLE.ORG', + master key name 'K/M@EXAMPLE.ORG' + You will be prompted for the database Master Password. + It is important that you NOT FORGET this password. + Enter KDC database master key: + +Then retype the password: + +.. code-block:: console + + Re-enter KDC database master key to verify: + +If successfully applied, the following message is displayed: + +.. code-block:: console + + Now that your realm is set up you may wish to create an administrative + principal using the addprinc subcommand of the kadmin.local program. + Then, this principal can be added to /etc/krb5kdc/kadm5.acl so that + you can use the kadmin program on other computers. Kerberos admin + principals usually belong to a single user and end in /admin. For + example, if jruser is a Kerberos administrator, then in addition to + the normal jruser principal, a jruser/admin principal should be + created. + + Don't forget to set up DNS information so your clients can find your + KDC and admin servers. Doing so is documented in the administration + guide. + +The next step is to create the principals for the BIND 9 DNS server +(the service protected by the GSS-TSIG TKEY) and for the DNS client +(the Kea DHCP-DDNS server). + +The BIND 9 DNS server principal (used for authentication) is created the +following way: + +.. code-block:: console + + kadmin.local -q "addprinc -randkey DNS/server.example.org" + +If successfully created, the following message is displayed: + +.. code-block:: console + + No policy specified for DNS/server.example.org@EXAMPLE.ORG; defaulting to no policy + Authenticating as principal root/admin@EXAMPLE.ORG with password. + Principal "DNS/server.example.org@EXAMPLE.ORG" created. + +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 it is exported to the keytab +file with the name ``dns.keytab``. + +.. code-block:: console + + kadmin.local -q "ktadd -k /tmp/dns.keytab DNS/server.example.org" + +If successfully exported, the following message is displayed: + +.. code-block:: console + + 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. + +The DHCP client principal (used by the Kea DHCP-DDNS server) is created the +following way: + +.. code-block:: console + + kadmin.local -q "addprinc -randkey DHCP/admin.example.org" + +If successfully created, the following message is 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. + +The DHCP client principal must be exported so that it can be used by the +Kea DHCP-DDNS server and the 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: + +.. code-block:: console + + systemctl restart krb5-admin-server.service + +BIND 9 with GSS-TSIG Configuration +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The BIND 9 DNS server must be configured to use GSS-TSIG, and to use the +previously exported DNS server principal from the keytab file ``dns.keytab``. +Updating the ``named.conf`` file is required: + +.. code-block:: console + + options { + ... + directory "/var/cache/bind"; + dnssec-validation auto; + listen-on-v6 { any; }; + tkey-gssapi-keytab "/etc/bind/dns.keytab"; + }; + zone "example.org" { + type master; + file "/var/lib/bind/db.example.org"; + update-policy { + grant "DHCP/admin.example.org@EXAMPLE.ORG" zonesub any; + }; + }; + zone "84.102.10.in-addr.arpa" { + type master; + file "/etc/bind/db.10"; + }; + +The zone files should have an entry for the server principal FQDN +``server.example.org``. + +The ``/etc/bind/db.10`` file needs to be created or updated: + +.. code-block:: console + + ; + ; BIND reverse data file for local loopback interface + ; + $TTL 604800 ; 1 week + @ IN SOA server.example.org. root.example.org. ( + 2 ; Serial + 604800 ; Refresh + 86400 ; Retry + 2419200 ; Expire + 604800 ; Negative Cache TTL + ) + ; + @ IN NS ns. + 40 IN PTR ns.example.org. + +The ``/var/lib/bind/db.example.org`` file needs to be created or updated: + +.. code-block:: console + + $ORIGIN . + $TTL 604800 ; 1 week + example.org IN SOA server.example.org. root.example.org. ( + 8 ; serial + 604800 ; refresh (1 week) + 86400 ; retry (1 day) + 2419200 ; expire (4 weeks) + 604800 ; minimum (1 week) + ) + NS example.org. + A ${BIND9_IP_ADDR} + AAAA ::1 + $ORIGIN 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 the status or restart the 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 it describes only the steps used +for GSS-TSIG deployment. (For the complete configuration process, please refer to +Microsoft's 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, such as + the client key table of Kea + - the second account is 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, the problem was that the Kea D2 server was trying to perform an update of a reverse +DNS zone while it was not configured. An easy solution is to add a reverse DNS +zone similar to the one configured in Kea. To do that, open the "DNS Manager" and choose +"DNS" from the list; from the dropdown list, choose "Reverse Lookup Zones"; then +click "Action" and "New Zone"; finally, follow the New Zone Wizard to add a new zone. + +The standard requires both anti-replay and sequence services. Experiences with the BIND 9 nsupdate +showed the sequence service led to problems so it is disabled by default in the hook. It seems +the anti-replay service can also lead to problems with Microsoft DNS servers so it is now +configurable. Note that these security services are useless for DNS dynamic update which was +designed to run over UDP so with out of order and duplicated messages. + +.. _gss-tsig-using: + +Using GSS-TSIG +-------------- + +There are a number of steps required to enable the GSS-TSIG mechanism: + +1. :ischooklib:`libddns_gss_tsig.so` must be loaded by :iscman:`kea-dhcp-ddns`. +2. The GSS-TSIG-capable DNS servers must be specified with their parameters. + +An excerpt from a D2 server configuration is provided below; more examples are available in the +``doc/examples/ddns`` directory in the Kea sources. + +.. code-block:: javascript + :linenos: + :emphasize-lines: 57-117 + + + { + "DhcpDdns": { + // The following parameters are used to receive NCRs (NameChangeRequests) + // from the local Kea DHCP server. Make sure your kea-dhcp4 and kea-dhcp6 + // matches this. + "ip-address": "127.0.0.1", + "port": 53001, + "dns-server-timeout" : 1000, + + // Forward zone: secure.example.org. It uses GSS-TSIG. It is served + // by two DNS servers, which listen for DDNS requests at 192.0.2.1 + // and 192.0.2.2. + "forward-ddns": + { + "ddns-domains": + [ + // DdnsDomain for zone "secure.example.org." + { + "name": "secure.example.org.", + "comment": "DdnsDomain example", + "dns-servers": + [ + { // This server has an entry in gss/servers and + // thus will use GSS-TSIG. + "ip-address": "192.0.2.1" + }, + { // This server also has an entry there, so will + // use GSS-TSIG, too. + "ip-address": "192.0.2.2", + "port": 5300 + } + ] + } + ] + }, + + // Reverse zone: we want to update the reverse zone "2.0.192.in-addr.arpa". + "reverse-ddns": + { + "ddns-domains": + [ + { + "name": "2.0.192.in-addr.arpa.", + "dns-servers": + [ + { + // There is a GSS-TSIG definition for this server (see + // DhcpDdns/gss-tsig/servers), so it will use + // Krb/GSS-TSIG. + "ip-address": "192.0.2.1" + } + ] + } + ] + }, + + // The GSS-TSIG hook is loaded and its configuration is specified here. + "hooks-libraries": [ + { + "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 + // an entry here to be able to use GSS-TSIG defaults (optional, + // if specified they apply to all the GSS-TSIG servers, unless + // overwritten on specific server level). + + "server-principal": "DNS/server.example.org@EXAMPLE.ORG", + "client-principal": "DHCP/admin.example.org@EXAMPLE.ORG", + + // client-keytab and credentials-cache can both be used to + // store client keys. As credentials cache is more flexible, + // it is recommended to use it. Typically, using both at the + // same time may cause problems. + // "client-keytab": "FILE:/etc/dhcp.keytab", // toplevel only + "credentials-cache": "FILE:/etc/ccache", // toplevel only + "gss-replay-flag": true, // GSS anti replay service + "gss-sequence-flag": false, // no GSS sequence service + "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": [ + { + // First server (identification is required) + "id": "server1", + "domain-names": [ ], // if not specified or empty, will + // match all domains that want to + // use this IP+port pair + "ip-address": "192.0.2.1", + "port": 53, + "server-principal": "DNS/server1.example.org@EXAMPLE.ORG", + "client-principal": "DHCP/admin1.example.org@EXAMPLE.ORG", + "gss-replay-flag": false, // no GSS anti replay service + "gss-sequence-flag": false, // no GSS sequence service + "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 + // as those are using the defaults specified above) + "id": "server2", + "ip-address": "192.0.2.2", + "port": 5300 + } + ] + } + } + ] + + // Additional parameters, such as logging, control socket and + // others omitted for clarity. + } + + } + +This configuration file contains a number of extra elements. + +First, a list of forward and/or reverse domains with related DNS servers +identified by their IP+port pairs is defined. If the port is not +specified, the default of 53 is assumed. This is similar to basic mode, with no +authentication done using TSIG keys, with the +exception that static TSIG keys are not referenced by name. + +Second, :ischooklib:`libddns_gss_tsig.so` must 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 the ``parameters`` scope as defaults. In the example above, the defaults that apply +to all servers, unless otherwise specified on a per-server scope, are defined in +lines 63 through 68. The defaults can be skipped if there is only one server +defined, or if all servers have different values. + +.. 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 | + +-------------------+----------+---------+---------------------+--------------------------------+ + | gss-replay-flag | global / | true / | true | require the GSS anti replay | + | | server | false | | service (GSS_C_REPLAY_FLAG) | + +-------------------+----------+---------+---------------------+--------------------------------+ + | gss-sequence-flag | global / | true / | false | require the GSS sequence | + | | server | false | | service (GSS_C_SEQUENCE_FLAG) | + +-------------------+----------+---------+---------------------+--------------------------------+ + | 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 (not 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. An 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, + if using a directory which supports more than one principal, + ``DIR:<directory-path>``. + This parameter can be specified only once, in the parameters scope, + and is the equivalent of setting the ``KRB5CCNAME`` environment + variable. An empty value is silently ignored. + +- ``server-principal`` is the Kerberos principal name of the DNS + server that receives updates. In other words, this is the + DNS server's name in the Kerberos system. This parameter is + mandatory, and uses the typical Kerberos notation: + ``<SERVICE-NAME>/<server-domain-name>@<REALM>``. + +- ``client-principal`` is the Kerberos principal name of the Kea D2 + service. It is optional, and uses the typical Kerberos notation: + ``<SERVICE-NAME>/<server-domain-name>@<REALM>``. + +- ``gss-replay-flag`` determines if the GSS anti replay service is + required. It is by default but this can be disabled. + +- ``gss-sequence-flag`` determines if the GSS sequence service is + required. It is not by default but is required by the standard + so it can be enabled. + +- ``tkey-protocol`` determines which protocol is used to establish the + security context with the DNS servers. Currently, the only supported + values are TCP (the default) and UDP. + +- ``tkey-lifetime`` determines the lifetime of GSS-TSIG keys in the + TKEY protocol. The value must be greater than the ``rekey-interval`` + value. It is expressed in seconds and defaults to 3600 (one hour). + +- ``rekey-interval`` governs the time interval at which the keys for each configured + server are checked for rekeying, i.e. when a new key is created to replace the + current usable one if its age is greater than the ``rekey-interval`` value. + The value must be smaller than the ``tkey-lifetime`` value (it is recommended + to be set between 50% and 80% of the ``tkey-lifetime`` value). It is expressed in + seconds and defaults to 2700 (45 minutes, or 75% of one hour). + +- ``retry-interval`` governs the time interval at which 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 defaults to 120 (2 minutes). + +- ``fallback`` governs the behavior when GSS-TSIG should be used (a + matching DNS server is configured) but no GSS-TSIG key is available. + If set to ``false`` (the default), this server is skipped; if + set 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 amount of time to wait for the GSS-TSIG TKEY + exchange to finish before the process times out. It is expressed in milliseconds and + defaults to 3000 (3 seconds). + +- ``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. + +- ``servers`` specifies the list of DNS servers where GSS-TSIG is enabled. + +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, and must be both not empty and unique. + +- ``domain-names`` governs the many-to-one relationship between D2 DNS + servers and GSS-TSIG DNS servers: for each domain name on this list, + Kea looks for a D2 DNS server for this domain with the specified IP address + and port. An empty list (the default) means that all domains + match. + +- ``ip-address`` specifies the IP address at which the GSS-TSIG DNS server + listens for DDNS and TKEY requests. It is a mandatory parameter. + +- ``port`` specifies the DNS transport port on which the GSS-TSIG DNS server + listens for DDNS and TKEY requests. It defaults to 53. + +- ``server-principal`` is the Kerberos principal name of the DNS server + that receives updates. The ``server-principal`` parameter set at the per-server + level takes precedence over one set at the global level. It is a mandatory parameter which must be specified at + either the global or the server level. + +- ``client-principal`` is the Kerberos principal name of the Kea D2 + service for this DNS server. The ``client-principal`` parameter set at the per-server + level takes precedence over one set at the global level. It is an optional parameter. + +- ``gss-replay-flag`` determines if the GSS anti replay service is + required. The ``gss-replay-flag`` parameter set at the per-server + level takes precedence over one set at the global level. It is an optional parameter + which defaults to true. + +- ``gss-sequence-flag`` determines if the GSS sequence service is + required. The ``gss-sequence-flag`` parameter set at the per-server + level takes precedence over one set at the global level. It is an optional parameter + which defaults to false. + +- ``tkey-protocol`` determines which protocol is used to establish the + security context with the DNS server. The ``tkey-protocol`` parameter set at the per-server + level takes precedence over one set at the global level. The default and supported values + for the per-server level parameter are the same as + for the global-level parameter. + +- ``tkey-lifetime`` determines the lifetime of GSS-TSIG keys in the + TKEY protocol for the DNS server. The ``tkey-lifetime`` parameter set at the per-server + level takes precedence over one set at the global level. The default and supported values + for the per-server level parameter are the same as + for the global-level parameter. + +- ``rekey-interval`` governs the time interval at which the keys for this particular + server are checked for rekeying, i.e. when a new key is created to replace the + current usable one if its age is greater than the ``rekey-interval`` value. + The value must be smaller than the ``tkey-lifetime`` value (it is recommended + to be set between 50% and 80% of the ``tkey-lifetime`` value). The ``rekey-interval`` + parameter set at the per-server level takes precedence over one set at the global + level. The default and supported values for the per-server level parameter are the same as + for the global-level parameter. + +- ``retry-interval`` governs the time interval at which 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 set at the per-server level takes precedence over one set at the global + level. The default and supported values for the per-server level parameter 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 set at the per-server level takes precedence over one set at the global + level. The default and supported values for the per-server level parameter are the same as + for the global-level parameter.. + +- ``exchange-timeout`` governs the amount of time to wait for the GSS-TSIG TKEY + exchange to finish before the process times out. The ``exchange-timeout`` parameter + set at the per-server level takes precedence over one set at the global + level. The default and supported values for the per-server level parameter 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. + +.. note:: + + Generally it is not recommended to specify both the client keytab (``client-keytab``) + and the credentials cache (``credentials-cache``), although this may + differ between Kerberos implementations. The client keytab is just for + the client key and is typically used to specify the key explicitly in more + static manner, while the credentials cache can be used to store multiple + credentials and can be dynamically updated by the Kerberos library. As such, + the credentials-cache is more flexible and thus the recommended alternative. + + Also note that only the read access right is needed to use the cache. + Fetching credentials and updating the cache requires the write access + right. + + +GSS-TSIG Automatic Key Removal +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The server periodically deletes keys after they have been expired more than three times the +length of the maximum key lifetime (the ``tkey-lifetime`` parameter). +The user has the option to purge keys on demand by using the :isccmd:`gss-tsig-purge-all` +command or the :isccmd:`gss-tsig-purge` command. + + +GSS-TSIG Configuration for Deployment +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When using Kerberos 5 and BIND 9 as described in :ref:`gss-tsig-deployment`, +the local resolver must point to the BIND 9 ``named`` server address. The +local Kerberos must also be configured by putting the following text into 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, which also provides +the Kerberos service. The required text in 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 for performance to get and cache credentials. + +This can be done manually via the command: + +.. 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``). + +When using BIND 9, the server principal is in the form "DNS/server.example.org@EXAMPLE.ORG¨; +with AD, the format is "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`` - the number of created GSS-TSIG keys +- ``tkey-sent`` - the number of sent TKEY exchange initial requests +- ``tkey-success`` - the number of TKEY exchanges which completed with a success +- ``tkey-timeout`` - the number of TKEY exchanges which completed on timeout +- ``tkey-error`` - the number of TKEY exchanges which completed with an error other than + a timeout + +The relationship between keys and DNS servers is 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 only used by one DNS server inside a dedicated + set of keys. + +.. _commands-gss-tsig: + +GSS-TSIG Commands +----------------- + +The GSS-TSIG hook library supports some commands, which are described below. + +.. isccmd:: gss-tsig-get-all +.. _command-gss-tsig-get-all: + +The ``gss-tsig-get-all`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This command lists all the GSS-TSIG servers and keys. + +An example command invocation looks like this: + +.. code-block:: json + + { + "command": "gss-tsig-get-all" + } + +Here is an example of a response returning one GSS-TSIG server and one key: + +.. code-block:: json + + { + "result": 0, + "text": "1 GSS-TSIG servers and 1 keys", + "arguments": { + "gss-tsig-servers": [ + { + "id": "foo", + "ip-address": "192.1.2.3", + "port": 53, + "server-principal": "DNS/foo.com@FOO.COM", + "key-name-suffix": "foo.com.", + "tkey-lifetime": 3600, + "tkey-protocol": "TCP", + "keys": [ + { + "name": "1234.sig-foo.com.", + "inception-date": "2021-09-05 12:23:36.281176", + "server-id": "foo", + "expire-date": "2021-09-05 13:23:36.281176", + "status": "not yet ready", + "tkey-exchange": true + } + ] + }, + { + "id": "bar", + "ip-address": "192.1.2.4", + "port": 53, + "server-principal": "DNS/bar.com@FOO.COM", + "key-name-suffix": "bar.com.", + "tkey-lifetime": 7200, + "tkey-protocol": "UDP", + "keys": [ ] + } + ] + } + } + +.. isccmd:: gss-tsig-get +.. _command-gss-tsig-get: + +The ``gss-tsig-get`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This command retrieves information about the specified GSS-TSIG server. + +An example command invocation looks like this: + +.. code-block:: json + + { + "command": "gss-tsig-get", + "arguments": { + "server-id": "foo" + } + } + +Here is an example of a response returning information about the server "foo": + +.. code-block:: json + + { + "result": 0, + "text": "GSS-TSIG server[foo] found", + "arguments": { + "id": "foo", + "ip-address": "192.1.2.3", + "port": 53, + "server-principal": "DNS/foo.com@FOO.COM", + "key-name-suffix": "foo.com.", + "tkey-lifetime": 3600, + "tkey-protocol": "TCP", + "keys": [ + { + "name": "1234.sig-foo.com.", + "server-id": "foo", + "inception-date": "2021-09-05 12:23:36.281176", + "expire-date": "2021-09-05 13:23:36.281176", + "status": "not yet ready", + "tkey-exchange": true + } + ] + } + } + +.. isccmd:: gss-tsig-list +.. _command-gss-tsig-list: + +The ``gss-tsig-list`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This command generates a list of GSS-TSIG server IDs and key names. + +An example command invocation looks like this: + +.. code-block:: json + + { + "command": "gss-tsig-list" + } + +Here is an example of a response returning two GSS-TSIG servers and three keys: + +.. code-block:: json + + { + "result": 0, + "text": "2 GSS-TSIG servers and 3 keys", + "arguments": { + "gss-tsig-servers": [ + "foo", + "bar" + ], + "gss-tsig-keys": [ + "1234.example.com.", + "5678.example.com.", + "43888.example.org." + ] + } + } + +.. isccmd:: gss-tsig-key-get +.. _command-gss-tsig-key-get: + +The ``gss-tsig-key-get`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This command retrieves information about the specified GSS-TSIG key. + +An example command invocation looks like this: + +.. code-block:: json + + { + "command": "gss-tsig-key-get", + "arguments": { + "key-name": "1234.sig-foo.com." + } + } + +Here is an example of a response returning information about GSS-TSIG key "1234.sig-foo.com.": + +.. code-block:: json + + { + "result": 0, + "text": "GSS-TSIG key '1234.sig-foo.com.' found", + "arguments": { + "name": "1234.sig-foo.com.", + "server-id": "foo", + "inception-date": "2021-09-05 12:23:36.281176", + "expire-date": "2021-09-05 13:23:36.281176", + "status": "not yet ready", + "tkey-exchange": true + } + } + +.. isccmd:: gss-tsig-key-expire +.. _command-gss-tsig-key-expire: + +The ``gss-tsig-key-expire`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This command expires the specified GSS-TSIG key. + +An example command invocation looks like this: + +.. code-block:: json + + { + "command": "gss-tsig-key-expire", + "arguments": { + "key-name": "1234.sig-foo.com." + } + } + +Here is an example of a response indicating that GSS-TSIG key "1234.sig-foo.com." has been expired: + +.. code-block:: json + + { + "result": 0, + "text": "GSS-TSIG key '1234.sig-foo.com.' expired" + } + +.. isccmd:: gss-tsig-key-del +.. _command-gss-tsig-key-del: + +The ``gss-tsig-key-del`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This command deletes the specified GSS-TSIG key. + +An example command invocation looks like this: + +.. code-block:: json + + { + "command": "gss-tsig-key-del", + "arguments": { + "key-name": "1234.sig-foo.com." + } + } + +Here is an example of a response indicating that GSS-TSIG key "1234.sig-foo.com." has been deleted: + +.. code-block:: json + + { + "result": 0, + "text": "GSS-TSIG key '1234.sig-foo.com.' deleted" + } + +.. isccmd:: gss-tsig-purge-all +.. _command-gss-tsig-purge-all: + +The ``gss-tsig-purge-all`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This command removes all unusable GSS-TSIG keys. + +An example command invocation looks like this: + +.. code-block:: json + + { + "command": "gss-tsig-purge-all" + } + +Here is an example of a response indicating that two GSS-TSIG keys have been purged: + +.. code-block:: json + + { + "result": 0, + "text": "2 purged GSS-TSIG keys" + } + +.. isccmd:: gss-tsig-purge +.. _command-gss-tsig-purge: + +The ``gss-tsig-purge`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This command removes unusable GSS-TSIG keys for the specified server. + +An example command invocation looks like this: + +.. code-block:: json + + { + "command": "gss-tsig-purge", + "arguments": { + "server-id": "foo" + } + } + +Here is an example of a response indicating that two GSS-TSIG keys for server "foo" have been purged: + +.. code-block:: json + + { + "result": 0, + "text": "2 purged keys for GSS-TSIG server[foo]" + } + +.. isccmd:: gss-tsig-rekey-all +.. _command-gss-tsig-rekey-all: + +The ``gss-tsig-rekey-all`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This command unconditionally creates new GSS-TSIG keys (rekeys) for +all DNS servers. + +An example command invocation looks like this: + +.. code-block:: json + + { + "command": "gss-tsig-rekey-all" + } + +Here is an example of a response indicating that a rekey was performed: + +.. code-block:: json + + { + "result": 0, + "text": "rekeyed" + } + +This command is useful when, for instance, the DHCP-DDNS server is +reconnected to the network. + +.. isccmd:: gss-tsig-rekey +.. _command-gss-tsig-rekey: + +The ``gss-tsig-rekey`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This command unconditionally creates new GSS-TSIG keys (rekeys) for +a specified DNS server. + +An example command invocation looks like this: + +.. code-block:: json + + { + "command": "gss-tsig-rekey", + "arguments": { + "server-id": "foo" + } + } + +Here is an example of a response indicating that a rekey was performed: + +.. code-block:: json + + { + "result": 0, + "text": "GSS-TSIG server[foo] rekeyed" + } + +This command is typically used when a DNS server has been rebooted, so +that existing GSS-TSIG keys shared with this server can no longer be used. diff --git a/doc/sphinx/arm/ext-netconf.rst b/doc/sphinx/arm/ext-netconf.rst new file mode 100644 index 0000000..b21e7bb --- /dev/null +++ b/doc/sphinx/arm/ext-netconf.rst @@ -0,0 +1,1159 @@ +.. _netconf: + +YANG/NETCONF +============ + +.. _netconf-overview: + +Overview +-------- + +The Network Configuration Protocol, or NETCONF, is a network management protocol defined +in `RFC 4741 <https://tools.ietf.org/html/rfc4741>`__. It uses the YANG modeling language, +defined in `RFC 6020 <https://tools.ietf.org/html/rfc6020>`__, to provide a uniform way +of handling the configuration syntax of various networking devices. Kea provides optional +support for a YANG/NETCONF interface with the :iscman:`kea-netconf` agent. + +.. _netconf-install: + +Installing NETCONF +------------------ + +To get its NETCONF capabilities, Kea requires the v2 versions of libyang and +Sysrepo. The specific versions that have been thoroughly tested with Kea are: + +* libyang v2.1.4 +* sysrepo v2.2.12 +* libyang-cpp v1.1.0 (ae7d649ea75da081725c119dd553b2ef3121a6f8) +* sysrepo-cpp v1.1.0 (02634174ffc60568301c3d9b9b7cf710cff6a586) + +.. note:: + + For users who are unable to upgrade to one of the versions of libyang + and Sysrepo listed above, these are the oldest versions known to work + reliably with current Kea releases: + + * libyang v2.0.256 (56d4e07ef1cdeab3eb2e6700247f83ec9148edcc) + * sysrepo v2.1.84 + * libyang-cpp v1.1.0 (7824d9a862f2dc1d8ad4f6a90ab6cee9200f7c81) + * sysrepo-cpp v1.1.0 (e66b2f0c53a428eeb743d355cf86fb30e8e491f1) + +.. note:: + + :iscman:`kea-netconf` may be compatible with later versions of libyang and + Sysrepo, but only the versions listed above have been thoroughly + tested by ISC. + +Installing from packages is recommended, if they are provided by the system. If +not, users can build from sources following the directions below, which +should work on all popular operating systems. + +.. _libyang-install-sources: + +Installing ``libyang`` From Sources +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: console + + $ git clone https://github.com/CESNET/libyang.git + $ cd libyang + $ git checkout v2.1.4 + $ mkdir build + $ cd build + $ cmake .. + $ make + $ make install + +.. _sysrepo-install-sources: + +Installing ``sysrepo`` From Sources +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: console + + $ git clone https://github.com/sysrepo/sysrepo.git + $ cd sysrepo + $ git checkout v2.2.12 + $ mkdir build + $ cd build + $ cmake -DREPO_PATH=/etc/sysrepo .. + $ make + $ make install # without sudo if you're doing development and want to run unit tests + +.. _libyang-cpp-install-sources: + +Installing ``libyang-cpp`` From Sources +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: console + + $ git clone https://github.com/CESNET/libyang-cpp.git + $ cd libyang-cpp + $ git checkout ae7d649ea75da081725c119dd553b2ef3121a6f8 + $ mkdir build + $ cd build + $ cmake -DBUILD_TESTING=OFF .. + $ make + $ make install + +.. _sysrepo-cpp-install-sources: + +Installing ``sysrepo-cpp`` From Sources +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: console + + $ git clone https://github.com/sysrepo/sysrepo-cpp.git + $ cd sysrepo-cpp + $ git checkout 02634174ffc60568301c3d9b9b7cf710cff6a586 + $ mkdir build + $ cd build + $ cmake -DBUILD_TESTING=OFF .. + $ make + $ make install + +.. _compiling-with-netconf: + +Compiling With NETCONF +---------------------- + +1. Obtain the Kea sources. + +.. code-block:: console + + $ git clone gitlab.isc.org/isc-projects/kea.git + $ cd kea + +2. Configure the build. + +.. code-block:: console + + $ autoreconf -f -i + $ ./configure --with-libyang --with-libyang-cpp --with-sysrepo --with-sysrepo-cpp + +.. note:: + + If any of the libraries are installed in a custom location, the + ``--with`` flags accept the installations paths as values. + +3. Check ``config.report`` to verify NETCONF support. + +:: + + NETCONF: + yes + + libyang: + LIBYANG_CPPFLAGS: + LIBYANG_INCLUDEDIR: -I/usr/local/include + LIBYANG_LIBS: -L/usr/local/lib -lyang -Wl,-R/usr/local/lib -lyang + LIBYANG_PREFIX: /usr/local + LIBYANG_VERSION: 2.1.4 + + libyang-cpp: + LIBYANGCPP_CPPFLAGS: + LIBYANGCPP_INCLUDEDIR: -I/usr/local/include + LIBYANGCPP_LIBS: -L/usr/local/lib -lyang-cpp -Wl,-R/usr/local/lib -lyang-cpp + LIBYANGCPP_PREFIX: /usr/local + LIBYANGCPP_VERSION: 1.1.0 + + sysrepo: + SYSREPO_CPPFLAGS: + SYSREPO_INCLUDEDIR: -I/usr/local/include + SYSREPO_LIBS: -L/usr/local/lib -lsysrepo -Wl,-R/usr/local/lib -lsysrepo + SYSREPO_PREFIX: /usr/local + SYSREPO_VERSION: 2.2.12 + + SR_REPO_PATH: /etc/sysrepo + SR_PLUGINS_PATH: /usr/local/lib/sysrepo/plugins + SRPD_PLUGINS_PATH: /usr/local/lib/sysrepo-plugind/plugins + + sysrepo-cpp: + SYSREPOCPP_CPPFLAGS: + SYSREPOCPP_INCLUDEDIR: -I/usr/local/include + SYSREPOCPP_LIBS: -L/usr/local/lib -lsysrepo-cpp -Wl,-R/usr/local/lib -lsysrepo-cpp + SYSREPOCPP_PREFIX : /usr/local + SYSREPOCPP_VERSION: 1.1.0 + +4. Build as usual. + + $ make + +.. _sysrepo-overview: + +Quick Sysrepo Overview +---------------------- + +This section offers a brief overview of a subset of available +functions in Sysrepo. For more complete information, see the +`Sysrepo homepage <https://www.sysrepo.org>`__. + +In YANG, configurations and state data are described in YANG syntax +in module files named ``<module-name>[@<revision>].yang`` + +The revision part is optional and follows the ``YYYY-MM-DD`` format. An alternate +XML syntax YIN is defined but less user-friendly. Top-level modules are +named in Kea models (a short version of schema models). + +There are two major modules that Kea is able to support: ``kea-dhcp4-server`` and +``kea-dhcp6-server``. While there is an active effort in the DHC working group at +IETF to develop a DHCPv6 YANG model, a similar initiative in the past for DHCPv4 +failed. Therefore, Kea uses its own dedicated models for DHCPv4 and DHCPv6 but +partially supports the IETF model for DHCPv6. + +All of the models have extra modules as dependencies, which are also provided. +All of the modules can be found in ``src/share/yang/modules`` in sources and in +``share/kea/yang/modules`` in the installation directory. This directory is +referred to as `${share_directory}` in the commands below. + +To install modules from sources or upgrade them from older revisions, +run the following command. In the case of a revision upgrade, YANG +data will be migrated automatically to the new module schema. + +.. code-block:: console + + $ ${share_directory}/yang/modules/utils/reinstall.sh + +However, if there are any issues during the upgrade process, and data can be recreated from a NETCONF +client or through other means, Kea modules can be easily uninstalled before installing again +via this command: + +.. code-block:: console + + $ ${share_directory}/yang/modules/utils/reinstall.sh -u + +This script should be able to reinstall Sysrepo. However, the ``-s`` +flag can also be used to specify a path: + +.. code-block:: console + + $ ./src/share/yang/modules/utils/reinstall.sh -s /path/to/sysrepo + +To individually install all modules: + +.. code-block:: console + + $ cd ./src/share/yang/modules + $ sysrepoctl -i ./ietf-dhcpv6-server*.yang + $ sysrepoctl -i ./kea-dhcp4-server*.yang + $ sysrepoctl -i ./kea-dhcp6-server*.yang + ... + +The installation should look similar to the following: + +.. code-block:: console + + $ ./src/share/yang/modules/utils/reinstall.sh + [INF] Connection 2 created. + [INF] Module "keatest-module" was installed. + [INF] File "keatest-module@2022-11-30.yang" was installed. + [INF] No datastore changes to apply. + [INF] Connection 4 created. + [ERR] Module "ietf-interfaces@2018-02-20" already installed. + [INF] No datastore changes to apply. + [INF] Connection 7 created. + [ERR] Module "ietf-dhcpv6-client" is already in sysrepo. + [INF] No datastore changes to apply. + [INF] Connection 9 created. + [ERR] Module "ietf-dhcpv6-relay" is already in sysrepo. + [INF] No datastore changes to apply. + [INF] Connection 11 created. + [ERR] Module "ietf-dhcpv6-server" is already in sysrepo. + [INF] No datastore changes to apply. + [INF] Connection 13 created. + [ERR] Write permission "ietf-yang-types" check failed. + [INF] No datastore changes to apply. + [INF] Connection 15 created. + [ERR] Module "ietf-dhcpv6-options" is already in sysrepo. + [INF] No datastore changes to apply. + [INF] Connection 17 created. + [ERR] Module "ietf-dhcpv6-types" is already in sysrepo. + [INF] No datastore changes to apply. + [INF] Connection 21 created. + [INF] Module "kea-types" was installed. + [INF] File "kea-types@2019-08-12.yang" was installed. + [INF] No datastore changes to apply. + [INF] Connection 23 created. + [INF] Module "kea-dhcp-types" was installed. + [INF] File "kea-dhcp-types@2022-11-30.yang" was installed. + [INF] No datastore changes to apply. + [INF] Connection 25 created. + [INF] Module "kea-dhcp-ddns" was installed. + [INF] File "kea-dhcp-ddns@2022-07-27.yang" was installed. + [INF] No datastore changes to apply. + [INF] Connection 27 created. + [INF] Module "kea-ctrl-agent" was installed. + [INF] File "kea-ctrl-agent@2019-08-12.yang" was installed. + [INF] No datastore changes to apply. + [INF] Connection 29 created. + [INF] Module "kea-dhcp4-server" was installed. + [INF] File "kea-dhcp4-server@2022-11-30.yang" was installed. + [INF] No datastore changes to apply. + [INF] Connection 31 created. + [INF] Module "kea-dhcp6-server" was installed. + [INF] File "kea-dhcp6-server@2022-11-30.yang" was installed. + [INF] No datastore changes to apply. + +To confirm whether the modules have been imported correctly, check the list of +currently installed YANG modules. It should be similar to this: + +.. code-block:: console + + $ sysrepoctl -l + Sysrepo repository: /etc/sysrepo + + Module Name | Revision | Flags | Owner | Startup Perms | Submodules | Features + --------------------------------------------------------------------------------------------------- + ietf-datastores | 2018-02-14 | I | user:user | 444 | | + ietf-dhcpv6-client | 2018-09-04 | I | user:user | 600 | | + ietf-dhcpv6-options | 2018-09-04 | I | user:user | 600 | | + ietf-dhcpv6-relay | 2018-09-04 | I | user:user | 600 | | + ietf-dhcpv6-server | 2018-09-04 | I | user:user | 600 | | + ietf-dhcpv6-types | 2018-09-04 | I | user:user | 600 | | + ietf-inet-types | 2013-07-15 | I | user:user | 444 | | + ietf-interfaces | 2018-02-20 | I | user:user | 600 | | + ietf-netconf | 2013-09-29 | I | user:user | 644 | | + ietf-netconf-acm | 2018-02-14 | I | user:user | 600 | | + ietf-netconf-notifications | 2012-02-06 | I | user:user | 644 | | + ietf-netconf-with-defaults | 2011-06-01 | I | user:user | 444 | | + ietf-origin | 2018-02-14 | I | user:user | 444 | | + ietf-yang-library | 2019-01-04 | I | user:user | 644 | | + ietf-yang-metadata | 2016-08-05 | i | | | | + ietf-yang-schema-mount | 2019-01-14 | I | user:user | 644 | | + ietf-yang-types | 2013-07-15 | I | user:user | 444 | | + kea-ctrl-agent | 2019-08-12 | I | user:user | 600 | | + kea-dhcp-ddns | 2022-07-27 | I | user:user | 600 | | + kea-dhcp-types | 2022-11-30 | I | user:user | 600 | | + kea-dhcp4-server | 2022-11-30 | I | user:user | 600 | | + kea-dhcp6-server | 2022-11-30 | I | user:user | 600 | | + kea-types | 2019-08-12 | I | user:user | 600 | | + keatest-module | 2022-11-30 | I | user:user | 600 | | + sysrepo-monitoring | 2022-04-08 | I | user:user | 600 | | + sysrepo-plugind | 2022-03-10 | I | user:user | 644 | | + yang | 2022-06-16 | I | user:user | 444 | | + + Flags meaning: I - Installed/i - Imported; R - Replay support + +To reinstall a module, if the revision YANG entry was bumped, simply installing +it will update it automatically. Otherwise, it must first be uninstalled: + +.. code-block:: console + + $ sysrepoctl -u kea-dhcp4-server + +If the module is used (i.e. imported) by other modules, it can be uninstalled +only after the dependent modules have first been uninstalled. +Installation and uninstallation must be done in dependency order and +reverse-dependency order, as appropriate. + +.. _netconf-models: + +Supported YANG Models +--------------------- + +The currently supported models are ``kea-dhcp4-server`` and +``kea-dhcp6-server``. There is partial support for +``ietf-dhcpv6-server``, but the primary focus of testing has been on Kea DHCP +servers. Other models (:iscman:`kea-dhcp-ddns` and :iscman:`kea-ctrl-agent`) +are currently not supported. + +.. _using-netconf: + +Using the NETCONF Agent +----------------------- + +The NETCONF agent follows this algorithm: + +- For each managed server, get the initial configuration from the + server through the control socket. + +- Open a connection with the Sysrepo environment and establish two + sessions with the startup and running datastores. + +- Check that the used (not-essential) and required (essential) modules are + installed in the Sysrepo repository at the right revision. If an + essential module - that is, a module where the configuration schema for a + managed server is defined - is not installed, raise a fatal error. + +- For each managed server, get the YANG configuration from the startup + datastore, translate it to JSON, and load it onto the server being + configured. + +- For each managed server, subscribe a module change callback using its + model name. + +- When a running configuration is changed, try to validate or load the + updated configuration via the callback to the managed server. + +.. _netconf-configuration: + +Configuration +------------- + +The behavior described in :ref:`using-netconf` +is controlled by several configuration flags, which can be set in the +global scope or in a specific managed-server scope. If the latter, +the value defined in the managed-server scope takes precedence. These +flags are: + +- ``boot-update`` - controls the initial configuration phase; when + ``true`` (the default), the initial configuration retrieved from the + classic Kea server JSON configuration file is loaded first, and then + the startup YANG model is loaded. This setting lets administrators + define a control socket in the local JSON file and then download the + configuration from YANG. When set to ``false``, this phase is skipped. + +- ``subscribe-changes`` - controls the module change + subscription; when ``true`` (the default), a module change callback is + subscribed, but when ``false`` the phase is skipped and running + configuration updates are disabled. When set to ``true``, the running + datastore is used to subscribe for changes. + +- ``validate-changes`` - controls how Kea monitors changes in + the Sysrepo configuration. Sysrepo offers two stages where Kea can + interact: validation and application. At the validation (or + ``SR_EV_CHANGE`` event, in the Sysrepo naming convention) stage, Kea + retrieves the newly committed configuration and verifies it. If the + configuration is incorrect for any reason, the Kea servers reject it + and the error is propagated back to the Sysrepo, which then returns + an error. This step only takes place if ``validate-changes`` is set to + ``true``. In the application (or ``SR_EV_UPDATE`` event in the Sysrepo naming + convention) stage, the actual configuration is applied. At this stage + Kea can receive the configuration, but it is too late to signal back + any errors as the configuration has already been committed. + +The idea behind the initial configuration phase is to boot Kea servers +with a minimal configuration which includes only a control socket, +making them manageable. For instance, for the DHCPv4 server: + +.. code-block:: json + + { + "Dhcp4": { + "control-socket": { + "socket-name": "/tmp/kea-dhcp4-ctrl.sock", + "socket-type": "unix" + } + } + } + +With module change subscriptions enabled, the :iscman:`kea-netconf` daemon +monitors any configuration changes as they appear in the Sysrepo. Such +changes can be done using the ``sysrepocfg`` tool or remotely using any +NETCONF client. For details, please see the Sysrepo documentation or +:ref:`operation-example`. +Those tools can be used to modify YANG configurations in the running +datastore. Note that committed configurations are only updated in the +running datastore; to keep them between server reboots they must be +copied to the startup datastore. + +When module changes are tracked (using ``subscribe-changes`` set to +``true``) and the running configuration has changed (e.g. using +``sysrepocfg`` or any NETCONF client), the callback validates the +modified configuration (if ``validate-changes`` was not set to ``false``) +and runs a second time to apply the new configuration. If the validation +fails, the callback is still called again but with an ``SR_EV_ABORT`` +(vs. ``SR_EV_DONE``) event with rollback changes. + +The returned code of the callback on an ``SR_EV_DONE`` event is ignored, as it is +too late to refuse a bad configuration. + +There are four ways in which a modified YANG configuration might +be incorrect: + +1. It could be non-compliant with the schema, e.g. an unknown entry, missing a + mandatory entry, a value with a bad type, or not matching a constraint. + +2. It could fail to be translated from YANG to JSON, e.g. an invalid user + context. + +3. It could fail Kea server sanity checks, e.g. an out-of-subnet-pool range + or an unsupported database type. + +4. The syntax may be correct and pass server sanity checks but the + configuration could fail to run, e.g. the configuration specifies database + credentials but the database refuses the connection. + +The first case is handled by Sysrepo. The second and third cases are +handled by :iscman:`kea-netconf` in the validation phase (if not disabled by +setting ``validate-changes`` to ``true``). The last case causes the +application phase to fail without a sensible report to Sysrepo. + +The managed Kea servers and agents are described in the +``managed-servers`` section. Each sub-section begins with the service +name: ``dhcp4``, ``dhcp6``, ``d2`` (the DHCP-DDNS server does not +support the control-channel feature yet), and ``ca`` (the control +agent). + +Each managed server entry may contain: + +- control flags - ``boot-update``, ``subscribe-changes``, and/or ``validate-changes``. + +- ``model`` - specifies the YANG model/module name. For each service, + the default is the corresponding Kea YANG model, e.g. for ``"dhcp4"`` + it is ``"kea-dhcp4-server"``. + +- ``control-socket`` - specifies the control socket for managing the + service configuration. + +A control socket is specified by: + +- ``socket-type`` - the socket type is either ``stdout``, ``unix``, or ``http``. + ``stdout`` is the default; + it is not really a socket, but it allows :iscman:`kea-netconf` to run in + debugging mode where everything is printed on stdout, and it can also be + used to redirect commands easily. ``unix`` is the standard direct + server control channel, which uses UNIX sockets; ``http`` uses + a control agent, which accepts HTTP connections. + +- ``socket-name`` - the local socket name for the ``unix`` socket type + (default empty string). + +- ``socket-url`` - the HTTP URL for the ``http`` socket type (default + ``http://127.0.0.1:8000/``). + +User contexts can store arbitrary data as long as they are in valid JSON +syntax and their top-level element is a map (i.e. the data must be +enclosed in curly brackets). They are accepted at the NETCONF entry, +i.e. below the top-level, managed-service entry, and control-socket +entry scopes. + +Hook libraries can be loaded by the NETCONF agent just as with other +servers or agents; however, currently no hook points are defined. The +``hooks-libraries`` list contains the list of hook libraries that +should be loaded by :iscman:`kea-netconf`, along with their configuration +information specified with ``parameters``. + +Please consult :ref:`logging` for details on how to configure +logging. The name of the NETCONF agent's main logger is :iscman:`kea-netconf`, as +given in the example above. + +.. _netconf-example: + +A :iscman:`kea-netconf` Configuration Example +--------------------------------------------- + +The following example demonstrates the basic NETCONF configuration. More +examples are available in the ``doc/examples/netconf`` directory in the +Kea sources. + +.. code-block:: javascript + + // This is a simple example of a configuration for the NETCONF agent. + // This server provides a YANG interface for all Kea servers and the agent. + { + "Netconf": + { + // Control flags can be defined in the global scope or + // in a managed server scope. Precedences are: + // - use the default value (true) + // - use the global value + // - use the local value. + // So this overwrites the default value: + "boot-update": false, + + // This map specifies how each server is managed. For each server there + // is a name of the YANG model to be used and the control channel. + // Currently three control channel types are supported: + // "stdout" which outputs the configuration on the standard output, + // "unix" which uses the local control channel supported by the + // "dhcp4" and "dhcp6" servers ("d2" support is not yet available), + // and "http" which uses the Control Agent "ca" to manage itself or + // to forward commands to "dhcp4" or "dhcp6". + "managed-servers": + { + // This is how kea-netconf can communicate with the DHCPv4 server. + "dhcp4": + { + "comment": "DHCPv4 server", + "model": "kea-dhcp4-server", + "control-socket": + { + "socket-type": "unix", + "socket-name": "/tmp/kea4-ctrl-socket" + } + }, + + // DHCPv6 parameters. + "dhcp6": + { + "model": "kea-dhcp6-server", + "control-socket": + { + "socket-type": "unix", + "socket-name": "/tmp/kea6-ctrl-socket" + } + }, + + // Currently the DHCP-DDNS (nicknamed D2) server does not support + // a command channel. + "d2": + { + "model": "kea-dhcp-ddns", + "control-socket": + { + "socket-type": "stdout", + "user-context": { "in-use": false } + } + }, + + // Of course the Control Agent (CA) supports HTTP. + "ca": + { + "model": "kea-ctrl-agent", + "control-socket": + { + "socket-type": "http", + "socket-url": "http://127.0.0.1:8000/" + } + } + }, + + // kea-netconf is able to load hook libraries that augment its operation. + // Currently there are no hook points defined in kea-netconf + // processing. + "hooks-libraries": [ + // The hook libraries list may contain more than one library. + { + // The only necessary parameter is the library filename. + "library": "/opt/local/custom_hooks_example.so", + + // Some libraries may support parameters. Make sure you + // type this section carefully, as kea-netconf does not + // validate it (because the format is library-specific). + "parameters": { + "param1": "foo" + } + } + ], + + // Similar to other Kea components, NETCONF also uses logging. + "loggers": [ + { + "name": "kea-netconf", + "output-options": [ + { + "output": "/var/log/kea-netconf.log", + // Several additional parameters are possible in + // addition to the typical output. + // Flush determines whether logger flushes output + // to a file. + // Maxsize determines maximum filesize before + // the file is rotated. + // Maxver specifies the maximum number of + // rotated files to be kept. + "flush": true, + "maxsize": 204800, + "maxver": 4 + } + ], + "severity": "INFO", + "debuglevel": 0 + } + ] + } + } + +.. _netconf-start-stop: + +Starting and Stopping the NETCONF Agent +--------------------------------------- + +:iscman:`kea-netconf` accepts the following command-line switches: + +- ``-c file`` - specifies the configuration file. + +- ``-d`` - specifies whether the agent logging should be switched to + debug/verbose mode. In verbose mode, the logging severity and + debuglevel specified in the configuration file are ignored and + "debug" severity and the maximum debuglevel (99) are assumed. The + flag is convenient for temporarily switching the server into maximum + verbosity, e.g. when debugging. + +- ``-t file`` - specifies the configuration file to be tested. + :iscman:`kea-netconf` attempts to load it and conducts sanity checks; + certain checks are possible only while running the actual server. The + actual status is reported with exit code (0 = configuration appears valid, + 1 = error encountered). Kea prints out log messages to standard + output and error to standard error when testing the configuration. + +- ``-v`` - displays the version of :iscman:`kea-netconf` and exits. + +- ``-V`` - displays the extended version information for :iscman:`kea-netconf` + and exits. The listing includes the versions of the libraries + dynamically linked to Kea. + +- ``-W`` - displays the Kea configuration report and exits. The report + is a copy of the ``config.report`` file produced by ``./configure``; + it is embedded in the executable binary. + + The contents of the ``config.report`` file may also be accessed by examining + certain libraries in the installation tree or in the source tree. + + .. code-block:: shell + + # from installation using libkea-process.so + $ strings ${prefix}/lib/libkea-process.so | sed -n 's/;;;; //p' + + # from sources using libkea-process.so + $ strings src/lib/process/.libs/libkea-process.so | sed -n 's/;;;; //p' + + # from sources using libkea-process.a + $ strings src/lib/process/.libs/libkea-process.a | sed -n 's/;;;; //p' + + # from sources using libcfgrpt.a + $ strings src/lib/process/cfgrpt/.libs/libcfgrpt.a | sed -n 's/;;;; //p' + +.. _operation-example: + +A Step-by-Step NETCONF Agent Operation Example +---------------------------------------------- + +.. note:: + + Copies of example configurations presented within this section can be + found in the Kea source code, under + ``doc/examples/netconf/kea-dhcp6-operations``. + +.. _operation-example-setup: + +Setup of NETCONF Agent Operation Example +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The test box has an Ethernet interface named eth1. On some systems it is +possible to rename interfaces; for instance, on Linux with an ens38 +interface: + +.. code-block:: console + + # ip link set down dev ens38 + # ip link set name eth1 dev ens38 + # ip link set up dev eth1 + +The interface must have an address in the test prefix: + +.. code-block:: console + + # ip -6 addr add 2001:db8::1/64 dev eth1 + +The Kea DHCPv6 server must be launched with the configuration specifying +a control socket used to receive control commands. The :iscman:`kea-netconf` +process uses this socket to communicate with the DHCPv6 server, i.e. it +pushes translated configurations to that server using control commands. +The following is an example control socket specification for the Kea +DHCPv6 server: + +.. code-block:: json + + { + "Dhcp6": { + "control-socket": { + "socket-name": "/tmp/kea-dhcp6-ctrl.sock", + "socket-type": "unix" + } + } + } + +In order to launch the Kea DHCPv6 server using the configuration +contained within the ``boot.json`` file, run: + +.. code-block:: console + + # kea-dhcp6 -d -c boot.json + +The current configuration of the server can be fetched via a control +socket by running: + +.. code-block:: console + + # echo '{ "command": "config-get" }' | socat UNIX:/tmp/kea-dhcp6-ctrl.sock '-,ignoreeof' + +The following is the example ``netconf.json`` configuration for +:iscman:`kea-netconf`, to manage the Kea DHCPv6 server: + +.. code-block:: json + + { + "Netconf": { + "loggers": [ + { + "debuglevel": 99, + "name": "kea-netconf", + "output-options": [ + { + "output": "stderr" + } + ], + "severity": "DEBUG" + } + ], + "managed-servers": { + "dhcp6": { + "control-socket": { + "socket-name": "/tmp/kea-dhcp6-ctrl.sock", + "socket-type": "unix" + } + } + } + } + } + +Note that in production there should not be a need to log at the DEBUG level. + +The Kea NETCONF agent is launched by: + +.. code-block:: console + + # kea-netconf -d -c netconf.json + +Now that both :iscman:`kea-netconf` and :iscman:`kea-dhcp6` are running, it is +possible to populate updates to the configuration to the DHCPv6 server. +The following is the configuration extracted from ``startup.xml``: + +.. code-block:: xml + + <config xmlns="urn:ietf:params:xml:ns:yang:kea-dhcp6-server"> + <subnet6> + <id>1</id> + <pool> + <start-address>2001:db8::1:0</start-address> + <end-address>2001:db8::1:ffff</end-address> + <prefix>2001:db8::1:0/112</prefix> + </pool> + <subnet>2001:db8::/64</subnet> + </subnet6> + <interfaces-config> + <interfaces>eth1</interfaces> + </interfaces-config> + <control-socket> + <socket-name>/tmp/kea-dhcp6-ctrl.sock</socket-name> + <socket-type>unix</socket-type> + </control-socket> + </config> + +To populate this new configuration: + +.. code-block:: console + + $ sysrepocfg -d startup -f xml -m kea-dhcp6-server --import=startup.xml + +:iscman:`kea-netconf` pushes the configuration found in the Sysrepo startup +datastore to all Kea servers during its initialization phase, after it +subscribes to module changes in the Sysrepo running datastore. This +action copies the configuration from the startup datastore to the +running datastore and enables the running datastore, making it +available. + +Changes to the running datastore are applied after validation to the Kea +servers. Note that they are not by default copied back to the startup +datastore, i.e. changes are not permanent. + +.. note:: + + :iscman:`kea-netconf` fetches the entire configuration from any Sysrepo datastore in a + single ``get-config`` NETCONF operation. Prior to Kea 2.3.2, a ``get-config`` operation + was done for each leaf and leaf-list node. Because of the significant changes, + :iscman:`kea-netconf` is considered experimental. + +.. _operation-example-errors: + +Example of Error Handling in NETCONF Operation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +There are four classes of issues with configurations applied via +NETCONF: + +1. The configuration does not comply with the YANG schema. + +2. The configuration cannot be translated from YANG to the Kea JSON. + +3. The configuration is rejected by the Kea server. + +4. The configuration was validated by the Kea server but cannot be + applied. + +In the first case, consider the following ``BAD-schema.xml`` +configuration file: + +.. code-block:: xml + + <config xmlns="urn:ietf:params:xml:ns:yang:kea-dhcp6-server"> + <subnet4> + <id>1</id> + <pool> + <start-address>2001:db8::1:0</start-address> + <end-address>2001:db8::1:ffff</end-address> + <prefix>2001:db8::1:0/112</prefix> + </pool> + <subnet>2001:db8::/64</subnet> + </subnet6> + <interfaces-config> + <interfaces>eth1</interfaces> + </interfaces-config> + <control-socket> + <socket-name>/tmp/kea-dhcp6-ctrl.sock</socket-name> + <socket-type>unix</socket-type> + </control-socket> + </config> + +It is directly rejected by ``sysrepocfg``: + +.. code-block:: console + + $ sysrepocfg -d running -f xml -m kea-dhcp6-server --import=BAD-schema.xml + +In the second case, the configuration is rejected by :iscman:`kea-netconf`. +For example, consider this ``BAD-translator.xml`` file: + +.. code-block:: xml + + <config xmlns="urn:ietf:params:xml:ns:yang:kea-dhcp6-server"> + <subnet6> + <id>1</id> + <pool> + <start-address>2001:db8::1:0</start-address> + <end-address>2001:db8::1:ffff</end-address> + <prefix>2001:db8::1:0/112</prefix> + </pool> + <subnet>2001:db8::/64</subnet> + </subnet6> + <interfaces-config> + <interfaces>eth1</interfaces> + </interfaces-config> + <control-socket> + <socket-name>/tmp/kea-dhcp6-ctrl.sock</socket-name> + <socket-type>unix</socket-type> + </control-socket> + <user-context>bad</user-context> + </config> + +In the third case, the configuration is presented to the Kea DHCPv6 +server and fails to validate, as in this ``BAD-config.xml`` file: + +.. code-block:: xml + + <config xmlns="urn:ietf:params:xml:ns:yang:kea-dhcp6-server"> + <subnet6> + <id>1</id> + <pool> + <start-address>2001:db8:1::0</start-address> + <end-address>2001:db8:1::ffff</end-address> + <prefix>2001:db8:1::0/112</prefix> + </pool> + <subnet>2001:db8::/64</subnet> + </subnet6> + <interfaces-config> + <interfaces>eth1</interfaces> + </interfaces-config> + <control-socket> + <socket-name>/tmp/kea-dhcp6-ctrl.sock</socket-name> + <socket-type>unix</socket-type> + </control-socket> + </config> + +In the last case, the misconfiguration is detected too late and the +change must be reverted in Sysrepo, e.g. using the startup datastore as +a backup. + +.. _operation-example-2pools: + +NETCONF Operation Example with Two Pools +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This example adds a second pool to the initial (i.e. startup) +configuration in the ``twopools.xml`` file: + +.. code-block:: xml + + <config xmlns="urn:ietf:params:xml:ns:yang:kea-dhcp6-server"> + <subnet6> + <id>1</id> + <pool> + <start-address>2001:db8::1:0</start-address> + <end-address>2001:db8::1:ffff</end-address> + <prefix>2001:db8::1:0/112</prefix> + </pool> + <pool> + <start-address>2001:db8::2:0</start-address> + <end-address>2001:db8::2:ffff</end-address> + <prefix>2001:db8::2:0/112</prefix> + </pool> + <subnet>2001:db8::/64</subnet> + </subnet6> + <interfaces-config> + <interfaces>eth1</interfaces> + </interfaces-config> + <control-socket> + <socket-name>/tmp/kea-dhcp6-ctrl.sock</socket-name> + <socket-type>unix</socket-type> + </control-socket> + </config> + +This configuration is installed by: + +.. code-block:: console + + $ sysrepocfg -d running -f xml -m kea-dhcp6-server --import=twopools.xml + +.. _operation-example-2subnets: + +NETCONF Operation Example with Two Subnets +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This example specifies two subnets in the ``twosubnets.xml`` file: + +.. code-block:: xml + + <config xmlns="urn:ietf:params:xml:ns:yang:kea-dhcp6-server"> + <subnet6> + <id>1</id> + <pool> + <start-address>2001:db8:1::</start-address> + <end-address>2001:db8:1::ffff</end-address> + <prefix>2001:db8:1::/112</prefix> + </pool> + <subnet>2001:db8:1::/64</subnet> + </subnet6> + <subnet6> + <id>2</id> + <pool> + <start-address>2001:db8:2::</start-address> + <end-address>2001:db8:2::ffff</end-address> + <prefix>2001:db8:2::/112</prefix> + </pool> + <subnet>2001:db8:2::/64</subnet> + </subnet6> + <interfaces-config> + <interfaces>eth1</interfaces> + </interfaces-config> + <control-socket> + <socket-name>/tmp/kea-dhcp6-ctrl.sock</socket-name> + <socket-type>unix</socket-type> + </control-socket> + </config> + +This configuration is installed by: + +.. code-block:: console + + $ sysrepocfg -d running -f xml -m kea-dhcp6-server --import=twosubnets.xml + +.. _operation-example-logging: + +NETCONF Operation Example With Logging +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This example adds a logger entry to the initial (i.e. startup) +configuration in the ``logging.xml`` file: + +.. code-block:: xml + + <config xmlns="urn:ietf:params:xml:ns:yang:kea-dhcp6-server"> + <interfaces-config> + <interfaces>eth1</interfaces> + </interfaces-config> + <subnet6> + <id>1</id> + <pool> + <start-address>2001:db8::1:0</start-address> + <end-address>2001:db8::1:ffff</end-address> + <prefix>2001:db8::1:0/112</prefix> + </pool> + <subnet>2001:db8::/64</subnet> + </subnet6> + <control-socket> + <socket-name>/tmp/kea-dhcp6-ctrl.sock</socket-name> + <socket-type>unix</socket-type> + </control-socket> + <logger> + <name>kea-dhcp6</name> + <output-option> + <output>stderr</output> + </output-option> + <debuglevel>99</debuglevel> + <severity>DEBUG</severity> + </logger> + </config> + +The corresponding Kea configuration in JSON is: + +.. code-block:: json + + { + "Dhcp6": { + "control-socket": { + "socket-name": "/tmp/kea-dhcp6-ctrl.sock", + "socket-type": "unix" + }, + "interfaces-config": { + "interfaces": [ "eth1" ] + }, + "subnet6": [ + { + "id": 1, + "pools": [ + { + "pool": "2001:db8::1:0/112" + } + ], + "subnet": "2001:db8::/64" + } + ], + "loggers": [ + { + "name": "kea-dhcp6", + "output-options": [ + { + "output": "stderr" + } + ], + "severity": "DEBUG", + "debuglevel": 99 + } + ] + } + } + +Finally, any of the previous examples can be replayed by using +``sysrepocfg`` in edit mode as follows: + +.. code-block:: console + + $ sysrepocfg -d running -f xml -m kea-dhcp6-server --edit + +or by using a NETCONF client like ``netopeer2-cli`` from the +`Netopeer2 <https://github.com/CESNET/Netopeer2>`__ NETCONF Toolset. + +.. _migrating-yang-data: + +Migrating YANG Data From a Prior Sysrepo Version +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +1. Shut down :iscman:`kea-netconf`. This ensures that backups for both datastores +are done at the same configuration state and that no change happens between exporting them. + +2. Make data backups for all YANG modules, with one XML for each datastore. + +.. code-block:: console + + $ sysrepocfg --datastore running --export=save.xml --format=xml + $ sysrepocfg --datastore startup --export=save.xml --format=xml + +.. note:: + + Sysrepo v0 does not support import/export of all YANG modules; this capability was added in + Sysrepo v1. Users that are migrating from Sysrepo v0 will need to do per-module backups. This has + the added benefit of isolating potential failures and preventing them from affecting all + modules. The command is the same, except it has the module name added to it at the end. + + .. code-block:: console + + $ sysrepocfg --datastore running --export=save.xml --format=xml kea-dhcp6-server + $ sysrepocfg --datastore startup --export=save.xml --format=xml kea-dhcp6-server + +3. Upgrade Sysrepo to the newer version and then run: + +.. code-block:: console + + $ sysrepocfg --datastore running --import=save.xml + $ sysrepocfg --datastore startup --import=save.xml diff --git a/doc/sphinx/arm/ext-radius.rst b/doc/sphinx/arm/ext-radius.rst new file mode 100644 index 0000000..08ca631 --- /dev/null +++ b/doc/sphinx/arm/ext-radius.rst @@ -0,0 +1,559 @@ +.. _radius: + +RADIUS +====== + +.. _radius-overview: + +RADIUS Overview +--------------- + +This hook library allows Kea to interact with two types of RADIUS +services: access and accounting. Although the most common DHCP and RADIUS +integration is done on the DHCP relay-agent level (DHCP clients send +DHCP packets to DHCP relays; those relays contact the RADIUS server and +depending on the response either send the packet to the DHCP server or +drop it), it does require DHCP relay hardware to support RADIUS +communication. Also, even if the relay has the necessary support, it is +often not flexible enough to send and receive additional RADIUS +attributes. As such, the alternative looks more appealing: to extend the +DHCP server to talk to RADIUS directly. That is the goal of this library. + +.. note:: + + This library can only be loaded by the :iscman:`kea-dhcp4` or the + :iscman:`kea-dhcp6` process. + +The major feature of this hook library is the ability to use RADIUS +authorization. When a DHCP packet is received, the Kea server sends an +Access-Request to the RADIUS server and waits for a response. The server +then sends back either an Access-Accept with specific client attributes, +or an Access-Reject. There are two cases supported here: first, the +Access-Accept includes a Framed-IP-Address attribute (for DHCPv4) or a +Framed-IPv6-Address attribute (for DHCPv6), which are interpreted by Kea as +instructions to assign the specified IPv4 or IPv6 address. This +effectively means RADIUS can act as an address-reservation database. + +The second supported case is the ability to assign clients to specific +pools based on a RADIUS response. In this case, the RADIUS server sends +back an Access-Accept with a Framed-Pool attribute. +For both DHCPv4 and DHCPv6, Kea interprets this attribute as a client class. +With the addition of the ability to limit access to pools to +specific classes (see :ref:`classification-pools`), RADIUS can be +used to force the client to be assigned a dynamic address from a +specific pool. Furthermore, the same mechanism can be used to control +what kind of options the client gets if there are DHCP options +specified for a particular class. + +.. _radius-config: + +RADIUS Hook Library Configuration +--------------------------------- + +The RADIUS hook is a library that must be loaded by either :iscman:`kea-dhcp4` or +:iscman:`kea-dhcp6` servers. Unlike some other available hook libraries, this one +takes many parameters. For example, this configuration can be used: + +.. parsed-literal:: + + { + "Dhcp4": { + + // Your regular DHCPv4 configuration parameters goes here. + + "hooks-libraries": [ + { + // Note that RADIUS requires host-cache for proper operation, + // so that library is loaded as well. + "library": "/usr/local/lib/kea/hooks/libdhcp_host_cache.so" + }, + { + "library": "/usr/local/lib/kea/hooks/libdhcp_radius.so", + "parameters": { + + // Specify where the dictionary is located. + "dictionary": "/etc/kea/radius/dictionary", + + // Specify which address to use to communicate with RADIUS servers + "bindaddr": "*" + + // More RADIUS parameters go here. + } + } + ] + } + } + +RADIUS is a complicated environment. As such, it is not feasible +to provide a default configuration that works for everyone. +However, we do have an example that showcases some of the more common +features. Please see ``doc/examples/kea4/hooks-radius.json`` in the Kea +sources. + +The RADIUS hook library supports the following global configuration +flags: + +- ``bindaddr`` (default ``"*"``) - specifies the address to be used by the + hook library in communication with RADIUS servers. The ``"*"`` special + value tells the kernel to choose the address at hook library load time. + +- ``canonical-mac-address`` (default ``false``) - specifies whether MAC + addresses in attributes follow the canonical RADIUS format (lowercase + pairs of hexadecimal digits separated by ``-``). + +- ``client-id-pop0`` (default ``false``) - is used with + :ischooklib:`libdhcp_flex_id.so`. Removes the leading zero (or pair of zeroes + in DHCPv6) type in the client id (duid in DHCPv6). See + ``client-id-printable`` for any value implications when used in conjunction + with it. + +- ``client-id-printable`` (default ``false``) - checks whether the + ``client-id``/``duid`` content is printable and uses it as is instead of in + hexadecimal. Implies ``client-id-pop0`` and ``extract-duid`` as 0 and 255 are + not printable. + +- ``deadtime`` (default ``0``) - is a mechanism that helps in sorting the + servers such that the servers that have proved responsive so far are inquired + first, and the servers that have proved unresponsive are left at the end. The + deadtime value specifies the number of seconds after which a server is + considered unresponsive. 0 disables the mechanism. + +- ``dictionary`` (default ``"/etc/kea/radius/dictionary"``) - is the + attribute and value dictionary. Note that it is a critical parameter. + A dictionary is provided by Kea and is set by default. + +- ``extract-duid`` (default ``true``) - extracts the embedded duid from an + RFC-4361-compliant DHCPv4 client id. See ``client-id-printable`` for any + value implications when used in conjunction with it. + +- ``identifier-type4`` (default ``"client-id"``) - specifies the identifier + type to build the User-Name attribute. It should be the same as the + host identifier. When :ischooklib:`libdhcp_flex_id.so` is used, then + ``replace-client-id`` must be set to ``true`` and ``client-id`` must be used + with ``client-id-pop0`` enabled. + +- ``identifier-type6`` (default ``"duid"``) - specifies the identifier type to + build the User-Name attribute. It should be the same as the host + identifier. When :ischooklib:`libdhcp_flex_id.so` is used, then + ``replace-client-id`` must be set to ``true`` and ``duid`` must be used with + ``client-id-pop0`` enabled. + +- ``nas-ports`` (default ``[]``), specifies the NAS port to use in place of + a subnet ID (default behavior). It is an array of maps, each map having two + elements at most: the mandatory NAS port value, and, optionally, a selector + consisting of either a subnet id, a subnet prefix, or a shared-network name. + If the selector is applied to the packet, the NAS port is used instead of the + subnet id. When the subnet id is 0 or missing, the specified NAS port acts as + a default. Its substition happens for all packets that did not match a + selector. + +- ``realm`` (default ``""``) - is the default realm. + +- ``reselect-subnet-address`` (default ``false``) - enables subnet reselection + according to the value of the Framed-IP-Address or, respectively, + the Framed-IPv6-Address attribute from the RADIUS access response. With this + flag enabled, if the IP address is not in range of the currently selected + subnet, but is in range of another subnet that is selectable with regards to + other criteria, the latter subnet is selected and used further in the lease + assignment process. + +- ``reselect-subnet-pool`` (default ``false``) - enables subnet reselection + according to the value of the Framed-Pool attribute from the RADIUS access + response. With this flag enabled, if the currently selected subnet is not + guarded by the client class represented by the attribute value, but there is + another selectable subnet that is guarded by it, the latter subnet is + selected and used further in the lease assignment process. + This reselection is attempted first, and if successful, it prevents the + function of reselect-subnet-address from coming into effect. + +- ``retries`` (default ``3``) - is the number of retries before trying the + next server. + +- ``session-history`` (default ``""``) - is the name of the file providing + persistent storage for accounting session history. + + - ``thread-pool-size`` (default ``0``) indicates the number of threads that + is used for sending RADIUS requests and processing RADIUS responses for both + access and accounting services before passing it to the core thread pool. A + value of ``0`` instructs the RADIUS hook library to use the same number of + threads used for core DHCP processing. This value is only relevant if Kea + core is configured as multi-threaded. Single-threaded Kea core results in + single-threaded RADIUS processing. + +- ``timeout`` (default ``10``) - is the number of seconds during which a + response is awaited. + +Two services are supported: + +- ``access`` - the authorization service. + +- ``accounting`` - the accounting service. + +At the service level, three sections can be configured: + +- Servers that define RADIUS services that the library is expected to + contact. Each server may have the following items specified: + + - ``name`` - specifies the IP address of the server. A domain name may be + used and will be resolved at hook library load time. + + - ``port`` - specifies the UDP port of the server. By default, it is 1812 + for access and 1813 for accounting. + + - ``secret`` - authenticates messages. + + When no server is specified, the service is disabled. + +- Attributes which define additional information that the Kea server + sends to a RADIUS server. The parameter must be identified either + by a name or type. Its value can be specified in one of three + possible ways: ``data`` (which defines a plain text value), ``raw`` (which + defines the value in hex), or ``expr`` (which defines an expression + that is evaluated for each incoming packet independently). + + - ``name`` - the name of the attribute. + + - ``type`` - the type of the attribute. Either the type or the name must be + provided, and the attribute must be defined in the dictionary. + + - ``data`` - the first of three ways to specify the attribute content. + It specifies the textual representation of the attribute content. + + - ``raw`` - the second of three ways to specify the attribute content. + It specifies the content in hexadecimal. + + - ``expr`` - the last of the three ways to specify the attribute content. + It specifies an evaluation expression on the DHCP query packet. + Currently this is restricted to the access service. + + Attributes are supported only for the access service. + +- The ``peer-updates`` boolean flag (default ``true``) controls whether lease + updates coming from an active High-Availability (HA) partner should result in + an accounting request. This may be desirable to remove duplicates if HA + partners are configured to send request to the same RADIUS server. The flag is + only supported by the accounting service. The lease synchronization process at + the startup of an HA node does not trigger a RADIUS accounting request, + regardless of the value of this flag. + +- The ``max-pending-requests`` positive integer (default ``0``) limits the + number of pending RADIUS requests. The value ``0`` means no limit. It is + supported only by the access service. ``64`` can be a good value to set it to. + +For example, to specify a single access server available on localhost +that uses ``"xyz123"`` as a secret, and tell Kea to send three additional +attributes (``User-Password``, ``Connect-Info``, and ``Configuration-Token``), +the following snippet could be used: + +.. parsed-literal:: + + { + "parameters": { + + // Other RADIUS parameters here + + "access": { + + // This starts the list of access servers. + "servers": [ + { + // These are parameters for the first (and only) access server + "name": "127.0.0.1", + "port": 1812, + "secret": "xyz123" + } + // Additional access servers could be specified here. + ], + + // This defines a list of additional attributes Kea will send to each + // access server in Access-Request. + "attributes": [ + { + // This attribute is identified by name (must be present in the + // dictionary) and has static value (i.e. the same value will be + // sent to every server for every packet). + "name": "User-Password", + "data": "mysecretpassword" + }, + { + // It is also possible to specify an attribute using its type, + // rather than a name. 77 is Connect-Info. The value is specified + // using hex. Again, this is a static value. It will be sent the + // same for every packet and to every server. + "type": 77, + "raw": "65666a6a71" + }, + { + // This example shows how an expression can be used to send dynamic value. + // The expression (see :ref:`classification-using-expressions`) may take any + // value from the incoming packet or even its metadata e.g. the + // interface it was received over from. + "name": "Configuration-Token", + "expr": "hexstring(pkt4.mac,':')" + } + ] // End of attributes + }, // End of access + + // Accounting parameters. + "accounting": { + // This starts the list of accounting servers. + "servers": [ + { + // These are parameters for the first (and only) accounting server + "name": "127.0.0.1", + "port": 1813, + "secret": "sekret" + } + // Additional accounting servers could be specified here. + ] + } + } + } + +Customization is sometimes required for certain attributes by devices belonging +to various vendors. This is a great way to leverage the expression evaluation +mechanism. For example, MAC addresses which might be used as a convenience +value for the ``User-Password`` attribute are most likely to appear in colon-hexadecimal +notation (``de:ad:be:ef:ca:fe``), but they might need to be expressed in +hyphen-hexadecimal notation (``de-ad-be-ef-ca-fe``). Here's how to specify that: + +.. code-block:: json + + { + "parameters": { + "access": { + "attributes": [ + { + "name": "User-Password", + "expr": "hexstring(pkt4.mac, '-')" + } + ] + } + } + } + +And here's how to specify period-separated hexadecimal notation (``dead.beef.cafe``), preferred by Cisco devices: + +.. code-block:: json + + { + "parameters": { + "access": { + "attributes": [ + { + "name": "User-Password", + "expr": "substring(hexstring(pkt4.mac, ''), 0, 4) + '.' + substring(hexstring(pkt4.mac, ''), 4, 4) + '.' + substring(hexstring(pkt4.mac, ''), 8, 4)" + } + ] + } + } + } + + +For :ischooklib:`libdhcp_radius.so` to operate properly in DHCPv4, +:ischooklib:`libdhcp_host_cache.so` must also be loaded. The reason for this +is somewhat complex. In a typical deployment, the DHCP clients send +their packets via DHCP relay, which inserts certain Relay Agent +Information options, such as ``circuit-id`` or ``remote-id``. The values of +those options are then used by the Kea DHCP server to formulate the +necessary attributes in the Access-Request message sent to the RADIUS +server. However, once the DHCP client gets its address, it then renews +by sending packets directly to the DHCP server. As a result, the relays +are not able to insert their RAI options, and the DHCP server cannot send +the Access-Request queries to the RADIUS server by using just the +information from incoming packets. Kea needs to keep the information +received during the initial Discover/Offer exchanges and use it again +later when sending accounting messages. + +This mechanism is implemented based on user context in host +reservations. (See :ref:`user-context` and :ref:`user-context-hooks` for +details.) The host-cache mechanism allows the information retrieved by +RADIUS to be stored and later used for sending access and accounting +queries to the RADIUS server. In other words, the host-cache mechanism +is mandatory, unless administrators do not want RADIUS communication for messages +other than Discover and the first Request from each client. + +.. note:: + + Currently the RADIUS hook library is incompatible with the + ``early-global-reservations-lookup`` global parameter i.e. + setting the parameter to ``true`` raises an error when the + hook library is loaded. + +.. note:: + + Currently the RADIUS hook library is incompatible with the + multi-subnet shared networks that have host reservations other + than global. Loading the RADIUS hook library in a Kea DHCP server + that has this configuration raises an error. + +.. _radius-server-example: + +RADIUS Server Setup Example +--------------------------- + +The RADIUS hook library requires at least one RADIUS server to function. One +popular open-source implementation is FreeRADIUS. This is how it can be +set up to enable basic functionality in Kea. + +1. Install FreeRADIUS through the package manager or from the tarballs available + on [the freeradius.org download page](https://freeradius.org/releases/). + +2. Establish the FreeRADIUS configuration directory. It's commonly + ``/etc/freeradius``, but it may be ``/etc/raddb``. + +3. Generate certificates. Go to ``/etc/freeradius/certs``. + Run ``./bootstrap`` or ``make``. + Wait until finished. It should take a few seconds. + +4. Check that the server is able to start. + Running with the ``-X`` flag is a good way to display potential errors. + Run ``radiusd -X`` or ``freeradius -X``, whichever is available. + It should display ``Ready to process requests`` on the final line. + +5. If the Kea DHCP server and the RADIUS server are on different machines, + edit ``/etc/freeradius/clients.conf`` with the proper address under + ``ipadddr``. This file is also where the secret is set, which needs to match + the one set in the hook library's configuration. + +6. If RADIUS is used for the purpose of authorizing DHCP clients, each DHCP + client needs to have an entry in the authorize file, which can be commonly + found at: + + - ``/etc/raddb/mods-config/files/authorize`` + - ``/etc/freeradius/3.0/mods-config/files/authorize`` + - ``/etc/freeradius/users`` (for RADIUS 2.x series) + + Entries need to have the password set which needs to match the password + configured in the configuration of the RADIUS hook library under the + ``User-Password`` attribute. Each entry can have zero, one or multiple + attributes. + + In the following example, there are 6 entries with the password set to the + client ID, which would need to be dynamically set in the hook library's + configuration. Here's how the entries can look like: + + :: + + 01:00:0c:01:02:03:04 Cleartext-password := "00:0c:01:02:03:04" + + 01:00:0c:01:02:03:05 Cleartext-password := "00:0c:01:02:03:05" + Framed-IP-Address = "192.0.2.5" + + 01:00:0c:01:02:03:06 Cleartext-password := "00:0c:01:02:03:06" + Framed-IP-Address = "192.0.2.6", + Framed-Pool = "classical" + + 00:03:00:01:00:0c:01:02:03:07 Cleartext-password := "00:0c:01:02:03:07" + + 00:03:00:01:00:0c:01:02:03:08 Cleartext-password := "00:0c:01:02:03:08" + Framed-IPv6-Address = "2001:db8::8" + + 00:03:00:01:00:0c:01:02:03:09 Cleartext-password := "00:0c:01:02:03:09" + Framed-IPv6-Address = "2001:db8::9", + Framed-Pool = "classroom" + +7. Accounting should work out of the box with Kea, but customizations are + possible in the accounting file, which can be commonly found at: + + - ``/etc/radius-config/mods-config/files/accounting`` + - ``/etc/freeradius/3.0/mods-config/files/accounting`` + +.. _radius-lease-allocation: + +RADIUS Workflows for Lease Allocation +------------------------------------- + +The following diagrams show a high level view of how RADIUS assists with the +lease allocation process in :iscman:`kea-dhcp4` and :iscman:`kea-dhcp6`. + +.. figure:: ../uml/radius.* + +Somewhat tangential to lease allocation, and not shown in the diagrams above, +is the ``command_processed`` callout, which sends Accounting-Request messages +when a lease command is received. + +.. _radius-differences: + +Differences Between RADIUS Hook Libraries Prior To 2.4.0 and As Of 2.6.0 +------------------------------------------------------------------------ + +The RADIUS hook library in 2.4.0 and prior versions relied on the FreeRADIUS +client library to function. Starting with 2.6.0 and onwards, the RADIUS hook +library is standalone with its own RADIUS client implementation and its own +RADIUS dictionary. There are differences: + +.. list-table:: + :header-rows: 1 + + * - Feature + + - Old + + - New + + * - Support for Attribute Data Types + + - string, ipaddr, ipv4prefix, integer, integer64, date, ifid, ipv6addr, ipv6prefix, tlv, abinary, byte, ether, short, signed, octets + + - string (can simulate any other unsupported data type too), ipaddr, integer, date (interpreted as integer), ipv6addr, ipv6prefix + + * - Names of Standard Attributes + + - Taken from the FreeRADIUS dictionary. + + - Taken from the Kea RADIUS dictionary and the IANA registry. There is an aliasing mechanism built into the library that ensures backward compatibility e.g. ``Password`` translates to the standard name of the attribute ``User-Password``. + + * - Resolution of RADIUS Server Domain Names + + - At run time. + + - At hook library load time. + + * - Automatic Deduction of Source Address for Reaching RADIUS Servers (configured with ``bindaddr: "*"``) + + - At run time. + + - At hook library load time. + + * - RADIUS Server Limit per Service + + - 8 + + - Unlimited + + * - Support for Including Dictionaries Inside Dictionaries + + - Yes + + - No + + * - Support for Vendor Attributes + + - Yes + + - No + + * - Attribute Names and Attribute Values + + - Case-insensitive + + - Case-sensitive + + * - Integer Values + + - Do not require an attribute definition. + + - Must have an associated attribute definition in the dictionary. + + * - Reply-Message Presence in the Kea Logs + + - Only as part of the aggregated list of attributes in ``RADIUS_AUTHENTICATION_ACCEPTED``, ``RADIUS_ACCESS_CACHE_INSERT``, ``RADIUS_ACCESS_CACHE_GET`` log messages. + + - Also has a dedicated ``RADIUS_REPLY_MESSAGE_ATTRIBUTE`` message per each Reply-Message attribute logged after a valid RADIUS reply is received. + + * - Behavior of Multiple Attributes of the Same Type (except Reply-Message) + + - Experimentally, only the **first** attribute on the wire from an Access-Accept message is considered. + + - Experimentally, only the **last** attribute on the wire from an Access-Accept message is considered. diff --git a/doc/sphinx/arm/hammer.rst b/doc/sphinx/arm/hammer.rst new file mode 100644 index 0000000..2d25a52 --- /dev/null +++ b/doc/sphinx/arm/hammer.rst @@ -0,0 +1,137 @@ +.. _hammer: + +Hammer Building Tool +==================== + +Hammer is a Python 3 script that lets users automate tasks related to building +Kea, such as setting up virtual machines, installing Kea dependencies, +compiling Kea with various options, running unit-tests and more. This +tool was created primarily for internal QA purposes at ISC and it is not +included in the Kea distribution; however, it is available in the Kea +git repository. This tool was developed primarily for internal purposes +and ISC cannot guarantee its proper operation. Administrators who decide to use it +should do so with care. + +.. note:: + + Use of this tool is completely optional. Everything it does can be + done manually. + +The first-time user is strongly encouraged to look at Hammer's built-in +help: + +.. code-block:: console + + $ ./hammer.py --help + +It will list available parameters. + +Hammer is able to set up various operating systems running either in LXC +or in VirtualBox. For a list of supported systems, use the +``supported-systems`` command: + +.. code-block:: console + + $ ./hammer.py supported-systems + fedora: + - 37: lxc + - 38: + centos: + - 8: lxc, virtualbox + - 9: + rhel: + - 8: virtualbox + - 9: + ubuntu: + - 18.04: lxc, virtualbox + - 20.04: lxc + - 22.04: lxc + debian: + - 10: lxc, virtualbox + - 11: lxc + - 12: lxc + freebsd: + - 12.0: virtualbox + - 12.1: + - 13.0: virtualbox + alpine: + - 3.15: lxc + - 3.16: lxc + - 3.17: lxc + +It is also possible to run the build locally, in the current system (if the OS +is supported). + +First, the Hammer dependencies must be installed: Vagrant +and either VirtualBox or LXC. Hammer can install +Vagrant and the required Vagrant plugins using the command: + +.. code-block:: console + + $ ./hammer.py ensure-hammer-deps + +VirtualBox and LXC must be installed manually. + +The basic functions provided by Hammer are to prepare the build environment +and perform the actual build, and to run the unit tests locally in the current +system. This can be achieved by running the command: + +.. code-block:: console + + $ ./hammer.py build -p local + +The scope of the process can be defined using the ``--with`` (``-w``) and ``--without`` +(``-x``) options. By default, the ``build`` command builds Kea with +documentation, installs it locally, and runs unit tests. + +To exclude the installation and generation of docs, type: + +.. code-block:: console + + $ ./hammer.py build -p local -x install docs + +The basic scope can be extended by mysql, pgsql, native-pkg, shell, and forge. +Please check ``./hammer.py build --help`` for more details. + +.. note:: + + If building Kea locally, Hammer dependencies like Vagrant are + not needed. + +Hammer can be told to set up a new virtual machine with a specified +operating system, without the build: + +.. code-block:: console + + $ ./hammer.py prepare-system -p virtualbox -s freebsd -r 12.0 + +This way, a system can be prepared for our own use. To get to such a system +using SSH, invoke: + +.. code-block:: console + + $ ./hammer.py ssh -p virtualbox -s freebsd -r 12.0 + +It is possible to speed up subsequent Hammer builds via +`ccache <https://ccache.samba.org/>`__. During +compilation, ccache stores objects in a shared folder. In subsequent runs, +instead of doing an actual compilation, ccache returns the stored earlier +objects. The cache with these objects for reuse must be stored outside of VM +or LXC. To indicate the folder, the ``--ccache-dir`` +parameter for Hammer must be included. In the indicated folder, there are separate stored objects for each target +operating system. + +.. code-block:: console + + $ ./hammer.py build -p lxc -s ubuntu -r 18.04 --ccache-dir ~/kea-ccache + +.. note:: + + ccache is currently only supported for LXC in Hammer; support + for VirtualBox may be added later. + +For more information check: + +.. code-block:: console + + $ ./hammer.py --help diff --git a/doc/sphinx/arm/hooks-bootp.rst b/doc/sphinx/arm/hooks-bootp.rst new file mode 100644 index 0000000..7f8a749 --- /dev/null +++ b/doc/sphinx/arm/hooks-bootp.rst @@ -0,0 +1,91 @@ +.. ischooklib:: libdhcp_bootp.so +.. _hooks-bootp: + +``libdhcp_bootp.so``: Support for BOOTP Clients +=============================================== + +This hook library adds support for BOOTP with vendor-information extensions +(`RFC 1497 <https://tools.ietf.org/html/rfc1497>`__). Received BOOTP +requests are recognized, translated into DHCPREQUEST packets by adding +a ``dhcp-message-type`` option, and put into the "BOOTP" client class. +Members of this class get infinite lifetime leases but the class can +also be used to guard a pool of addresses. + +The DHCP-specific options, such as ``dhcp-message-type``, are removed from +the server's responses; responses shorter than the BOOTP minimum +size of 300 octets are padded to this size. + +.. note:: + + :ischooklib:`libdhcp_bootp.so` is part of the open source code and is + available to every Kea user. + +.. note:: + + This library can only be loaded by the :iscman:`kea-dhcp4` process, + as there is no BOOTP protocol for IPv6. + +This library is loaded similarly to other hook libraries, and +it takes no parameters. + +:: + + "Dhcp4": { + "hooks-libraries": [ + { "library": "/usr/local/lib/libdhcp_bootp.so" }, + ... + ] + } + +.. note:: + + A host reservation for a BOOTP client should use the hardware address + as the identifier (the ``client-id`` option is a DHCP-specific option). + +.. _hooks-bootp-config: + +Incoming BOOTP packets are added to the BOOTP class, allowing administrators +to segregate BOOTP clients into separate pools. For example: + +:: + + "Dhcp4": { + "client-classes": [ + { + // The DHCP class is the complement of the BOOTP class + "name": "DHCP", + "test": "not member('BOOTP')" + } + ], + "subnet4": [ + { + "subnet": "192.0.2.0/24", + "pools": [ + { + // BOOTP clients will be handled here + "pool": "192.0.2.200 - 192.0.2.254", + "client-class": "BOOTP" + }, + { + // Regular DHCP clients will be handled here + "pool": "192.0.2.1 - 192.0.2.199", + "client-class": "DHCP" + }], + ... + }, + ... + ], + ... + } + + +.. _hooks-bootp-limitations: + +BOOTP Hooks Limitations +~~~~~~~~~~~~~~~~~~~~~~~ + +Currently the BOOTP library has the following limitation: + +- Basic BOOTP, as defined in `RFC 951 + <https://tools.ietf.org/html/rfc951>`__, is not supported. Kea only + supports BOOTP with vendor-information extensions. diff --git a/doc/sphinx/arm/hooks-cb-cmds.rst b/doc/sphinx/arm/hooks-cb-cmds.rst new file mode 100644 index 0000000..237f911 --- /dev/null +++ b/doc/sphinx/arm/hooks-cb-cmds.rst @@ -0,0 +1,2248 @@ +.. ischooklib:: libdhcp_cb_cmds.so +.. _hooks-cb-cmds: + +``libdhcp_cb_cmds.so``: Configuration Backend Commands +====================================================== + +This hook library is used to manage Kea +servers' configurations in a configuration backend database. This library must +be used in conjunction with the available CB hook libraries implementing +the common APIs to create, read, update, and delete (CRUD) the +configuration information in the respective databases. For example: +:ischooklib:`libdhcp_mysql_cb.so` implements this API for MySQL while +:ischooklib:`libdhcp_pgsql_cb.so` implements this API for PostgreSQL. +To manage the configuration information in a MySQL database, both +:ischooklib:`libdhcp_mysql_cb.so` and :ischooklib:`libdhcp_cb_cmds.so` +must be loaded by the server used for the configuration management. +To manage the configuration information in a PostgreSQL database, both +:ischooklib:`libdhcp_pgsql_cb.so` and :ischooklib:`libdhcp_cb_cmds.so` +must be loaded by the server used for the configuration management. + +More information on how to configure the Configuration Backend hook library for +use with a MySQL or PostgreSQL database can be found in the :ref:`dhcp4-cb` +and :ref:`dhcp6-cb` sections. + +.. note:: + + :ischooklib:`libdhcp_cb_cmds.so` is available only to ISC customers with + a paid support contract. For more information on subscription options, + please complete the form at https://www.isc.org/contact. + +.. note:: + + This library can only be loaded by the :iscman:`kea-dhcp4` or + :iscman:`kea-dhcp6` process. + +.. note:: + + Please read about :ref:`cb-limitations` before using the commands + described in this section. + +Command Structure +~~~~~~~~~~~~~~~~~ + +There are 5 types of commands supported by this library: + +- ``del`` - delete the selected object from the database, e.g. + :isccmd:`remote-global-parameter4-del`. + +- ``get`` - fetch the selected object from the database, e.g. + :isccmd:`remote-subnet4-get-by-id`. + +- ``get-all`` - fetch all objects of the particular type from the + database, e.g. :isccmd:`remote-option-def4-get-all`. + +- ``list`` - list all objects of the particular type in the database, + e.g. :isccmd:`remote-network4-list`; this class of commands returns brief + information about each object compared to the output of ``get-all``. + +- ``set`` - creates or replaces an object of the given type in the + database, e.g. :isccmd:`remote-option4-global-set`. + +All types of commands accept an optional ``remote`` map which selects the +database instance to which the command refers. For example: + +.. code-block:: json + + { + "command": "remote-subnet4-list", + "arguments": { + "remote": { + "type": "mysql", + "host": "192.0.2.33", + "port": 3302 + } + } + } + +selects the MySQL database, running on host 192.0.2.33 and port 3302, to +fetch the list of subnets from. All parameters in the ``remote`` argument are +optional. The ``port`` parameter can be only specified in conjunction +with the ``host``. If no options in the ``remote`` parameter are to +be specified, the parameter should be omitted. In this case, the server +will use the first backend listed in the ``config-control`` map within +the configuration of the server receiving the command. + +.. note:: + + In the current Kea release, it is only possible to configure the Kea server + to use a single configuration backend. Strictly speaking, it is + possible to point the Kea server to at most one database (either MySQL or + PostgreSQL) using the ``config-control`` parameter. Therefore, the ``remote`` + parameter may be omitted in the commands and :ischooklib:`libdhcp_cb_cmds.so` + uses the sole backend by default. The example commands below most often show a + value of "mysql" for the ``type`` parameter; it should be assumed that the + value is "postgresql" for installations using a PostgreSQL database. + +.. _cb-cmds-dhcp: + +Control Commands for DHCP Servers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This section describes and gives some examples of the control commands +implemented by :ischooklib:`libdhcp_cb_cmds.so`, to manage the +configuration information of the DHCPv4 and DHCPv6 servers. Many of the +commands are almost identical between DHCPv4 and DHCPv6; they only +differ by the command name. Other commands differ slightly by the +structure of the inserted data; for example, the structure of the IPv4 subnet +information is different than that of the IPv6 subnet. +Nevertheless, they still share the structure of their command arguments +and thus it makes sense to describe them together. + +In addition, whenever the text in the subsequent sections refers to a +DHCP command or DHCP parameter, it refers to both DHCPv4 and DHCPv6 +variants. The text specific to the particular server type refers to them +as: DHCPv4 command, DHCPv4 parameter, DHCPv6 command, DHCPv6 parameter, +etc. + +.. _cb-cmds-metadata: + +Metadata +~~~~~~~~ + +The typical response to the ``get`` or ``list`` command includes a list +of returned objects (e.g. subnets), and each such object contains the +``metadata`` map with some database-specific information describing this +object. In other words, the metadata contains any information about the +fetched object which may be useful for an administrator but which is not +part of the object specification from the DHCP server standpoint. In the +present Kea release, the metadata is limited to the ``server-tag``. It +describes the association of the object with a particular server or +all servers. + +The following is the example response to the :isccmd:`remote-network4-list` +command, which includes the metadata: + +.. code-block:: json + + { + "result": 0, + "text": "1 IPv4 shared network(s) found.", + "arguments": { + "shared-networks": [ + { + "name": "level3", + "metadata": { + "server-tags": [ "all" ] + } + } + ], + "count": 1 + } + } + + +Client implementations must not assume that the metadata contains only +the ``server-tags`` parameter. In future releases, it is expected that this +map will be extended with additional information, e.g. object modification +time, log message created during the last modification, etc. + +.. isccmd:: remote-server4-del +.. _command-remote-server4-del: +.. isccmd:: remote-server6-del +.. _command-remote-server6-del: + +The ``remote-server4-del``, ``remote-server6-del`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This command is used to delete the information about a selected DHCP server from +the configuration database. The server is identified by a unique case +insensitive server tag. For example: + +.. code-block:: json + + { + "command": "remote-server4-del", + "arguments": { + "servers": [ + { + "server-tag": "server1" + } + ], + "remote": { + "type": "postgresql" + } + } + } + +As a result of this command, all associations of the configuration for the +user-defined server called "server1" are removed from the database, including +non-shareable configuration information, such as global parameters, option +definitions, and global options. Any shareable configuration information, +i.e. the configuration elements which may +be associated with more than one server, is preserved. In particular, the +subnets and shared networks associated with the deleted servers are +preserved. If any of the shareable configuration elements was associated only +with the deleted server, this object becomes unassigned (orphaned). For +example: if a subnet has been created and associated with "server1" using +the :isccmd:`remote-subnet4-set` command and "server1" is subsequently deleted, the +subnet remains in the database but no servers can use this subnet. The +subnet can be updated using the :isccmd:`remote-subnet4-set` command, and can be +associated with either another server or with all servers, using the special +server tag "all". Such a subnet can be also deleted from the database +using the :isccmd:`remote-subnet4-del-by-id` or +:isccmd:`remote-subnet4-del-by-prefix` command, if it is no longer needed. + +The following is the successful response to the :isccmd:`remote-server4-del` command: + +.. code-block:: json + + { + "result": 0, + "text": "1 DHCPv4 server(s) deleted.", + "arguments": { + "count": 1 + } + } + + +.. warning:: + + The :isccmd:`remote-server4-del` and + :isccmd:`remote-server6-del` commands must be used with + care, because an accidental deletion of the server can cause some parts of the + existing configurations to be lost permanently from the database. This + operation is not reversible. Re-creation of the accidentally deleted server + does not revert the lost configuration for that server and such configuration + must be re-created manually by the user. + +.. isccmd:: remote-server4-get +.. _command-remote-server4-get: +.. isccmd:: remote-server6-get +.. _command-remote-server6-get: + +The ``remote-server4-get``, ``remote-server6-get`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This command is used to fetch the information about the selected DHCP server +from the configuration database. For example: + +.. code-block:: json + + { + "command": "remote-server6-get", + "arguments": { + "servers": [ + { + "server-tag": "server1" + } + ], + "remote": { + "type": "mysql" + } + } + } + + +This command fetches the information about the DHCPv6 server identified by the +server tag "server1". The server tag is case-insensitive. A successful response +returns basic information about the server, such as the server tag and the user's +description of the server: + +.. code-block:: json + + { + "result": 0, + "text": "DHCP server server1 found.", + "arguments": { + "servers": [ + { + "server-tag": "server1", + "description": "A DHCPv6 server located on the first floor." + } + ], + "count": 1 + } + } + +.. isccmd:: remote-server4-get-all +.. _command-remote-server4-get-all: +.. isccmd:: remote-server6-get-all +.. _command-remote-server6-get-all: + +The ``remote-server4-get-all``, ``remote-server6-get-all`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This command is used to fetch all user-defined DHCPv4 or DHCPv6 servers from the +database. The command structure is very simple: + +.. code-block:: json + + { + "command": "remote-server4-get-all", + "arguments": { + "remote": { + "type": "mysql" + } + } + } + +The response includes basic information about each server, such as its server +tag and description: + +.. code-block:: json + + { + "result": 0, + "text": "DHCPv4 servers found.", + "arguments": { + "servers": [ + { + "server-tag": "server1", + "description": "A DHCP server located on the first floor." + }, + { + "server-tag": "server2", + "description": "An old DHCP server to be soon replaced." + } + ], + "count": 2 + } + } + +.. isccmd:: remote-server4-set +.. _command-remote-server4-set: +.. isccmd:: remote-server6-set +.. _command-remote-server6-set: + +The ``remote-server4-set``, ``remote-server6-set`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This command is used to create or replace an information about a DHCP server in +the database. The information about the server must be created when there is a +need to differentiate the configurations used by various Kea instances +connecting to the same database. Various configuration elements, e.g. global +parameters, subnets, etc. may be explicitly associated with the selected servers +(using server tags as identifiers), allowing only these servers to use the +respective configuration elements. Using the particular server tag to make such +associations is only possible when the server information has been stored in the +database via the :isccmd:`remote-server4-set` or +:isccmd:`remote-server6-set` commands. The +following command creates a new (or updates an existing) DHCPv6 server in the +database: + +.. code-block:: json + + { + "command": "remote-server6-set", + "arguments": { + "servers": [ + { + "server-tag": "server1", + "description": "A DHCP server on the ground floor." + } + ], + "remote": { + "type": "mysql" + } + } + } + +The server tag must be unique across all servers in the database. When the +server information under the given server tag already exists, it is replaced +with the new information. The specified server tag is case-insensitive, and the +maximum length of the server tag is 256 characters. The following keywords are +reserved and cannot be used as server tags: "all" and "any". + +The following is the example response to the above command: + +.. code-block:: json + + { + "result": 0, + "text": "DHCPv6 server successfully set.", + "arguments": { + "servers": [ + { + "server-tag": "server1", + "description": "A DHCP server on the ground floor." + } + ] + } + } + + +.. isccmd:: remote-global-parameter4-del +.. _command-remote-global-parameter4-del: + +.. isccmd:: remote-global-parameter6-del +.. _command-remote-global-parameter6-del: + +The ``remote-global-parameter4-del``, ``remote-global-parameter6-del`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These commands are used to delete a global DHCP parameter from the +configuration database. When the parameter is deleted from the database, +the server uses the value specified in the configuration file for +this parameter, or a default value if the parameter is not specified in +the configuration file. + +The following command attempts to delete the DHCPv4 ``renew-timer`` +parameter common for all servers from the database: + +.. code-block:: json + + { + "command": "remote-global-parameter4-del", + "arguments": { + "parameters": [ "renew-timer" ], + "remote": { + "type": "mysql" + }, + "server-tags": [ "all" ] + } + } + +If a server-specific parameter is to be deleted, the +``server-tags`` list must contain the tag of the appropriate +server. There must be exactly one server tag specified in this list. + +.. isccmd:: remote-global-parameter4-get +.. _command-remote-global-parameter4-get: + +.. isccmd:: remote-global-parameter6-get +.. _command-remote-global-parameter6-get: + +The ``remote-global-parameter4-get``, ``remote-global-parameter6-get`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These commands are used to fetch a scalar global DHCP parameter from the +configuration database. + +The following command attempts to fetch the ``boot-file-name`` +parameter for "server1": + +.. code-block:: json + + { + "command": "remote-global-parameter4-get", + "arguments": { + "parameters": [ "boot-file-name" ], + "remote": { + "type": "mysql" + }, + "server-tags": [ "server1" ] + } + } + + +The returned value has one of the four scalar types: string, integer, +real, or boolean. Non-scalar global configuration parameters, such as map +or list, are not returned by this command. + +In the case of the example above, the string value is returned, e.g.: + +.. code-block:: json + + { + "result": 0, + "text": "1 DHCPv4 global parameter found.", + "arguments": { + "parameters": { + "boot-file-name": "/dev/null", + "metadata": { + "server-tags": [ "all" ] + } + }, + "count": 1 + } + } + + +Note that the response above indicates that the returned parameter is associated +with "all" servers rather than "server1", used in the command. This indicates +that there is no "server1"-specific value in the database and therefore, the value +shared by all servers is returned. If there were a "server1"-specific value +in the database, that value would be returned instead. + +The example response for the integer value is: + +.. code-block:: json + + { + "result": 0, + "text": "1 DHCPv4 global parameter found.", + "arguments": { + "parameters": { + "renew-timer": 2000, + "metadata": { + "server-tags": [ "server1" ] + } + }, + "count": 1 + } + } + + +The real value: + +.. code-block:: json + + { + "result": 0, + "text": "1 DHCPv4 global parameter found.", + "arguments": { + "parameters": { + "t1-percent": 0.85, + "metadata": { + "server-tags": [ "all" ] + } + }, + "count": 1 + } + } + + +Finally, the boolean value: + +.. code-block:: json + + { + "result": 0, + "text": "1 DHCPv4 global parameter found.", + "arguments": { + "parameters": { + "match-client-id": true, + "metadata": { + "server-tags": [ "server2" ] + } + }, + "count": 1 + } + } + + +.. isccmd:: remote-global-parameter4-get-all +.. _command-remote-global-parameter4-get-all: + +.. isccmd:: remote-global-parameter6-get-all +.. _command-remote-global-parameter6-get-all: + +The ``remote-global-parameter4-get-all``, ``remote-global-parameter6-get-all`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These commands are used to fetch all global DHCP parameters from the database +for the specified server. The following example demonstrates how to fetch all +global parameters to be used by the server "server1": + +.. code-block:: json + + { + "command": "remote-global-parameter4-get-all", + "arguments": { + "remote": { + "type": "mysql" + }, + "server-tags": [ "server1" ] + } + } + +The example response may look as follows: + +.. code-block:: json + + { + "result": 0, + "text": "DHCPv4 global parameters found.", + "arguments": { + "parameters": [ + { + "boot-file-name": "/dev/null", + "metadata": { + "server-tags": [ "server1" ] + } + }, + { + "match-client-id": true, + "metadata": { + "server-tags": [ "all" ] + } + } + ], + "count": 2 + } + } + + +The example response contains two parameters: one string parameter and one +boolean parameter. The metadata returned for each parameter indicates +whether this parameter is specific to "server1" or applies to all servers. Since the +``match-client-id`` value is associated with "all" servers, +it indicates that there is no "server1"-specific setting for this parameter. +Each parameter always has exactly one server tag associated with it, because +global parameters are non-shareable configuration elements. + +.. note:: + + If the server tag is set to "all" in the command, the response will + contain only the global parameters associated with the logical server + "all". When the server tag points to the specific server (as in the + example above), the returned list combines parameters associated with + this server and all servers, but the former take precedence. + +.. isccmd:: remote-global-parameter4-set +.. _command-remote-global-parameter4-set: + +.. isccmd:: remote-global-parameter6-set +.. _command-remote-global-parameter6-set: + +The ``remote-global-parameter4-set``, ``remote-global-parameter6-set`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This command is used to create scalar global DHCP parameters in the +database. If any of the parameters already exists, its value is replaced +as a result of this command. It is possible to set multiple parameters +within a single command, each having one of the four types: string, +integer, real, or boolean. For example: + +.. code-block:: json + + { + "command": "remote-global-parameter4-set", + "arguments": { + "parameters": { + "boot-file-name": "/dev/null", + "renew-timer": 2000, + "t1-percent": 0.85, + "match-client-id": true + }, + "remote": { + "type": "mysql" + }, + "server-tags": [ "server1" ] + } + } + +An error is returned if any of the parameters is not supported by the DHCP +server or its type does not match. Care should be taken when multiple parameters +are specified in a single command, because it is possible that only some of the +parameters will be stored successfully and some will fail. If an error occurs when +processing this command, it is recommended to use +:isccmd:`remote-global-parameter4-get-all` or +:isccmd:`remote-global-parameter6-get-all` +to check which of the parameters have +been stored/updated successfully and which have failed. + +The ``server-tags`` list is mandatory and must contain a single server tag or +the keyword "all". In the example above, all specified parameters are associated +with the "server1" server. + +.. isccmd:: remote-network4-del +.. _command-remote-network4-del: + +.. isccmd:: remote-network6-del +.. _command-remote-network6-del: + +The ``remote-network4-del``, ``remote-network6-del`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These commands are used to delete an IPv4 or IPv6 shared network from +the database. The optional parameter ``subnets-action`` determines +whether the subnets belonging to the deleted shared network should also +be deleted or preserved. The ``subnets-action`` parameter defaults to ``keep``, +which preserves the subnets. If it is set to ``delete``, the subnets are +deleted along with the shared network. + +The following command: + +.. code-block:: json + + { + "command": "remote-network6-del", + "arguments": { + "shared-networks": [ + { + "name": "level3" + } + ], + "subnets-action": "keep", + "remote": { + "type": "mysql" + } + } + } + + +deletes the "level3" IPv6 shared network. The subnets are preserved, but +they are disassociated from the deleted shared network and become +global. This behavior corresponds to the behavior of the +:isccmd:`network4-del`, :isccmd:`network6-del` commands with respect to the +``subnets-action`` parameter. + +Note that the ``server-tags`` parameter cannot be used for this command. + +.. isccmd:: remote-network4-get +.. _command-remote-network4-get: + +.. isccmd:: remote-network6-get +.. _command-remote-network6-get: + +The ``remote-network4-get``, ``remote-network6-get`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These commands are used to retrieve information about an IPv4 or +IPv6 shared network. The optional parameter ``subnets-include`` denotes +whether the subnets belonging to the shared network should also be +returned. This parameter defaults to ``no``, in which case the subnets +are not returned. If this parameter is set to ``full``, the subnets are +returned together with the shared network. + +The following command fetches the "level3" IPv6 shared network along +with the full information about the subnets belonging to it: + +.. code-block:: json + + { + "command": "remote-network6-get", + "arguments": { + "shared-networks": [ + { + "name": "level3" + } + ], + "subnets-include": "full", + "remote": { + "type": "mysql" + } + } + } + +Note that the ``server-tags`` parameter cannot be used for this command. + +.. isccmd:: remote-network4-list +.. _command-remote-network4-list: + +.. isccmd:: remote-network6-list +.. _command-remote-network6-list: + +The ``remote-network4-list``, ``remote-network6-list`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These commands are used to list all IPv4 or IPv6 shared networks for a server. + +The following command retrieves all shared networks to be used by +"server1" and "server2": + +.. code-block:: json + + { + "command": "remote-network4-list", + "arguments": { + "remote": { + "type": "mysql" + }, + "server-tags": [ "server1", "server2" ] + } + } + +The ``server-tags`` parameter is mandatory and contains one or more server +tags. It may contain the keyword "all" to fetch the shared networks associated +with all servers. When the ``server-tags`` list contains the +``null`` value, the returned response contains a list of unassigned shared +networks, i.e. the networks which are associated with no servers. For example: + +.. code-block:: json + + { + "command": "remote-network4-list", + "arguments": { + "remote": { + "type": "mysql" + }, + "server-tags": [ null ] + } + } + +The example response to this command when non-null server tags are specified +looks similar to this: + +.. code-block:: json + + { + "result": 0, + "text": "3 IPv4 shared network(s) found.", + "arguments": { + "shared-networks": [ + { + "name": "ground floor", + "metadata": { + "server-tags": [ "all" ] + } + }, + { + "name": "floor2", + "metadata": { + "server-tags": [ "server1" ] + } + }, + { + "name": "floor3", + "metadata": { + "server-tags": [ "server2" ] + } + } + ], + "count": 3 + } + } + +The returned information about each shared network merely contains the shared +network name and the metadata. To fetch detailed information about +the selected shared network, use the :isccmd:`remote-network4-get` or +:isccmd:`remote-network6-get` command. + +The example response above contains three shared networks. One of the +shared networks is associated with all servers, so it is included in +the list of shared networks to be used by "server1" and "server2". +The remaining two shared networks are returned because one of them +is associated with "server1" and another one is associated with +"server2". + +When listing unassigned shared networks, the response looks similar +to this: + +.. code-block:: json + + { + "result": 0, + "text": "1 IPv4 shared network(s) found.", + "arguments": { + "shared-networks": [ + { + "name": "fancy", + "metadata": { + "server-tags": [ null ] + } + } + ], + "count": 1 + } + } + +The ``null`` value in the metadata indicates that the +returned shared network is unassigned. + +.. isccmd:: remote-network4-set +.. _command-remote-network4-set: + +.. isccmd:: remote-network6-set +.. _command-remote-network6-set: + +The ``remote-network4-set``, ``remote-network6-set`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These commands create a new or replace an existing IPv4 or IPv6 shared +network in the database. The structure of the shared network information +is the same as in the Kea configuration file (see +:ref:`shared-network4` and :ref:`shared-network6` for details), +except that specifying subnets along with the shared +network information is not allowed. Including the ``subnet4`` or ``subnet6`` parameter +within the shared network information results in an error. + +These commands are intended to be used for managing the shared +network-specific information and DHCP options. To associate and +disassociate the subnets with the shared networks, the +:isccmd:`remote-subnet4-set`, :isccmd:`remote-subnet6-set` +commands should be used. + +The following command adds the IPv6 shared network "level3" to the +database: + +.. code-block:: json + + { + "command": "remote-network6-set", + "arguments": { + "shared-networks": [ + { + "name": "level3", + "interface": "eth0", + "option-data": [ { + "name": "sntp-servers", + "data": "2001:db8:1::1" + } ] + } + ], + "remote": { + "type": "mysql" + }, + "server-tags": [ "all" ] + } + } + + +This command includes the ``interface`` parameter, which sets the shared +network-level interface name. Any remaining shared-network level parameters, +which are not specified with the command, will be marked as +"unspecified" in the database. The DHCP server uses the global +values for unspecified parameters or, if the global values are not +specified, the default values are used. + +The ``server-tags`` list is mandatory for this command and must include one or +more server tags. As a result, the shared network is associated with all listed +servers. The shared network may be associated with all servers connecting to the +database when the keyword "all" is included. + +.. note:: + + As with other "set" commands, this command replaces all the + information about the given shared network in the database, if the + shared network already exists. Therefore, when sending this command, + make sure to always include all parameters that must be specified for + the updated shared-network instance. Any unspecified parameter will + be marked unspecified in the database, even if its value was present + prior to sending the command. + +.. isccmd:: remote-option-def4-del +.. _command-remote-option-def4-del: + +.. isccmd:: remote-option-def6-del +.. _command-remote-option-def6-del: + +The ``remote-option-def4-del``, ``remote-option-def6-del`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These commands are used to delete a DHCP option definition from the +database. The option definition is identified by an option code and +option space. For example: + +.. code-block:: json + + { + "command": "remote-option-def6-del", + "arguments": { + "option-defs": [ + { + "code": 1, + "space": "isc" + } + ], + "remote": { + "type": "mysql" + }, + "server-tags": [ "server1" ] + } + } + + +deletes the definition of the option associated with "server1", having the +code of 1 and belonging to the option space "isc". The default option spaces are +"dhcp4" and "dhcp6" for the DHCPv4 and DHCPv6 top-level options, respectively. If +there is no such option explicitly associated with "server1", no option is +deleted. To delete an option belonging to "all" servers, the keyword +"all" must be used as the server tag. The ``server-tags`` list must contain exactly +one tag and cannot include the ``null`` value. + +.. isccmd:: remote-option-def4-get +.. _command-remote-option-def4-get: + +.. isccmd:: remote-option-def6-get +.. _command-remote-option-def6-get: + +The ``remote-option-def4-get``, ``remote-option-def6-get`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These commands are used to fetch a specified DHCP option definition from +the database. The option definition is identified by the option code and +option space. The default option spaces are "dhcp4" and "dhcp6" for the +DHCPv4 and DHCPv6 top-level options, respectively. + +The following command retrieves a DHCPv4 option definition associated with all +servers, having the code of 1 and belonging to the option space "isc": + +.. code-block:: json + + { + "command": "remote-option-def4-get", + "arguments": { + "option-defs": [ + { + "code": 1, + "space": "isc" + } + ], + "remote": { + "type": "mysql" + }, + "server-tags": [ "all" ] + } + } + +The ``server-tags`` list must include exactly one server tag or the keyword +"all", and cannot contain the `null` value. + +.. isccmd:: remote-option-def4-get-all +.. _command-remote-option-def4-get-all: + +.. isccmd:: remote-option-def6-get-all +.. _command-remote-option-def6-get-all: + +The ``remote-option-def4-get-all``, ``remote-option-def6-get-all`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These commands are used to fetch all DHCP option definitions from the database +for the given server or all servers. For example: + +.. code-block:: json + + { + "command": "remote-option-def6-get-all", + "arguments": { + "remote": { + "type": "mysql" + }, + "server-tags": [ "all" ] + } + } + +This command attempts to fetch all DHCPv6 option definitions associated +with "all" servers. The ``server-tags`` list is mandatory for +this command and must include exactly one server tag or the keyword "all". +It cannot include the ``null`` value. + +The following is the example response to this command: + +.. code-block:: json + + { + "result": 0, + "text": "1 DHCPv6 option definition(s) found.", + "arguments": { + "option-defs": [ + { + "name": "bar", + "code": 1012, + "space": "dhcp6", + "type": "record", + "array": true, + "record-types": "ipv6-address, uint16", + "encapsulate": "", + "metadata": { + "server-tags": [ "all" ] + } + } + ], + "count": 1 + } + } + +The response contains an option definition associated with all servers, as +indicated by the metadata. + +.. isccmd:: remote-option-def4-set +.. _command-remote-option-def4-set: + +.. isccmd:: remote-option-def6-set +.. _command-remote-option-def6-set: + +The ``remote-option-def4-set``, ``remote-option-def6-set`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These commands create a new DHCP option definition or replace an +existing option definition in the database. The structure of the option +definition information is the same as in the Kea configuration file (see +:ref:`dhcp4-custom-options` and :ref:`dhcp6-custom-options`). +The following command creates the DHCPv4 option definition at the +top-level "dhcp4" option space and associates it with "server1": + +.. code-block:: json + + { + "command": "remote-option-def4-set", + "arguments": { + "option-defs": [ + { + "name": "foo", + "code": 222, + "type": "uint32", + "array": false, + "record-types": "", + "space": "dhcp4", + "encapsulate": "" + } + ], + "remote": { + "type": "mysql" + }, + "server-tags": [ "server1" ] + } + } + +The ``server-tags`` list must include exactly one +server tag or the keyword "all", and cannot contain the +``null`` value. + +.. isccmd:: remote-option4-global-del +.. _command-remote-option4-global-del: + +.. isccmd:: remote-option6-global-del +.. _command-remote-option6-global-del: + +The ``remote-option4-global-del``, ``remote-option6-global-del`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These commands are used to delete a global DHCP option from the +database. The option is identified by an option code and option space. +For example: + +.. code-block:: json + + { + "command": "remote-option4-global-del", + "arguments": { + "options": [ + { + "code": 5, + "space": "dhcp4" + } + ], + "remote": { + "type": "mysql" + }, + "server-tags": [ "server1" ] + } + } + +The "dhcp4" value represents the top-level option space where the standard DHCPv4 +options belong. The ``server-tags`` parameter is mandatory and must include a +single option tag or the keyword "all". If the explicit server tag is specified, +this command attempts to delete a global option associated with this +server. If there is no such option associated with the given server, no option +is deleted. To delete an option associated with all servers, the +keyword "all" must be specified. + +.. isccmd:: remote-option4-global-get +.. _command-remote-option4-global-get: + +.. isccmd:: remote-option6-global-get +.. _command-remote-option6-global-get: + +The ``remote-option4-global-get``, ``remote-option6-global-get`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These commands are used to fetch a global DHCP option from the database. +The option is identified by the code and option space. The top-level +option spaces where DHCP standard options belong are called "dhcp4" and +"dhcp6" for the DHCPv4 and DHCPv6 servers, respectively. + +The following command retrieves the IPv6 "DNS Servers" (code 23) option +associated with all servers: + +.. code-block:: json + + { + "command": "remote-option6-global-get", + "arguments": { + "options": [ + { + "code": 23, + "space": "dhcp6" + } + ], + "remote": { + "type": "mysql" + }, + "server-tags": [ "all" ] + } + } + +The ``server-tags`` parameter is mandatory and must include exactly one +server tag or the keyword "all". It cannot contain the ``null`` +value. + +.. isccmd:: remote-option4-global-get-all +.. _command-remote-option4-global-get-all: + +.. isccmd:: remote-option6-global-get-all +.. _command-remote-option6-global-get-all: + +The ``remote-option4-global-get-all``, ``remote-option6-global-get-all`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These commands are used to fetch all global DHCP options from the configuration +database for the given server or for all servers. The following command +fetches all global DHCPv4 options for "server1": + +.. code-block:: json + + { + "command": "remote-option6-global-get-all", + "arguments": { + "remote": { + "type": "mysql" + }, + "server-tags": [ "server1" ] + } + } + +The ``server-tags`` list is mandatory for this command and +must contain exactly one server tag or a keyword "all"; it cannot contain +the ``null`` value. + +The following is a example response to this +command with a single option being associated with "server1" returned: + +.. code-block:: json + + { + "result": 0, + "text": "DHCPv4 options found.", + "arguments": { + "options": [ + { + "name": "domain-name-servers", + "code": 6, + "space": "dhcp4", + "csv-format": false, + "data": "192.0.2.3", + "metadata": { + "server-tags": [ "server1" ] + } + } + ], + "count": 1 + } + } + +.. isccmd:: remote-option4-global-set +.. _command-remote-option4-global-set: + +.. isccmd:: remote-option6-global-set +.. _command-remote-option6-global-set: + +The ``remote-option4-global-set``, ``remote-option6-global-set`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These commands create a new global DHCP option or replace an existing +option in the database. The structure of the option information is the +same as in the Kea configuration file (see :ref:`dhcp4-std-options` +and :ref:`dhcp6-std-options`). For example: + +.. code-block:: json + + { + "command": "remote-option6-global-set", + "arguments": { + "options": [ + { + "name": "dns-servers", + "data": "2001:db8:1::1" + } + ], + "remote": { + "type": "mysql" + }, + "server-tags": [ "server1" ] + } + } + +The ``server-tags`` list is mandatory for this command +and must include exactly one server tag or the keyword "all"; it cannot +include the ``null`` value. The command above associates +the option with the "server1" server. + +Note that specifying an option name instead of the option code only +works reliably for standard DHCP options. When specifying a value +for a user-defined DHCP option, the option code should be indicated +instead of the name. For example: + +.. code-block:: json + + { + "command": "remote-option6-global-set", + "arguments": { + "options": [ + { + "code": 1, + "space": "isc", + "data": "2001:db8:1::1" + } + ], + "server-tags": [ "server1" ] + } + } + +.. isccmd:: remote-option4-network-del +.. _command-remote-option4-network-del: + +.. isccmd:: remote-option6-network-del +.. _command-remote-option6-network-del: + +The ``remote-option4-network-del``, ``remote-option6-network-del`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These commands are used to delete a shared-network-specific DHCP +option from the database. The option is identified by an option code +and option space and these two parameters are passed within the +``options`` list. Another list, ``shared-networks``, contains a map +with the name of the shared network from which the option is to +be deleted. If the option is not explicitly specified for this +shared network, no option is deleted. In particular, the given +option may be present for a subnet belonging to the shared network. +Such an option instance is not affected by this command as this +command merely deletes the shared-network level option. To +delete a subnet-level option, the :isccmd:`remote-option4-subnet-del`, +:isccmd:`remote-option6-subnet-del` commands must be used instead. + +The following command attempts to delete an option having the +option code 5 in the top-level option space from the shared +network "fancy". + +.. code-block:: json + + { + "command": "remote-option4-network-del", + "arguments": { + "shared-networks": [ + { + "name": "fancy" + } + ], + "options": [ + { + "code": 5, + "space": "dhcp4" + } + ], + "remote": { + "type": "mysql" + } + } + } + +The "dhcp4" value represents the top-level option space where the standard DHCPv4 +options belong. The ``server-tags`` parameter cannot be specified for this command. + +.. isccmd:: remote-option4-network-set +.. _command-remote-option4-network-set: + +.. isccmd:: remote-option6-network-set +.. _command-remote-option6-network-set: + +The ``remote-option4-network-set``, ``remote-option6-network-set`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These commands create a new shared-network-specific DHCP option or replace +an existing option in the database. The structure of the option information +is the same as in the Kea configuration file (see :ref:`dhcp4-std-options` +and :ref:`dhcp6-std-options`). The option information is carried in the +``options`` list. Another list, ``shared-networks``, contains a map with the +name of the shared network for which the option is to be set. If such an option +already exists for the shared network, it is replaced with the new instance. + +.. code-block:: json + + { + "command": "remote-option6-network-set", + "arguments": { + "shared-networks": [ + { + "name": "fancy" + } + ], + "options": [ + { + "name": "dns-servers", + "data": "2001:db8:1::1" + } + ], + "remote": { + "type": "mysql" + } + } + } + +The ``server-tags`` parameter cannot be specified for this command. + +Specifying an option name instead of the option code only works reliably +for standard DHCP options. When specifying a value for a user-defined +DHCP option, the option code should be indicated instead of the name. + +.. isccmd:: remote-option6-pd-pool-del +.. _command-remote-option6-pd-pool-del: + +The ``remote-option6-pd-pool-del`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This command is used to delete a prefix delegation pool-specific DHCPv6 +option from the database. The option is identified by an option code +and option space, and these two parameters are passed within the +``options`` list. Another list, ``pd-pools``, contains a map with the +prefix-delegation-pool prefix and length identifying the pool. If the +option is not explicitly specified for this pool, no option is deleted. +In particular, the given option may exist for a subnet containing +the specified pool. Such an option instance is not affected by this +command, as this command merely deletes a prefix delegation pool-level +option. To delete a subnet level option, the +:isccmd:`remote-option6-subnet-del` command must be used instead. + +.. code-block:: json + + { + "command": "remote-option6-pd-pool-del", + "arguments": { + "pd-pools": [ + { + "prefix": "3000::", + "prefix-len": 64 + } + ], + "options": [ + { + "code": 23, + "space": "dhcp6" + } + ], + "remote": { + "type": "mysql" + } + } + } + +The "dhcp6" value represents the top-level option space where the standard DHCPv6 +options belong. The ``server-tags`` parameter cannot be specified for this command. + +.. isccmd:: remote-option6-pd-pool-set +.. _command-remote-option6-pd-pool-set: + +The ``remote-option6-pd-pool-set`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This command creates a new prefix delegation pool-specific DHCPv6 option or +replaces an existing option in the database. The structure of the option +information is the same as in the Kea configuration file (see :ref:`dhcp4-std-options` +and :ref:`dhcp6-std-options`). The option information is carried in the +``options`` list. Another list, ``pd-pools``, contains a map with the +prefix-delegation-pool prefix and the prefix length identifying the pool. If such an +option already exists for the prefix delegation pool, it is replaced with +the new instance. + +For example: + +.. code-block:: json + + { + "command": "remote-option6-pd-pool-set", + "arguments": { + "pd-pools": [ + { + "prefix": "3001:1::", + "length": 64 + } + ], + "options": [ + { + "name": "dns-servers", + "data": "2001:db8:1::1" + } + ], + "remote": { + "type": "mysql" + } + } + } + +The ``server-tags`` parameter cannot be specified for this command. + +Specifying an option name instead of the option code only works reliably +for standard DHCP options. When specifying a value for a user-defined +DHCP option, the option code should be indicated instead of the name. + +.. isccmd:: remote-option4-pool-del +.. _command-remote-option4-pool-del: + +.. isccmd:: remote-option6-pool-del +.. _command-remote-option6-pool-del: + +The ``remote-option4-pool-del``, ``remote-option6-pool-del`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These commands are used to delete an address-pool-specific DHCP +option from the database. The option is identified by an option code +and option space, and these two parameters are passed within the +``options`` list. Another list, ``pools``, contains a map with the +IP address range or prefix identifying the pool. If the option +is not explicitly specified for this pool, no option is deleted. +In particular, the given option may exist for a subnet containing +the specified pool. Such an option instance is not affected by this +command, as this command merely deletes a pool-level option. To +delete a subnet-level option, the :isccmd:`remote-option4-subnet-del`, +:isccmd:`remote-option6-subnet-del` commands must be used instead. + +The following command attempts to delete an option having the +option code 5 in the top-level option space from an IPv4 address +pool: + +.. code-block:: json + + { + "command": "remote-option4-pool-del", + "arguments": { + "pools": [ + { + "pool": "192.0.2.10 - 192.0.2.100" + } + ], + "options": [ + { + "code": 5, + "space": "dhcp4" + } + ], + "remote": { + "type": "mysql" + } + } + } + +The "dhcp4" value represents the top-level option space where the standard DHCPv4 +options belong. The ``server-tags`` parameter cannot be specified for this command. + +.. isccmd:: remote-option4-pool-set +.. _command-remote-option4-pool-set: + +.. isccmd:: remote-option6-pool-set +.. _command-remote-option6-pool-set: + +The ``remote-option4-pool-set``, ``remote-option6-pool-set`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These commands create a new address-pool-specific DHCP option or replace +an existing option in the database. The structure of the option information +is the same as in the Kea configuration file (see :ref:`dhcp4-std-options` +and :ref:`dhcp6-std-options`). The option information is carried in the +``options`` list. Another list, ``pools``, contains a map with the IP address +range or prefix identifying the pool. If such an option already exists for +the pool, it is replaced with the new instance. + +For example: + +.. code-block:: json + + { + "command": "remote-option4-pool-set", + "arguments": { + "pools": [ + { + "pool": "192.0.2.10 - 192.0.2.100" + } + ], + "options": [ + { + "name": "domain-name-servers", + "data": "10.0.0.1" + } + ], + "remote": { + "type": "mysql" + } + } + } + +The ``server-tags`` parameter cannot be specified for this command. + +Specifying an option name instead of the option code only works reliably +for standard DHCP options. When specifying a value for a user-defined +DHCP option, the option code should be indicated instead of the name. + +.. isccmd:: remote-option4-subnet-del +.. _command-remote-option4-subnet-del: + +.. isccmd:: remote-option6-subnet-del +.. _command-remote-option6-subnet-del: + +The ``remote-option4-subnet-del``, ``remote-option6-subnet-del`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These commands are used to delete a subnet-specific DHCP option +from the database. The option is identified by an option code +and option space, and these two parameters are passed within the +``options`` list. Another list, ``subnets``, contains a map with the +identifier of the subnet from which the option is to be deleted. +If the option is not explicitly specified for this subnet, no +option is deleted. + +The following command attempts to delete an option having the +option code 5 in the top-level option space from the subnet +having an identifier of 123. + +.. code-block:: json + + { + "command": "remote-option4-subnet-del", + "arguments": { + "subnets": [ + { + "id": 123 + } + ], + "options": [ + { + "code": 5, + "space": "dhcp4" + } + ], + "remote": { + "type": "mysql" + } + } + } + +The "dhcp4" value represents the top-level option space where the standard DHCPv4 +options belong. The ``server-tags`` parameter cannot be specified for this command. + +.. isccmd:: remote-option4-subnet-set +.. _command-remote-option4-subnet-set: + +.. isccmd:: remote-option6-subnet-set +.. _command-remote-option6-subnet-set: + +The ``remote-option4-subnet-set``, ``remote-option6-subnet-set`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These commands create a new subnet-specific DHCP option or replace an existing +option in the database. The structure of the option information is the same as +in the Kea configuration file (see :ref:`dhcp4-std-options` +and :ref:`dhcp6-std-options`). The option information is carried in the +``options`` list. Another list, ``subnets``, contains a map with the identifier of +the subnet for which the option is to be set. If such an option already exists +for the subnet, it is replaced with the new instance. + +.. code-block:: json + + { + "command": "remote-option6-subnet-set", + "arguments": { + "subnets": [ + { + "id": 123 + } + ], + "options": [ + { + "name": "dns-servers", + "data": "2001:db8:1::1" + } + ], + "remote": { + "type": "mysql" + } + } + } + +The ``server-tags`` parameter cannot be specified for this command. + +Specifying an option name instead of the option code only works reliably +for the standard DHCP options. When specifying a value for the user-defined +DHCP option, the option code should be indicated instead of the name. + +.. isccmd:: remote-subnet4-del-by-id +.. _command-remote-subnet4-del-by-id: + +.. isccmd:: remote-subnet6-del-by-id +.. _command-remote-subnet6-del-by-id: + +The ``remote-subnet4-del-by-id``, ``remote-subnet6-del-by-id`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This is the first variant of the commands used to delete an IPv4 or IPv6 +subnet from the database. It uses the subnet ID to identify the subnet. For +example, to delete the IPv4 subnet with an ID of 5: + +.. code-block:: json + + { + "command": "remote-subnet4-del-by-id", + "arguments": { + "subnets": [ + { + "id": 5 + } + ], + "remote": { + "type": "mysql" + } + } + } + +The ``server-tags`` parameter cannot be used with this command. + +.. isccmd:: remote-subnet4-del-by-prefix +.. _command-remote-subnet4-del-by-prefix: + +.. isccmd:: remote-subnet6-del-by-prefix +.. _command-remote-subnet6-del-by-prefix: + +The ``remote-subnet4-del-by-prefix``, ``remote-subnet6-del-by-prefix`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This is the second variant of the commands used to delete an IPv4 or +IPv6 subnet from the database. It uses the subnet prefix to identify the +subnet. For example: + +.. code-block:: json + + { + "command": "remote-subnet6-del-by-prefix", + "arguments": { + "subnets": [ + { + "subnet": "2001:db8:1::/64" + } + ], + "remote": { + "type": "mysql" + } + } + } + +The ``server-tags`` parameter cannot be used with this command. + +.. isccmd:: remote-subnet4-get-by-id +.. _command-remote-subnet4-get-by-id: + +.. isccmd:: remote-subnet6-get-by-id +.. _command-remote-subnet6-get-by-id: + +The ``remote-subnet4-get-by-id``, ``remote-subnet6-get-by-id`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This is the first variant of the commands used to fetch an IPv4 or IPv6 +subnet from the database. It uses a subnet ID to identify the subnet. +For example: + +.. code-block:: json + + { + "command": "remote-subnet4-get-by-id", + "arguments": { + "subnets": [ + { + "id": 5 + } + ], + "remote": { + "type": "mysql" + } + } + } + +The ``server-tags`` parameter cannot be used with this command. + +.. isccmd:: remote-subnet4-get-by-prefix +.. _command-remote-subnet4-get-by-prefix: + +.. isccmd:: remote-subnet6-get-by-prefix +.. _command-remote-subnet6-get-by-prefix: + +The ``remote-subnet4-get-by-prefix``, ``remote-subnet6-get-by-prefix`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This is the second variant of the commands used to fetch an IPv4 or IPv6 +subnet from the database. It uses a subnet prefix to identify the +subnet. For example: + +.. code-block:: json + + { + "command": "remote-subnet6-get-by-prefix", + "arguments": { + "subnets": [ + { + "subnet": "2001:db8:1::/64" + } + ], + "remote": { + "type": "mysql" + } + } + } + +The ``server-tags`` parameter cannot be used with this command. + +.. isccmd:: remote-subnet4-list +.. _command-remote-subnet4-list: + +.. isccmd:: remote-subnet6-list +.. _command-remote-subnet6-list: + +The ``remote-subnet4-list``, ``remote-subnet6-list`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These commands are used to list all IPv4 or IPv6 subnets from the database for +selected servers or all servers. The following command retrieves all servers to +be used by "server1" and "server2": + +.. code-block:: json + + { + "command": "remote-subnet4-list", + "arguments": { + "remote": { + "type": "mysql" + }, + "server-tags": [ "server1", "server2" ] + } + } + +The ``server-tags`` parameter is mandatory and contains one or +more server tags. It may contain the keyword "all", to fetch the subnets +associated with all servers. When the ``server-tags`` list +contains the ``null`` value, the returned response contains a list +of unassigned subnets, i.e. the subnets which are associated with no servers. +For example: + +.. code-block:: json + + { + "command": "remote-subnet4-list", + "arguments": { + "remote": { + "type": "mysql" + }, + "server-tags": [ null ] + } + } + +The example response to this command when non-null server tags are specified +looks similar to this: + +.. code-block:: json + + { + "result": 0, + "text": "2 IPv4 subnet(s) found.", + "arguments": { + "subnets": [ + { + "id": 1, + "subnet": "192.0.2.0/24", + "shared-network-name": null, + "metadata": { + "server-tags": [ "server1", "server2" ] + } + }, + { + "id": 2, + "subnet": "192.0.3.0/24", + "shared-network-name": null, + "metadata": { + "server-tags": [ "all" ] + } + } + ], + "count": 2 + } + } + +The returned information about each subnet is limited to the subnet identifier, +prefix, and associated shared network name. To retrieve full +information about the selected subnet, use +the :isccmd:`remote-subnet4-get-by-id`, :isccmd:`remote-subnet6-get-by-id` commands +or the :isccmd:`remote-subnet4-get-by-prefix`, :isccmd:`remote-subnet6-get-by-prefix` commands. + +The example response above contains two subnets. One of the subnets is +associated with both servers: "server1" and "server2". The second subnet is +associated with all servers, so it is also present in the configurations for +"server1" and "server2". + +When listing unassigned subnets, the response will look similar to this: + +.. code-block:: json + + { + "result": 0, + "text": "1 IPv4 subnet(s) found.", + "arguments": { + "subnets": [ + { + "id": 3, + "subnet": "192.0.4.0/24", + "shared-network-name": null, + "metadata": { + "server-tags": [ null ] + } + } + ], + "count": 1 + } + } + +The ``null`` value in the metadata indicates that the +returned subnet is unassigned. + +.. isccmd:: remote-subnet4-set +.. _command-remote-subnet4-set: + +.. isccmd:: remote-subnet6-set +.. _command-remote-subnet6-set: + +The ``remote-subnet4-set``, ``remote-subnet6-set`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These commands are used to create a new IPv4 or IPv6 subnet or replace +an existing subnet in the database. Setting the subnet also associates +or disassociates the subnet with a shared network. + +The structure of the subnet information is similar to the structure used +in the configuration file (see :ref:`dhcp4-configuration` and +:ref:`dhcp6-configuration`). The subnet information conveyed in the +:isccmd:`remote-subnet4-set`, :isccmd:`remote-subnet6-set` commands +must include the additional parameter +``shared-network-name``, which denotes whether the subnet belongs to a +shared network. + +Consider the following example: + +.. code-block:: json + + { + "command": "remote-subnet4-set", + "arguments": { + "subnets": [ + { + "id": 5, + "subnet": "192.0.2.0/24", + "shared-network-name": "level3", + "pools": [ { "pool": "192.0.2.100-192.0.2.200" } ], + "option-data": [ { + "name": "routers", + "data": "192.0.2.1" + } ] + } + ], + "remote": { + "type": "mysql" + }, + "server-tags": [ "all" ] + } + } + +It creates the subnet and associates it with the "level3" shared +network. The "level3" shared network must be created with the :isccmd:`remote-network4-set` +command prior to creating the subnet. + +If the created subnet must be global - that is, not associated with any shared +network - the ``shared-network-name`` must be explicitly set to +``null``: + +.. code-block:: json + + { + "command": "remote-subnet4-set", + "arguments": { + "subnets": [ + { + "id": 5, + "subnet": "192.0.2.0/24", + "shared-network-name": null, + "pools": [ { "pool": "192.0.2.100-192.0.2.200" } ], + "option-data": [ { + "name": "routers", + "data": "192.0.2.1" + } ] + } + ], + "server-tags": [ "all" ] + } + } + +The subnet created in the previous example is replaced with the new +subnet having the same parameters, but it becomes global. + +The ``shared-network-name`` parameter is mandatory for the +:isccmd:`remote-subnet4-set` command. The ``server-tags`` list is mandatory and must +include one or more server tags. As a result, the subnet is associated with all +of the listed servers. It may also be associated with all servers connecting +to the database when the keyword "all" is used as the server tag. + +.. note:: + + As with other "set" commands, this command replaces all the + information about the particular subnet in the database, if the + subnet information is already present. Therefore, when sending this + command, make sure to always include all parameters that must be + specified for the updated subnet instance. Any unspecified parameter + will be marked as unspecified in the database, even if its value was + present prior to sending the command. + +.. isccmd:: remote-class4-del +.. _command-remote-class4-del: + +.. isccmd:: remote-class6-del +.. _command-remote-class6-del: + +The ``remote-class4-del``, ``remote-class6-del`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These commands delete a DHCPv4 or DHCPv6 client class by name. If any client +classes in the database depend on the deleted class, an error is returned in +response to this command. In this case, to successfully delete the class, +the dependent client classes must be deleted first. Use the +:isccmd:`remote-class4-get-all` command to fetch all client classes and find +the dependent ones. + +.. code-block:: json + + { + "command": "remote-class4-del", + "arguments": { + "client-classes": [ + { + "name": "foo" + } + ], + "remote": { + "type": "mysql" + } + } + } + +The ``server-tags`` parameter cannot be used for this command because client +classes are uniquely identified by name. + +.. isccmd:: remote-class4-get +.. _command-remote-class4-get: + +.. isccmd:: remote-class6-get +.. _command-remote-class6-get: + +The ``remote-class4-get``, ``remote-class6-get`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These commands retrieve DHCPv4 or DHCPv6 client class information by a +client-class name. + +.. code-block:: json + + { + "command": "remote-class4-get", + "arguments": { + "client-classes": [ + { + "name": "foo" + } + ], + "remote": { + "type": "mysql" + } + } + } + +The ``server-tags`` parameter cannot be used for this command because client +classes are uniquely identified by name. + +A response to the command looks similar to this: + +.. code-block:: json + + { + "result": 0, + "text": "DHCPv4 client class 'foo' found.", + "arguments": { + "client-classes": [ + { + "name": "foo", + "metadata": { + "server-tags": [ "all" ] + } + } + ], + "count": 1 + } + } + +.. isccmd:: remote-class4-get-all +.. _command-remote-class4-get-all: + +.. isccmd:: remote-class6-get-all +.. _command-remote-class6-get-all: + +The ``remote-class4-get-all``, ``remote-class6-get-all`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These commands retrieve all DHCPv4 or DHCPv6 client classes for a particular server, +multiple explicitly listed servers, and/or all servers. A given server has its own +server-specific tag and also has the "all" server tag; these commands retrieve +the classes for both an individual server and for "all" servers. For example, the +following command retrieves all client classes defined for "server1" as well as +the client classes defined for "all" servers: + +.. code-block:: json + + { + "command": "remote-class4-get-all", + "arguments": { + "remote": { + "type": "mysql" + }, + "server-tags": [ "server1" ] + } + } + +The ``server-tags`` parameter is mandatory and contains one or more server +tags. If other server tags are specified, "all" does not need to be included +in ``server-tags``, as every server automatically also has the "all" server tag. +If ``server-tags`` contains only the keyword "all", only the client classes associated +with "all" servers are returned. When the ``server-tags`` list contains the +``null`` value, the returned response contains a list of unassigned client +classes, i.e. the networks which are associated with no servers. + +A response to the command looks similar to this: + +.. code-block:: json + + { + "result": 0, + "text": "2 DHCPv4 client class(es) found.", + "arguments": { + "client-classes": [ + { + "name": "foo", + "metadata": { + "server-tags": [ "all" ] + } + }, + { + "name": "bar", + "test": "member('foo')", + "metadata": { + "server-tags": [ "all" ] + } + } + ], + "count": 2 + } + } + +.. isccmd:: remote-class4-set +.. _command-remote-class4-set: + +.. isccmd:: remote-class6-set +.. _command-remote-class6-set: + +The ``remote-class4-set``, ``remote-class6-set`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These commands insert a new or replace an existing DHCPv4 or DHCPv6 client class in +the database. The client class information structure is the same as in the Kea +configuration file (see :ref:`dhcp4-client-classifier` and +:ref:`dhcp6-client-classifier` for details). + +.. code-block:: json + + { + "command": "remote-class4-set", + "arguments": { + "client-classes": [ + { + "name": "foo", + "test": "member('KNOWN') or member('bar')", + "option-def": [ + { + "name": "configfile", + "code": 224, + "type": "string" + } + ], + "option-data": [ + { + "name": "configfile", + "data": "1APC" + } + ] + } + ], + "remote": { + "type": "mysql" + }, + "server-tags": [ "all" ] + } + } + + +Client-class ordering rules described in :ref:`classification-using-expressions` +apply to the classes inserted into the database. They imply that the class `bar` +referenced in the test expression must exist in the database when issuing the +above command. + +By default, a new client class is inserted at the end of the class hierarchy in +the database and can reference any class associated with the same server tag or +with the special server tag "all". If an existing class is updated, it remains +at its current position within the class hierarchy. + +However, the class commands allow the position of the inserted +or updated client class to be specified. The optional ``follow-class-name`` parameter can be +included in the command to indicate the name of the existing class after which +the managed class should be placed. Suppose there are two DHCPv6 classes in the +database: `first-class` and `second-class`. To add a new class, `third-class`, +between these two, use a command similar to the following: + +.. code-block:: json + + { + "command": "remote-class6-set", + "arguments": { + "client-classes": [ + { + "name": "third-class", + "test": "member('first-class')" + } + ], + "follow-class-name": "first-class", + "remote": { + "type": "mysql" + }, + "server-tags": [ "all" ] + } + } + +Note that `third-class` can depend on `first-class` because it is placed +after `first-class`; `third-class` cannot depend on `second-class` +because it is placed before it. However, `second-class` could be updated to +depend on `third-class`. + +The ``follow-class-name`` parameter can be explicitly set to ``null``, e.g.: + +.. code-block:: json + + { + "command": "remote-class6-set", + "arguments": { + "client-classes": [ + { + "name": "third-class", + "test": "member('first-class')" + } + ], + "follow-class-name": null, + "remote": { + "type": "mysql" + }, + "server-tags": [ "all" ] + } + } + +It yields the same behavior as if the ``follow-class-name`` parameter were not included, +i.e. the new class is appended at the end of the class hierarchy, and the updated +class remains at the current position. diff --git a/doc/sphinx/arm/hooks-cb-mysql.rst b/doc/sphinx/arm/hooks-cb-mysql.rst new file mode 100644 index 0000000..8e5ab42 --- /dev/null +++ b/doc/sphinx/arm/hooks-cb-mysql.rst @@ -0,0 +1,18 @@ +.. ischooklib:: libdhcp_mysql_cb.so +.. _hooks-cb-mysql: + +``libdhcp_mysql_cb.so``: Configuration Backend for MySQL +======================================================== + +This hook library works in conjunction with :ischooklib:`libdhcp_cb_cmds.so` to +implement the API to create, read, update, and delete (CRUD) the +configuration in a MySQL database. Please see :ref:`hooks-cb-cmds` +for more details. + +.. note:: + + :ischooklib:`libdhcp_mysql_cb.so` is part of the open source code and is + available to every Kea user, but it requires :ischooklib:`libdhcp_cb_cmds.so` + which is available only to ISC customers with + a paid support contract. For more information on subscription options, + please complete the form at https://www.isc.org/contact. diff --git a/doc/sphinx/arm/hooks-cb-pgsql.rst b/doc/sphinx/arm/hooks-cb-pgsql.rst new file mode 100644 index 0000000..c652693 --- /dev/null +++ b/doc/sphinx/arm/hooks-cb-pgsql.rst @@ -0,0 +1,18 @@ +.. ischooklib:: libdhcp_pgsql_cb.so +.. _hooks-cb-pgsql: + +``libdhcp_pgsql_cb.so``: Configuration Backend for PostgreSQL +============================================================= + +This hook library works in conjunction with :ischooklib:`libdhcp_cb_cmds.so` to +implement the API to create, read, update, and delete (CRUD) the +configuration in a PostgreSQL database. Please see :ref:`hooks-cb-cmds` +for more details. + +.. note:: + + :ischooklib:`libdhcp_pgsql_cb.so` is part of the open source code and is + available to every Kea user, but it requires :ischooklib:`libdhcp_cb_cmds.so` + which is available only to ISC customers with + a paid support contract. For more information on subscription options, + please complete the form at https://www.isc.org/contact. diff --git a/doc/sphinx/arm/hooks-class-cmds.rst b/doc/sphinx/arm/hooks-class-cmds.rst new file mode 100644 index 0000000..5a55cc5 --- /dev/null +++ b/doc/sphinx/arm/hooks-class-cmds.rst @@ -0,0 +1,255 @@ +.. ischooklib:: libdhcp_class_cmds.so +.. _hooks-class-cmds: + +``libdhcp_class_cmds.so``: Class Commands +========================================= + +This hook library exposes +several control commands for manipulating client classes (part of the +Kea DHCP servers' configurations) without the need to restart those +servers. Using these commands it is possible to add, update, delete, and +list the client classes configured for a given server. + +.. note:: + + :ischooklib:`libdhcp_class_cmds.so` is available only to ISC customers with + a paid support contract. For more information on subscription options, + please complete the form at https://www.isc.org/contact. + +.. note:: + + This library can only be loaded by the :iscman:`kea-dhcp4` or + :iscman:`kea-dhcp6` process. + +.. isccmd:: class-add +.. _command-class-add: + +The ``class-add`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~ + +The :isccmd:`class-add` command adds a new client class to the DHCP server +configuration. This class is appended at the end of the list of classes +used by the server and may depend on any of the already-configured +client classes. + +The following example demonstrates how to add a new client class to the +DHCPv4 server configuration: + +:: + + { + "command": "class-add", + "arguments": { + "client-classes": [ + { + "name": "ipxe_efi_x64", + "test": "option[93].hex == 0x0009", + "next-server": "192.0.2.254", + "server-hostname": "hal9000", + "boot-file-name": "/dev/null" + } + ] + } + } + +Note that the ``client-classes`` parameter is a JSON list, but it allows +only a single client class to be present. + +Here is the response to the :isccmd:`class-add` command in our example: + +:: + + { + "result": 0, + "text": "Class 'ipxe_efi_x64' added." + } + +.. isccmd:: class-update +.. _command-class-update: + +The ``class-update`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The :isccmd:`class-update` command updates an existing client class in the +DHCP server configuration. If the client class with the given name +does not exist, the server returns the result code of 3, which means that +the server configuration is not modified and the client class does not +exist. The :isccmd:`class-add` command must be used instead to create the new +client class. + +The :isccmd:`class-update` command has the same argument structure as the +:isccmd:`class-add` command: + +:: + + { + "command": "class-update", + "arguments": { + "client-classes": [ + { + "name": "ipxe_efi_x64", + "test": "option[93].hex == 0x0017", + "next-server": "0.0.0.0", + "server-hostname": "xfce", + "boot-file-name": "/dev/null" + } + ] + } + } + +Here is the response for our example: + +:: + + { + "result": 0, + "text": "Class 'ipxe_efi_x64' updated." + } + +Any parameter of the client class can be modified with this command, +except ``name``. There is currently no way to rename the class, because +the class name is used as a key for searching the class to be updated. +To achieve a similar effect to renaming the class, an existing class can +be removed with the :isccmd:`class-del` command and then added again with a +different name using :isccmd:`class-add`. Note, however, that the class with +the new name will be added at the end of the list of configured classes. + +As with other update commands, this command overwrites all the contents of the +entry. If the client class previously had a resource assigned to it, and the +:isccmd:`class-update` command is missing the resource, it is deleted from the server +configuration. If an incremental update of the class is desired, then this can +be achieved by doing a :isccmd:`class-get` to get the current state +of the client class, picking the client class out of the response, modifying it +to the required outcome, and then issuing the ``client-update`` command with the +resulting client class attached. + +.. isccmd:: class-del +.. _command-class-del: + +The ``class-del`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~ + + +The :isccmd:`class-del` command is used to remove a particular class from the server +configuration. The class to be removed is identified by name. The class +is not removed if there are other classes depending on it; to remove +such a class, the dependent classes must be removed first. + +The following is a sample command removing the ``ipxe_efi_x64`` class: + +:: + + { + "command": "class-del", + "arguments": { + "name": "ipxe_efi_x64" + } + } + +Here is the response to the :isccmd:`class-del` command in our example, when +the specified client class has been found: + +:: + + { + "result": 0, + "text": "Class 'ipxe_efi_x64' deleted." + } + +If the class does not exist, the result of 3 is returned. + +.. isccmd:: class-list +.. _command-class-list: + +The ``class-list`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +:isccmd:`class-list` is used to retrieve a list of all client classes. This +command includes no arguments: + +:: + + { + "command": "class-list" + } + +Here is the response of the server in our example, including the list of +client classes: + +:: + + { + "result": 0, + "text": "2 classes found", + "arguments": { + "client-classes": [ + { + "name": "ipxe_efi_x64" + }, + { + "name": "pxeclient" + } + ] + } + } + +Note that the returned list does not contain full class definitions, but +merely class names. To retrieve full class information, the +:isccmd:`class-get` command should be used. + +.. isccmd:: class-get +.. _command-class-get: + +The ``class-get`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~ + +:isccmd:`class-get` is used to retrieve detailed information about a specified +class. The command structure is very simple: + +:: + + { + "command": "class-get", + "arguments": { + "name": "pxeclient" + } + } + +If the class with the specified name does not exist, the status code of +3 is returned. If the specified client class exists, the class details +are returned in the following format: + +:: + + { + "result": 0, + "text": "Class 'pxeclient' definition returned", + "arguments": { + "client-classes": [ + { + "name": "pxeclient", + "only-if-required": true, + "test": "option[vendor-class-identifier].text == 'PXEClient'", + "option-def": [ + { + "name": "configfile", + "code": 209, + "type": "string" + } + ], + "option-data": [ ], + "next-server": "0.0.0.0", + "server-hostname": "xfce", + "boot-file-name": "/dev/null" + } + ] + } + } + +Note that the example above is DHCPv4-specific; the last three +parameters are only returned by the DHCPv4 server and are never returned +by the DHCPv6 server. Also, some of the parameters provided in this +example may not be returned if they are not specified for the class. +Specifically, ``only-if-required``, ``test``, and ``option-def`` are not +returned if they are not specified for the class. diff --git a/doc/sphinx/arm/hooks-ddns-tuning.rst b/doc/sphinx/arm/hooks-ddns-tuning.rst new file mode 100644 index 0000000..72b2a49 --- /dev/null +++ b/doc/sphinx/arm/hooks-ddns-tuning.rst @@ -0,0 +1,217 @@ +.. ischooklib:: libdhcp_ddns_tuning.so +.. _hooks-ddns-tuning: + +``libdhcp_ddns_tuning.so``: DDNS Tuning +======================================= + +This hook library adds support for fine-tuning various DNS update aspects. +It currently supports procedural host-name generation and the ability to skip +performing DDNS updates for select clients. + +.. note:: + + :ischooklib:`libdhcp_ddns_tuning.so` is available as a premium + hook library from ISC. Please visit https://www.isc.org/shop/ to purchase + the premium hook libraries, or contact us at https://www.isc.org/contact for + more information. + +The library, which was added in Kea 2.1.5, can be loaded by the :iscman:`kea-dhcp4` +and :iscman:`kea-dhcp6` daemons by adding it to the ``hooks-libraries`` element of the +server's configuration: + +.. code-block:: javascript + + { + "hooks-libraries": [ + { + "library": "/usr/local/lib/libdhcp_ddns_tuning.so", + "parameters": { + ... + } + }, + ... + ], + ... + } + +Procedural Host-Name Generation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This hook library provides the ability to generate host names procedurally, based on +an expression. The expression can be defined globally in the hook parameters, using +`hostname-expr`. If defined globally, it applies to all hosts in all subnets. The +expressions can use all tokens defined in :ref:`classify`. An example of a global +expression is shown below: + +.. code-block:: javascript + + { + "hooks-libraries": [ + { + "library": "/usr/local/lib/libdhcp_ddns_tuning.so", + "parameters": { + "hostname-expr": "'host-'+hexstring(pkt4.mac,'-')", + ... + } + }, + ... + ], + ... + } + +It is also possible to define this parameter in a subnet, using the user-context mechanism. +If defined at the subnet level, the expression applies to a specific subnet only. If the +subnet expression is defined as empty, ``""``, it suppresses (or disables) the use of a +global expression for that subnet. An example subnet expression is shown below: + +.. code-block:: javascript + + { + "subnet4": [{ + "subnet": "192.0.2.0/24", + "pools": [{ + "pool": "192.0.2.10 - 192.0.2.20" + } ], + + // This is a subnet-specific user context. + "user-context": { + "ddns-tuning": { + "hostname-expr": "'guest-'+int8totext(substring(pkt4.yiaddr, 0,1))+'-' \ + +int8totext(substring(pkt4.yiaddr, 1,2))+'-' \ + +int8totext(substring(pkt4.yiaddr, 2,3))+'-' \ + +int8totext(substring(pkt4.yiaddr, 3,4))" + }, + "last-modified": "2017-09-04 13:32", + "description": "you can put anything you like here", + "phones": [ "x1234", "x2345" ], + "devices-registered": 42, + "billing": false + } + }], + ... + } + +.. note:: + + The expression value above uses a backslash, ``\``, to show line continuation. This is for + clarity only and is not valid JSON supported by Kea parsing. The actual value must + be expressed on a single line. + +.. note:: + + Privacy should be taken into consideration when generating a host name. The host name + is usually inserted into the DNS, which is a public system. Exposing identifiers that + can be used to track devices, such as a MAC address, are usually a very bad idea. + The global expression example here used a MAC address for simplicity. + +DHCPv4 Host-Name Generation +--------------------------- + +With this library installed, the behavior for :iscman:`kea-dhcp4` when forming host names in +response to a client query (e.g. DISCOVER, REQUEST) is as follows: + + 1. If a host name is supplied via a host reservation, use it with the DDNS + behavioral parameters to form the final host name. Go to step 4. + + 2. If the client supplied an FQDN option (option 81), use the domain name value + specified within it, with the DDNS behavioral parameters, to form the final + host name. Go to step 4. + + 3. If the client supplied a host-name option (option 12), use the host name specified + within it, with the DDNS behavioral parameters, to form the final host name. + + 4. If there is a ``ddns-tuning`` in-scope host-name expression (either global or subnet), + calculate the host name using the expression. If the calculated value is not a fully + qualified name and there is an in-scope ``ddns-qualifying-suffix``, append the suffix. + + 5. If the value calculated by the hook is not an empty string and is different than + the host name formed in steps 1 or 2, the calculated value becomes the + final host name. + +DHCPv6 Host-Name Generation +--------------------------- + +With this library installed, the behavior for :iscman:`kea-dhcp6` when forming host names in +response to a client query (e.g. SOLICIT, REQUEST, RENEW, REBIND) is as follows: + + 1. If the client supplied an FQDN option (option 39), use the domain name value + specified within it, with the DDNS behavioral parameters, to form the final + host name. Go to step 4. + + 2. If the client did not supply an FQDN but ``ddns-replace-client-name`` is either + ``always`` or ``when-not-present``, then calculate the final form of the host + name and use it to create an outbound FQDN. Go to step 4. + + 3. If there is no outbound FQDN at this point, client-name processing for this + packet stops. Without an outbound FQDN there is no way to communicate a host + name to the client. + + 4. If a host name is supplied via a host reservation, use it along with the DDNS + behavioral parameters to form the final host name; it supersedes the FQDN value + calculated in steps 1 or 2. + + 5. If there is a ``ddns-tuning`` in-scope host name expression (either global or subnet), + calculate the host name using the expression. If the calculated value is not a fully + qualified name and there is an in-scope ``ddns-qualifying-suffix``, append the suffix. + + 6. If the value calculated by the hook is not an empty string and is different than + the host name formed in steps 1 or 2, the calculated value becomes the + final host name. + + +Skipping DDNS Updates +~~~~~~~~~~~~~~~~~~~~~ + +:ischooklib:`libdhcp_ddns_tuning.so` also provides the ability to skip DDNS updates on a +per-client basis. The library recognizes a special client class, "SKIP_DDNS"; when a +client is matched to this class, the Kea servers (:iscman:`kea-dhcp4` and :iscman:`kea-dhcp6`) do not +send DDNS update requests (NCRs) to :iscman:`kea-dhcp-ddns`. A common use case would be +to skip DDNS updates for fixed-address host reservations. This is done easily by +simply assigning the class to the host reservation as shown below: + +.. code-block:: javascript + + { + "reservations": [ + { + "hw-address": "01:02:03:04:05:06", + "ip-address": "192.0.2.1", + "client-classes": [ "SKIP_DDNS", "foo", "bar" ] + }] + } + +The :ischooklib:`libdhcp_ddns_tuning.so` hook library notes the +presence of the ``"SKIP_DDNS"`` class in the +client's class list each time the client requests, renews, or releases its lease, +and instructs :iscman:`kea-dhcp4` to bypass sending DDNS updates. A similar workflow is +supported for :iscman:`kea-dhcp6`: + +.. code-block:: javascript + + { + "reservations": [ + { + "duid": "01:02:03:04:05:06", + "ip-address": "2001:db8::1", + "client-classes": [ "SKIP_DDNS", "foo", "bar" ] + }] + } + +Although "SKIP_DDNS" is a special class, it can be defined with a test +expression. Defining it as shown below would omit DDNS updates for all KNOWN +clients: + +.. code-block:: javascript + + { + "client-classes":[ + { + "name": "SKIP_DDNS", + "test": "member('KNOWN')" + }] + } + +.. note:: + + The :ischooklib:`libdhcp_ddns_tuning.so` hook library must be + loaded for the ``"SKIP_DDNS"`` class to have an effect. diff --git a/doc/sphinx/arm/hooks-flex-id.rst b/doc/sphinx/arm/hooks-flex-id.rst new file mode 100644 index 0000000..d485f0b --- /dev/null +++ b/doc/sphinx/arm/hooks-flex-id.rst @@ -0,0 +1,286 @@ +.. ischooklib:: libdhcp_flex_id.so +.. _hooks-flex-id: + +``libdhcp_flex_id.so``: Flexible Identifier for Host Reservations +================================================================= + +The Kea software provides a way to handle +host reservations that include addresses, prefixes, options, client +classes, and other features. The reservation can be based on hardware +address, DUID, circuit-id, or client-id in DHCPv4 and on hardware +address or DUID in DHCPv6. However, there are sometimes scenarios where +the reservation is more complex; it may use options other than those mentioned +above, use parts of specific options, or perhaps even use a combination of +several options and fields to uniquely identify a client. Those +scenarios are addressed by the Flexible Identifiers hook application. + +.. note:: + + :ischooklib:`libdhcp_flex_id.so` is available as a premium + hook library from ISC. Please visit https://www.isc.org/shop/ to purchase + the premium hook libraries, or contact us at https://www.isc.org/contact for + more information. + +.. note:: + + This library can only be loaded by the :iscman:`kea-dhcp4` or :iscman:`kea-dhcp6` + process. + +:ischooklib:`libdhcp_flex_id.so` allows the definition of an expression, using notation initially +used only for client classification. (See +:ref:`classification-using-expressions` for a detailed description of +the syntax available.) One notable difference is that for client +classification, the expression currently has to evaluate to either ``true`` +or ``false``, while the flexible identifier expression is expected to +evaluate to a string that will be used as an identifier. It is a valid case +for the expression to evaluate to an empty string (e.g. in cases where a +client does not send specific options). This expression is then +evaluated for each incoming packet, and this evaluation generates an +identifier that is used to identify the client. In particular, there may +be host reservations that are tied to specific values of the flexible +identifier. + +The library can be loaded similarly to other hook libraries. It +takes a mandatory parameter ``identifier-expression`` and some optional boolean +parameters like ``replace-client-id`` and ``ignore-iaid``: + +:: + + "Dhcp6": { + "hooks-libraries": [ + { + "library": "/path/libdhcp_flex_id.so", + "parameters": { + "identifier-expression": "expression", + "replace-client-id": false, + "ignore-iaid": false + } + }, + ... + ] + } + +The flexible identifier library supports both DHCPv4 and DHCPv6. + +Let's consider a case of an IPv6 network that has an +independent interface for each of its connected customers. Customers are +able to plug in whatever device they want, so any type of identifier +(e.g. a client-id) is unreliable. Therefore, the operator may decide to +use an option inserted by a relay agent to differentiate between +clients. In this particular deployment, the operator has verified that the +interface-id is unique for each customer-facing interface, so it +is suitable for usage as a reservation. However, only the first six bytes of +the interface-id are interesting, because the remaining bytes are either +randomly changed or not unique between devices. Therefore, the customer +decides to use the first six bytes of the interface-id option inserted by the +relay agent. After adding ``flex-id``, the ``host-reservation-identifiers`` goal +can be achieved by using the following configuration: + +:: + + "Dhcp6": { + "subnet6": [{ + # subnet definition starts here + "reservations": [{ + "flex-id": "'port1234'", + # value of the first 8 bytes of the interface-id + "ip-addresses": [ "2001:db8::1" ] + }, + ... + ], + ... + }, + ... + ], + # end of subnet definitions + "host-reservation-identifiers": ["duid", "flex-id"], + # add "flex-id" to reservation identifiers + "hooks-libraries": [ + { + "library": "/path/libdhcp_flex_id.so", + "parameters": { + "identifier-expression": "substring(relay6[0].option[18].hex,0,8)" + } + }, + ... + ], + ... + } + +.. note:: + + Care should be taken when adjusting the expression. If the expression + changes, then all the ``flex-id`` values may change, possibly rendering + all reservations based on ``flex-id`` unusable until they are manually updated. + It is strongly recommended that administrators start with the expression and a + handful of reservations, and then adjust the expression as needed. Once + the desired result is obtained with the expression, host reservations + can be deployed on a broader scale. + +``flex-id`` values in host reservations can be specified in two ways. First, +they can be expressed as a hex string, e.g. the string "bar" can be represented +as 626174. Alternatively, it can be expressed as a quoted value (using +double and single quotes), e.g. "'bar'". The former is more convenient +for printable characters, while hex string values are more convenient +for non-printable characters and do not require the use of the +``hexstring`` operator. + +:: + + "Dhcp6": { + "subnet6": [{ + # subnet definition starts here + "reservations": [{ + "flex-id": "01:02:03:04:05:06", + # value of the first 8 bytes of the interface-id + "ip-addresses": [ "2001:db8::1" ] + }, + ... + ], + ... + }, + ... + ], + # end of subnet definitions + "host-reservation-identifiers": ["duid", "flex-id"], + # add "flex-id" to reservation identifiers + "hooks-libraries": [ + { + "library": "/path/libdhcp_flex_id.so", + "parameters": { + "identifier-expression": "vendor[4491].option[1026].hex" + } + }, + ... + ], + ... + } + +.. note:: + + One less common scenario where the examples above may prove useful is for + DHCPv6 clients that change their DUIDs between exchanges. Certain PXE + clients are known to behave this way. + +The ``replace-client-id`` Flag +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When ``replace-client-id`` is set to ``false`` (which is the default setting), +:ischooklib:`libdhcp_flex_id.so` uses the evaluated flexible identifier solely for +identifying host reservations, i.e. searching for reservations within a +database. This is the functional equivalent of other identifiers, similar +to hardware address or circuit-id. However, this mode of operation +implies that if a client device is replaced, it may cause a +conflict between an existing lease (allocated to the old device) and the +new lease being allocated to the new device. The conflict arises +because the same flexible identifier is computed for the replaced device, +so the server will try to allocate the same lease. The mismatch between +client identifiers sent by the new device and the old device causes the server +to refuse this new allocation until the old lease expires. A +manifestation of this problem is dependent on the specific expression used +as the flexible identifier, and is likely to appear if only options +and other parameters are used that identify where the device is connected +(e.g. circuit-id), rather than the device identification itself (e.g. +MAC address). + +:ischooklib:`libdhcp_flex_id.so` offers a way to overcome the problem with lease +conflicts by dynamically replacing the client identifier (or DUID in DHCPv6) +with a value derived from the flexible identifier. The server +processes the client's query as if the flexible identifier were sent in the +client identifier (or DUID) option. This guarantees that a returning +client (for which the same flexible identifier is evaluated) will be +assigned the same lease, despite the client identifier and/or MAC address +change. + +The following is a stub configuration that enables this behavior: + +:: + + "Dhcp4": { + "hooks-libraries": [ + { + "library": "/path/libdhcp_flex_id.so", + "parameters": { + "identifier-expression": "expression", + "replace-client-id": true + } + }, + ... + ] + } + +In the DHCPv4 case, the value derived from the flexible identifier is +formed by prepending one byte with a value of zero to the flexible identifier. +In the DHCPv6 case, it is formed by prepending two zero bytes before the +flexible identifier. + +Note that for this mechanism to take effect, the DHCPv4 server must be +configured to respect the client identifier option value during lease +allocation, i.e. ``match-client-id`` must be set to ``true``. See +:ref:`dhcp4-match-client-id` for details. No additional settings are +required for DHCPv6. + +If the ``replace-client-id`` option is set to ``true``, the value of the +``echo-client-id`` parameter (which governs whether to send back a +client-id option) is ignored. + +The :ref:`hooks-lease-cmds` section describes commands used to retrieve, +update, and delete leases using various identifiers, such as ``hw-address`` and +``client-id``. :ischooklib:`libdhcp_lease_cmds.so` does not natively support querying +for leases by flexible identifier. However, when ``replace-client-id`` is +set to ``true``, it makes it possible to query for leases using a value +derived from the flexible identifier. In DHCPv4, the query +looks similar to this: + +:: + + { + "command": "lease4-get", + "arguments": { + "identifier-type": "client-id", + "identifier": "00:54:64:45:66", + "subnet-id": 44 + } + } + +where the hexadecimal value of "54:64:45:66" is a flexible identifier +computed for the client. + +In DHCPv6, the corresponding query looks something like this: + +:: + + { + "command": "lease6-get", + "arguments": { + "identifier-type": "duid", + "identifier": "00:00:54:64:45:66", + "subnet-id": 10 + } + } + +The ``ignore-iaid`` Flag +~~~~~~~~~~~~~~~~~~~~~~~~ + +When ``ignore-iaid`` is set to ``true`` (the default value is ``false``), +:ischooklib:`libdhcp_flex_id.so` causes the Kea DHCPv6 server to ignore the IAID value +from incoming IPv6 packets. This parameter is ignored by the Kea DHCPv4 server. + +If the packet contains only one IA_NA, the IAID value will be changed to ``0`` +and stored as such in the lease storage. Similarly, if the packet contains only +one IA_PD, the IAID value will be changed to ``0`` and stored as such in the +lease storage. The IAID is restored to its initial value in the response back +to the client. The change is visible in the identifier expression if the IAID is +part of the expression. + +.. note:: + + To avoid lease conflicts, if the incoming packet contains more than one + IA_NA, the IAID value is not changed on any of the IA_NAs. Similarly, + if the incoming packet contains more than one IA_PD, the IAID value is not + changed on any of the IA_PDs. + +.. warning:: + + This functionality breaks RFC compliance and should be enabled only if + required. When enabled, a warning message is issued at configure time. diff --git a/doc/sphinx/arm/hooks-flex-option.rst b/doc/sphinx/arm/hooks-flex-option.rst new file mode 100644 index 0000000..ffac090 --- /dev/null +++ b/doc/sphinx/arm/hooks-flex-option.rst @@ -0,0 +1,196 @@ +.. ischooklib:: libdhcp_flex_option.so +.. _hooks-flex-option: + +``libdhcp_flex_option.so``: Flexible Option Actions for Option Value Settings +============================================================================= + +This library allows administrators to define an action to take, for a given +option, based upon on the result of an expression. These actions are carried +out during the final stages of constructing a query response packet, just +before it is sent to the client. The three actions currently supported are +``add``, ``supersede``, and ``remove``. + +.. note:: + + :ischooklib:`libdhcp_flex_option.so` is part of the open source code and is + available to every Kea user. + +The syntax used for the action expressions is the same syntax used +for client classification and the Flexible Identifier hook library; +see either :ref:`classification-using-expressions` or :ref:`hooks-flex-id` +for a detailed description of the syntax. + +The ``add`` and ``supersede`` actions use an expression returning a +string, and do nothing if the string is empty. The +``remove`` application uses an expression returning ``true`` or ``false``, +and does nothing on ``false``. When it is necessary to set an option to the +empty value this mechanism does not work, but a client class can be +used instead. + +The ``add`` action adds an option only when the option does not already +exist and the expression does not evaluate to the empty string. +The ``supersede`` action is similar, but it overwrites the option value +if it already exists. The ``remove`` action removes the option from +the response packet if it already exists and the expression evaluates to +true. + +The option to which an action applies may be specified by either its +numeric code or its name; either the code or the name must be +specified. The option space is DHCPv4 or DHCPv6, depending +on the server where the hook library is loaded. + +Similar to other hook libraries, :ischooklib:`libdhcp_flex_option.so` can be loaded +by either the :iscman:`kea-dhcp4` or :iscman:`kea-dhcp6` +process. It takes a mandatory ``options`` parameter with a list of +per-option parameter maps, with ``code``, ``name``, ``add``, ``supersede``, and +``remove`` actions. Action entries take a string value representing an +expression. + +.. code-block:: json + + { + "Dhcp4": { + "hooks-libraries": [ + { + "library": "/usr/local/lib/libdhcp_flex_option.so", + "parameters": { + "options": [ + { + "code": 67, + "add": "ifelse(option[host-name].exists,concat(option[host-name].text,'.boot'),'')" + } + ] + } + } + ] + } + } + +If (and only if) the **query** includes a ``host-name`` option (code 12), a +``boot-file-name`` option (code 67) is added to the response with the host name +followed by ``.boot`` for content. + +A commonly discussed use case is modifying the DHCPv4 subnet mask option +(code 1). The following example demonstrates that capability. All ingress +packets identified by the gateway address 192.168.0.1 are met with a /32 subnet +mask in the response. + +.. code-block:: json + + { + "Dhcp4": { + "hooks-libraries": [ + { + "library": "/usr/local/lib/libdhcp_flex_option.so", + "parameters": { + "options": [ + { + "code": 1, + "supersede": "ifelse(pkt4.giaddr==192.168.0.1, '255.255.255.255', '')" + } + ] + } + } + ] + } + } + +The flexible option library supports both DHCPv4 and DHCPv6. + +Since Kea 1.9.0, the ``add`` and ``supersede`` actions take an optional +```csv-format``` boolean parameter. If not specified or set to ``false``, the +option data is set using the raw value of the evaluated expression. When it is +configured to ``true``, this value is parsed using the option definition from +the option data specified in the configuration file. This eases option setting +for options using complex record formats or fully qualified domain names. + +For instance, if the expression evaluation returns "example.com" and +the option is defined with the ``fqdn`` type, the domain name will be +encoded into DNS binary format. + +Since Kea 2.1.4, the ``client-class`` parameter specifies a class guard. +It takes a client class name. If not empty, the client's packet needs to +belong to specified class for this entry to be used. + +Since Kea 2.1.4, it is allowed to have multiple entries for the same option, +but each entry must have exactly one action. If the option is not defined +in the ``dhcp4`` for DHCPv4 or ``dhcp6`` for DHCPv6 you can specify the +space where to find the option definition using its name with the new +``space`` parameter. + +Since Kea 2.1.4, sub-options are supported with a new entry ``sub-options`` +which replaces the action in the configuration of the container option, +i.e. the option where sub-options are located. + +The ``sub-options`` entry takes a list of sub-option configuration similar +to the option one with: + +- ``code`` - specifies the sub-option code, either the ``code`` or ``name`` + must be specified. When both are given they must match or the configuration + is rejected at load time. + +- ``name`` - specifies the sub-option name, either the ``code`` or ``name`` + must be specified. When both are given they must match or the configuration + is rejected at load time. + +- ``space`` - specifies the space where the sub-option can be defined. This + parameter is optional because it can be found in the container option + definition. The configuration is rejected if no valid space name is + available at load time. Note that vendor spaces are supported for the + DHCPv4 ``vivso-suboptions`` and for the DHCPv6 ``vendor-opts``, both + pre-defined (e.g. DoCSIS vendor id 4491) or custom. + +- ``add`` - (action) adds a sub-option only if it does not already exist + and the expression does not evaluate to the empty string. + +- ``supersede`` - (action) adds or overwrites a sub-option if the expression + does not evaluate to the empty string. + +- ``remove`` - (action) removes a sub-option if it already exists and the + expression evaluates to true. + +- ``container-add`` - boolean value which specifies if the container option + should be created if it does not exit in the ``add`` and ``supersede`` + action. When not specified, it defaults to true. + +- ``container-remove`` - boolean value which specifies if the container option + should be deleted if it remains empty after the removal of a sub-option by + the ``remove`` action. When not specified, it defaults to true. + +- ``csv-format`` - boolean value which specifies if the raw value of the + evaluated expression is used (false, default) or parsed using the sub-option + definition (true). + +- ``client-class`` - specifies if the sub-option entry must be skipped when + the **query** does not belong to the specified client class. Note the similar + parameter in the container option entry applies to the whole ``sub-options`` + list. + +For instance this configuration adds a string sub-option in the DHCPv4 +``vendor-encapsulated-options`` (code 43) option. Note this option +in last resort encapsulates the ``vendor-encapsulated-options`` space. + +.. code-block:: json + + { + "Dhcp4": { + "hooks-libraries": [ + { + "library": "/usr/local/lib/libdhcp_flex_option.so", + "parameters": { + "options": [ + { + "code": 43, + "sub-options": [ + { + "code": 1, + "add": "'foobar'" + } + ] + } + ] + } + } + ] + } + } diff --git a/doc/sphinx/arm/hooks-gss-tsig.rst b/doc/sphinx/arm/hooks-gss-tsig.rst new file mode 100644 index 0000000..7c4e0b9 --- /dev/null +++ b/doc/sphinx/arm/hooks-gss-tsig.rst @@ -0,0 +1,15 @@ +.. ischooklib:: libddns_gss_tsig.so +.. _hooks-gss-tsig: + +``libddns_gss_tsig.so``: Sign DNS Updates With GSS-TSIG +======================================================= + +This hook library allows the :iscman:`kea-dhcp-ddns` server to use +GSS-TSIG to sign DNS updates. For a full discussion of GSS-TSIG in Kea, +please see :ref:`gss-tsig`. + +.. note:: + + :ischooklib:`libddns_gss_tsig.so` is available only to ISC customers with + a paid support contract. For more information on subscription options, + please complete the form at https://www.isc.org/contact. diff --git a/doc/sphinx/arm/hooks-ha.rst b/doc/sphinx/arm/hooks-ha.rst new file mode 100644 index 0000000..9acfffe --- /dev/null +++ b/doc/sphinx/arm/hooks-ha.rst @@ -0,0 +1,2662 @@ +.. ischooklib:: libdhcp_ha.so +.. _hooks-high-availability: + +``libdhcp_ha.so``: High Availability Outage Resilience for Kea Servers +====================================================================== + +This hook library can be loaded on a pair of DHCPv4 or DHCPv6 servers, to +increase the reliability of the DHCP service in the event of an outage on one +server. + +.. note:: + + :ischooklib:`libdhcp_ha.so` is part of the open source code and is + available to every Kea user. It was previously available only to ISC + customers with a paid support contract. + +.. note:: + + This library can only be loaded by the :iscman:`kea-dhcp4` or :iscman:`kea-dhcp6` process. + +High Availability (HA) of the DHCP service is provided by running multiple +cooperating server instances. If any of these instances becomes unavailable for +any reason (DHCP software crash, Control Agent software crash, power outage, +hardware failure), a surviving server instance can continue providing reliable +service to clients. Many DHCP server implementations include the "DHCP Failover" +protocol, whose most significant features are communication between the servers, +partner failure detection, and lease synchronization between the servers. +However, the DHCPv4 failover standardization process was never completed by the +IETF. The DHCPv6 failover standard (RFC 8156) was published, but it is complex +and difficult to use, has significant operational constraints, and is different +from its v4 counterpart. Although it may be useful to use a "standard" failover +protocol, most Kea users are simply interested in a working solution which +guarantees high availability of the DHCP service. Therefore, the Kea HA hook +library derives major concepts from the DHCP failover protocol but uses its own +solutions for communication and configuration. It offers its own state machine, +which greatly simplifies its implementation and generally fits better into Kea, +and it provides the same features in both DHCPv4 and DHCPv6. This document +intentionally uses the term "high availability" rather than "failover" to +emphasize that it is not the failover protocol implementation. + +The following sections describe the configuration and operation of the Kea HA +hook library. + +.. _ha-supported-configurations: + +Supported Configurations +~~~~~~~~~~~~~~~~~~~~~~~~ + +The Kea HA hook library supports three configurations, also known as HA modes: +``load-balancing``, ``hot-standby``, and ``passive-backup``. In the +``load-balancing`` mode, two servers respond to DHCP requests. The +``load-balancing`` function is implemented as described in `RFC +3074 <https://tools.ietf.org/html/rfc3074>`__, with each server responding to +half the received DHCP queries. When one of the servers allocates a lease for a +client, it notifies the partner server over the control channel (via the RESTful +API), so the partner can save the lease information in its own database. If the +communication with the partner is unsuccessful, the DHCP query is dropped and +the response is not returned to the DHCP client. If the lease update is +successful, the response is returned to the DHCP client by the server which has +allocated the lease. By exchanging lease updates, both servers get a copy of all +leases allocated by the entire HA setup, and either server can be switched to +handle the entire DHCP traffic if its partner becomes unavailable. + +In the ``load-balancing`` configuration, one of the servers must be designated +as ``primary`` and the other as ``secondary``. Functionally, there is no +difference between the two during normal operation. However, this distinction is +required when the two servers are started at (nearly) the same time and have to +synchronize their lease databases. The primary server synchronizes the database +first. The secondary server waits for the primary server to complete the lease +database synchronization before it starts the synchronization. + +In the ``hot-standby`` configuration, one of the servers is designated as +``primary`` and the other as ``standby``. During normal operation, the primary +server is the only one that responds to DHCP requests. The standby server +receives lease updates from the primary over the control channel; however, it +does not respond to any DHCP queries as long as the primary is running or, more +accurately, until the standby considers the primary to be offline. If the +standby server detects the failure of the primary, it starts responding to all +DHCP queries. + +.. note:: + + Operators often wonder whether to use ``load-balancing`` or ``hot-standby`` + mode. The ``load-balancing`` mode has the benefit of splitting the DHCP load + between two instances, reducing the traffic processed by each of them. + However, it is not always clear to the operators that using the + ``load-balancing`` mode requires manually splitting the address pools between + two Kea instances using client classification, to preclude both servers from + allocating the same address to different clients. + Such a split is not needed in the ``hot-standby`` mode. Thus, the benefit + of using ``hot-standby`` over ``load-balancing`` is that the former has a + simpler configuration. Conversely, ``load-balancing`` has higher performance + potential at the cost of more complex configuration. + See :ref:`ha-load-balancing-config` for details on how to split the pools + using client classification. + +In the configurations described above, both the primary and secondary/standby +are referred to as ``active`` servers, because they receive lease updates and +can automatically react to the partner's failures by responding to the DHCP +queries which would normally be handled by the partner. The HA hook library +supports another server type/role: ``backup``. The use of a backup server is +optional, and can be implemented in both ``load-balancing`` and ``hot-standby`` +setup, in addition to the active servers. There is no limit on the number of +backup servers in the HA setup; however, the presence of backup servers may +increase the latency of DHCP responses, because not only do active servers send +lease updates to each other, but also to the backup servers. The active servers +do not expect acknowledgments from the backup servers before responding to the +DHCP clients, so the overhead of sending lease updates to the backup servers is +minimized. + +In the last supported configuration, ``passive-backup``, there is only one +active server and typically one or more backup servers. A ``passive-backup`` +configuration with no backup servers is also accepted, but it is no different +than running a single server with no HA function at all. + +The ``passive-backup`` configuration is used in situations when an administrator +wants to take advantage of the backup server(s) as an additional storage for +leases without running the full-blown failover setup. In this case, if the +primary server fails, the DHCP service is lost; it requires the administrator to +manually restart the primary to resume DHCP service. The administrator may also +configure one of the backup servers to provide DHCP service to the clients, as +these servers should have accurate or nearly accurate information about the +allocated leases. The major advantage of the ``passive-backup`` mode is that it +provides some redundancy of the lease information but with better performance of +the primary server responding to the DHCP queries. +The primary server does not have to wait for acknowledgments to the lease +updates from the backup servers before it sends a response to the DHCP client. +This reduces the response time compared to the ``load-balancing`` and +``hot-standby`` cases, in which the server responding to the DHCP query has to +wait for the acknowledgment from the other active server before it can respond +to the client. + +.. note:: + + An interesting use case for a single active server running in the + ``passive-backup`` mode is a notification service, in which software + pretending to be a backup server receives live notifications about allocated + and deleted leases from the primary server and can display them on a + monitoring screen, trigger alerts, etc. + +Clocks on Active Servers +~~~~~~~~~~~~~~~~~~~~~~~~ + +Synchronized clocks are essential for the HA setup to operate reliably. +The servers share lease information - via lease updates and during +synchronization of the databases - including the time when the lease was +allocated and when it expires. Some clock skew between the servers participating +in the HA setup usually exists; this is acceptable as long as the clock skew is +relatively low, compared to the lease lifetimes. However, if the clock skew +becomes too high, the different lease expiration times on different servers may +cause the HA system to malfunction. For example, one server may consider a lease +to be expired when it is actually still valid. The lease reclamation process may +remove a name associated with this lease from the DNS, causing problems when the +client later attempts to renew the lease. + +Each active server monitors the clock skew by comparing its current time with +the time returned by its partner in response to the :isccmd:`ha-heartbeat` command. This +gives a good approximation of the clock skew, although it does not take into +account the time between the partner sending the response and the receipt of +this response by the server which sent the :isccmd:`ha-heartbeat` command. If the clock skew +exceeds 30 seconds, a warning log message is issued. The administrator may +correct this problem by synchronizing the clocks (e.g. using NTP); the servers +should notice the clock skew correction and stop issuing the warning. + +If the clock skew is not corrected and exceeds 60 seconds, the HA service on +each of the servers is terminated, i.e. the state machine enters the +``terminated`` state. The servers will continue to respond to DHCP clients (as +in the ``load-balancing`` or ``hot-standby`` mode), but will exchange neither +lease updates nor heartbeats and their lease databases will diverge. In this +case, the administrator should synchronize the clocks and restart the servers. + +.. note:: + + It is possible to restart the servers one at a time, in no particular order. + The clocks must be in sync before restarting the servers. + +.. note:: + + The clock skew is only assessed between two active servers, and only the + active servers enter the ``terminated`` state if the skew is too high. The + clock skew between active and backup servers is not assessed, because active + servers do not exchange heartbeat messages with backup servers. + +.. _ha-https-support: + +HTTPS Support +~~~~~~~~~~~~~ + +Since Kea 1.9.7, the High Availability hook library supports HTTPS via TLS, as +described in :ref:`tls`. + +The HTTPS configuration parameters are: + +- ``trust-anchor`` - specifies the name of a file or directory where the + certification authority certificate of a Control Agent can be found. + +- ``cert-file`` - specifies the name of the file containing the end-entity + certificate to use. + +- ``key-file`` - specifies the private key of the end-entity certificate to use. + +These parameters can be configured at the global and peer levels. When +configured at both levels the peer value is used, allowing common values to be +shared. + +The three parameters must be either all not specified (HTTPS disabled) or all +specified (HTTPS enabled). Specification of the empty string is considered not +specified; this can be used, for instance, to disable HTTPS for a particular +peer when it is enabled at the global level. + +As the High Availability hook library is an HTTPS client, there is no +``cert-required`` parameter in this hook configuration. +This parameter can be set in the Control Agent to require and verify a client +certificate in client-server communication. It does not affect communication +between HA peers at the client side; see below for information on the server +side. + +Before Kea 2.1.7 using HTTPS in the HA setup required use of the Control Agent +on all peers. (See :ref:`tls` for Control Agent TLS configuration). + +Since Kea 2.1.7 the HTTPS server side is supported: + +- the peer entry for the server name is used for the TLS setting. + +- the new ``require-client-certs`` parameter specifies whether client + certificates are required and verified, i.e. like ``cert-required``. It + defaults to ``true`` and is an HA config (vs. peer config) parameter. + +Kea 2.1.7 added a new security feature with the ``restrict-commands`` HA config +parameter: when set to ``true``, commands which are not used by the hook are +rejected. The default is ``false``. + +The following is an example of an HA server pair and Control Agent configuration +for ``hot-standby`` with TLS. + +Server 1: + +.. code-block:: json + + { + "Dhcp4": { + "hooks-libraries": [{ + "library": "/usr/lib/kea/hooks/libdhcp_lease_cmds.so", + "parameters": { } + }, { + "library": "/usr/lib/kea/hooks/libdhcp_ha.so", + "parameters": { + "high-availability": [{ + "this-server-name": "server1", + "trust-anchor": "/usr/lib/kea/CA.pem", + "cert-file": "/usr/lib/kea/server1_cert.pem", + "key-file": "/usr/lib/kea/server1_key.pem", + "mode": "hot-standby", + "heartbeat-delay": 10000, + "max-response-delay": 60000, + "max-ack-delay": 5000, + "max-unacked-clients": 5, + "peers": [{ + "name": "server1", + "url": "http://192.168.56.33:8000/", + "role": "primary", + "auto-failover": true + }, { + "name": "server2", + "url": "http://192.168.56.66:8000/", + "role": "standby", + "auto-failover": true + }] + }] + } + }], + + "subnet4": [{ + "id": 1, + "subnet": "192.0.3.0/24", + "pools": [{ + "pool": "192.0.3.100 - 192.0.3.250" + }] + }] + } + } + +Server 2: + +.. code-block:: json + + { + "Dhcp4": { + "hooks-libraries": [{ + "library": "/usr/lib/kea/hooks/libdhcp_lease_cmds.so", + "parameters": { } + }, { + "library": "/usr/lib/kea/hooks/libdhcp_ha.so", + "parameters": { + "high-availability": [{ + "this-server-name": "server2", + "trust-anchor": "/usr/lib/kea/CA.pem", + "cert-file": "/usr/lib/kea/server2_cert.pem", + "key-file": "/usr/lib/kea/server2_key.pem", + "mode": "hot-standby", + "heartbeat-delay": 10000, + "max-response-delay": 60000, + "max-ack-delay": 5000, + "max-unacked-clients": 5, + "peers": [{ + "name": "server1", + "url": "http://192.168.56.33:8000/", + "role": "primary", + "auto-failover": true + }, { + "name": "server2", + "url": "http://192.168.56.66:8000/", + "role": "standby", + "auto-failover": true + }] + }] + } + }], + + "subnet4": [{ + "id": 1, + "subnet": "192.0.3.0/24", + "pools": [{ + "pool": "192.0.3.100 - 192.0.3.250" + }] + }] + } + } + +Control Agent on Server 1: +:: + + { + "Control-agent": { + "http-host": "192.168.56.33", + "http-port": 8000, + "control-sockets": { + "dhcp4": { + "socket-type": "unix", + "socket-name": "/var/run/kea/control_socket" + } + }, + "trust-anchor": "/var/lib/kea/CA.pem", + "cert-file": "/var/lib/kea/server1_cert.pem", + "key-file": "/var/lib/kea/server1_key.pem", + "cert-required": true + } + } + +Control Agent on Server 2: +:: + + { + "Control-agent": { + "http-host": "192.168.56.66", + "http-port": 8000, + "control-sockets": { + "dhcp4": { + "socket-type": "unix", + "socket-name": "/var/run/kea/control_socket" + } + }, + "trust-anchor": "/var/lib/kea/CA.pem", + "cert-file": "/var/lib/kea/server2_cert.pem", + "key-file": "/var/lib/kea/server2_key.pem", + "cert-required": true + } + } + +.. _ha-server-states: + +Server States +~~~~~~~~~~~~~ + +A DHCP server operating within an HA setup runs a state machine, and the state +of the server can be retrieved by its peers using the :isccmd:`ha-heartbeat` command +sent over the RESTful API. If the partner server does not respond to the +:isccmd:`ha-heartbeat` command within the specified amount of time, the communication +is considered interrupted and the server may, depending on the configuration, +use additional measures (described later in this document) to verify that the +partner is still operating. If it finds that the partner is not operating, the +server transitions to the ``partner-down`` state to handle all the DHCP traffic +directed to the system. + +In this case, the surviving server continues to send the :isccmd:`ha-heartbeat` +command to detect when the partner wakes up. At that time, the partner +synchronizes the lease database. When it is again ready to operate, the +surviving server returns to normal operation, i.e. the ``load-balancing`` or +``hot-standby`` state. + +The following is the list of all possible server states: + +- ``backup`` - normal operation of the backup server. In this state it receives + lease updates from the active server(s). + +- ``communication-recovery`` - an active server running in ``load-balancing`` + mode may transition to this state when it experiences communication issues + with a partner server over the control channel. This is an intermediate state + between the ``load-balancing`` and ``partner-down`` states. In this state the + server continues to respond to DHCP queries but does not send lease updates + to the partner; lease updates are queued and are sent when normal + communication is resumed. If communication does not resume within the time + specified, the primary server then transitions to the ``partner-down`` state. + The ``communication-recovery`` state was introduced to ensure reliable DHCP + service when both active servers remain operational but the communication + between them is interrupted for a prolonged period of time. Either server can + be configured to never enter this state by setting the + ``delayed-updates-limit`` to 0 (please refer to + :ref:`ha-load-balancing-config`, later in this chapter, for details on this + parameter). Disabling entry into the ``communication-recovery`` state causes + the server to begin testing for the ``partner-down`` state as soon as the + server is unable to communicate with its partner. + +.. note:: + + In Kea 1.9.4, with the introduction of ``delayed-updates-limit``, the default + server's behavior in ``load-balancing`` mode changed. When a server + experiences communication issues with its partner, it now enters the + ``communication-recovery`` state and queues lease updates until communication + is resumed. Prior to Kea 1.9.4, a server that could not communicate with its + partner in ``load-balancing`` mode would immediately begin the transition to + the ``partner-down`` state. + +- ``hot-standby`` - normal operation of the active server running in the + ``hot-standby`` mode; both the primary and the standby server are in this + state during their normal operation. The primary server responds to DHCP + queries and sends lease updates to the standby server and to any backup + servers that are present. + +- ``load-balancing`` - normal operation of the active server running in the + ``load-balancing`` mode; both the primary and the secondary server are in + this state during their normal operation. Both servers respond to DHCP + queries and send lease updates to each other and to any backup servers that + are present. + +- ``in-maintenance`` - an active server transitions to this state as a result + of being notified by its partner that the administrator requested maintenance + of the HA setup. The administrator requests the maintenance by sending the + :isccmd:`ha-maintenance-start` command to the server which is supposed to take over + the responsibility for responding to the DHCP clients while the other server + is taken offline for maintenance. If the server is in the ``in-maintenance`` + state it can be safely shut down. The partner transitions to the + ``partner-down`` state immediately after discovering that the server in + maintenance has been shut down. + +- ``partner-down`` - an active server transitions to this state after detecting + that its partner (another active server) is offline. The server does not + transition to this state if only a backup server is unavailable. In the + ``partner-down`` state the active server responds to all DHCP queries, + including those queries which are normally handled by the server that is now + unavailable. + +- ``partner-in-maintenance`` - an active server transitions to this state + after receiving a :isccmd:`ha-maintenance-start` command from the administrator. + The server in this state becomes responsible for responding to all DHCP + requests. The server sends a :isccmd:`ha-maintenance-notify` command to the partner, + which should enter the ``in-maintenance`` state. The server remaining in the + ``partner-in-maintenance`` state keeps sending lease updates to the partner + until it finds that the partner has stopped responding to those lease updates, + heartbeats, or any other commands. In this case, the server in the + ``partner-in-maintenance`` state transitions to the ``partner-down`` state + and keeps responding to the queries, but no longer sends lease updates. + +- ``passive-backup`` - a primary server running in the ``passive-backup`` HA + mode transitions to this state immediately after it boots up. The primary + server in this state responds to all DHCP traffic and sends lease updates to + the backup servers it is connected to. By default, the primary server does + not wait for acknowledgments from the backup servers and responds to a DHCP + query right after sending lease updates to all backup servers. If any of the + lease updates fail, a backup server misses the lease update but the DHCP + client is still provisioned. This default configuration can be changed by + setting the ``wait-backup-ack`` configuration parameter to ``true``, in which + case the primary server always waits for the acknowledgements and drops the + DHCP query if sending any of the corresponding lease updates fails. This + improves lease database consistency between the primary and the secondary. + However, if a communication failure between the active server and any of the + backups occurs, it effectively causes the failure of the DHCP service from + the DHCP clients' perspective. + +- ``ready`` - an active server transitions to this state after synchronizing + its lease database with an active partner. This state indicates to the + partner (which may be in the ``partner-down`` state) that it should return to + normal operation. If and when it does, the server in the ``ready`` state also + starts normal operation. + +- ``syncing`` - an active server transitions to this state to fetch leases from + the active partner and update the local lease database. When in this state, + the server issues the :isccmd:`dhcp-disable` command to disable the DHCP service of + the partner from which the leases are fetched. The DHCP service is disabled + for a maximum time of 60 seconds, after which it is automatically re-enabled, + in case the syncing partner was unable to re-enable the service. If the + synchronization completes successfully, the synchronizing server issues the + :isccmd:`ha-sync-complete-notify` command to notify the partner. In most states, + the partner re-enables its DHCP service to continue responding to the DHCP + queries. In the ``partner-down`` state, the partner first ensures that + communication between the servers is re-established before enabling the DHCP + service. The syncing operation is synchronous; the server waits for an answer + from the partner and does nothing else while the lease synchronization takes + place. A server that is configured not to synchronize the lease database with + its partner, i.e. when the ``sync-leases`` configuration parameter is set to + ``false``, will never transition to this state. Instead, it transitions + directly from the ``waiting`` state to the ``ready`` state. + +- ``terminated`` - an active server transitions to this state when the High + Availability hook library is unable to further provide reliable service and a + manual intervention of the administrator is required to correct the problem. + Various issues with the HA setup may cause the server to transition to this + state. While in this state, the server continues responding to DHCP clients + based on the HA mode selected (``load-balancing`` or ``hot-standby``), but + lease updates are not exchanged and heartbeats are not sent. Once a server + has entered the ``terminated`` state, it remains in this state until it is + restarted. The administrator must correct the issue which caused this + situation prior to restarting the server (e.g. synchronize the clocks); + otherwise, the server will return to the ``terminated`` state once it finds + that the issue persists. + +- ``waiting`` - each started server instance enters this state. A backup server + transitions directly from this state to the ``backup`` state. An active + server sends a heartbeat to its partner to check its state; if the partner + appears to be unavailable, the server transitions to the ``partner-down`` + state. If the partner is available, the server transitions to the ``syncing`` + or ``ready`` state, depending on the setting of the ``sync-leases`` + configuration parameter. If both servers appear to be in the ``waiting`` + state (concurrent startup), the primary server transitions to the next state + first. The secondary or standby server remains in the ``waiting`` state until + the primary transitions to the ``ready`` state. + +.. note:: + + Currently, restarting the HA service from the ``terminated`` state requires + restarting the DHCP server or reloading its configuration. + +Whether the server responds to DHCP queries and which queries it responds to is +a matter of the server's state, if no administrative action is performed to +configure the server otherwise. The following table provides the default +behavior for various states. + +The ``DHCP Service Scopes`` denote which group of received DHCP queries the +server responds to in the given state. The HA configuration must specify a +unique name for each server within the HA setup. This document uses the +following convention within the provided examples: "server1" for a primary +server, "server2" for the secondary or standby server, and "server3" for the +backup server. In real life any names can be used as long as they remain unique. + +An in-depth explanation of the scopes can be found below. + +.. table:: Default behavior of the server in various HA states + + +------------------------+-----------------+-----------------+----------------+ + | State | Server Type | DHCP Service | DHCP Service | + | | | | Scopes | + +========================+=================+=================+================+ + | backup | backup server | disabled | none | + +------------------------+-----------------+-----------------+----------------+ + | communication-recovery | primary or | enabled | "HA_server1" | + | | secondary | | or | + | | (load-balancing | | "HA_server2" | + | | mode only) | | | + +------------------------+-----------------+-----------------+----------------+ + | hot-standby | primary or | enabled | "HA_server1" | + | | standby | | if primary, | + | | (hot-standby | | none otherwise | + | | mode) | | | + +------------------------+-----------------+-----------------+----------------+ + | load-balancing | primary or | enabled | "HA_server1" | + | | secondary | | or | + | | (load-balancing | | "HA_server2" | + | | mode) | | | + +------------------------+-----------------+-----------------+----------------+ + | in-maintenance | active server | disabled | none | + +------------------------+-----------------+-----------------+----------------+ + | partner-down | active server | enabled | all scopes | + +------------------------+-----------------+-----------------+----------------+ + | partner-in-maintenance | active server | enabled | all scopes | + +------------------------+-----------------+-----------------+----------------+ + | passive-backup | active server | enabled | all scopes | + +------------------------+-----------------+-----------------+----------------+ + | ready | active server | disabled | none | + +------------------------+-----------------+-----------------+----------------+ + | syncing | active server | disabled | none | + +------------------------+-----------------+-----------------+----------------+ + | terminated | active server | enabled | same as in the | + | | | | load-balancing | + | | | | or hot-standby | + | | | | state | + +------------------------+-----------------+-----------------+----------------+ + | waiting | any server | disabled | none | + +------------------------+-----------------+-----------------+----------------+ + +In the ``load-balancing`` mode there are two scopes specified for the active +servers: "HA_server1" and "HA_server2". The DHCP queries load-balanced to +``server1`` belong to the "HA_server1" scope and the queries load-balanced to +``server2`` belong to the "HA_server2" scope. If either server is in the +``partner-down`` state, the active partner is responsible for serving both +scopes. + +In the ``hot-standby`` mode, there is only one scope - "HA_server1" - because +only ``server1`` is responding to DHCP queries. If that server becomes +unavailable, ``server2`` becomes responsible for this scope. + +The backup servers do not have their own scopes. In some cases they can be used +to respond to queries belonging to the scopes of the active servers. Also, a +backup server which is neither in the ``partner-down`` state nor in normal +operation serves no scopes. + +The scope names can be used to associate pools, subnets, and networks with +certain servers, so that only these servers can allocate addresses or prefixes +from those pools, subnets, or networks. This is done via the client +classification mechanism (see :ref:`ha-load-balancing-advanced-config` for more +details). + +.. _ha-scope-transition: + +Scope Transition in a Partner-Down Case +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When one of the servers finds that its partner is unavailable, it starts serving +clients from both its own scope and the scope of the unavailable partner. This +is straightforward for new clients, i.e. those sending DHCPDISCOVER (DHCPv4) or +Solicit (DHCPv6), because those requests are not sent to any particular server. +The available server responds to all such queries when it is in the +``partner-down`` state. + +When a client renews a lease, it sends its DHCPREQUEST (DHCPv4) or Renew (DHCPv6) +message directly to the server which has allocated the lease being renewed. If +this server is no longer available, the client will get no response. In that +case, the client continues to use its lease and attempts to renew until the +rebind timer (T2) elapses. The client then enters the rebinding phase, in which +it sends a DHCPREQUEST (DHCPv4) or Rebind (DHCPv6) message to any available +server. The surviving server receives the rebinding request and typically +extends the lifetime of the lease. The client then continues to contact that new +server to renew its lease as appropriate. + +If and when the other server once again becomes available, both active servers +will eventually transition to the ``load-balancing`` or ``hot-standby`` state, +in which they will again be responsible for their own scopes. Some clients +belonging to the scope of the restarted server will try to renew their leases +via the surviving server, but this server will no longer respond to them; the +client will eventually transition back to the correct server via the rebinding +mechanism. + +.. _ha-load-balancing-config: + +Load-Balancing Configuration +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following is the configuration snippet to enable high availability on the +primary server within the ``load-balancing`` configuration. The same +configuration should be applied on the secondary and backup servers, with the +only difference that ``this-server-name`` should be set to "server2" and +"server3" on those servers, respectively. + +.. note:: + + Remember that ``load-balancing`` mode requires the address pools and + delegated prefix pools to be split between the active servers. During normal + operation, the servers use non-overlapping pools to avoid allocating the same + lease to different clients by both instances. A server only uses the pool + fragments owned by the partner when the partner is not running. See the notes + in :ref:`ha-supported-configurations` highlighting differences between the + ``load-balancing`` and ``hot-standby`` modes. The semantics of pool + partitioning is explained further in this section. + The :ref:`ha-load-balancing-advanced-config` section provides advanced + pool-partitioning examples. + +:: + + "Dhcp4": { + "hooks-libraries": [{ + "library": "/usr/lib/kea/hooks/libdhcp_lease_cmds.so", + "parameters": { } + }, { + "library": "/usr/lib/kea/hooks/libdhcp_ha.so", + "parameters": { + "high-availability": [{ + "this-server-name": "server1", + "mode": "load-balancing", + "heartbeat-delay": 10000, + "max-response-delay": 60000, + "max-ack-delay": 5000, + "max-unacked-clients": 5, + "max-rejected-lease-updates": 10, + "delayed-updates-limit": 100, + "peers": [{ + "name": "server1", + "url": "http://192.168.56.33:8000/", + "role": "primary", + "auto-failover": true + }, { + "name": "server2", + "url": "http://192.168.56.66:8000/", + "role": "secondary", + "auto-failover": true + }, { + "name": "server3", + "url": "http://192.168.56.99:8000/", + "role": "backup", + "basic-auth-user": "foo", + "basic-auth-password": "bar", + "auto-failover": false + }] + }] + } + }], + + "subnet4": [{ + "id": 1, + "subnet": "192.0.3.0/24", + "pools": [{ + "pool": "192.0.3.100 - 192.0.3.150", + "client-class": "HA_server1" + }, { + "pool": "192.0.3.200 - 192.0.3.250", + "client-class": "HA_server2" + }], + + "option-data": [{ + "name": "routers", + "data": "192.0.3.1" + }], + + "relay": { "ip-address": "10.1.2.3" } + }] + } + +Two hook libraries must be loaded to enable HA: :ischooklib:`libdhcp_lease_cmds.so` and +:ischooklib:`libdhcp_ha.so`. The latter implements the HA feature, while the former +enables control commands required by HA to fetch and manipulate leases on the +remote servers. In the example provided above, it is assumed that Kea libraries +are installed in the ``/usr/lib`` directory. If Kea is not installed in the +``/usr`` directory, the hook libraries' locations must be updated accordingly. + +The HA configuration is specified within the scope of :ischooklib:`libdhcp_ha.so`. +Note that while the top-level parameter ``high-availability`` is a list, only a +single entry is currently supported. + +The following are the global parameters which control the server's behavior with +respect to HA: + +- ``this-server-name`` - is a unique identifier of the server within this HA + setup. It must match one of the servers specified within the ``peers`` list. + +- ``mode`` - specifies an HA mode of operation. The currently supported modes + are ``load-balancing`` and ``hot-standby``. + +- ``heartbeat-delay`` - specifies a duration in milliseconds between sending + the last heartbeat (or other command sent to the partner) and the next + heartbeat. Heartbeats are sent periodically to gather the status of the + partner and to verify whether the partner is still operating. The default + value of this parameter is 10000 ms. + +- ``max-response-delay`` - specifies a duration in milliseconds since the last + successful communication with the partner, after which the server assumes + that communication with the partner is interrupted. This duration should be + greater than the ``heartbeat-delay``; typically it should be a multiple of + ``heartbeat-delay``. When the server detects that communication is + interrupted, it may transition to the ``partner-down`` state (when + ``max-unacked-clients`` is 0) or trigger the failure-detection procedure + using the values of the two parameters below. The default value of this + parameter is 60000 ms. + +- ``max-ack-delay`` - is one of the parameters controlling partner + failure-detection. When communication with the partner is interrupted, the + server examines the values of the "secs" field (DHCPv4) or "elapsed time" + option (DHCPv6), which denote how long the DHCP client has been trying to + communicate with the DHCP server. This parameter specifies the maximum time + in milliseconds for the client to try to communicate with the DHCP server, + after which this server assumes that the client failed to communicate with + the DHCP server (is unacknowledged or "unacked"). The default value of this + parameter is 10000. + +- ``max-unacked-clients`` - specifies how many "unacked" clients are allowed + (see ``max-ack-delay``) before this server assumes that the partner is + offline and transitions to the ``partner-down`` state. The special value of 0 + is allowed for this parameter, which disables the failure-detection mechanism. + In this case, a server that cannot communicate with its partner over the + control channel assumes that the partner server is down and transitions to + the ``partner-down`` state immediately. The default value of this parameter + is 10. + +- ``max-rejected-lease-updates`` - specifies how many lease updates for distinct + clients can fail, due to a conflict between the lease and the partner configuration + or state, before the server transitions to the ``terminated`` state. Conflict + can be a sign of a misconfiguration; usually, a small number of conflicted + leases are acceptable because they affect only a few devices. However, if + the conflicts occur for many devices (e.g., an entire subnet), the HA service + becomes unreliable and should be terminated, and the problem must be manually + corrected by an administrator. It is up to the administrator to select + the highest acceptable value of ``max-rejected-lease-updates``. The default + value is 10. The special value of 0 configures the server to never terminate + the HA service due to lease conflicts. If the value is 1, the server + transitions to the ``terminated`` state when the first conflict occurs. + This parameter does not pertain to conflicting lease updates sent to + the backup servers. + +- ``delayed-updates-limit`` - specifies the maximum number of lease updates + which can be queued while the server is in the ``communication-recovery`` + state. This parameter was introduced in Kea 1.9.4. The special value of 0 + configures the server to never transition to the ``communication-recovery`` + state and the server behaves as in earlier Kea versions, i.e. if the server + cannot reach its partner, it goes straight into the ``partner-down`` state. + The default value of this parameter is 100. + +.. note:: + + The ``max-rejected-lease-updates`` parameter was introduced in Kea 2.3.1. + Previously, the server did not differentiate between a lease update + failure due to a non-functioning partner and a failure due to a conflict + (e.g., configuration issues). + As a result, the server could sometimes transition to the ``partner-down`` + state even though the partner was operating normally, but only certain leases + had issues. Conflicts should no longer cause such a transition. However, + depending on the ``max-rejected-lease-updates`` setting, too many conflicts + can lead to termination of the High Availability service. In that case, both + servers continue to respond to DHCP queries but no longer send lease updates. + +The values of ``max-ack-delay`` and ``max-unacked-clients`` must be selected +carefully, taking into account the specifics of the network in which the DHCP +servers are operating. The server in question may not respond to some DHCP +clients following administrative policy, or the server may drop malformed +queries from clients. Therefore, selecting too low a value for the +``max-unacked-clients`` parameter may result in a transition to the +``partner-down`` state even though the partner is still operating. On the other +hand, selecting too high a value may result in never transitioning to the +``partner-down`` state if the DHCP traffic in the network is very low (e.g. at +night), because the number of distinct clients trying to communicate with the +server could be lower than the ``max-unacked-clients`` setting. + +In some cases it may be useful to disable the failure-detection mechanism +altogether, if the servers are located very close to each other and network +partitioning is unlikely, i.e. failure to respond to heartbeats is only possible +when the partner is offline. In such cases, set ``max-unacked-clients`` to 0. + +The ``delayed-updates-limit`` parameter is used to enable or disable the +``communication-recovery`` procedure, and controls the server's behavior in the +``communication-recovery`` state. This parameter can only be used in the +``load-balancing`` mode. + +If a server in the ``load-balancing`` state experiences communication issues +with its partner (a heartbeat or lease-update failure), the server transitions +to the ``communication-recovery`` state. In this state, the server keeps +responding to DHCP queries but does not send lease updates to the partner. The +lease updates are queued until communication is re-established, to ensure that +DHCP service remains available even in the event of the communication loss +between the partners. There may appear to be communication loss when either one +of the servers has terminated, or when both servers remain available but cannot +communicate with each other. In the former case, the surviving server will +follow the normal procedure and should eventually transition to the +``partner-down`` state. In the latter case, both servers should transition to +the ``communication-recovery`` state and should never transition to the +``partner-down`` state (if ``max-unacked-clients`` is set to a non-zero value), +because all DHCP queries are answered and neither server would see any unacked +DHCP queries. + +Introduction of the ``communication-recovery`` procedure was motivated by issues +which may appear when two servers remain online but the communication between +them remains interrupted for a period of time. In earlier Kea versions, the +servers having communication issues used to drop DHCP packets before +transitioning to the ``partner-down`` state. In some cases they both +transitioned to the ``partner-down`` state, which could potentially result in +allocations of the same IP addresses or delegated prefixes to different clients +by both servers. By entering the intermediate ``communication-recovery`` state, +these problems are avoided. + +If a server in the ``communication-recovery`` state re-establishes communication +with its partner, it tries to send the partner all of the outstanding lease +updates it has queued. This is done synchronously and may take a considerable +amount of time before the server transitions to the ``load-balancing`` state and +resumes normal operation. +The maximum number of lease updates which can be queued in the +``communication-recovery`` state is controlled by ``delayed-updates-limit``. +If the limit is exceeded, the server stops queuing lease updates and performs a +full database synchronization after re-establishing the connection with the +partner, instead of sending outstanding lease updates before transitioning to +the ``load-balancing`` state. Even if the limit is exceeded, the server in the +``communication-recovery`` state remains responsive to DHCP clients. + +It may be preferable to set higher values of ``delayed-updates-limit`` when +there is a risk of prolonged communication interruption between the servers and +when the lease database is large, to avoid costly lease-database synchronization. +On the other hand, if the lease database is small, the time required to send +outstanding lease updates may be longer than the lease-database synchronization. +In such cases it may be better to use a lower value, e.g. 10. The default value +of 100 is a reasonable compromise and should work well in most deployments with +moderate traffic. + +.. note:: + + This parameter is new and values for it that work well in some environments + may not work well in others. Feedback from users will help us build a better + working set of recommendations. + +The ``peers`` parameter contains a list of servers within this HA setup. +This configuration must contain at least one primary and one secondary server. +It may also contain an unlimited number of backup servers. In this example, +there is one backup server which receives lease updates from the active servers. + +Since Kea version 1.9.0, basic HTTP authentication is available +to protect the Kea control agent against local attackers. + +These are the parameters specified for each of the peers within this +list: + +- ``name`` - specifies a unique name for the server. + +- ``url`` - specifies the URL to be used to contact this server over the + control channel. Other servers use this URL to send control commands to that + server. + +- ``basic-auth-user`` - specifies the user ID for basic HTTP authentication. If + not specified or specified as an empty string, no authentication header is + added to HTTP transactions. It must not contain the colon (:) character. + +- ``basic-auth-password`` - specifies the password for basic HTTP + authentication. This parameter is ignored when the user ID is not specified + or is empty. The password is optional; if not specified, an empty password is + used. + +- ``basic-auth-password-file`` - is an alternative to ``basic-auth-password``: + instead of presenting the password in the configuration file it is specified + in the file indicated by this parameter. + +- ``role`` - denotes the role of the server in the HA setup. The following + roles are supported in the ``load-balancing`` configuration: ``primary``, + ``secondary``, and ``backup``. There must be exactly one primary and one + secondary server in the ``load-balancing`` setup. + +- ``auto-failover`` - a boolean value which denotes whether a server detecting + a partner's failure should automatically start serving the partner's clients. + The default value of this parameter is ``true``. + +In our example configuration above, both active servers can allocate leases from +the subnet "192.0.3.0/24". This subnet contains two address pools: +"192.0.3.100 - 192.0.3.150" and "192.0.3.200 - 192.0.3.250", which are +associated with HA server scopes using client classification. When ``server1`` +processes a DHCP query, it uses the first pool for lease allocation. Conversely, +when ``server2`` processes a DHCP query it uses the second pool. If either of +the servers is in the ``partner-down`` state, the other can serve leases from +both pools; it selects the pool which is appropriate for the received query. In +other words, if the query would normally be processed by ``server2`` but this +server is not available, ``server1`` allocates the lease from the pool of +"192.0.3.200 - 192.0.3.250". The Kea control agent in front of ``server3`` +requires basic HTTP authentication, and authorizes the user ID "foo" with the +password "bar". + +.. note:: + + The ``url`` schema can be ``http`` or ``https``, but since Kea version 1.9.6 + the ``https`` schema requires a TLS setup. The hostname part must be an IPv4 + address or an IPv6 address between square brackets, e.g. + ``http://[2001:db8::1]:8080/``. Names are not accepted. + +.. _ha-load-balancing-advanced-config: + +Load Balancing With Advanced Classification +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In the previous section, we provided an example of a ``load-balancing`` +configuration with client classification limited to the "HA_server1" and +"HA_server2" classes, which are dynamically assigned to the received DHCP +queries. In many cases, HA is needed in deployments which already use some other +client classification. + +Suppose there is a system which classifies devices into two groups: "phones" and +"laptops", based on some classification criteria specified in the Kea +configuration file. Both types of devices are allocated leases from different +address pools. Introducing HA in ``load-balancing`` mode results in a further +split of each of those pools, as each server allocates leases for some phones +and some laptops. This requires each of the existing pools to be split between +"HA_server1" and "HA_server2", so we end up with the following classes: + +- "phones_server1" +- "laptops_server1" +- "phones_server2" +- "laptops_server2" + +The corresponding server configuration, using advanced classification (and the +``member`` expression), is provided below. For brevity's sake, the HA hook +library configuration has been removed from this example. + +.. code-block:: json + + { + "Dhcp4": { + "client-classes": [{ + "name": "phones", + "test": "substring(option[60].hex,0,6) == 'Aastra'" + }, { + "name": "laptops", + "test": "not member('phones')" + }, { + "name": "phones_server1", + "test": "member('phones') and member('HA_server1')" + }, { + "name": "phones_server2", + "test": "member('phones') and member('HA_server2')" + }, { + "name": "laptops_server1", + "test": "member('laptops') and member('HA_server1')" + }, { + "name": "laptops_server2", + "test": "member('laptops') and member('HA_server2')" + }], + + "hooks-libraries": [{ + "library": "/usr/lib/kea/hooks/libdhcp_lease_cmds.so", + "parameters": { } + }, { + "library": "/usr/lib/kea/hooks/libdhcp_ha.so", + "parameters": { + "high-availability": [{ + }] + } + }], + + "subnet4": [{ + "id": 1, + "subnet": "192.0.3.0/24", + "pools": [{ + "pool": "192.0.3.100 - 192.0.3.125", + "client-class": "phones_server1" + }, { + "pool": "192.0.3.126 - 192.0.3.150", + "client-class": "laptops_server1" + }, { + "pool": "192.0.3.200 - 192.0.3.225", + "client-class": "phones_server2" + }, { + "pool": "192.0.3.226 - 192.0.3.250", + "client-class": "laptops_server2" + }], + + "option-data": [{ + "name": "routers", + "data": "192.0.3.1" + }], + + "relay": { "ip-address": "10.1.2.3" } + }] + } + } + +The configuration provided above splits the address range into four pools: two +pools dedicated to "HA_server1" and two to "HA_server2". Each server can assign +leases to both phones and laptops. Both groups of devices are assigned addresses +from different pools. The "HA_server1" and "HA_server2" classes are built-in +(see :ref:`built-in-client-classes`) and do not need to be declared. +They are assigned dynamically by the HA hook library as a result of the +``load-balancing`` algorithm. "phones_*" and "laptop_*" evaluate to ``true`` +when the query belongs to a given combination of other classes, e.g. "HA_server1" +and "phones". The pool is selected accordingly as a result of such an evaluation. + +Consult :ref:`classify` for details on how to use the ``member`` expression and +class dependencies. + +.. _ha-hot-standby-config: + +Hot-Standby Configuration +~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following is an example configuration of the primary server in a +``hot-standby`` configuration: + +:: + + "Dhcp4": { + "hooks-libraries": [{ + "library": "/usr/lib/kea/hooks/libdhcp_lease_cmds.so", + "parameters": { } + }, { + "library": "/usr/lib/kea/hooks/libdhcp_ha.so", + "parameters": { + "high-availability": [{ + "this-server-name": "server1", + "mode": "hot-standby", + "heartbeat-delay": 10000, + "max-response-delay": 60000, + "max-ack-delay": 5000, + "max-unacked-clients": 5, + "max-rejected-lease-updates": 10, + "peers": [{ + "name": "server1", + "url": "http://192.168.56.33:8000/", + "role": "primary", + "auto-failover": true + }, { + "name": "server2", + "url": "http://192.168.56.66:8000/", + "role": "standby", + "auto-failover": true + }, { + "name": "server3", + "url": "http://192.168.56.99:8000/", + "basic-auth-user": "foo", + "basic-auth-password": "bar", + "role": "backup", + "auto-failover": false + }] + }] + } + }], + + "subnet4": [{ + "id": 1, + "subnet": "192.0.3.0/24", + "pools": [{ + "pool": "192.0.3.100 - 192.0.3.250", + "client-class": "HA_server1" + }], + + "option-data": [{ + "name": "routers", + "data": "192.0.3.1" + }], + + "relay": { "ip-address": "10.1.2.3" } + }] + } + +This configuration is very similar to the ``load-balancing`` configuration +described in :ref:`ha-load-balancing-config`, with a few notable differences. + +The ``mode`` is now set to ``hot-standby``, in which only one server responds to +DHCP clients. If the primary server is online, it responds to all DHCP queries. +The ``standby`` server takes over all DHCP traffic only if it discovers that the +primary is unavailable. + +In this mode, the non-primary active server is called ``standby`` and that is +its role. + +Finally, because there is always only one server responding to DHCP queries, +there is only one scope - "HA_server1" - in use within pool definitions. In fact, +the ``client-class`` parameter could be removed from this configuration without +harm, because there can be no conflicts in lease allocations by different +servers as they do not allocate leases concurrently. The ``client-class`` +remains in this example mostly for demonstration purposes, to highlight the +differences between the ``hot-standby`` and ``load-balancing`` modes of +operation. + +.. _ha-passive-backup-config: + +Passive-Backup Configuration +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following is an example configuration file for the primary server in a +``passive-backup`` configuration: + +.. code-block:: json + + { + "Dhcp4": { + "hooks-libraries": [{ + "library": "/usr/lib/kea/hooks/libdhcp_lease_cmds.so", + "parameters": { } + }, { + "library": "/usr/lib/kea/hooks/libdhcp_ha.so", + "parameters": { + "high-availability": [{ + "this-server-name": "server1", + "mode": "passive-backup", + "wait-backup-ack": false, + "peers": [{ + "name": "server1", + "url": "http://192.168.56.33:8000/", + "role": "primary" + }, { + "name": "server2", + "url": "http://192.168.56.66:8000/", + "role": "backup" + }, { + "name": "server3", + "url": "http://192.168.56.99:8000/", + "basic-auth-user": "foo", + "basic-auth-password": "bar", + "role": "backup" + }] + }] + } + }], + + "subnet4": [{ + "id": 1, + "subnet": "192.0.3.0/24", + "pools": [{ + "pool": "192.0.3.100 - 192.0.3.250" + }], + + "option-data": [{ + "name": "routers", + "data": "192.0.3.1" + }], + + "relay": { "ip-address": "10.1.2.3" } + }] + } + } + +The configurations of three peers are included: one for the primary and two for +the backup servers. + +Many of the parameters present in the ``load-balancing`` and ``hot-standby`` +configuration examples are not relevant in the ``passive-backup`` mode, thus +they are not specified here. For example: ``heartbeat-delay``, +``max-unacked-clients``, ``max-rejected-lease-updates``, and others related to +the failover mechanism should not be specified in the ``passive-backup`` mode. + +The ``wait-backup-ack`` is a boolean parameter not present in previous examples. +It defaults to ``false`` and must not be modified in the ``load-balancing`` and +``hot-standby`` modes. In the ``passive-backup`` mode this parameter can be set +to ``true``, which causes the primary server to expect acknowledgments to the +lease updates from the backup servers prior to responding to the DHCP client. It +ensures that the lease has propagated to all servers before the client is given +the lease, but it poses a risk of losing a DHCP service if there is a +communication problem with one of the backup servers. This setting also +increases the latency of the DHCP response, because of the time that the primary +spends waiting for the acknowledgements. We recommend that the +``wait-backup-ack`` setting be left at its default value (``false``) if the DHCP +service reliability is more important than consistency of the lease information +between the primary and the backups, and in all cases when the DHCP service +latency should be minimal. + +.. note:: + + Currently, active servers place lease updates to be sent to peers onto + internal queues (one queue per peer/URL). In ``passive-backup`` mode, active + servers do not wait for lease updates to be acknowledged; thus during times + of heavy client traffic it is possible for the number of lease updates queued + for transmission to accumulate faster than they can be delivered. As client + traffic lessens the queues begin to empty. Since Kea 2.0.0, active servers + monitor the size of these queues and emit periodic warnings (see + HTTP_CLIENT_QUEUE_SIZE_GROWING in :ref:`kea-messages`) if they perceive a + queue as growing too quickly. The warnings cease once the queue size begins + to shrink. These messages are intended as a bellwether and seeing them + sporadically during times of heavy traffic load does not necessarily indicate + a problem. If, however, they occur continually during times of routine + traffic load, they likely indicate potential mismatches in server + capabilities and/or configuration; this should be investigated, as the size + of the queues may eventually impair an active server's ability to respond to + clients in a timely manner. + +.. _ha-sharing-lease-info: + +Lease Information Sharing +~~~~~~~~~~~~~~~~~~~~~~~~~ + +An HA-enabled server informs its active partner about allocated or renewed +leases by sending appropriate control commands, and the partner updates the +lease information in its own database. When the server starts up for the first +time or recovers after a failure, it synchronizes its lease database with its +partner. These two mechanisms guarantee consistency of the lease information +between the servers and allow the designation of one of the servers to handle +the entire DHCP traffic load if the other server becomes unavailable. + +In some cases, though, it is desirable to disable lease updates and/or database +synchronization between the active servers, if the exchange of information about +the allocated leases is performed using some other mechanism. Kea supports +various database types that can be used to store leases, including MySQL and +PostgreSQL. Those databases include built-in solutions for data replication +which are often used by Kea administrators to provide redundancy. + +The HA hook library supports such scenarios by disabling lease updates over the +control channel and/or lease-database synchronization, leaving the server to +rely on the database replication mechanism. This is controlled by the two +boolean parameters ``send-lease-updates`` and ``sync-leases``, whose values +default to ``true``: + +:: + + "Dhcp4": { + "hooks-libraries": [ + { + "library": "/usr/lib/kea/hooks/libdhcp_lease_cmds.so", + "parameters": { } + }, + { + "library": "/usr/lib/kea/hooks/libdhcp_ha.so", + "parameters": { + "high-availability": [ { + "this-server-name": "server1", + "mode": "load-balancing", + "send-lease-updates": false, + "sync-leases": false, + "peers": [ + { + "name": "server1", + "url": "http://192.168.56.33:8000/", + "role": "primary" + }, + { + "name": "server2", + "url": "http://192.168.56.66:8000/", + "role": "secondary" + } + ] + } ] + } + } + ], + ... + } + +In the most typical use case, both parameters are set to the same value, i.e. +both are ``false`` if database replication is in use, or both are ``true`` +otherwise. Introducing two separate parameters to control lease updates and +lease-database synchronization is aimed at possible special use cases; for +example, when synchronization is performed by copying a lease file (therefore +``sync-leases`` is set to ``false``), but lease updates should be conducted as +usual (``send-lease-updates`` is set to ``true``). It should be noted that Kea +does not natively support such use cases, but users may develop their own +scripts and tools around Kea to provide such mechanisms. The HA hook library +configuration is designed to maximize flexibility of administration. + +.. _ha-syncing-page-limit: + +Controlling Lease-Page Size Limit +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +An HA-enabled server initiates synchronization of the lease database after +downtime or upon receiving the :isccmd:`ha-sync` command. The server uses commands +:isccmd:`lease4-get-page` and :isccmd:`lease6-get-page` +to fetch leases from its partner server (lease queries). The size of the results +page (the maximum number of leases to be returned in a single response to one of +these commands) can be controlled via configuration of the HA hook library. +Increasing the page size decreases the number of lease queries sent to the +partner server, but it causes the partner server to generate larger responses, +which lengthens transmission time as well as increases memory and CPU +utilization on both servers. Decreasing the page size helps to decrease resource +utilization, but requires more lease queries to be issued to fetch the entire +lease database. + +The default value of the ``sync-page-limit`` command controlling the page size +is 10000. This means that the entire lease database can be fetched with a single +command if the size of the database is equal to or less than 10000 lines. + +.. _ha-syncing-timeouts: + +Timeouts +~~~~~~~~ + +In deployments with a large number of clients connected to the network, +lease-database synchronization after a server failure may be a time-consuming +operation. The synchronizing server must gather all leases from its partner, +which yields a large response over the RESTful interface. The server receives +leases using the paging mechanism described in :ref:`ha-syncing-page-limit`. +Before the page of leases is fetched, the synchronizing server sends a +:isccmd:`dhcp-disable` command to disable the DHCP service on the partner server. If +the service is already disabled, this command resets the timeout for the DHCP +service being disabled, which by default is set to 60 seconds. If fetching a +single page of leases takes longer than the specified time, the partner server +assumes that the synchronizing server has died and resumes its DHCP service. The +connection of the synchronizing server with its partner is also protected by the +timeout. If the synchronization of a single page of leases takes longer than the +specified time, the synchronizing server terminates the connection and the +synchronization fails. Both timeout values are controlled by a single +configuration parameter, ``sync-timeout``. The following configuration snippet +demonstrates how to modify the timeout for automatic re-enabling of the DHCP +service on the partner server and how to increase the timeout for fetching a +single page of leases from 60 seconds to 90 seconds: + +:: + + "Dhcp4": { + "hooks-libraries": [ + { + "library": "/usr/lib/kea/hooks/libdhcp_lease_cmds.so", + "parameters": { } + }, + { + "library": "/usr/lib/kea/hooks/libdhcp_ha.so", + "parameters": { + "high-availability": [ { + "this-server-name": "server1", + "mode": "load-balancing", + "sync-timeout": 90000, + "peers": [ + { + "name": "server1", + "url": "http://192.168.56.33:8000/", + "role": "primary" + }, + { + "name": "server2", + "url": "http://192.168.56.66:8000/", + "role": "secondary" + } + ] + } ] + } + } + ], + ... + } + +It is important to note that extending this ``sync-timeout`` value may sometimes +be insufficient to prevent issues with timeouts during lease-database +synchronization. The control commands travel via the Control Agent, which also +monitors incoming (with a synchronizing server) and outgoing (with a DHCP server) +connections for timeouts. The DHCP server also monitors the connection from the +Control Agent for timeouts. Those timeouts cannot currently be modified via +configuration; extending these timeouts is only possible by modifying them in +the Kea code and recompiling the server. The relevant constants are located in +the Kea source at: ``src/lib/config/timeouts.h``. + +.. _ha-pause-state-machine: + +Pausing the HA State Machine +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``high-availability`` state machine includes many different states described +in detail in :ref:`ha-server-states`. The server enters each state when certain +conditions are met, most often taking into account the partner server's state. +In some states the server performs specific actions, e.g. synchronization of the +lease database in the ``syncing`` state, or responding to DHCP queries according +to the configured mode of operation in the ``load-balancing`` and ``hot-standby`` +states. + +By default, transitions between the states are performed automatically and the +server administrator has no direct control over when the transitions take place; +in most cases, the administrator does not need such control. In some situations, +however, the administrator may want to "pause" the HA state machine in a +selected state to perform some additional administrative actions before the +server transitions to the next state. + +Consider a server failure which results in the loss of the entire lease database. +Typically, the server rebuilds its lease database when it enters the ``syncing`` +state by querying the partner server for leases, but it is possible that the +partner was also experiencing a failure and lacks lease information. In this +case, it may be required to reconstruct lease databases on both servers from +some external source, e.g. a backup server. If the lease database is to be +reconstructed via the RESTful API, the servers should be started in the initial, +i.e. ``waiting``, state and remain in this state while leases are being added. +In particular, the servers should not attempt to synchronize their lease +databases nor start serving DHCP clients. + +The HA hook library provides configuration parameters and a command to control +pausing and resuming the HA state machine. The following configuration causes +the HA state machine to pause in the ``waiting`` state after server startup. + +:: + + "Dhcp4": { + "hooks-libraries": [ + { + "library": "/usr/lib/kea/hooks/libdhcp_lease_cmds.so", + "parameters": { } + }, + { + "library": "/usr/lib/kea/hooks/libdhcp_ha.so", + "parameters": { + "high-availability": [ { + "this-server-name": "server1", + "mode": "load-balancing", + "peers": [ + { + "name": "server1", + "url": "http://192.168.56.33:8000/", + "role": "primary" + }, + { + "name": "server2", + "url": "http://192.168.56.66:8000/", + "role": "secondary" + } + ], + "state-machine": { + "states": [ + { + "state": "waiting", + "pause": "once" + } + ] + } + } ] + } + } + ], + ... + } + +The ``pause`` parameter value ``once`` denotes that the state machine should be +paused upon the first transition to the ``waiting`` state; later transitions to +this state will not cause the state machine to pause. Two other supported values +of the ``pause`` parameter are ``always`` and ``never``. The latter is the +default value for each state, which instructs the server never to pause the +state machine. + +In order to "unpause" the state machine, the :isccmd:`ha-continue` command must be +sent to the paused server. This command does not take any arguments. See +:ref:`ha-control-commands` for details about commands specific to :ischooklib:`libdhcp_ha.so`. + +It is possible to configure the state machine to pause in more than one state. +Consider the following configuration: + +:: + + "Dhcp4": { + "hooks-libraries": [ + { + "library": "/usr/lib/kea/hooks/libdhcp_lease_cmds.so", + "parameters": { } + }, + { + "library": "/usr/lib/kea/hooks/libdhcp_ha.so", + "parameters": { + "high-availability": [ { + "this-server-name": "server1", + "mode": "load-balancing", + "peers": [ + { + "name": "server1", + "url": "http://192.168.56.33:8000/", + "role": "primary" + }, + { + "name": "server2", + "url": "http://192.168.56.66:8000/", + "role": "secondary" + } + ], + "state-machine": { + "states": [ + { + "state": "ready", + "pause": "always" + }, + { + "state": "partner-down", + "pause": "once" + } + ] + } + } ] + } + } + ], + ... + } + +This configuration instructs the server to pause the state machine every time it +transitions to the ``ready`` state and upon the first transition to the +``partner-down`` state. + +Refer to :ref:`ha-server-states` for a complete list of server states. The state +machine can be paused in any of the supported states; however, it is not +practical to pause in the ``backup`` or ``terminated`` states because the server +never transitions out of these states anyway. + +.. note:: + + In the ``syncing`` state the server is paused before it makes an attempt to + synchronize the lease database with a partner. To pause the state machine + after lease-database synchronization, use the ``ready`` state instead. + +.. note:: + + The state of the HA state machine depends on the state of the cooperating + server. Therefore, pausing the state machine of one server may affect the + operation of the partner server. For example: if the primary server is paused + in the ``waiting`` state, the partner server will also remain in the + ``waiting`` state until the state machine of the primary server is resumed + and that server transitions to the ``ready`` state. + +.. _ha-ctrl-agent-config: + +Control Agent Configuration +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The :ref:`kea-ctrl-agent` describes in detail the Kea daemon, which provides a +RESTful interface to control the Kea servers. The same functionality is used by +the High Availability hook library to establish communication between the HA +peers. Therefore, the HA library requires that the Control Agent (CA) be started +for each DHCP instance within the HA setup. If the Control Agent is not started, +the peers cannot communicate with a particular DHCP server (even if the DHCP +server itself is online) and may eventually consider this server to be offline. + +The following is an example configuration for the CA running on the same +machine as the primary server. This configuration is valid for both the +``load-balancing`` and the ``hot-standby`` cases presented in previous sections. + +:: + + { + "Control-agent": { + "http-host": "192.168.56.33", + + // If enabling HA and multi-threading, the 8000 port is used by the HA + // hook library http listener. When using HA hook library with + // multi-threading to function, make sure the port used by dedicated + // listener is different (e.g. 8001) than the one used by CA. Note + // the commands should still be sent via CA. The dedicated listener + // is specifically for HA updates only. + "http-port": 8000, + + "control-sockets": { + "dhcp4": { + "socket-type": "unix", + "socket-name": "/tmp/kea-dhcp4-ctrl.sock" + }, + "dhcp6": { + "socket-type": "unix", + "socket-name": "/tmp/kea-dhcp6-ctrl.sock" + } + } + } + } + +Since Kea 1.9.0, basic HTTP authentication is supported. + +.. _ha-mt-config: + +Multi-Threaded Configuration (HA+MT) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +HA peer communication consists of specialized API commands sent between HA peers. +Prior to Kea 1.9.7, each peer had to be paired with a local instance of +:iscman:`kea-ctrl-agent` in order to exchange commands. The agent received HA commands +via HTTP, communicated via Linux socket with the local peer to carry out the +command, and then sent the response back to the requesting peer via HTTP. To +send HA commands, each peer opened its own HTTP client connection to the URL of +each of its peers. + +In Kea 1.9.7 and newer, it is possible to configure HA to use direct +multi-threaded communication between peers. We refer to this mode as HA+MT. +With HA+MT enabled, each peer runs its own dedicated, internal HTTP listener +(i.e. server) which receives and responds to commands directly, thus eliminating +the need for an agent to carry out HA protocol between peers. In addition, both +the listener and client components use multi-threading to support multiple, +concurrent connections between peers. By eliminating the agent and executing +multiple command exchanges in parallel, HA throughput between peers should +improve considerably in most situations. + +The following parameters have been added to the HA configuration, to support +HA+MT operation: + +- ``enable-multi-threading`` - enables or disables multi-threading HA peer + communication (HA+MT). Kea core multi-threading must be enabled for HA+MT to + operate. When ``false``, the server relies on :iscman:`kea-ctrl-agent` for + communication with its peer, and uses single-threaded HTTP client processing. + The default is ``true``. + +- ``http-dedicated-listener`` - enables or disables the creation of a dedicated, + internal HTTP listener through which the server receives HA messages from its + peers. The internal listener replaces the role of :iscman:`kea-ctrl-agent` traffic, + allowing peers to send their HA commands directly to each other. The listener + listens on the peer's ``url``. When ``false``, the server + relies on :iscman:`kea-ctrl-agent`. This parameter has been provided largely for + flexibility and testing; running HA+MT without dedicated listeners enabled + will substantially limit HA throughput. The default is ``true``. + +- ``http-listener-threads`` - indicates the maximum number of threads the + dedicated listener should use. A value of ``0`` instructs the server to use the + same number of threads that the Kea core is using for DHCP multi-threading. + The default is ``0``. + +- ``http-client-threads`` - indicates the maximum number of threads that should + be used to send HA messages to its peers. A value of ``0`` instructs the server + to use the same number of threads that the Kea core is using for DHCP + multi-threading. The default is ``0``. + +These parameters are grouped together under a map element, ``multi-threading``, +as illustrated below: + +:: + + "Dhcp4": { + "hooks-libraries": [ + { + "library": "/usr/lib/kea/hooks/libdhcp_lease_cmds.so", + "parameters": { } + }, + { + "library": "/usr/lib/kea/hooks/libdhcp_ha.so", + "parameters": { + "high-availability": [ { + "this-server-name": "server1", + "multi-threading": { + "enable-multi-threading": true, + "http-dedicated-listener": true, + "http-listener-threads": 4, + "http-client-threads": 4 + }, + "peers": [ + // This is the configuration of this server instance. + { + "name": "server1", + // This specifies the URL of our server instance. + // Since the HA+MT uses a direct connection, the + // DHCPv4 server open its own socket. Note that it + // must be different than the one used by the CA + // (typically 8000). In this example, 8001 is used. + "url": "http://192.0.2.1:8001/", + // This server is primary. The other one must be + // secondary. + "role": "primary" + }, + // This is the configuration of our HA peer. + { + "name": "server2", + // This specifies the URL of our server instance. + // Since the HA+MT uses a direct connection, the + // DHCPv4 server open its own socket. Note that it + // must be different than the one used by the CA + // (typically 8000). In this example, 8001 is used. + "url": "http://192.0.2.2:8001/", + // The partner is a secondary. This server is a + // primary as specified in the previous "peers" + // entry and in "this-server-name" before that. + "role": "secondary" + }, + ... + ], + ... + }, + ... + ] + } + }, + ... + ], + ... + } + + +In the example above, HA+MT is enabled with four threads for the listener and +four threads for the client. + +.. note:: + + It is essential to configure the ports correctly. One common mistake is to + configure CA to listen on port 8000 and also configure dedicated listeners on + port 8000. In such a configuration, the communication will still work over CA, + but it will be slow and the DHCP server will fail to bind sockets. + Administrators should ensure that dedicated listeners use a different port + (8001 is a suggested alternative); if ports are misconfigured or the ports + dedicated to CA are used, the performance bottlenecks caused by the + single-threaded nature of CA and the sequential nature of the UNIX socket + that connects CA to DHCP servers will nullify any performance gains offered + by HA+MT. + +.. _ha-parked-packet-limit: + +Parked-Packet Limit +~~~~~~~~~~~~~~~~~~~ + +Kea servers contain a mechanism by which the response to a client packet may +be held, pending completion of hook library work. We refer to this as "parking" +the packet. The HA hook library makes use of this mechanism. When an HA server +needs to send a lease update to its peer(s) to notify it of the change to the +lease, it will "park" the client response until the peer acknowledges the lease +update. At that point, the server will "unpark" the response and send it to the +client. This applies to client queries which cause lease changes, such as +DHCPREQUEST for DHCPv4 and Request, Renew, and Rebind for DHCPv6. It does not +apply to DHPCDISCOVERs (v4) or Solicits (v6). + +There is a global parameter, ``parked-packet-limit``, that may be used to limit +the number of responses that may be parked at any given time. This acts as a +form of congestion handling and protects the server from being swamped when the +volume of client queries is outpacing the server's ability to respond. Once the +limit is reached, the server emits a log and drops any new responses until +parking spaces are available. + +In general, smaller values for the parking lot limit are likely to cause more +drops but with shorter response times. Larger values are likely to result in +fewer drops but with longer response times. Currently, the default value for +``parked-packet-limit`` is 256. + +.. warning:: + + Using too small a value may result in an unnecessarily high drop rate, while + using too large a value may lead to response times that are simply too long + to be useful. A value of 0, while allowed, disables the limit altogether, but + this is highly discouraged as it may lead to Kea servers becoming + unresponsive to clients. Choosing the best value is very site-specific; we + recommend users initially leave it at the default value of 256 and observe + how the system behaves over time with varying load conditions. + +:: + + "Dhcp6": { + // Limit the number of concurrently parked packets to 128. + "parked-packet-limit": 128, + "hooks-libraries": [ + { + "library": "/usr/lib/kea/hooks/libdhcp_lease_cmds.so", + "parameters": { } + }, + { + "library": "/usr/lib/kea/hooks/libdhcp_ha.so", + "parameters": { + "high-availability": [ { + "this-server-name": "server1", + ... + } ] + } + }, + ... + ], + ... + } + +.. note:: + + While ``parked-packet-limit`` is not specifically tied to HA, currently HA + is the only ISC hook that employs packet parking. + +.. _ha-maintenance: + +Controlled Shutdown and Maintenance of DHCP Servers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Having a pair of servers providing High Availability allows for controlled +shutdown and maintenance of those servers without disrupting the DHCP service. +For example, an administrator can perform an upgrade of one of the servers while +the other one continues to respond to DHCP queries. When the first server is +upgraded and back online, the upgrade can be performed for the second server. + +A typical problem reported with early versions of the High Availability hook +library was that the administrator did not have direct control over the state of +the DHCP server. Shutting down one of the servers for maintenance did not +necessarily cause the other server to start responding to all DHCP queries, +because the failure-detection algorithm described in :ref:`ha-scope-transition` +requires that the partner not respond for a configured period of time and, +depending on the configuration, may also require that a number of DHCP requests +not be responded to for a specified period of time. The maintenance procedure, +however, requires that the administrator be able to instruct one of the servers +to instantly start serving all DHCP clients, and the other server to instantly +stop serving any DHCP clients, so it can be safely shut down. + +The maintenance feature of the High Availability hook library addresses this +situation. The :isccmd:`ha-maintenance-start` command was introduced to allow the +administrator to put the pairs of the active servers in a state in which one of +them is responding to all DHCP queries and the other one is awaiting shutdown. + +Suppose that the HA setup includes two active servers, ``server1`` and +``server2``, and the latter needs to be shut down for maintenance. +The administrator can send the :isccmd:`ha-maintenance-start` command to ``server1``, +as this is the server which is going to handle the DHCP traffic while the other +one is offline. ``server1`` responds with an error if its state or the partner's +state does not allow for a maintenance shutdown: for example, if maintenance is +not supported for the backup server or if the server is in the ``terminated`` +state. Also, an error is returned if the :isccmd:`ha-maintenance-start` request was +already sent to the other server. + +Upon receiving the :isccmd:`ha-maintenance-start` command, ``server1`` sends the +:isccmd:`ha-maintenance-notify` command to ``server2`` to put it in the +``in-maintenance`` state. If ``server2`` confirms, ``server1`` transitions to +the ``partner-in-maintenance`` state. This is similar to the ``partner-down`` +state, except that in the ``partner-in-maintenance`` state ``server1`` continues +to send lease updates to ``server2`` until the administrator shuts down +``server2``. ``server1`` now responds to all DHCP queries. + +The administrator can now safely shut down ``server2`` in the ``in-maintenance`` +state and perform any necessary maintenance actions. While ``server2`` is +offline, ``server1`` will obviously not be able to communicate with its partner, +so it will immediately transition to the ``partner-down`` state; it will +continue to respond to all DHCP queries but will no longer send lease updates to +``server2``. Restarting ``server2`` after the maintenance will trigger normal +state negotiation, lease-database synchronization, and, ultimately, a transition +to the normal ``load-balancing`` or ``hot-standby`` state. Maintenance can then +be performed on ``server1``, after sending the :isccmd:`ha-maintenance-start` command +to ``server2``. + +If the :isccmd:`ha-maintenance-start` command was sent to the server and the server +has transitioned to the ``partner-in-maintenance`` state, it is possible to +transition both it and its partner back to their previous states to resume the +normal operation of the HA pair. This is achieved by sending the +:isccmd:`ha-maintenance-cancel` command to the server that is in the +``partner-in-maintenance`` state. However, if the server has already +transitioned to the ``partner-down`` state as a result of detecting that the +partner is offline, canceling the maintenance is no longer possible. In that +case, it is necessary to restart the other server and allow it to complete its +normal state negotiation process. + +If the server has many relationships with different partners, the ``ha-maintenance-start`` +command attempts to transition all of the relationships into the +``partner-in-maintenance`` state by sending the ``ha-mainteance-notify`` to all +partner servers. If this step fails for any server an error is returned. +In that case, send the ``ha-maintenance-cancel`` command to resume normal +operation and fix the issue. + + +Upgrading From Older HA Versions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To upgrade from an older HA hook library to the current version, the +administrator must shut down one of the servers and rely on the failover +mechanism to force the online server to transition to the ``partner-down`` state, +where it starts serving all DHCP clients. Once the hook library on the first +server is upgraded to a current version, the :isccmd:`ha-maintenance-start` command +can be used to upgrade the second server. + +In such a case, shut down the server running the old version. Next, send the +:isccmd:`ha-maintenance-start` command to the server that has been upgraded. This +server should immediately transition to the ``partner-down`` state as it cannot +communicate with its offline partner. In the ``partner-down`` state the first +(upgraded) server will respond to all DHCP requests, allowing the administrator +to perform the upgrade on the second server. + +.. note:: + + Do not send the :isccmd:`ha-maintenance-start` command while the server running the + old hook library is still online. The server receiving this command will + return an error. + + +.. _ha-control-commands: + +Control Commands for High Availability +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Even though the HA hook library is designed to automatically resolve issues with +DHCP service interruptions by redirecting the DHCP traffic to a surviving server +and synchronizing the lease database as needed, it may be useful for the +administrator to have more control over both servers' behavior. In particular, +it may be useful to be able to trigger lease-database synchronization on demand, +or to manually set the HA scopes that are being served. + +The backup server can sometimes be used to handle DHCP traffic if both active +servers are down. The backup server does not perform the failover function +automatically; thus, in order to use the backup server to respond to DHCP +queries, the server administrator must enable this function manually. + +The following sections describe commands supported by the HA hook library which +are available for the administrator. + +.. isccmd:: ha-sync +.. _command-ha-sync: + +The ``ha-sync`` Command +----------------------- + +The :isccmd:`ha-sync` command instructs the server to synchronize its local lease +database with the selected peer. The server fetches all leases from the peer and +updates any locally stored leases which are older than those fetched. It also +creates new leases when any of those fetched do not exist in the local database. +All leases that are not returned by the peer but are in the local database are +preserved. The database synchronization is unidirectional; only the database on +the server to which the command has been sent is updated. To synchronize the +peer's database, a separate :isccmd:`ha-sync` command must be issued to that peer. + +Database synchronization may be triggered for both active and backup server +types. The :isccmd:`ha-sync` command has the following structure (in a DHCPv4 example): + +:: + + { + "command": "ha-sync", + "service": [ "dhcp4 "], + "arguments": { + "server-name": "server2", + "max-period": 60 + } + } + +When the server receives this command it first disables the DHCP service of the +server from which it will be fetching leases, by sending the :isccmd:`dhcp-disable` +command to that server. The ``max-period`` parameter specifies the maximum +duration (in seconds) for which the DHCP service should be disabled. If the DHCP +service is successfully disabled, the synchronizing server fetches leases from +the remote server by issuing one or more :isccmd:`lease4-get-page` commands. When the +lease-database synchronization is complete, the synchronizing server sends the +:isccmd:`dhcp-enable` command to the peer to re-enable its DHCP service. + +The ``max-period`` value should be sufficiently long to guarantee that it does +not elapse before the synchronization is completed. Otherwise, the DHCP server +will automatically enable its DHCP function while the synchronization is still +in progress. If the DHCP server subsequently allocates any leases during the +synchronization, those new (or updated) leases will not be fetched by the +synchronizing server, leading to database inconsistencies. + +.. isccmd:: ha-scopes +.. _command-ha-scopes: + +The ``ha-scopes`` Command +------------------------- + +This command allows an administrator to modify the HA scopes being served. +Consult :ref:`ha-load-balancing-config` and :ref:`ha-hot-standby-config` to +learn which scopes are available for the different HA modes of operation. The +:isccmd:`ha-scopes` command has the following structure (in a DHCPv4 example): + +:: + + { + "command": "ha-scopes", + "service": [ "dhcp4" ], + "arguments": { + "scopes": [ "HA_server1", "HA_server2" ], + "server-name": "server2" + } + } + +This command configures the server to handle traffic from both the "HA_server1" +and "HA_server2" scopes. To disable all scopes specify an empty list: + +:: + + { + "command": "ha-scopes", + "service": [ "dhcp4 "], + "arguments": { + "scopes": [ ], + "server-name": "server2" + } + } + +The optional ``server-name`` parameter specifies a name of one of the partners belonging +to the HA relationship this command pertains to. This parameter can be omitted if the +server receiving this command has only one HA relationship in the configuration. + +.. isccmd:: ha-continue +.. _command-ha-continue: + +The ``ha-continue`` Command +--------------------------- + +This command is used to resume the operation of the paused HA state machine, as +described in :ref:`ha-pause-state-machine`. It takes no arguments, so the +command structure is simply: + +:: + + { + "command": "ha-continue", + "service": [ "dhcp4" ], + "arguments": { + "scopes": [ ], + "server-name": "server2" + } + } + +The optional ``server-name`` parameter specifies a name of one of the partners belonging +to the HA relationship this command pertains to. This parameter can be omitted if the +server receiving this command has only one HA relationship in the configuration. + +.. isccmd:: ha-heartbeat +.. _command-ha-heartbeat: + +The ``ha-heartbeat`` Command +---------------------------- + +The :ref:`ha-server-states` section describes how the :isccmd:`ha-heartbeat` command +is used by a pair of active HA servers to detect one partner's failure. This +command, however, can also be sent by the system administrator to one or both +servers to check their HA state. This allows a monitoring system to be deployed +on the HA enabled servers to periodically check whether they are operational or +whether any manual intervention is required. The :isccmd:`ha-heartbeat` command takes +no arguments: + +:: + + { + "command": "ha-heartbeat", + "service": [ "dhcp4" ], + "arguments": { + "scopes": [ ], + "server-name": "server2" + } + } + +The optional ``server-name`` parameter specifies a name of one of the partners belonging +to the HA relationship this command pertains to. This parameter can be omitted if the +server receiving this command has only one HA relationship in the configuration. + +Upon successful communication with the server, a response similar to this should +be returned: + +:: + + { + "result": 0, + "text": "HA peer status returned.", + "arguments": + { + "state": "partner-down", + "date-time": "Thu, 07 Nov 2019 08:49:37 GMT", + "scopes": [ "server1" ], + "unsent-update-count": 123 + } + } + +The returned ``state`` value should be one of the values listed in +:ref:`ha-server-states`. In the example above, the ``partner-down`` state is +returned, which indicates that the server which responded to the command +believes that its partner is offline; thus, it is serving all DHCP requests sent +to the servers. To ensure that the partner is indeed offline, the administrator +should send the :isccmd:`ha-heartbeat` command to the second server. If sending the +command fails, e.g. due to an inability to establish a TCP connection to the +Control Agent, or if the Control Agent reports issues with communication with +the DHCP server, it is very likely that the server is not running. + +The ``date-time`` parameter conveys the server's notion of time. + +The ``unsent-update-count`` value is a cumulative count of all unsent lease +updates since the server was booted; its value is set to 0 when the server is +started. It is never reset to 0 during the server's operation, even after the +partner synchronizes the database. It is incremented by the partner sending the +heartbeat response when it cannot send the lease update. For example, suppose +the failure is a result of a temporary communication interruption. In that case, +the partner receiving the ``partner-down`` heartbeat response tracks the value +changes and can determine, once communication is reestablished, whether there +are any new lease updates that it did not receive. If the values on both servers +do not match, it is an indication that the partner should synchronize its lease +database. A non-zero value itself is not an indication of any present issues +with lease updates, but a constantly incrementing value is. + +The typical response returned by one server when both are +operational is: + +:: + + { + "result": 0, + "text": "HA peer status returned.", + "arguments": + { + "state": "load-balancing", + "date-time": "Thu, 07 Nov 2019 08:49:37 GMT", + "scopes": [ "server1" ], + "unsent-update-count": 0 + } + } + +In most cases, the :isccmd:`ha-heartbeat` command should be sent to both HA-enabled +servers to verify the state of the entire HA setup. In particular, if one of the +servers indicates that it is in the ``load-balancing`` state, it means that this +server is operating as if its partner is functional. When a partner goes down, +it takes some time for the surviving server to realize it. The +:ref:`ha-scope-transition` section describes the algorithm which the surviving +server follows before it transitions to the ``partner-down`` state. If the +:isccmd:`ha-heartbeat` command is sent during the time window between the failure of +one of the servers and the transition of the surviving server to the +``partner-down`` state, the response from the surviving server does not reflect +the failure. Resending the command detects the failure once the surviving server +has entered the ``partner-down`` state. + +.. note: + + Always send the :isccmd:`ha-heartbeat` command to both active HA servers to check + the state of the entire HA setup. Sending it to only one of the servers may + not reflect issues that just began with one of the servers. + +.. isccmd:: ha-status-get +.. _command-ha-status-get: + +The ``status-get`` Command +-------------------------- + +:isccmd:`status-get` is a general-purpose command supported by several Kea daemons, +not only the DHCP servers. However, when sent to a DHCP server with HA enabled, +it can be used to get insight into the details of the HA-specific server status. +Not only does the response contain the status information of the server +receiving this command, but also the information about its partner if it is +available. + +The following is an example response to the :isccmd:`status-get` command, including +the HA status of two ``load-balancing`` servers: + +.. code-block:: json + + { + "result": 0, + "text": "", + "arguments": { + "pid": 1234, + "uptime": 3024, + "reload": 1111, + "high-availability": [ + { + "ha-mode": "load-balancing", + "ha-servers": { + "local": { + "role": "primary", + "scopes": [ "server1" ], + "state": "load-balancing", + "server-name": "server1" + }, + "remote": { + "age": 10, + "in-touch": true, + "role": "secondary", + "last-scopes": [ "server2" ], + "last-state": "load-balancing", + "communication-interrupted": true, + "connecting-clients": 2, + "unacked-clients": 1, + "unacked-clients-left": 2, + "analyzed-packets": 8, + "server-name": "server2" + } + } + } + ], + "multi-threading-enabled": true, + "thread-pool-size": 4, + "packet-queue-size": 64, + "packet-queue-statistics": [ 0.2, 0.1, 0.1 ], + "sockets": { + "status": "ready" + } + } + } + +The ``high-availability`` argument is a list which currently comprises only one +element. + +The ``ha-servers`` map contains two structures: ``local`` and ``remote``. The +former contains the status information of the server which received the command, +while the latter contains the status information known to the local server about +the partner. The ``role`` of the partner server is gathered from the local +configuration file, and thus should always be available. The remaining status +information, such as ``last-scopes`` and ``last-state``, is not available until +the local server communicates with the remote by successfully sending the +:isccmd:`ha-heartbeat` command. If at least one such communication has taken place, +the returned value of the ``in-touch`` parameter is set to ``true``. By +examining this value, the command's sender can determine whether the information +about the remote server is reliable. + +The ``last-scopes`` and ``last-state`` parameters contain information about the +HA scopes served by the partner and its state. This information is gathered +during the :isccmd:`ha-heartbeat` command exchange, so it may not be accurate if a +communication problem occurs between the partners and this status information is +not refreshed. In such a case, it may be useful to send the :isccmd:`status-get` +command to the partner server directly to check its current state. The ``age`` +parameter specifies the age of the information from the partner, in seconds. + +The ``communication-interrupted`` boolean value indicates whether the server +receiving the :isccmd:`status-get` command (the local server) has been unable to +communicate with the partner longer than the duration specified as +``max-response-delay``. In such a situation, the active servers are considered +to be in the ``communication-interrupted`` state. At this point, the local +server may start monitoring the DHCP traffic directed to the partner to see if +the partner is responding to this traffic. More about the failover procedure can +be found in :ref:`ha-load-balancing-config`. + +The ``connecting-clients``, ``unacked-clients``, ``unacked-clients-left``, and +``analyzed-packets`` parameters were introduced along with the +``communication-interrupted`` parameter and they convey useful information about +the state of the DHCP traffic monitoring in the ``communication-interrupted`` +state. Once the server leaves the ``communication-interrupted`` state, these +parameters are all reset to 0. + +These parameters have the following meaning in the ``communication-interrupted`` +state: + +- ``connecting-clients`` - this is the number of different clients which have + attempted to get a lease from the remote server. These clients are + differentiated by their MAC address and client identifier (in DHCPv4) or DUID + (in DHCPv6). This number includes "unacked" clients (for which the "secs" + field or "elapsed time" value exceeded the ``max-response-delay``). + +- ``unacked-clients`` - this is the number of different clients which have been + considered "unacked", i.e. the clients which have been trying to get the + lease longer than the value of the "secs" field, or for which the + "elapsed time" exceeded the ``max-response-delay`` setting. + +- ``unacked-clients-left`` - this indicates the number of additional clients + which have to be considered "unacked" before the server enters the + ``partner-down`` state. This value decreases when the ``unacked-clients`` + value increases. The local server enters the ``partner-down`` state when this + value decreases to 0. + +- ``analyzed-packets`` - this is the total number of packets directed to the + partner server and analyzed by the local server since entering the + communication interrupted state. It includes retransmissions from the same + clients. + +Monitoring these values helps to predict when the local server will enter the +``partner-down`` state or to understand why the server has not yet entered this +state. + +The ``ha-mode`` parameter returns the HA mode of operation selected using the +``mode`` parameter in the configuration file. It can hold one of the following +values: ``load-balancing``, ``hot-standby``, or ``passive-backup``. + +The :isccmd:`status-get` response has the format described above only in the +``load-balancing`` and ``hot-standby`` modes. In the ``passive-backup`` mode the +``remote`` map is not included in the response because in this mode there is +only one active server (local). The response includes no information about the +status of the backup servers. + +.. isccmd:: ha-maintenance-start +.. _command-ha-maintenance-start: + +The ``ha-maintenance-start`` Command +------------------------------------ + +This command is used to initiate the transition of the server's partners into the +``in-maintenance`` state and the transition of the server receiving the command +into the ``partner-in-maintenance`` state in each HA relationship. See the +:ref:`ha-maintenance` section for details. + +:: + + { + "command": "ha-maintenance-start", + "service": [ "dhcp4" ] + } + +.. isccmd:: ha-maintenance-cancel +.. _command-ha-maintenance-cancel: + +The ``ha-maintenance-cancel`` Command +------------------------------------- + +This command is used to cancel the maintenance previously initiated using the +:isccmd:`ha-maintenance-start` command. The server receiving this command will first +send :isccmd:`ha-maintenance-notify`, with the ``cancel`` flag set to ``true``, to its +partners. Next, the server reverts from the ``partner-in-maintenance`` state to +its previous state. See the :ref:`ha-maintenance` section for details. + +:: + + { + "command": "ha-maintenance-cancel", + "service": [ "dhcp4" ] + } + +.. isccmd:: ha-maintenance-notify +.. _command-ha-maintenance-notify: + +The ``ha-maintenance-notify`` Command +------------------------------------- + +This command is sent by the server receiving the :isccmd:`ha-maintenance-start` or the +:isccmd:`ha-maintenance-cancel` command to its partner, to cause the partner to +transition to the ``in-maintenance`` state or to revert from this state to a +previous state. See the :ref:`ha-maintenance` section for details. + +:: + + { + "command": "ha-maintenance-notify", + "service": [ "dhcp4" ], + "arguments": { + "cancel": false, + "server-name": "server2" + } + } + +The optional ``server-name`` parameter specifies a name of one of the partners belonging +to the HA relationship this command pertains to. This parameter can be omitted if the +server receiving this command has only one HA relationship in the configuration. + +.. warning:: + + The :isccmd:`ha-maintenance-notify` command is not meant to be used by system + administrators. It is used for internal communication between a pair of + HA-enabled DHCP servers. Direct use of this command is not supported and may + produce unintended consequences. + +.. isccmd:: ha-reset +.. _command-ha-reset: + +The ``ha-reset`` Command +------------------------ + +This command causes the server to reset its High Availability state machine by +transitioning it to the ``waiting`` state. A partner in the +``communication-recovery`` state may send this command to cause the server +to synchronize its lease database. Database synchronization is required when the +partner has failed to send all lease database updates after re-establishing +connection after a temporary connection failure. It is also required when the +``delayed-updates-limit`` is exceeded, when the server is in the +``communication-recovery`` state. + +A server administrator may send this command to reset a misbehaving state +machine. + +:: + + { + "command": "ha-reset", + "service": [ "dhcp4" ], + "arguments": { + "server-name": "server2" + } + } + +The optional ``server-name`` parameter specifies a name of one of the partners belonging +to the HA relationship this command pertains to. This parameter can be omitted if the +server receiving this command has only one HA relationship in the configuration. + +It elicits the response: + +:: + + { + "result": 0, + "text": "HA state machine reset." + } + +If the server receiving this command is already in the ``waiting`` state, the +command has no effect. + +.. isccmd:: ha-sync-complete-notify +.. _command-ha-sync-complete-notify: + +The ``ha-sync-complete-notify`` Command +--------------------------------------- + +A server sends this command to its partner to signal that it has completed +lease-database synchronization. The partner may enable its DHCP service if it +can allocate new leases in its current state. The partner does not enable the +DHCP service in the ``partner-down`` state until it sends a successful :isccmd:`ha-heartbeat` +test to its partner server. If the connection is still unavailable, the server +in the ``partner-down`` state enables its own DHCP service to continue +responding to clients. + +:: + + { + "command": "ha-sync-complete-notify", + "service": [ "dhcp4" ], + "arguments": { + "origin": 2000, + "server-name": "server2" + } + } + +The optional ``server-name`` parameter specifies a name of one of the partners belonging +to the HA relationship this command pertains to. This parameter can be omitted if the +server receiving this command has only one HA relationship in the configuration. + +The ``origin`` parameter is used to select the HA service for which the receiving server should +enable the DHCP service when it receives this notification. This is the same origin the +sending server used previously to disable the DHCP service before synchronization. + +It elicits the response: + +:: + + { + "result": 0, + "text": "Server successfully notified about the synchronization completion." + } + +.. warning:: + + The :isccmd:`ha-sync-complete-notify` command is not meant to be used by system + administrators. It is used for internal communication between a pair of + HA-enabled DHCP servers. Direct use of this command is not supported and may + produce unintended consequences. + + +.. _ha-hub-and-spoke: + +Hub and Spoke Configuration +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The hub-and-spoke is a common arrangement of the DHCP servers for resiliency. It contains +one central server and multiple branch servers. The branch servers are the primary servers +in the ``hot-standby`` mode and respond to the local DHCP traffic in their respective +locations. The central server acts as a standby server for each branch server. +It maintains independent state machines with the branch servers, called relationships. +If one of the branch servers experiences a failure, the central server can take over its +DHCP traffic. In this case, we say that one of the central server's relationships is in +the ``partner-down`` state. The remaining relationships may still be in the ``hot-standby`` +state and not actively respond to DHCP traffic. When the branch server becomes active again, +it synchronizes the lease database with the central server, and the central server becomes +fully passive again. In rare cases, when multiple branch servers stop, the central server +takes responsibility for all their traffic (possibly the entire DHCP traffic in the network +when all branch servers are down). A simple hub-and-spoke arrangement consisting of two +branch servers and one central server is shown below. + +:: + + + +----- Central Server ------+ + | | + +----------+ relationship 1 | +----------+----------+ | relationship 2 +----------+ + | Server 1 |===================| Server 2 | Server 4 |===================| Server 3 | + +----------+ | +----------+----------+ | +----------+ + | | + +---------------------------+ + +Each branch server's configuration comprises a set of subnets appropriate for the branch +server. Different branch servers serve different subnets. The central server's configuration +comprises all subnets of the branch servers so that it can respond to the DHCP traffic +directed to any of the failing branch servers. The subnets in the central server must be +grouped into relationships like in the snippet below: + +.. code-block:: json + + { + "Dhcp6": { + "interfaces-config": { + "interfaces": [ "enp0s8", "enp0s9" ] + }, + "hooks-libraries": [ + { + "library": "/usr/lib/kea/hooks/libdhcp_lease_cmds.so", + "parameters": {} + }, + { + "library": "/usr/lib/kea/hooks/libdhcp_ha.so", + "parameters": { + "high-availability": [ + { + "this-server-name": "server2", + "mode": "hot-standby", + "multi-threading": { + "enable-multi-threading": true, + "http-dedicated-listener": true, + "http-listener-threads": 4, + "http-client-threads": 4 + }, + "peers": [ + { + "name": "server1", + "url": "http://192.168.56.66:8000/", + "role": "primary", + "auto-failover": true + }, + { + "name": "server2", + "url": "http://192.168.56.33:8000/", + "role": "standby", + "auto-failover": true + } + ] + }, + { + "this-server-name": "server4", + "mode": "hot-standby", + "multi-threading": { + "enable-multi-threading": true, + "http-dedicated-listener": true, + "http-listener-threads": 4, + "http-client-threads": 4 + }, + "peers": [ + { + "name": "server3", + "url": "http://192.168.57.99:8000/", + "role": "primary", + "auto-failover": true + }, + { + "name": "server4", + "url": "http://192.168.57.33:8000/", + "role": "standby", + "auto-failover": true + } + ] + } + ] + } + } + ], + "subnet6": [ + { + "id": 1, + "subnet": "2001:db8:1::/64", + "pools": [ { "pool": "2001:db8:1::/80" } ], + "interface": "enp0s8", + "user-context": { + "ha-server-name": "server2" + } + }, + { + "id": 2, + "subnet": "2001:db8:2::/64", + "pools": [ { "pool": "2001:db8:2::/80" } ], + "interface": "enp0s9", + "user-context": { + "ha-server-name": "server4" + } + } + ] + } + } + + + + +The peer names in the relationships must be unique. The user context for each subnet contains +the ``ha-server-name`` parameter associating a subnet with a relationship. The ``ha-server-name`` +can be any of the peer names in the relationship. Suppose a relationship contains peer names +``server1`` and ``server2``. It doesn't matter whether the ``ha-server-name`` is ``server1`` or +``server2``. In both cases, it associates a subnet with that relationship. + +It is not required to specify the ``ha-server-name`` in the branch servers, assuming that the +branch servers only contain the subnets they serve. Consider the following configuration for +branch ``server3``: + +.. code-block:: json + + { + "Dhcp6": { + "interfaces-config": { + "interfaces": [ "enp0s8" ] + }, + "hooks-libraries": [ + { + "library": "/usr/lib/kea/hooks/libdhcp_lease_cmds.so", + "parameters": {} + }, + { + "library": "/usr/lib/kea/hooks/libdhcp_ha.so", + "parameters": { + "high-availability": [ + { + "this-server-name": "server3", + "mode": "hot-standby", + "multi-threading": { + "enable-multi-threading": true, + "http-dedicated-listener": true, + "http-listener-threads": 4, + "http-client-threads": 4 + }, + "peers": [ + { + "name": "server3", + "url": "http://192.168.57.99:8000/", + "role": "primary", + "auto-failover": true + }, + { + "name": "server4", + "url": "http://192.168.57.33:8000/", + "role": "standby", + "auto-failover": true + } + ] + } + ] + } + } + ], + "subnet6": [ + { + "id": 2, + "subnet": "2001:db8:2::/64", + "pools": [ + { + "pool": "2001:db8:2::/80" + } + ], + "interface": "enp0s8", + "user-context": { + "ha-server-name": "server3" + } + } + ] + } + } + +.. note:: + + Even though it is not required to include the ``ha-server-name`` user context parameters in the + branch servers, we recommend including them. The servers fetch all leases from the + partners during the database synchronization. If the subnets are not explicitly associated with + the relationship, the branch server inserts all fetched leases from the central server (including + those from other relationships) into its database. Specifying ``ha-server-name`` parameter for + each configured subnet in the branch server guarantees that only the leases belonging to its + relationship are inserted into the branch server's database. + +.. note:: + + The peer names in the branch servers must match the peer names in the respective central + server's relationships because these names are used for signaling between the HA partners. diff --git a/doc/sphinx/arm/hooks-host-cache.rst b/doc/sphinx/arm/hooks-host-cache.rst new file mode 100644 index 0000000..ebf0cd9 --- /dev/null +++ b/doc/sphinx/arm/hooks-host-cache.rst @@ -0,0 +1,324 @@ +.. ischooklib:: libdhcp_host_cache.so +.. _hooks-host-cache: + +``libdhcp_host_cache.so``: Host Cache Reservations for Improved Performance +=========================================================================== + +Some database backends, such as RADIUS, are slow and may take +a long time to respond. Since Kea in general is synchronous, backend +performance directly affects DHCP performance. To minimize the +impact and improve performance, the Host Cache library provides a way to +cache information from the database locally. This includes negative +caching, i.e. the ability to remember that there is no client +information in the database. + +.. note:: + + :ischooklib:`libdhcp_host_cache.so` is available only to ISC customers with + a paid support contract. For more information on subscription options, + please complete the form at https://www.isc.org/contact. + +.. note:: + + This library can only be loaded by the :iscman:`kea-dhcp4` or + :iscman:`kea-dhcp6` process. + +In principle, this hook library can be used with any backend that may +introduce performance degradation (MySQL, PostgreSQL or RADIUS). Host Cache +must be loaded for the RADIUS accounting mechanism to work. + +The Host Cache hook library is very simple. It takes only one +optional parameter (``maximum``), which defines the maximum number of hosts +to be cached. If not specified, the default value of 0 is used, which +means there is no limit. This hook library can be loaded the same way as +any other hook library; for example, this configuration could be used: + +:: + + "Dhcp4": { + + # Your regular DHCPv4 configuration parameters here. + + "hooks-libraries": [ + { + "library": "/usr/local/lib/kea/hooks/libdhcp_host_cache.so", + "parameters": { + + # Tells Kea to never cache more than 1000 hosts. + "maximum": 1000 + + } + } ], + ... + } + +Once loaded, the Host Cache hook library provides a number of new +commands which can be used either over the control channel (see +:ref:`ctrl-channel-client`) or the RESTful API (see +:ref:`agent-overview`). An example RESTful API client is described in +:ref:`shell-overview`. The following sections describe the commands +available. + +.. isccmd:: cache-flush +.. _command-cache-flush: + +The ``cache-flush`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This command allows removal of a specified number of cached host +entries. It takes one parameter, which defines the number of hosts to be +removed. An example usage looks as follows: + +:: + + { + "command": "cache-flush", + "arguments": 1000 + } + +This command removes 1000 hosts; to delete *all* cached +hosts, use :isccmd:`cache-clear` instead. The hosts are stored in FIFO +(first-in, first-out) order, so the oldest entries are always removed. + +.. isccmd:: cache-clear +.. _command-cache-clear: + +The ``cache-clear`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This command allows removal of all cached host entries. An example usage +looks as follows: + +:: + + { + "command": "cache-clear" + } + +This command removes all hosts. To delete only a certain +number of cached hosts, please use :isccmd:`cache-flush` instead. + +.. isccmd:: cache-size +.. _command-cache-size: + +The ``cache-size`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This command returns the number of host entries. An example usage looks +as follows: + +:: + + { + "command": "cache-size" + } + +.. isccmd:: cache-write +.. _command-cache-write: + +The ``cache-write`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In general, the cache content is considered a runtime state and the +server can be shut down or restarted as usual; the cache is then +repopulated after restart. However, there are some cases when it is +useful to store the contents of the cache. One such case is RADIUS, +where the cached hosts also retain additional cached RADIUS attributes; +there is no easy way to obtain this information again, because renewing +clients send their packet to the DHCP server directly. Another use case +is when an administrator wants to restart the server and, for performance reasons, +wants it to start with a hot (populated) cache. + +This command allows writing the contents of the in-memory cache to a +file on disk. It takes one parameter, which defines the filename. An +example usage looks as follows: + +:: + + { + "command": "cache-write", + "arguments": "/tmp/kea-host-cache.json" + } + +This causes the contents to be stored in the ``/tmp/kea-host-cache.json`` +file. That file can then be loaded with the :isccmd:`cache-load` command or +processed by any other tool that is able to understand JSON format. + +.. isccmd:: cache-load +.. _command-cache-load: + +The ``cache-load`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +See the previous section for a discussion of use cases where it may be +useful to write and load contents of the host cache to disk. + +This command allows the contents of a file on disk to be loaded into an +in-memory cache. It takes one parameter, which defines the filename. An +example usage looks as follows: + +:: + + { + "command": "cache-load", + "arguments": "/tmp/kea-host-cache.json" + } + +This command stores the contents to the ``/tmp/kea-host-cache.json`` +file. That file can then be loaded with the :isccmd:`cache-load` command or +processed by any other tool that is able to understand JSON format. + +.. isccmd:: cache-get +.. _command-cache-get: + +The ``cache-get`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~ + +This command is similar to :isccmd:`cache-write`, but instead of writing the cache +contents to disk, it returns the contents to whoever sent the command. + +This command allows the contents of a file on disk to be loaded into an +in-memory cache. It takes one parameter, which defines the filename. An +example usage looks as follows: + +:: + + { + "command": "cache-get" + } + +This command returns all the cached hosts; the response +may be large. + +.. isccmd:: cache-get-by-id +.. _command-cache-get-by-id: + +The ``cache-get-by-id`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This command is similar to :isccmd:`cache-get`, but instead of returning the whole +content it returns only the entries matching the given identifier. + +It takes one parameter, which defines the identifier of wanted cached +host reservations. An example usage looks as follows: + +:: + + { + "command": "cache-get-by-id", + "arguments": { + "hw-address": "01:02:03:04:05:06" + } + } + +This command returns all the cached hosts with the given hardware +address. + +.. isccmd:: cache-insert +.. _command-cache-insert: + +The ``cache-insert`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This command may be used to manually insert a host into the cache; there +are very few use cases when this command might be useful. This command +expects its arguments to follow the usual syntax for specifying host +reservations (see :ref:`host-reservation-v4` or +:ref:`host-reservation-v6`), with one difference: the ``subnet-id`` +value must be explicitly specified. + +An example command to insert an IPv4 host into the host cache +looks as follows: + +:: + + { + "command": "cache-insert", + "arguments": { + "hw-address": "01:02:03:04:05:06", + "subnet-id4": 4, + "subnet-id6": 0, + "ip-address": "192.0.2.100", + "hostname": "somehost.example.org", + "client-classes4": [ ], + "client-classes6": [ ], + "option-data4": [ ], + "option-data6": [ ], + "next-server": "192.0.0.2", + "server-hostname": "server-hostname.example.org", + "boot-file-name": "bootfile.efi", + "host-id": 0 + } + } + +An example command to insert an IPv6 host into the host cache +looks as follows: + +:: + + { + "command": "cache-insert", + "arguments": { + "hw-address": "01:02:03:04:05:06", + "subnet-id4": 0, + "subnet-id6": 6, + "ip-addresses": [ "2001:db8::cafe:babe" ], + "prefixes": [ "2001:db8:dead:beef::/64" ], + "hostname": "", + "client-classes4": [ ], + "client-classes6": [ ], + "option-data4": [ ], + "option-data6": [ ], + "next-server": "0.0.0.0", + "server-hostname": "", + "boot-file-name": "", + "host-id": 0 + } + } + +.. isccmd:: cache-remove +.. _command-cache-remove: + +The ``cache-remove`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Sometimes it is useful to remove a single entry from the host cache: for +example, consider a situation where the device is active, Kea has already +provided configuration, and the host entry is in cache. As a result of +administrative action (e.g. the customer hasn't paid their bills or has +been upgraded to better service), the information in the backend database +(e.g. MySQL or RADIUS) is being updated. However, since the cache is in use, +Kea does not notice the change as the cached values are used. The +:isccmd:`cache-remove` command can solve this problem by removing a cached entry +after administrative changes. + +The :isccmd:`cache-remove` command works similarly to the :isccmd:`reservation-get` command. +It allows querying by two parameters: either ``subnet-id4`` or ``subnet-id6``; +or ``ip-address`` (may be an IPv4 or IPv6 address), ``hw-address`` (specifies +a hardware/MAC address), ``duid``, ``circuit-id``, ``client-id``, or ``flex-id``. + +An example command to remove an IPv4 host with reserved address +192.0.2.1 from a subnet with a ``subnet-id`` 123 looks as follows: + +:: + + { + "command": "cache-remove", + "arguments": { + "ip-address": "192.0.2.1", + "subnet-id": 123 + } + } + +Another example that removes an IPv6 host identifier by DUID and +specific ``subnet-id`` is: + +:: + + { + "command": "cache-remove", + "arguments": { + "duid": "00:01:ab:cd:f0:a1:c2:d3:e4", + "subnet-id": 123 + } + } diff --git a/doc/sphinx/arm/hooks-host-cmds.rst b/doc/sphinx/arm/hooks-host-cmds.rst new file mode 100644 index 0000000..bcfc54f --- /dev/null +++ b/doc/sphinx/arm/hooks-host-cmds.rst @@ -0,0 +1,1212 @@ +.. ischooklib:: libdhcp_host_cmds.so +.. _hooks-host-cmds: + +``libdhcp_host_cmds.so``: Host Commands +======================================= + +Kea can store host reservations in a database; in many larger deployments, +it is useful to be able to manage that information while the server is +running. The Host Commands library provides management commands for adding, querying, +and deleting host reservations in a safe way without restarting the +server. In particular, it validates the parameters, so an attempt to +insert incorrect data - such as adding a host with a conflicting identifier in the +same subnet - is rejected. Those commands are exposed via the command +channel (JSON over UNIX sockets) and the Control Agent (JSON over a RESTful +interface). + +.. note:: + + :ischooklib:`libdhcp_host_cmds.so` is available as a premium + hook library from ISC. Please visit https://www.isc.org/shop/ to purchase + the premium hook libraries, or contact us at https://www.isc.org/contact for + more information. + +.. note:: + + This library can only be loaded by the :iscman:`kea-dhcp4` or :iscman:`kea-dhcp6` + process. + +Currently, the following commands are supported: + +- :isccmd:`reservation-add`, which adds a new host reservation. + +- :isccmd:`reservation-get`, which returns an existing reservation if specified + criteria are matched. + +- :isccmd:`reservation-get-all`, which returns all reservations in a specified subnet. + +- :isccmd:`reservation-get-page`, a variant of :isccmd:`reservation-get-all` that returns + reservations by pages, either all or in a specified subnet. + +- :isccmd:`reservation-get-by-address`, which returns all reservations with a + specified IP address or a delegated prefix (without a prefix length), and optionally a subnet id. + +- :isccmd:`reservation-get-by-hostname`, which returns all reservations with a + specified hostname and optionally in a subnet. + +- :isccmd:`reservation-get-by-id`, which returns all reservations with a specified + identifier (since Kea version 1.9.0). + +- :isccmd:`reservation-del`, which attempts to delete a reservation matching specified + criteria. + +- :isccmd:`reservation-update`, which updates (replaces) an existing reservation + matching the given identifiers in a subnet. + +To use the commands that change reservation information +(i.e. :isccmd:`reservation-add`, :isccmd:`reservation-del`, and :isccmd:`reservation-update`) to +modify data stored in the host database, the hosts database must be specified +and it must not operate in read-only mode (for details, see the +``hosts-databases`` descriptions in :ref:`hosts-databases-configuration4` and +:ref:`hosts-databases-configuration6`). If the ``hosts-databases`` are not +specified or are running in read-only mode, :ischooklib:`libdhcp_host_cmds.so` will +load, but any attempts to use :isccmd:`reservation-add`, :isccmd:`reservation-del`, and +:isccmd:`reservation-update` to modify data in that database will fail. + +These commands can also modify hosts from the JSON configuration independently +from the hosts database. The changes provided in the JSON configuration are +volatile and can be made permanent by sending the :isccmd:`config-write` command. + +For a description of proposed future commands, see the `Control API +Requirements <https://gitlab.isc.org/isc-projects/kea/wikis/designs/commands>`__ +document. + +All host commands use JSON syntax. They can be issued either using the +control channel (see :ref:`ctrl-channel`) or via the Control Agent (see +:ref:`kea-ctrl-agent`). + +The library can be loaded similarly to other hook libraries. It +does not take any parameters, and it supports both the DHCPv4 and DHCPv6 +servers. + +:: + + "Dhcp6": { + "hooks-libraries": [ + { + "library": "/path/libdhcp_host_cmds.so" + }, + ... + ] + } + +The ``subnet-id`` Parameter +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Before examining the individual commands, it is worth discussing the +parameter ``subnet-id``. Currently this parameter is mandatory for all of the +commands supplied by this library, with the exception of +:isccmd:`reservation-get-by-hostname` and :isccmd:`reservation-get-by-address`, +where it is optional. Since Kea 1.9.0, +``subnet-id`` is also optional in :isccmd:`reservation-get-page`, and +it is forbidden in :isccmd:`reservation-get-by-id`. + +Reservations can be specified globally, and are not necessarily specific to any +subnet. When reservations are supplied via the configuration file, the +ID of the containing subnet (or lack thereof) is implicit in the +configuration structure. However, when managing reservations using +host commands, it is necessary to explicitly identify the scope to which +the reservation belongs. This is done via the ``subnet-id`` parameter. +For global reservations, use a value of zero (0). For reservations +scoped to a specific subnet, use that subnet's ID. + +On the other hand, when the ``subnet-id`` is not specified in the command +parameters, it is added to each host in responses. If the ``subnet-id`` +has the unused special value, this means the host entry belongs only +to the other IP version (i.e. IPv6 in DHCPv4 server or IPv4 in DHCPv6 +server) and this entry is ignored. + +The ``operation-target`` Parameter +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Most host commands accept the ``operation-target`` parameter that selects +the host data source. The commands may process data from the server +configuration (i.e., memory operation target), a database (database target), +or both of them (all sources). The operation target parameter is optional. +By default, the commands that only read the data use all data sources +(memory and database); the commands that modify the state (i.e., :isccmd:`reservation-add`, +:isccmd:`reservation-del`, and :isccmd:`reservation-update`) only use the +database target. + +The ``operation-target`` parameter accepts the following values: + +- ``memory`` - query or update the runtime server configuration. +- ``database`` - query or update host database(s). +- ``all`` - query or update both runtime configuration and host database(s). +- ``default`` - query or update a default host data source - it is command specific. + +.. isccmd:: reservation-add +.. _command-reservation-add: + +The ``reservation-add`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:isccmd:`reservation-add` allows for the insertion of a new host. It takes a +set of arguments that vary depending on the nature of the host +reservation. Any parameters allowed in the configuration file that +pertain to host reservation are permitted here. For details regarding +IPv4 reservations, see :ref:`host-reservation-v4`; for IPv6 reservations, see +:ref:`host-reservation-v6`. The ``subnet-id`` is mandatory. Use a +value of zero (0) to add a global reservation, or the ID of the subnet +to which the reservation should be added. The command can be as simple as having +only the two mandatory entries: + +.. code-block:: json + + { + "command": "reservation-add", + "arguments": { + "reservation": { + "subnet-id": 1, + "hw-address": "1a:1b:1c:1d:1e:1f" + } + } + } + +In that case, however, it does not assign any resources to the host. An IPv4 +address can be assigned like so: + +.. code-block:: json + + { + "command": "reservation-add", + "arguments": { + "reservation": { + "subnet-id": 1, + "hw-address": "1a:1b:1c:1d:1e:1f", + "ip-address": "192.0.2.202" + } + } + } + +It can also take many more parameters, for example: + +.. code-block:: json + + { + "command": "reservation-add", + "arguments": { + "reservation": { + "subnet-id": 1, + "client-id": "01:0a:0b:0c:0d:0e:0f", + "ip-address": "192.0.2.205", + "next-server": "192.0.2.1", + "server-hostname": "hal9000", + "boot-file-name": "/dev/null", + "option-data": [ + { + "name": "domain-name-servers", + "data": "10.1.1.202,10.1.1.203" + } + ], + "client-classes": [ "special_snowflake", "office" ] + } + } + } + +Here is an example of a complex IPv6 reservation: + +.. code-block:: json + + { + "command": "reservation-add", + "arguments": { + "reservation": { + "subnet-id": 1, + "duid": "01:02:03:04:05:06:07:08:09:0A", + "ip-addresses": [ "2001:db8:1:cafe::1" ], + "prefixes": [ "2001:db8:2:abcd::/64" ], + "hostname": "foo.example.com", + "option-data": [ + { + "name": "vendor-opts", + "data": "4491" + }, + { + "name": "tftp-servers", + "space": "vendor-4491", + "data": "3000:1::234" + } + ] + } + } + } + +The command accepts the ``operation-target`` argument. By default, it adds the +reservation to the hosts database only. + +.. code-block:: json + + { + "command": "reservation-add", + "arguments": { + "reservation": {}, + "operation-target": "all" + } + } + +The command returns a status that indicates either success (result 0) +or failure (result 1). A failed command always includes a text parameter +that explains the cause of the failure. Here's an example of a successful +addition: + +.. code-block:: json + + { + "result": 0, + "text": "Host added." + } + +And here's an example of a failure: + +.. code-block:: json + + { + "result": 1, + "text": "Mandatory 'subnet-id' parameter missing." + } + + +As :isccmd:`reservation-add` is expected to store the host, the ``hosts-databases`` +parameter must be specified in the configuration, and databases must not +run in read-only mode. + +.. isccmd:: reservation-get +.. _command-reservation-get: + +The ``reservation-get`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:isccmd:`reservation-get` can be used to query the host database and retrieve +existing reservations. This command supports two types of parameters: +(``subnet-id``, ``address``) or (``subnet-id``, ``identifier-type``, +``identifier``). The first type of query is used when the address (either +IPv4 or IPv6) is known, but the details of the reservation are not. One +common use for this type of query is to find out whether a given +address is reserved. The second query uses identifiers. For +maximum flexibility, Kea stores the host identifying information as a +pair of values: the type and the actual identifier. Currently supported +identifiers are ``"hw-address"``, ``"duid"``, ``"circuit-id"``, ``"client-id"``, and +``"flex-id"``. The ``subnet-id`` is mandatory. Use a value +of zero (0) to fetch a global reservation, or the ID of the subnet to +which the reservation belongs. + +An example command for getting a host reservation by a (``subnet-id``, +``address``) pair looks as follows: + +:: + + { + "command": "reservation-get", + "arguments": { + "subnet-id": 1, + "ip-address": "192.0.2.202" + } + } + +An example query by (``subnet-id``, ``identifier-type``, ``identifier``) looks as +follows: + +:: + + { + "command": "reservation-get", + "arguments": { + "subnet-id": 4, + "identifier-type": "hw-address", + "identifier": "01:02:03:04:05:06" + } + } + +The command accepts the ``operation-target`` argument. By default, it gets the +reservation from both JSON configuration and the hosts database. + +.. code-block:: json + + { + "command": "reservation-get", + "arguments": { + "subnet-id": 1, + "ip-address": "192.0.2.202", + "operation-target": "alternate" + } + } + +Command :isccmd:`reservation-get` typically returns the result 0 when a query was +conducted properly. In particular, 0 is returned when the host was not +found. If the query was successful, the host parameters are +returned. An example of a query that did not find the host looks as +follows: + +:: + + { "result": 0, "text": "Host not found." } + +Here's an example of a result returned when the host was found successfully: + +:: + + { + "arguments": { + "boot-file-name": "bootfile.efi", + "client-classes": [ + + ], + "hostname": "somehost.example.org", + "hw-address": "01:02:03:04:05:06", + "ip-address": "192.0.2.100", + "next-server": "192.0.0.2", + "option-data": [ + + ], + "server-hostname": "server-hostname.example.org", + "subnet-id": 4 + }, + "result": 0, + "text": "Host found." + } + +An example result returned when the query was malformed might look like this: + +:: + + { "result": 1, "text": "No 'ip-address' provided and 'identifier-type' is either missing or not a string." } + +.. isccmd:: reservation-get-all +.. _command-reservation-get-all: + +The ``reservation-get-all`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:isccmd:`reservation-get-all` can be used to query the host database and +retrieve all reservations in a specified subnet. This command uses +parameters providing the mandatory ``subnet-id``. Global host reservations +can be retrieved by using a ``subnet-id`` value of zero (0). + +For instance, retrieving host reservations for the subnet 1: + +:: + + { + "command": "reservation-get-all", + "arguments": { + "subnet-id": 1 + } + } + +returns some IPv4 hosts: + +:: + + { + "arguments": { + "hosts": [ + { + "boot-file-name": "bootfile.efi", + "client-classes": [ ], + "hostname": "somehost.example.org", + "hw-address": "01:02:03:04:05:06", + "ip-address": "192.0.2.100", + "next-server": "192.0.0.2", + "option-data": [ ], + "server-hostname": "server-hostname.example.org", + "subnet-id": 1 + }, + { + "boot-file-name": "bootfile.efi", + "client-classes": [ ], + "hostname": "otherhost.example.org", + "hw-address": "01:02:03:04:05:ff", + "ip-address": "192.0.2.200", + "next-server": "192.0.0.2", + "option-data": [ ], + "server-hostname": "server-hostname.example.org", + "subnet-id": 1 + }, + ... + ] + }, + "result": 0, + "text": "72 IPv4 host(s) found." + } + +The response returned by :isccmd:`reservation-get-all` can be very long. The +DHCP server does not handle DHCP traffic while preparing a response to +:isccmd:`reservation-get-all`, so if there are many reservations in a subnet, this +may be disruptive; use with caution. For larger deployments, please +consider using :isccmd:`reservation-get-page` instead. + +The command accepts the ``operation-target`` argument. By default, it gets the +reservation from both JSON configuration and the hosts database. + +.. code-block:: json + + { + "command": "reservation-get-all", + "arguments": { + "subnet-id": 1, + "operation-target": "alternate" + } + } + +For more information, see :ref:`command-reservation-get-all`. + +.. isccmd:: reservation-get-page +.. _command-reservation-get-page: + +The ``reservation-get-page`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:isccmd:`reservation-get-page` can be used to query the host database and +retrieve all reservations in a specified subnet, by pages. This command +uses parameters providing the mandatory ``subnet-id``. Use a value of zero +(0) to fetch global reservations. The second mandatory parameter is the +page size limit. The optional ``source-index`` and ``from-host-id`` parameters, both +of which default to 0, are used to chain page queries. +Since Kea version 1.9.0, the ``subnet-id`` parameter is optional. + +The usage of the ``from`` and ``source-index`` parameters requires additional +explanation. For the first call, those parameters should not be specified +(or should be specified as zeros). For any follow-up calls, they should be set to +the values returned in previous calls, in a next map holding ``from`` and +``source-index`` values. Subsequent calls should be issued until all +reservations are returned. The end is reached once the returned list is +empty, the count is 0, no next map is present, and result status 3 (empty) is +returned. + +.. note:: + + The ``from`` and ``source-index`` parameters reflect the internal state of + the search. There is no need to understand what they represent; it is + simply a value that should be copied from one response to the + next query. However, for those who are curious, the ``from`` field represents a + 64-bit representation of the host identifier used by a host backend. The + ``source-index`` is an internal representation of multiple host + backends: 0 is used to represent hosts defined in a configuration + file, and 1 represents the first database backend. In some uncommon cases + there may be more than one database backend configured, so + potentially there may be a 2. In any case, Kea iterates over all + backends configured. + +For instance, retrieving host reservations for the subnet 1 and +requesting the first page can be done by: + +:: + + { + "command": "reservation-get-page", + "arguments": { + "subnet-id": 1, + "limit": 10 + } + } + +Since this is the first call, ``source-index`` and ``from`` should not be +specified. They are set to their zero default values. + +Some hosts are returned with information to get the next page: + +:: + + { + "arguments": { + "count": 72, + "hosts": [ + { + "boot-file-name": "bootfile.efi", + "client-classes": [ ], + "hostname": "somehost.example.org", + "hw-address": "01:02:03:04:05:06", + "ip-address": "192.0.2.100", + "next-server": "192.0.0.2", + "option-data": [ ], + "server-hostname": "server-hostname.example.org" + }, + { + "boot-file-name": "bootfile.efi", + "client-classes": [ ], + "hostname": "otherhost.example.org", + "hw-address": "01:02:03:04:05:ff", + "ip-address": "192.0.2.200", + "next-server": "192.0.0.2", + "option-data": [ ], + "server-hostname": "server-hostname.example.org" + }, + ... + ], + "next": { + "from": 1234567, + "source-index": 1 + } + }, + "result": 0, + "text": "72 IPv4 host(s) found." + } + +Note that the ``from`` and ``source-index`` fields were specified in the response in +the next map. Those two must be copied to the next command, so Kea +continues from the place where the last command finished. To get the +next page the following command can be sent: + +:: + + { + "command": "reservation-get-page", + "arguments": { + "subnet-id": 1, + "source-index": 1, + "from": 1234567, + "limit": 10 + } + } + +The response will contain a list of hosts with updated ``source-index`` +and ``from`` fields. Continue calling the command until the last +page is received. Its response will look like this: + +.. code-block:: json + + { + "arguments": { + "count": 0, + "hosts": [ ] + }, + "result": 3, + "text": "0 IPv4 host(s) found." + } + +The command doesn't accept the ``operation-target`` argument. + +This command is more complex than :isccmd:`reservation-get-all`, but lets +users retrieve larger host reservations lists in smaller chunks. For +small deployments with few reservations, it is easier to use +:isccmd:`reservation-get-all`. + +.. isccmd:: reservation-get-by-address +.. _command-reservation-get-by-address: + +The ``reservation-get-by-address`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:isccmd:`reservation-get-by-address` can be used to query the host database and +retrieve all reservations for given IP address or a delegated prefix (without +a prefix length) in a specified subnet or in all subnets. This command uses +parameters providing the mandatory ``ip-address`` and the optional ``subnet-id`` +and ``operation-target``. + +For instance, retrieving host reservations for the IPv4 address "192.0.200.181" +in the subnet 1: + +:: + + { + "command": "reservation-get-by-address", + "arguments": { + "ip-address": "192.0.200.181", + "subnet-id": 1 + }, + "service": [ + "dhcp4" + ] + } + +can return two IPv4 hosts: + +:: + + { + "arguments": { + "hosts": [ + { + "boot-file-name": "", + "client-classes": [], + "hostname": "", + "hw-address": "99:99:99:99:99:01", + "ip-address": "192.0.200.181", + "next-server": "0.0.0.0", + "option-data": [], + "server-hostname": "", + "subnet-id": 1 + }, + { + "boot-file-name": "", + "circuit-id": "1234", + "client-classes": [], + "hostname": "", + "ip-address": "192.0.200.181", + "next-server": "0.0.0.0", + "option-data": [], + "server-hostname": "", + "subnet-id": 1 + } + ] + }, + "result": 0, + "text": "2 IPv4 host(s) found." + } + +To search for all reservations in all subnets simply skip the ``subnet-id`` parameter: + +:: + + { + "command": "reservation-get-by-address", + "arguments": { + "ip-address": "192.0.200.181" + }, + "service": [ + "dhcp4" + ] + } + +An example response can be: + +:: + + { + "arguments": { + "hosts": [ + { + "boot-file-name": "", + "client-classes": [], + "hostname": "", + "hw-address": "99:99:99:99:99:01", + "ip-address": "192.0.200.181", + "next-server": "0.0.0.0", + "option-data": [], + "server-hostname": "", + "subnet-id": 1 + }, + { + "boot-file-name": "", + "circuit-id": "1234", + "client-classes": [], + "hostname": "", + "ip-address": "192.0.200.181", + "next-server": "0.0.0.0", + "option-data": [], + "server-hostname": "", + "subnet-id": 1 + }, + { + "boot-file-name": "", + "client-classes": [], + "hostname": "", + "hw-address": "99:99:99:99:99:02", + "ip-address": "192.0.200.181", + "next-server": "0.0.0.0", + "option-data": [], + "server-hostname": "", + "subnet-id": 0 + }, + { + "boot-file-name": "", + "client-classes": [], + "hostname": "", + "hw-address": "99:99:99:99:99:03", + "ip-address": "192.0.200.181", + "next-server": "0.0.0.0", + "option-data": [], + "server-hostname": "", + "subnet-id": 2 + } + ] + }, + "result": 0, + "text": "4 IPv4 host(s) found." + } + +When using the command for retrieving DHCP6 host reservations, one can provide +either an IPv6 address or a delegated prefix as the ``ip-address`` parameter. +Please notice that this command does not take prefix length as a parameter in the +current implementation. That's why searching by an IP address ``2001:db8:2:cafe::`` +can return host reservations having delegated prefixes matching this search with +different lengths. For example: ``2001:db8:2:cafe::/63``, ``2001:db8:2:cafe::/64`` etc. +Please consider the example below: + +:: + + { + "command": "reservation-get-by-address", + "arguments": { + "ip-address": "2001:db8:2:cafa::" + }, + "service": [ + "dhcp6" + ] + } + +Response: + +:: + + { + "arguments": { + "hosts": [ + { + "client-classes": [], + "duid": "01:02:03:04:05:06:07:88:98:fa", + "hostname": "foo.example.com", + "ip-addresses": [ + "2001:db8:1:cafe::2" + ], + "option-data": [], + "prefixes": [ + "2001:db8:2:abcd::/64", + "2001:db8:2:cafa::/63" + ], + "subnet-id": 8 + }, + { + "client-classes": [], + "duid": "01:02:03:04:05:06:07:88:98:fb", + "hostname": "foo.example.com", + "ip-addresses": [ + "2001:db8:1:cafe::2" + ], + "option-data": [], + "prefixes": [ + "2001:db8:2:abcd::/64", + "2001:db8:2:cafa::/64" + ], + "subnet-id": 8 + } + ] + }, + "result": 0, + "text": "2 IPv6 host(s) found." + } + +The command accepts the ``operation-target`` argument. By default, it gets the +reservation from both JSON configuration and the hosts database. + +.. code-block:: json + + { + "command": "reservation-get-by-address", + "arguments": { + "ip-address": "192.0.200.181", + "subnet-id": 1, + "operation-target": "alternate" + }, + "service": [ + "dhcp4" + ] + } + +.. note:: + + This command is useful in specific cases. By default, having more than + one host reservation for the same IP address in a given subnet is not allowed, + as explained in the + :ref:`Multiple Reservations for the Same IPv4 <multiple-reservations-same-ip4>` + or in the + :ref:`Multiple Reservations for the Same IPv6 <multiple-reservations-same-ip6>`. + That's why this command comes in handy + when the ``ip-reservations-unique`` boolean parameter is set to ``false``. + Other use case of this command is having overlapping subnets and having + the same IP address reservation (but with different identifier) in different + subnets. + +.. isccmd:: reservation-get-by-hostname +.. _command-reservation-get-by-hostname: + +The ``reservation-get-by-hostname`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:isccmd:`reservation-get-by-hostname` can be used to query the host database and +retrieve all reservations with a specified hostname or in +a specified subnet. This command uses parameters providing the mandatory +``hostname`` and the optional ``subnet-id``. Global host reservations +can be retrieved by using a ``subnet-id`` value of zero (0). +Hostname matching is case-insensitive. + +For instance, retrieving host reservations for "foobar" in the subnet 1: + +:: + + { + "command": "reservation-get-by-hostname", + "arguments": { + "hostname": "foobar.example.org", + "subnet-id": 1 + } + } + +returns some IPv4 hosts: + +:: + + { + "arguments": { + "hosts": [ + { + "boot-file-name": "bootfile.efi", + "client-classes": [ ], + "hostname": "foobar.example.org", + "hw-address": "01:02:03:04:05:06", + "ip-address": "192.0.2.100", + "next-server": "192.0.0.2", + "option-data": [ ], + "server-hostname": "server-hostname.example.org" + }, + { + "boot-file-name": "bootfile.efi", + "client-classes": [ ], + "hostname": "foobar.example.org", + "hw-address": "01:02:03:04:05:ff", + "ip-address": "192.0.2.200", + "next-server": "192.0.0.2", + "option-data": [ ], + "server-hostname": "server-hostname.example.org" + }, + ... + ] + }, + "result": 0, + "text": "5 IPv4 host(s) found." + } + +The response returned by :isccmd:`reservation-get-by-hostname` can be long, +particularly when responses are not limited to a subnet. + +The command accepts the ``operation-target`` argument. By default, it gets the +reservation from both JSON configuration and the hosts database. + +.. code-block:: json + + { + "command": "reservation-get-by-hostname", + "arguments": { + "hostname": "foobar.example.org", + "subnet-id": 1, + "operation-target": "alternate" + } + } + +For more information, see :ref:`command-reservation-get-by-hostname`. + +.. note:: + + When using MySQL as the host backend, this command relies on the fact + that the hostname column in the hosts table uses a case-insensitive + collation, as explained in the :ref:`mysql-database` section of + :ref:`admin`. + +.. isccmd:: reservation-get-by-id +.. _command-reservation-get-by-id: + +The ``reservation-get-by-id`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:isccmd:`reservation-get-by-id` can be used to query the host database and +retrieve all reservations with a specified identifier (``identifier-type`` +and ``identifier`` parameters), independently of subnets. The syntax for +parameters is the same as for :isccmd:`reservation-get`. +The ``subnet-id`` parameter cannot be used, to avoid confusion. +This command is available since Kea version 1.9.0. + +For instance, retrieving host reservations for the 01:02:03:04:05:06 MAC +address: + +:: + + { + "command": "reservation-get-by-id", + "arguments": { + "identifier-type": "hw-address", + "identifier": "01:02:03:04:05:06" + } + } + +returns some IPv4 hosts: + +:: + + { + "arguments": { + "hosts": [ + { + "boot-file-name": "bootfile.efi", + "client-classes": [ ], + "hostname": "foo.example.org", + "hw-address": "01:02:03:04:05:06", + "ip-address": "192.0.2.100", + "next-server": "192.0.0.2", + "option-data": [ ], + "server-hostname": "server-hostname.example.org", + "subnet-id": 123 + }, + { + "boot-file-name": "bootfile.efi", + "client-classes": [ ], + "hostname": "bar.example.org", + "hw-address": "01:02:03:04:05:06", + "ip-address": "192.0.2.200", + "next-server": "192.0.0.2", + "option-data": [ ], + "server-hostname": "server-hostname.example.org", + "subnet-id": 345 + }, + ... + ] + }, + "result": 0, + "text": "5 IPv4 host(s) found." + } + +The response returned by :isccmd:`reservation-get-by-id` can be long, +particularly when responses are not limited to a subnet. + +The command accepts the ``operation-target`` argument. By default, it gets the +reservation from both JSON configuration and the hosts database. + +.. code-block:: json + + { + "command": "reservation-get-by-id", + "arguments": { + "identifier-type": "hw-address", + "identifier": "01:02:03:04:05:06", + "operation-target": "alternate" + } + } + +For more information, see :ref:`command-reservation-get-by-id`. + +.. isccmd:: reservation-del +.. _command-reservation-del: + +The ``reservation-del`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:isccmd:`reservation-del` can be used to delete a reservation from the host +database and/or JSON configuration. This command supports two types of parameters: +(``subnet-id``, ``address``) or (``subnet-id``, ``identifier-type``, ``identifier``). The +first type of query is used when the address (either IPv4 or IPv6) is +known, but the details of the reservation are not. One common use for +this type of query is to remove a reservation (e.g. a specific +address should no longer be reserved). The second query uses identifiers. +For maximum flexibility, Kea stores the host identifying information as +a pair of values: the type and the actual identifier. Currently supported +identifiers are ``"hw-address"``, ``"duid"``, ``"circuit-id"``, ``"client-id"``, and +``"flex-id"``. The ``subnet-id`` is mandatory. Use a value +of zero (0) to delete a global reservation, or the ID of the subnet from +which the reservation should be deleted. + +An example command for deleting a host reservation by (``subnet-id``, +``address``) pair looks as follows: + +:: + + { + "command": "reservation-del", + "arguments": { + "subnet-id": 1, + "ip-address": "192.0.2.202" + } + } + +An example deletion by (``subnet-id``, ``identifier-type``, ``identifier``) looks as +follows: + +:: + + { + "command": "reservation-del", + "arguments": { + "subnet-id": 4, + "identifier-type": "hw-address", + "identifier": "01:02:03:04:05:06" + } + } + +Command :isccmd:`reservation-del` returns a result of 0 when the host deletion was +successful, or 1 if it failed. Descriptive text is provided in the event of +an error. Here are some examples of possible results: + +:: + + { + "result": 1, + "text": "Host not deleted (not found)." + } + +or + +:: + + { + "result": 0, + "text": "Host deleted." + } + +or + +:: + + { + "result": 1, + "text": "Unable to delete a host because there is no hosts-database configured." + } + +The command accepts the ``operation-target`` argument. By default, it removes +the reservation from the hosts database only. + +.. code-block:: json + + { + "command": "reservation-del", + "arguments": { + "subnet-id": 4, + "identifier-type": "hw-address", + "identifier": "01:02:03:04:05:06", + "operation-target": "primary" + } + } + +.. isccmd:: reservation-update +.. _command-reservation-update: + +The ``reservation-update`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:isccmd:`reservation-update` allows for the update of an existing host. It takes the +same set of arguments as :isccmd:`reservation-add`, and just as well, +requires a host identifier and a subnet ID to identify the host that is being +updated. The command can be as simple as having only the two mandatory entries: + +.. code-block:: json + + { + "command": "reservation-update", + "arguments": { + "reservation": { + "subnet-id": 1, + "hw-address": "1a:1b:1c:1d:1e:1f" + } + } + } + +In that case, however, it does not assign any resources to the host. An IPv4 +address can be assigned like so: + +.. code-block:: json + + { + "command": "reservation-update", + "arguments": { + "reservation": { + "subnet-id": 1, + "hw-address": "1a:1b:1c:1d:1e:1f", + "ip-address": "192.0.2.202" + } + } + } + +It can also take many more parameters, for example: + +.. code-block:: json + + { + "command": "reservation-update", + "arguments": { + "reservation": { + "subnet-id": 1, + "client-id": "01:0a:0b:0c:0d:0e:0f", + "ip-address": "192.0.2.205", + "next-server": "192.0.2.1", + "server-hostname": "hal9000", + "boot-file-name": "/dev/null", + "option-data": [ + { + "name": "domain-name-servers", + "data": "10.1.1.202,10.1.1.203" + } + ], + "client-classes": [ + "office", + "special_snowflake" + ] + } + } + } + +Here is an example of a complex IPv6 reservation update: + +.. code-block:: json + + { + "command": "reservation-update", + "arguments": { + "reservation": { + "subnet-id": 1, + "duid": "01:02:03:04:05:06:07:08:09:0A", + "ip-addresses": [ + "2001:db8:1:cafe::1" + ], + "prefixes": [ + "2001:db8:2:abcd::/64" + ], + "hostname": "foo.example.com", + "option-data": [ + { + "name": "vendor-opts", + "data": "4491" + }, + { + "name": "tftp-servers", + "space": "vendor-4491", + "data": "3000:1::234" + } + ] + } + } + } + +The command returns a status that indicates either success (result ``0``) or +failure (result ``1``) and a text parameter that confirms success or explains +the cause of the failure. Here's an example of a successful update: + +.. code-block:: json + + { + "result": 0, + "text": "Host updated." + } + +And here's an example of a failure: + +.. code-block:: json + + { + "result": 1, + "text": "Mandatory 'subnet-id' parameter missing." + } + +The command accepts the ``operation-target`` argument. By default, it adds the +reservation to the hosts database only. As :isccmd:`reservation-update` is expected +to store the host, the ``hosts-databases`` parameter must be specified in the +configuration, and databases must not run in read-only mode if the operation +target is not the JSON configuration. + +As with other update and set commands, this command overwrites all the contents +of the entry. If the host previously had a resource assigned to it, and the +:isccmd:`reservation-update` command is missing the resource, it is deleted from the +database. If an incremental update of the host is desired, then this can be +achieved by doing a :isccmd:`reservation-get-by-id` to get the current state of the +host, picking the host out of the response, modifying it to the required +outcome, and then issuing the :isccmd:`reservation-update` command with the resulting +host attached. + +.. _hooks-host-cmds-general-mentions: + +General Mentions +~~~~~~~~~~~~~~~~ + +.. note:: + + The host cache and RADIUS hook libraries are two host backends that do not + respond to commands that return a collection of host reservations, such as + :isccmd:`reservation-get-all`. Commands returning one host entry or dedicated host + cache commands should be used instead. diff --git a/doc/sphinx/arm/hooks-lease-cmds.rst b/doc/sphinx/arm/hooks-lease-cmds.rst new file mode 100644 index 0000000..61ee755 --- /dev/null +++ b/doc/sphinx/arm/hooks-lease-cmds.rst @@ -0,0 +1,1073 @@ +.. ischooklib:: libdhcp_lease_cmds.so +.. _hooks-lease-cmds: + +``libdhcp_lease_cmds.so``: Lease Commands for Easier Lease Management +===================================================================== + +Kea allows users to store lease information in several +backends (memfile, MySQL, and PostgreSQL), and the Lease Commands library provides an +interface that can manipulate leases in a unified, safe way. +In particular, it allows things that were previously impossible: lease +manipulation in memfile while Kea is running, sanity check changes, +lease existence checks, and removal of all leases belonging to a +specific subnet. The hook library can also catch more obscure errors, like an attempt +to add a lease with a ``subnet-id`` that does not exist in the +configuration, or configuring a lease to use an address that is outside +of the subnet to which it is supposed to belong. The library also +provides a non-programmatic way to manage user contexts associated with +leases. + +.. note:: + + :ischooklib:`libdhcp_lease_cmds.so` is part of the open source code and is + available to every Kea user. + +.. note:: + + This library can only be loaded by the :iscman:`kea-dhcp4` or the + :iscman:`kea-dhcp6` process. + +There are many situations where an administrative command may be useful; +for example, during migration between servers or different vendors, when +a certain network is being retired, or when a device has been +disconnected and the system administrator knows that it will not be coming +back. The ``get`` queries may be useful for automating certain management +and monitoring tasks, and they can also act as preparatory steps for lease +updates and removals. + +This library provides the following commands: + +- :isccmd:`lease4-add` - adds a new IPv4 lease. + +- :isccmd:`lease6-add` - adds a new IPv6 lease. + +- :isccmd:`lease6-bulk-apply` - creates, updates, and/or deletes multiple + IPv6 leases in a single transaction. + +- :isccmd:`lease4-get` - checks whether an IPv4 lease with the specified + parameters exists and returns it if it does. + +- :isccmd:`lease6-get` - checks whether an IPv6 lease with the specified + parameters exists and returns it if it does. + +- :isccmd:`lease4-get-all` - returns all IPv4 leases or all IPv4 leases for + the specified subnets. + +- :isccmd:`lease6-get-all` - returns all IPv6 leases or all IPv6 leases for + the specified subnets. + +- :isccmd:`lease4-get-page` - returns a set ("page") of leases from the list + of all IPv4 leases in the database. By iterating through the pages it + is possible to retrieve all the leases. + +- :isccmd:`lease6-get-page` - returns a set ("page") of leases from the list + of all IPv6 leases in the database. By iterating through the pages it + is possible to retrieve all the leases. + +- :isccmd:`lease4-get-by-hw-address` - returns all IPv4 leases with the specified + hardware address. + +- :isccmd:`lease4-get-by-client-id` - returns all IPv4 leases with the specified + ``client-id``. + +- :isccmd:`lease6-get-by-duid` - returns all IPv6 leases with the specified DUID. + +- :isccmd:`lease4-get-by-hostname` - returns all IPv4 leases with the specified + hostname. + +- :isccmd:`lease6-get-by-hostname` - returns all IPv6 leases with the specified + hostname. + +- :isccmd:`lease4-del` - deletes an IPv4 lease with the specified parameters. + +- :isccmd:`lease6-del` - deletes an IPv6 lease with the specified parameters. + +- :isccmd:`lease4-update` - updates (replaces) an existing IPv4 lease. + +- :isccmd:`lease6-update` - updates (replaces) an existing IPv6 lease. + +- :isccmd:`lease4-wipe` - removes all leases from a specific IPv4 subnet or + from all subnets. + +- :isccmd:`lease6-wipe` - removes all leases from a specific IPv6 subnet or + from all subnets. + +- :isccmd:`lease4-resend-ddns` - resends a request to update DNS entries for + an existing lease. + +- :isccmd:`lease6-resend-ddns` - resends a request to update DNS entries for + an existing lease. + +- :isccmd:`lease4-write` - writes the IPv4 memfile lease database into a file. + +- :isccmd:`lease6-write` - writes the IPv6 memfile lease database into a file. + +All commands use JSON syntax and can be issued either using the control +channel (see :ref:`ctrl-channel`) or Control Agent (see +:ref:`kea-ctrl-agent`). + +The library can be loaded in the same way as other hook libraries, and +it does not take any parameters. It supports both the DHCPv4 and DHCPv6 +servers. + +:: + + "Dhcp6": { + "hooks-libraries": [ + { + "library": "/path/libdhcp_lease_cmds.so" + }, + ... + ] + } + +.. isccmd:: lease4-add +.. _command-lease4-add: + +.. isccmd:: lease6-add +.. _command-lease6-add: + +The ``lease4-add``, ``lease6-add`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The :isccmd:`lease4-add` and +:isccmd:`lease6-add` commands allow a new lease +to be created. Typically Kea creates a lease when it first sees a new +device; however, sometimes it may be convenient to create the lease +manually. The :isccmd:`lease4-add` command requires at least two parameters: +an IPv4 address and an identifier, i.e. hardware (MAC) address. A third +parameter, ``subnet-id``, is optional. If the ``subnet-id`` is not specified or +the specified value is 0, Kea tries to determine the value by running +a subnet-selection procedure. If specified, however, its value must +match the existing subnet. The simplest successful call might look as +follows: + +:: + + { + "command": "lease4-add", + "arguments": { + "ip-address": "192.0.2.202", + "hw-address": "1a:1b:1c:1d:1e:1f" + } + } + +The :isccmd:`lease6-add` command requires three parameters: an IPv6 address, +an IAID value (identity association identifier, a value sent by +clients), and a DUID. As with :isccmd:`lease4-add`, the ``subnet-id`` parameter is +optional. If the ``subnet-id`` is not specified or the provided value is 0, +Kea tries to determine the value by running a subnet-selection +procedure. If specified, however, its value must match the existing +subnet. For example: + +:: + + { + "command": "lease6-add", + "arguments": { + "subnet-id": 66, + "ip-address": "2001:db8::3", + "duid": "1a:1b:1c:1d:1e:1f:20:21:22:23:24", + "iaid": 1234 + } + } + +The :isccmd:`lease6-add` command can also be used to add leases for IPv6 prefixes. +In this case there are three additional parameters that must be specified: +``subnet-id``, ``type`` (set to "IA_PD"), and prefix length. The actual +prefix is set using the ``ip-address`` field. Note that Kea cannot guess +``subnet-id`` values for prefixes; they must be specified explicitly. For +example, to configure a lease for prefix 2001:db8:abcd::/48, the +following command can be used: + +:: + + { + "command": "lease6-add", + "arguments": { + "subnet-id": 66, + "type": "IA_PD", + "ip-address": "2001:db8:abcd::", + "prefix-len": 48, + "duid": "1a:1b:1c:1d:1e:1f:20:21:22:23:24", + "iaid": 1234 + } + } + +The commands can take several additional optional parameters: + +- ``valid-lft`` - specifies the lifetime of the lease, expressed in + seconds. If not specified, the value configured in the subnet related + to the specified ``subnet-id`` is used. + +- ``expire`` - creates a timestamp of the lease expiration time, + expressed in UNIX format (seconds since 1 Jan 1970). If not + specified, the default value is the current time plus the lease lifetime (the value + of ``valid-lft``). + +- ``fqdn-fwd`` - specifies whether the lease should be marked as if a + forward DNS update were conducted. This only affects the + data stored in the lease database, and no DNS update will be + performed. If configured, a DNS update to remove the A or AAAA + records will be conducted when the lease is removed due to expiration + or being released by a client. If not specified, the default value is + ``false``. The hostname parameter must be specified if ``fqdn-fwd`` is set to + ``true``. + +- ``fqdn-rev`` - specifies whether the lease should be marked as if + reverse DNS update were conducted. This only affects the + data stored in the lease database, and no DNS update will be + performed.. If configured, a DNS update to remove the PTR record will + be conducted when the lease is removed due to expiration or being + released by a client. If not specified, the default value is ``false``. + The hostname parameter must be specified if ``fqdn-fwd`` is set to ``true``. + +- ``hostname`` - specifies the hostname to be associated with this + lease. Its value must be non-empty if either ``fqdn-fwd`` or ``fqdn-rev`` are + set to ``true``. If not specified, the default value is an empty string. + +- ``hw-address`` - optionally specifies a hardware (MAC) address for an + IPv6 lease. It is a mandatory parameter for an IPv4 lease. + +- ``client-id`` - optionally specifies a client identifier for an IPv4 + lease. + +- ``preferred-lft`` - optionally specifies a preferred lifetime for + IPv6 leases. If not specified, the value configured for the subnet + corresponding to the specified ``subnet-id`` is used. This parameter is + not used when adding an IPv4 lease. + +- ``state`` - specifies the state of an added lease, which can be 0 for ``default``, + 1 for ``declined``, and 2 for the ``expired-reclaimed`` state. Any other + value causes an error. Using 1 for a ``"IA_PD"`` lease type is + illegal and will be rejected. + +- ``user-context`` - specifies the user context to be associated with + this lease. It must be a JSON map. + +Here is an example of a fairly complex lease addition: + +:: + + { + "command": "lease6-add", + "arguments": { + "subnet-id": 66, + "ip-address": "2001:db8::3", + "duid": "01:02:03:04:05:06:07:08", + "iaid": 1234, + "hw-address": "1a:1b:1c:1d:1e:1f", + "preferred-lft": 500, + "valid-lft": 1000, + "expire": 12345678, + "fqdn-fwd": true, + "fqdn-rev": true, + "state": 0, + "hostname": "urania.example.org", + "user-context": { "version": 1 } + } + } + +The command returns a status that indicates either success (result 0) +or failure (result 1). A failed command always includes a text +parameter that explains the cause of failure. For example: + +:: + + { "result": 0, "text": "Lease added." } + +Example failure: + +:: + + { "result": 1, "text": "missing parameter 'ip-address' (<string>:3:19)" } + + +.. isccmd:: lease6-bulk-apply +.. _command-lease6-bulk-apply: + +The ``lease6-bulk-apply`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The :isccmd:`lease6-bulk-apply` was implemented to address +the performance penalty in High-Availability mode when a single DHCPv6 +transaction resulted in multiple lease updates sent to the partner, if +multiple address and/or prefix leases were allocated. Consider the case +when a DHCPv6 client requests the assignment of two IPv6 addresses and two IPv6 +prefixes: it may result in the allocation of four leases. In addition, +DHCPv6 may assign a different address than the one requested by the client during +the renew or rebind stage, and delete the leases previously used by this client. +There are six lease changes sent between the HA partners in this case. +Sending these updates as individual commands, e.g. via :isccmd:`lease6-update`, +is highly inefficient and produces unnecessary delays in communication, +both between the HA partners and in sending the response to the DHCPv6 client. + +The :isccmd:`lease6-bulk-apply` command deals with this +problem by aggregating all lease changes - both deleted leases and +new or updated leases - in a single command. +The receiving server iterates over the deleted leases and deletes them +from its lease database. Next, it iterates over the new/updated leases +and adds them to the database or updates them if they already exist. + +Even though High Availability is the major application for +this command, it can be freely used in all cases when it is desirable to +send multiple lease changes in a single command. + +In the following example, we delete two leases and add +or update two other leases in the database: + + +:: + + { + "command": "lease6-bulk-apply", + "arguments": { + "deleted-leases": [ + { + "ip-address": "2001:db8:abcd::", + "type": "IA_PD", + ... + }, + { + "ip-address": "2001:db8:abcd::234", + "type": "IA_NA", + ... + } + ], + "leases": [ + { + "subnet-id": 66, + "ip-address": "2001:db8:cafe::", + "type": "IA_PD", + ... + }, + { + "subnet-id": 66, + "ip-address": "2001:db8:abcd::333", + "type": "IA_NA", + ... + } + ] + } + } + +If any of the leases are malformed, no lease changes are applied +to the lease database. If the leases are well-formed but there is a +failure to apply any of the lease changes to the database, the command +continues to be processed for other leases. All the leases for which +the command was unable to apply the changes in the database are +listed in the response. For example: + +:: + + { + "result": 0, + "text": "Bulk apply of 2 IPv6 leases completed", + "arguments": { + "failed-deleted-leases": [ + { + "ip-address": "2001:db8:abcd::", + "type": "IA_PD", + "result": 3, + "error-message": "no lease found" + } + ], + "failed-leases": [ + { + "ip-address": "2001:db8:cafe::", + "type": "IA_PD", + "result": 1, + "error-message": "unable to communicate with the lease database" + } + ] + } + } + +The response above indicates that the hook library was unable to +delete the lease for prefix "2001:db8:abcd::" and add or update the lease +for prefix "2001:db8:cafe::". However, there are two other lease changes +which have been applied as indicated by the text message. The +``result`` is the status constant that indicates the type +of the error experienced for the particular lease. The meanings of the +returned codes are the same as the results returned for the commands. +In particular, the result of 1 indicates an error while processing the +lease, e.g. a communication error with the database. The result of 3 +indicates that an attempt to delete the lease was unsuccessful because +such a lease doesn't exist (an empty result). + +.. isccmd:: lease4-get +.. _command-lease4-get: + +.. isccmd:: lease6-get +.. _command-lease6-get: + +The ``lease4-get``, ``lease6-get`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:isccmd:`lease4-get` and :isccmd:`lease6-get` can be used to query the lease database +and retrieve existing leases. There are two types of parameters the +:isccmd:`lease4-get` command supports: (``address``) or (``subnet-id``, +``identifier-type``, ``identifier``). There are also two types for +:isccmd:`lease6-get`: (``address``, ``type``) or (``subnet-id``, ``identifier-type``, +``identifier``, ``IAID``, ``type``). The first type of query is used when the +address (either IPv4 or IPv6) is known, but the details of the lease are +not; one common use case of this type of query is to find out whether a +given address is being used. The second query uses identifiers; +currently supported identifiers for leases are: ``"hw-address"`` (IPv4 +only), ``"client-id"`` (IPv4 only), and ``"duid"`` (IPv6 only). + +An example :isccmd:`lease4-get` command for getting a lease using an IPv4 +address is: + +:: + + { + "command": "lease4-get", + "arguments": { + "ip-address": "192.0.2.1" + } + } + +An example of the :isccmd:`lease6-get` query is: + +:: + + { + "command": "lease6-get", + "arguments": { + "ip-address": "2001:db8:1234:ab::", + "type": "IA_PD" + } + } + +An example query by ``"hw-address"`` for an IPv4 lease looks as follows: + +:: + + { + "command": "lease4-get", + "arguments": { + "identifier-type": "hw-address", + "identifier": "08:08:08:08:08:08", + "subnet-id": 44 + } + } + +An example query by ``"client-id"`` for an IPv4 lease looks as follows: + +:: + + { + "command": "lease4-get", + "arguments": { + "identifier-type": "client-id", + "identifier": "01:01:02:03:04:05:06", + "subnet-id": 44 + } + } + +An example query by (``subnet-id``, ``identifier-type``, ``identifier``, ``iaid``, ``type``) +for an IPv6 lease is: + +:: + + { + "command": "lease4-get", + "arguments": { + "identifier-type": "duid", + "identifier": "08:08:08:08:08:08", + "iaid": 1234567, + "type": "IA_NA", + "subnet-id": 44 + } + } + +The ``type`` is an optional parameter. Supported values are: ``IA_NA`` +(non-temporary address) and ``IA_PD`` (IPv6 prefix). If not specified, ``IA_NA`` +is assumed. + +:isccmd:`lease4-get` and :isccmd:`lease6-get` return an indication of the result of the operation +and lease details, if found. The result has one of the following values: 0 +(success), 1 (error), or 3 (empty). An empty result means that a query +has been completed properly, but the object (a lease in this case) has +not been found. +The lease parameters, if found, are returned as arguments. +``client-id`` is not returned if empty. + +An example result returned when the host was found: + +:: + + { + "arguments": { + "client-id": "42:42:42:42:42:42:42:42", + "cltt": 12345678, + "fqdn-fwd": false, + "fqdn-rev": true, + "hostname": "myhost.example.com.", + "hw-address": "08:08:08:08:08:08", + "ip-address": "192.0.2.1", + "state": 0, + "subnet-id": 44, + "valid-lft": 3600 + }, + "result": 0, + "text": "IPv4 lease found." + } + +.. note:: + + The client last transaction time (``cltt`` field) is bound to the + valid lifetime (``valid-lft``) and to the expire date (not reported + here but stored in databases) by the equation + :math:`cltt + valid\_lft = expire` + + at the exception of the infinite valid lifetime coded by the + 0xfffffff (4294967295) special value which makes the expire value + to overflow on MySQL and old PostgreSQL backends where timestamps + are 32 bit long. So in these lease databases the expire date is the + same as the cltt i.e. + :math:`cltt = expire` when :math:`valid\_lft = 4294967295` and the + lease backend is MySQL or PostgreSQL. + +.. isccmd:: lease4-get-all +.. _command-lease4-get-all: + +.. isccmd:: lease6-get-all +.. _command-lease6-get-all: + +The ``lease4-get-all``, ``lease6-get-all`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:isccmd:`lease4-get-all` and :isccmd:`lease6-get-all` are used to retrieve all IPv4 +or IPv6 leases, or all leases for the specified set of subnets. All +leases are returned when there are no arguments specified with the +command, as in the following example: + +:: + + { + "command": "lease4-get-all" + } + +If arguments are provided, it is expected that they contain the +``"subnets"`` parameter, which is a list of subnet identifiers for which +leases should be returned. For example, to retrieve all IPv6 +leases belonging to the subnets with identifiers 1, 2, 3, and 4: + +:: + + { + "command": "lease6-get-all", + "arguments": { + "subnets": [ 1, 2, 3, 4 ] + } + } + +The returned response contains a detailed list of leases in the +following format: + +:: + + { + "arguments": { + "leases": [ + { + "cltt": 12345678, + "duid": "42:42:42:42:42:42:42:42", + "fqdn-fwd": false, + "fqdn-rev": true, + "hostname": "myhost.example.com.", + "hw-address": "08:08:08:08:08:08", + "iaid": 1, + "ip-address": "2001:db8:2::1", + "preferred-lft": 500, + "state": 0, + "subnet-id": 44, + "type": "IA_NA", + "valid-lft": 3600 + }, + { + "cltt": 12345678, + "duid": "21:21:21:21:21:21:21:21", + "fqdn-fwd": false, + "fqdn-rev": true, + "hostname": "", + "iaid": 1, + "ip-address": "2001:db8:0:0:2::", + "preferred-lft": 500, + "prefix-len": 80, + "state": 0, + "subnet-id": 44, + "type": "IA_PD", + "valid-lft": 3600 + } + ] + }, + "result": 0, + "text": "2 IPv6 lease(s) found." + } + +.. warning:: + + The :isccmd:`lease4-get-all` and + :isccmd:`lease6-get-all` commands may result in + very large responses. This may have a negative impact on the DHCP + server's responsiveness while the response is generated and + transmitted over the control channel, as the server imposes no + restriction on the number of leases returned as a result of this + command. + +.. isccmd:: lease4-get-page +.. _command-lease4-get-page: + +.. isccmd:: lease6-get-page +.. _command-lease6-get-page: + +The ``lease4-get-page``, ``lease6-get-page`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The :isccmd:`lease4-get-all` and +:isccmd:`lease6-get-all` commands may result in +very large responses; generating such a response may consume CPU +bandwidth as well as memory. It may even cause the server to become +unresponsive. In the case of large lease databases it is usually better to +retrieve leases in chunks, using the paging mechanism. +:isccmd:`lease4-get-page` and :isccmd:`lease6-get-page` implement a paging mechanism +for DHCPv4 and DHCPv6 servers, respectively. The following command +retrieves the first 1024 IPv4 leases: + +:: + + { + "command": "lease4-get-page", + "arguments": { + "from": "start", + "limit": 1024 + } + } + +The keyword ``start`` denotes that the first page of leases should be +retrieved. Alternatively, an IPv4 zero address can be specified to +retrieve the first page: + +:: + + { + "command": "lease4-get-page", + "arguments": { + "from": "0.0.0.0", + "limit": 1024 + } + } + +Similarly, the IPv6 zero address can be specified in the +:isccmd:`lease6-get-page` command: + +:: + + { + "command": "lease6-get-page", + "arguments": { + "from": "::", + "limit": 6 + } + } + +The response has the following structure: + +:: + + { + "arguments": { + "leases": [ + { + "ip-address": "2001:db8:2::1", + ... + }, + { + "ip-address": "2001:db8:2::9", + ... + }, + { + "ip-address": "2001:db8:3::1", + ... + }, + { + "ip-address": "2001:db8:5::3", + ... + }, + { + "ip-address": "2001:db8:4::1", + ... + }, + { + "ip-address": "2001:db8:2::7", + ... + }, + ... + ], + "count": 6 + }, + "result": 0, + "text": "6 IPv6 lease(s) found." + } + +Note that the leases' details were excluded from the response above for +brevity. + +Generally, the returned list is not sorted in any particular order. Some +lease database backends may sort leases in ascending order of addresses, +but the controlling client must not rely on this behavior. + +The ``count`` parameter contains the number of returned leases on the +page. + +To fetch the next page, the client must use the last address of the +current page as an input to the next :isccmd:`lease4-get-page` or +:isccmd:`lease6-get-page` command call. In this example it is: + +:: + + { + "command": "lease6-get-page", + "arguments": { + "from": "2001:db8:2::7", + "count": 6 + } + } + +because 2001:db8:2::7 is the last address on the current page. + +The client may assume that it has reached the last page when the +``count`` value is lower than that specified in the command; this +includes the case when the ``count`` is equal to 0, meaning that no +leases were found. + +.. isccmd:: lease4-get-by-hw-address +.. _command-lease4-get-by-hw-address: + +.. isccmd:: lease4-get-by-client-id +.. _command-lease4-get-by-client-id: + +.. isccmd:: lease6-get-by-duid +.. _command-lease6-get-by-duid: + +.. isccmd:: lease4-get-by-hostname +.. _command-lease4-get-by-hostname: + +.. isccmd:: lease6-get-by-hostname +.. _command-lease6-get-by-hostname: + +The ``lease4-get-by-*``, ``lease6-get-by-*`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``lease4-get-by-*`` and ``lease6-get-by-*`` can be used to query the lease database and +retrieve all existing leases matching a given feature (denoted by the ``*``). These +can include a specified hardware address (IPv4 +only), ``client-id`` IPv4 only), ``duid`` (IPv6 only) identifiers, or hostname. + +An example :isccmd:`lease4-get-by-hw-address` command for getting IPv4 leases +with a given hardware address is: + +:: + + { + "command": "lease4-get-by-hw-address", + "arguments": { + "hw-address": "08:08:08:08:08:08" + } + } + +An example of the :isccmd:`lease6-get-by-hostname` is: + +:: + + { + "command": "lease6-get-by-hostname", + "arguments": { + "hostname": "myhost.example.org" + } + } + +The ``by`` key is the only parameter. The returned response contains a detailed +list of leases in the same format as :isccmd:`lease4-get-all` or :isccmd:`lease6-get-all`. This list can be +empty and is usually not large. + +.. isccmd:: lease4-del +.. _command-lease4-del: + +.. isccmd:: lease6-del +.. _command-lease6-del: + +The ``lease4-del``, ``lease6-del`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:isccmd:`lease4-del` and :isccmd:`lease6-del` can be used to delete a lease from the lease database. +There are two types of parameters these commands support, similar to the +:isccmd:`lease4-get` and :isccmd:`lease6-get` commands: (``address``) for both v4 and v6, (``subnet-id``, +``identifier-type``, ``identifier``) for v4, and (``subnet-id``, ``identifier-type``, +``identifier``, ``type``, ``IAID``) for v6. The first type of query is used when the +address (either IPv4 or IPv6) is known, but the details of the lease are +not. One common use case is where an administrator wants a specified +address to no longer be used. The second form of the command uses +identifiers. For maximum flexibility, this interface uses identifiers as +a pair of values: the type and the actual identifier. The currently +supported identifiers are ``"hw-address"`` (IPv4 only), ``"client-id"`` (IPv4 +only), and ``"duid"`` (IPv6 only). + +An example command for deleting a lease by address is: + +:: + + { + "command": "lease4-del", + "arguments": { + "ip-address": "192.0.2.202" + } + } + +An example IPv4 lease deletion by ``"hw-address"`` is: + +:: + + { + "command": "lease4-del", + "arguments": { + "identifier": "08:08:08:08:08:08", + "identifier-type": "hw-address", + "subnet-id": 44 + } + } + + +Another parameter called ``update-ddns``, when ``true``, instructs the server to +queue a request to :iscman:`kea-dhcp-ddns` to remove DNS entries after the lease is +successfully deleted if: + +- DDNS updating is enabled (i.e. ``"dhcp-ddns":{ "enable-updates": true }``). +- The lease's hostname is not empty. +- At least one of the lease's DNS direction flags (``fqdn_fwd`` or ``fqdn_rev``) is true. + +This parameter defaults to ``false``. An example of its use is shown below: + +:: + + { + "command": "lease4-del", + "arguments": { + "ip-address": "192.0.2.202", + "update-ddns": true + } + } + + +Commands :isccmd:`lease4-del` and :isccmd:`lease6-del` return a result that indicates the outcome +of the operation. It has one of the following values: 0 (success), 1 (error), +or 3 (empty). The empty result means that a query has been completed properly, +but the object (a lease, in this case) has not been found. + +.. isccmd:: lease4-update +.. _command-lease4-update: + +.. isccmd:: lease6-update +.. _command-lease6-update: + +The ``lease4-update``, ``lease6-update`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The :isccmd:`lease4-update` and +:isccmd:`lease6-update` commands can be used to +update existing leases. Since all lease database backends are indexed by +IP addresses, it is not possible to update an address, but all other +fields may be altered. If an address needs to be changed, please use +:isccmd:`lease4-del` / :isccmd:`lease6-del` followed by :isccmd:`lease4-add` / :isccmd:`lease6-add`. + +The ``subnet-id`` parameter is optional. If not specified, or if the +specified value is 0, Kea tries to determine its value by running a +subnet-selection procedure. If specified, however, its value must match +the existing subnet. + +The optional boolean parameter ``"force-create"`` specifies whether the +lease should be created if it does not exist in the database. It defaults +to ``false``, which indicates that the lease is not created if it does not +exist. In such a case, an error is returned when trying to +update a non-existing lease. If the ``"force-create"`` parameter is set to +``true`` and the updated lease does not exist, the new lease is created as a +result of receiving the :isccmd:`lease4-update` / :isccmd:`lease6-update` command. + +An example of a command to update an IPv4 lease is: + +:: + + { + "command": "lease4-update", + "arguments": { + "ip-address": "192.0.2.1", + "hostname": "newhostname.example.org", + "hw-address": "1a:1b:1c:1d:1e:1f", + "subnet-id": 44, + "force-create": true + } + } + +An example of a command to update an IPv6 lease is: + +:: + + { + "command": "lease6-update", + "arguments": { + "ip-address": "2001:db8::1", + "duid": "88:88:88:88:88:88:88:88", + "iaid": 7654321, + "hostname": "newhostname.example.org", + "subnet-id": 66, + "force-create": false + } + } + +As with other update commands, this command overwrites all the contents of the +entry. If the lease previously had a resource assigned to it, and the +:isccmd:`lease4-update` / :isccmd:`lease6-update` command is missing the resource, it is +deleted from the lease database. If an incremental update of the lease is +desired, then this can be achieved by doing a :isccmd:`lease4-get` / :isccmd:`lease6-get` +command to get the current state of the lease, picking the lease out of the +response, modifying it to the required outcome, and then issuing the +:isccmd:`lease4-update` / :isccmd:`lease6-update` command with the resulting lease attached. + +.. isccmd:: lease4-wipe +.. _command-lease4-wipe: + +.. isccmd:: lease6-wipe +.. _command-lease6-wipe: + +The ``lease4-wipe``, ``lease6-wipe`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:isccmd:`lease4-wipe` and :isccmd:`lease6-wipe` are designed to remove all leases +associated with a given subnet. This administrative task is expected to +be used when an existing subnet is being retired. The leases +are not properly expired; no DNS updates are carried out, no log +messages are created, and hooks are not called for the leases being +removed. + +An example of :isccmd:`lease4-wipe` is: + +:: + + { + "command": "lease4-wipe", + "arguments": { + "subnet-id": 44 + } + } + +An example of :isccmd:`lease6-wipe` is: + +:: + + { + "command": "lease6-wipe", + "arguments": { + "subnet-id": 66 + } + } + +The commands return a text description of the number of leases removed, +plus the status code 0 (success) if any leases were removed or 3 (empty) +if there were no leases. Status code 1 (error) may be returned if the +parameters are incorrect or some other exception is encountered. + +``subnet-id`` 0 has a special meaning; it tells Kea to delete leases from +all configured subnets. Also, the ``subnet-id`` parameter may be omitted. If +not specified, leases from all subnets are wiped. + +Note: currently only memfile lease storage supports this command. + +.. isccmd:: lease4-resend-ddns +.. _command-lease4-resend-ddns: + +.. isccmd:: lease6-resend-ddns +.. _command-lease6-resend-ddns: + +The ``lease4-resend-ddns``, ``lease6-resend-ddns`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:isccmd:`lease4-resend-ddns` and :isccmd:`lease6-resend-ddns` can be used to generate +a request to :iscman:`kea-dhcp-ddns` to update the DNS entries for an existing +lease. The desired lease is selected by a single parameter, ``"ip-address"``. +For an update request to be generated, DDNS updating must be enabled +and DNS entries must have already been made (or attempted) for the lease. +In other words, all of the following must be true: + +- DDNS updating must be enabled (i.e. ``"dhcp-ddns":{ "enable-updates": true"}``). +- The lease's hostname must not be empty. +- At least one of the lease's DNS direction flags (``fqdn_fwd`` or ``fqdn_rev``) must be true. + +An example :isccmd:`lease4-resend-ddns` command for getting a lease using an IPv4 +address is: + +:: + + { + "command": "lease4-resend-ddns", + "arguments": { + "ip-address": "192.0.2.1" + } + } + +An example of the :isccmd:`lease6-resend-ddns` query is: + +:: + + { + "command": "lease6-resend-ddns", + "arguments": { + "ip-address": "2001:db8:1::1" + } + } + +Commands :isccmd:`lease4-resend-ddns` and :isccmd:`lease6-resend-ddns` return an indication of the +result of the operation. It has one of the following values: 0 (success), 1 (error), +or 3 (empty). An empty result means that a query has been completed properly, but the +object (a lease in this case) has not been found. + +A successful result does not mean that DNS has been successfully updated; it +indicates that a request to update DNS has been successfully created and +queued for transmission to :iscman:`kea-dhcp-ddns`. + +Here's an example of a result returned when the lease was found: + +:: + + { + "result": 0, + "text": "NCR generated for: 2001:db8:1::1, hostname: example.com." + } + +.. isccmd:: lease4-write +.. _command-lease4-write: + +.. isccmd:: lease6-write +.. _command-lease6-write: + +The ``lease4-write``, ``lease6-write`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:isccmd:`lease4-write` and :isccmd:`lease6-write` can be used for recovery in emergency +situations where the memfile lease file is damaged, e.g. removed by +accident or truncated by a full file system, but the in-memory database +is still valid. These commands are supported only by the memfile database +backend and write the lease database into a CSV file. They take the path +of the file as the ``filename`` argument. If the specified output file +is the same as the configured memfile one, the backend closes and reopens +the file in an attempt to synchronize both the files and the in-memory images +of the lease database. The extension ``.bak`` with server PID number is added +to the previous filename. For example ``.bak14326``. + +.. note:: + + These commands do not replace the LFC mechanism; they should be used + only in exceptional circumstances, such as when recovering after + running out of disk space. diff --git a/doc/sphinx/arm/hooks-lease-query.rst b/doc/sphinx/arm/hooks-lease-query.rst new file mode 100644 index 0000000..046001f --- /dev/null +++ b/doc/sphinx/arm/hooks-lease-query.rst @@ -0,0 +1,675 @@ +.. ischooklib:: libdhcp_lease_query.so +.. _hooks-lease-query: + +``libdhcp_lease_query.so``: Leasequery Support +============================================== + +This library provides support for DHCPv4 Leasequery as described in +`RFC 4388 <https://tools.ietf.org/html/rfc4388>`__; and for DHCPv6 +Leasequery as described in (`RFC 5007 <https://tools.ietf.org/html/rfc5007>`__). + +.. note:: + + :ischooklib:`libdhcp_lease_query.so` is available only to ISC customers with + a paid support contract. For more information on subscription options, + please complete the form at https://www.isc.org/contact. + +.. note:: + + This library can only be loaded by the :iscman:`kea-dhcp4` or + :iscman:`kea-dhcp6` process. + +Kea version 2.3.4 added support for DHCPv6 Bulk Leasequery +(`RFC 5460 <https://tools.ietf.org/html/rfc5460>`__); +Kea version 2.3.5 added support for DHCPv4 Bulk Leasequery +(`RFC 6926 <https://tools.ietf.org/html/rfc6926>`__) using +the memfile lease backend. + +.. _lease-query-dhcpv4: + +DHCPv4 Leasequery +~~~~~~~~~~~~~~~~~ + +DHCPv4 simple Leasequery provides a requester the ability to query for +active lease information for either a single IP address or a single client. +RFC 4388 calls for three such queries: + +- Query by IP address + + The IP address of interest is contained within the ``ciaddr`` field of + the query. +- Query by hardware address + + The hardware address of interest is contained with the ``chaddr`` field + of the query. +- Query by client identifier + + The client identifier of interest is sent in the ``dhcp-client-identifier`` + option (61) of the query. + +The inbound DHCPLEASEQUERY packet must supply only one of the three values +above. Queries which supply more than one of these values are dropped. + +In addition, the query must contain the IP address of the requester in +``giaddr``. This value is used not only as the destination for the +query response but also to validate the requester against a known +list of IP addresses which are permitted to query. This list of valid +requester addresses is specified as part of the Leasequery hook library's +configuration (see the section on configuration below). + +In response to a valid query, the server returns one of three message +types: + +- DHCPLEASEUNKNOWN + + Returned when the IP address of interest is not one the server knows + about (query by IP address); or there are no active leases for the + client of interest (query by hardware address or client ID). + +- DHCPLEASEUNASSIGNED + + Returned when the IP address is one the server knows of but for which + there are no active leases (applies only to query by IP address). + +- DHCPLEASEACTIVE + + Returned when there is at least one active lease found matching the + criteria. + +For both DHCPLEASEUNKNOWN and DHCPLEASEUNASSIGNED responses, the only +information sent back to the requester in response is the query parameter +itself (i.e. one of: IP address, hardware address, or client identifier). + +For DHCPLEASEACTIVE the server provides the following information +for the newest active lease that matches the criteria, in the response: + +- ``ciaddr`` - set to the lease's IP address +- ``chaddr`` - set to the lease's hardware address + +In addition, one or more of the following options are included: + +.. tabularcolumns:: |p{0.2\linewidth}|p{0.1\linewidth}|p{0.7\linewidth}| + +.. table:: DHCPLEASEACTIVE options + :class: longtable + :widths: 30 10 70 + + +------------------------------+-------+-----------------------------------------------+ + | Option | Code | Content | + +==============================+=======+===============================================+ + | dhcp-client-identifier | 61 | copied from the lease (if appropriate) | + +------------------------------+-------+-----------------------------------------------+ + | client-last-transaction-time | 91 | the amount of time that has elapsed since the | + | | | lease's client-last-transaction-time (CLTT). | + | | | This value is also used by the server to | + | | | adjust lifetime and timer values. | + +------------------------------+-------+-----------------------------------------------+ + | dhcp-lease-time | 51 | lease's lifetime reduced by CLTT | + +------------------------------+-------+-----------------------------------------------+ + | dhcp-renewal-time | 58 | as controlled by kea-dhcp4 configuration and | + | | | then reduced by CLTT | + +------------------------------+-------+-----------------------------------------------+ + | dhcp-rebind-time | 59 | as dictated by kea-dhcp4 configuration and | + | | | then reduced by CLTT | + +------------------------------+-------+-----------------------------------------------+ + | dhcp-agent-options | 82 | if stored on the lease. (See | + | | | :ref:`dhcp4-store-extended-info`) | + +------------------------------+-------+-----------------------------------------------+ + | associated-ip | 92 | a list of all other IP addresses for which | + | | | the client has active leases. (Does not apply | + | | | to query by IP address) | + +------------------------------+-------+-----------------------------------------------+ + +The ``dhcp-server-identifier`` option (54) is returned in all responses in keeping with +RFC 2131, section 4.3.1. + +RFC 4388 allows requesters to ask for specific options via the +``dhcp-parameter-request-list`` (PRL, option 55). This is not currently supported in Kea. + +.. _lease-query-dhcpv4-config: + +DHCPv4 Leasequery Configuration +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Configuring the Leasequery hook library for use is straightforward. It +supports a single parameter, ``requesters``, which is a list of IP addresses from +which DHCPLEASEQUERY packets are accepted. In other words, it is a list of +known requesters. The following code shows an example configuration with two requester +addresses: + +:: + + { + "hooks-libraries": [ + { + "library": "lib/kea/hooks/libdhcp_lease_query.so", + "parameters": { + "requesters": [ "192.0.1.1", "10.0.0.2" ] + } + } + ], + ... + } + +.. note:: + + For security purposes, there is no way to specify wildcards. Each requester address + must be explicitly listed. + +.. _lease-query-dhcpv6: + +DHCPv6 Leasequery +~~~~~~~~~~~~~~~~~ + +DHCPv6 simple Leasequery gives a requester the ability to query for +active lease information for either a single IP address or a single client +DUID. The query type and parameters are conveyed in an ``lq-query`` option (44) +attached to a ``DHCPV6_LEASEQUERY`` message: + +- ``query-type`` + + This is either ``query-by-address`` (1) or ``query-by-clientid`` (2) + +- ``link-address`` + + The global link address, when not empty, instructs the query to be + limited to leases within that "link." Kea uses this value to + select only leases that belong to subnets whose prefix matches + this value. Active leases for prefix delegations for + a matched subnet are included in the query reply, even if the + delegated prefix itself falls outside the subnet prefix. + +- ``query-options`` + + A single ``iaaddr`` option (12) must be supplied when querying by address. + When querying by client ID, a single ``clientid`` option (1) must be + supplied. RFC 5007 also calls for an optional, ``oro`` option (6), to + request specific options be returned for matched leases. This is + not currently implemented. + +.. note:: + + `RFC 5007, Section 3.3 <https://tools.ietf.org/html/rfc5007#section-3.3>`__ + states that querying by IP address should return either a lease (e.g. + binding) for the address itself or a lease for a delegated prefix that + contains the address. The latter case is not supported by releases + prior to Kea 2.3.7. + +``DHCPV6_LEASEQUERY`` queries are only honored if the source address of +the query matches an entry in a list of known IP addresses which are +permitted to query. This list of valid requester addresses is specified +as part of the Leasequery hook library’s configuration (see the section +on configuration below). Queries received from unknown requesters are +logged and dropped. + +In response to a valid query, the server carries out the requisite +activities and returns a ``DHCPV6_LEASEQUERY_REPLY``. All replies contain +at least a ``status-code`` option (13) that indicates the outcome of the query +as detailed in the following table: + +.. tabularcolumns:: |p{0.5\linewidth}|p{0.3\linewidth}|p{0.1\linewidth}|p{0.3\linewidth}| + +.. table:: DHCPV6_LEASEQUERY_REPLY status option values per query outcome + :class: longtable + :widths: 50 30 10 30 + + +--------------------------------------+-------------------------+--------+------------------------------+ + | | Status | Status | Status | + | Query Outcome | Label | Code | Text | + +======================================+=========================+========+==============================+ + | Invalid query type field | STATUS_UnknownQueryType | 7 | "unknown query-type" | + +--------------------------------------+-------------------------+--------+------------------------------+ + | Query by IP address that does not | STATUS_Malformed | 10 | "missing D6O_IAADDR" | + | contain an address option | | | | + +--------------------------------------+-------------------------+--------+------------------------------+ + | Query by IP address for an address | STATUS_NotConfigured | 9 | "address not in a configured | + | that does fall within any configured | | | pool" | + | pools | | | | + +--------------------------------------+-------------------------+--------+------------------------------+ + | Query by IP address which found only | STATUS_Success | 0 | "inactive lease exists" | + | an inactive lease (e.g. expired, | | | | + | declined, reclaimed-expired) | | | | + +--------------------------------------+-------------------------+--------+------------------------------+ + | Query by IP address that found no | STATUS_Success | 0 | "no active lease" | + | leases (active or otherwise) | | | | + +--------------------------------------+-------------------------+--------+------------------------------+ + | Query by IP address that found an | STATUS_Success | 0 | "active lease found" | + | active lease for the address | | | | + +--------------------------------------+-------------------------+--------+------------------------------+ + | Query by Client ID that does not | STATUS_Malformed | 10 | "missing D6O_CLIENTID" | + | contain a client ID option | | | | + +--------------------------------------+-------------------------+--------+------------------------------+ + | Query by Client ID with a link | STATUS_NotConfigured | 9 | "not a configured link" | + | address that does not match any | | | | + | configured subnets | | | | + +--------------------------------------+-------------------------+--------+------------------------------+ + | Query by client ID which found no | STATUS_Success | 0 | "no active leases" | + | matching leases | | | | + +--------------------------------------+-------------------------+--------+------------------------------+ + | Query by client ID which found one | STATUS_Success | 0 | "active lease(s) found" | + | or more active leases | | | | + +--------------------------------------+-------------------------+--------+------------------------------+ + +For those scenarios where the query was either invalid or for which no matching active +leases were found, the ``DHCPV6_LEASEQUERY_REPLY`` only contains the ``status-code`` +option (12) per the above table. + +When a query finds active leases in more than one subnet and the query's ``link-address`` +is empty, then, in addition to the status-code, the ``DHCPV6_LEASEQUERY_REPLY`` +contains an ``lq-client-link`` option (48). The ``lq-client-link`` contains a list of +IPv6 addresses, one for each subnet in which a lease was found (see +`RFC 5007, Section 4.1.2.5 <https://tools.ietf.org/html/rfc5007#section-4.1.2.5>`__) +If, however, the query's ``link-address`` is not empty, the list of queries is +pruned to contain only leases that belong to that subnet. + +When the query results in one or more active leases which all belong to a single +subnet, in addition to the ``status-code``, the ``DHCPV6_LEASEQUERY_REPLY`` contains a +``client-data`` option (45) (see +`RFC 5007, Section 4.1.2.2 <https://tools.ietf.org/html/rfc5007#section-4.1.2.2>`__). +The client-data option encapsulates the following options: + +.. tabularcolumns:: |p{0.2\linewidth}|p{0.1\linewidth}|p{0.7\linewidth}| + +.. table:: OPTION_CLIENT_DATA returned when active lease(s) are found + :class: longtable + :widths: 30 10 70 + + +------------------------------+-------+-----------------------------------------------+ + | Option | Code | Content | + +==============================+=======+===============================================+ + | clientid | 1 | copied from the lease (if one exists) | + +------------------------------+-------+-----------------------------------------------+ + | clt-time | 46 | amount of time that has elapsed since the | + | | | lease's client-last-transaction-time (CLTT). | + | | | This value will also be used by the server to | + | | | adjust lifetime and timer values. | + +------------------------------+-------+-----------------------------------------------+ + | iaaddr | 5 | One option per matched address. Fields in | + | | | each option: | + | | | - lease address | + | | | - valid lifetime reduced by CLTT | + | | | - preferred lifetime reduced by CLTT | + +------------------------------+-------+-----------------------------------------------+ + | iaprefix | 26 | One option per matched prefix. Fields in | + | | | each option: | + | | | - prefix | + | | | - prefix length | + | | | - valid lifetime reduced by CLTT | + | | | - preferred lifetime reduced by CLTT | + +------------------------------+-------+-----------------------------------------------+ + +If the lease with the most recent client-last-transaction-time (CLTT) +value has relay information in its user-context (see +:ref:`store-extended-info-v6`), then an ``OPTION_LQ_RELAY_DATA`` option is +added to the reply (see +`RFC 5007, Section 4.1.2.4 <https://tools.ietf.org/html/rfc5007#section-4.1.2.4>`__). + +The relay information on the lease is a list with an entry for each +relay layer the client packet (e.g. ``DHCPV6_REQUEST``) traversed, with the +first entry in the list being the outermost layer (closest to the server). The +``peer-address`` field of the ``lq-rely-option`` is set to the peer address of this +relay. The list of relays is then used to construct a ``DHCPV6_RELAY_FORW`` message +equivalent to that which contained the client packet, minus the client packet. +This message is stored in the ``DHCP-relay-message`` field of the ``lq-relay-data`` option. + +.. _lease-query-dhcpv6-config: + +DHCPv6 Leasequery Configuration +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Configuring the Leasequery hook library for use is straightforward. It +supports a single parameter, ``requesters``, which is a list of IP addresses from +which DHCPV6_LEASEQUERY packets are accepted. In other words, it is a list of +known requesters. The following code shows an example configuration with two requester +addresses: + +:: + + { + "hooks-libraries": [ + { + "library": "lib/kea/hooks/libdhcp_lease_query.so", + "parameters": { + "requesters": [ "2001:db8:1::1", "2001:db8:2::1" ], + "prefix-lengths": [ 72 ] + } + } + ], + ... + } + +.. note:: + + For security purposes, there is no way to specify wildcards. Each requester address + must be explicitly listed. + +When a query by IP address does not match an existing address lease, +a search for a matching delegated prefix is conducted. This is carried +out by iterating over a list of prefix lengths, in descending order, +extracting a prefix of that length from the query address and searching +for a delegation matching the resulting prefix. This continues for each +length in the list until a match is found or the list is exhausted. + +By default, the list of prefix lengths to use in the search is determined +dynamically after (re)configuration events. This resulting list will +contain unique values of ``delegated-len`` gleaned from the currently +configured set of PD pools. + +There is an optional parameter, ``prefix-lengths``, shown above which +provides the ability to explicitly configure the list rather than having +it be determined dynamically. This provides tighter control over which +prefix lengths are searched. In the above example, the prefix length +search will be restricted to single pass, using a length of 72, regardless +of whether or not there are pools using other values for ``delegated-len``. +Specifying an empty list, as shown below: + +:: + + : + "prefix-lengths": [ ] + : + +disables the search for delegated prefixes for query by IP address. + +.. _bulk-lease-query-dhcpv4: + +DHCPv4 Bulk Leasequery +~~~~~~~~~~~~~~~~~~~~~~ + +DHCPv4 Bulk Leasequery gives a requester the ability to query for +active lease information over a TCP connection. This allows the server +to return all leases matching a given query. + +Two of the query types identified by RFC 4388 - Query by MAC address and +Query by Client-identifier - are Bulk Leasequery types specified by RFC +6926. That RFC also defines these new Bulk Leasequery types: + +- Query by Relay Identifier + + The query carries an RAI (dhcp-agent-options (82)) option with + a relay-id (12) sub-option. + +- Query by Remote ID + + The query carries an RAI (dhcp-agent-options (82) option) with + a remote-id (2) sub-option. + +- Query for All Configured IP Addresses + + This query type is selected when no other query type is specified. + +RFC 6926 also defines new options for Bulk Leasequery: + +- status-code (151) + + This reply option carries a status code such as MalformedQuery or + NotAllowed, with an optional text message. + +- base-time (152) + + This reply option carries the absolute current time that the response + was created. All other time-based reply options are related to + this value. + +- start-time-of-state (153) + + This reply option carries the time of the lease's transition into its + current state. + +- query-start-time (154) + + This query option specifies a start query time; replies will only + contain leases that are older than this value. + +- query-end-time (155) + + This query option specifies an end query time; replies will only + contain leases that are newer than this value. + +- dhcp-state (156) + + This reply option carries the lease state. + +- data-source (157) + + This reply option carries the source of the data as a remote flag. + +RFC 6926 reuses and extends the Virtual Subnet Selection option (221) +defined in RFC 6607. + +.. note:: + + Kea does not yet support querying for all configured IP addresses, + so the dhcp-state option cannot be used, as only active leases can be + returned in replies. Kea does not keep the start time of the lease's state, + nor the local/remote information, so it cannot emit the corresponding + start-time-of-state and data-source options. Kea does not support VPNs + so the presence of option 221 in the query is considered a + (NotAllowed) error. + +.. note:: + + The new query types are only supported with the memfile lease backend. + +.. _bulk-lease-query-dhcpv6: + +DHCPv6 Bulk Leasequery +~~~~~~~~~~~~~~~~~~~~~~ + +DHCPv6 Bulk Leasequery gives a requester the ability to query for +active lease information over a TCP connection. This allows the server +to return all active leases matching a query. + +New query types are available: ``query-by-relay-id`` (3), +``query-by-link-address`` (4), and ``query-by-remote-id`` (5). + +A new status code, ``STATUS_QueryTerminated`` (11), has been defined but it is +not yet used by the hook library. + +.. note:: + + Kea attempts to map link address parameters to the prefixes of configured + subnets. If a given address falls outside all configured subnet prefixes, + the query fails with a status code of ``STATUS_NotConfigured``. If + the link address parameter for ``query-by-relay-id`` or ``query-by-remote-id`` + is not ``::`` (i.e. not empty), only delegated prefixes that lie within matching + subnet prefixes are returned. Currently, ``query-by-address`` does not + support finding delegated prefixes by specifying an address that lies within + the prefix. + +.. note:: + + The new query types are only supported with the memfile lease backend. + +.. _bulk-lease-query-dhcpv6-config: + +Bulk Leasequery Configuration +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Bulk Leasequery configuration is done via a new map parameter, ``advanced``, +with these possible entries: + +- ``bulk-query-enabled`` + + When ``true``, Kea accepts connections from IP addresses in the requesters + list and processes received Bulk Leasequeries. The default is ``false``. + +- ``active-query-enabled`` + + This is an anticipated parameter: if set, it must be ``false``. + +- ``extended-info-tables-enabled`` + + When ``true``, the lease backend manages DHCPv6 lease extended info + (relay info) in tables to support the new DHCPv6 Bulk Leasequery + by-relay-id and by-remote-id types. The default is to use the + same value as ``bulk-query-enabled``. + +- ``lease-query-ip`` + + This is the IP address upon which to listen for connections. The address must be + of the same family as the server, e.g. IPv6 for DHCPv6 server. + +- ``lease-query-port`` + + This is the port upon which to listen. The default is 67 for IPv4 and 547 for IPv6, + i.e. the same value as for the UDP DHCP service but for TCP. + +- ``max-bulk-query-threads`` + + This indicates the maximum number of threads that Bulk Leasequery processing + should use. A value of 0 instructs the server to use the same number of + threads that the Kea core is using for DHCP multi-threading. + The default is 0. + +- ``max-requester-connections`` + + This is the maximum number of concurrent requester connections. The default + is 10; the value must be greater than 0. + +- ``max-concurrent-queries`` + + This is the maximum number of concurrent queries per connection. The value 0 + allows Kea to determine the number, and is the default. + +- ``max-requester-idle-time`` + + This is the amount of time that may elapse after receiving data from a requester + before its connection is closed as idle, in seconds. The default + is 300. + +- ``max-leases-per-fetch`` + + This is the maximum number of leases to return in a single fetch. The default is 100. + +Once TLS is supported, we expect to implement common TLS parameters. + +For instance, for DHCPv4: + +:: + + { + "hooks-libraries": [ + { + "library": "lib/kea/hooks/libdhcp_lease_query.so", + "parameters": { + "requesters": [ "192.0.2.1", "192.0.2.2" ], + "advanced" : { + "bulk-query-enabled": true, + "active-query-enabled": false, + + "lease-query-ip": "127.0.0.1", + "lease-query-tcp-port": 67, + + "max-bulk-query-threads": 0, + "max-requester-connections": 10, + "max-concurrent-queries": 4, + "max-requester-idle-time": 300, + "max-leases-per-fetch": 100 + } + } + } + ], + ... + } + +or for DHCPv6: + +:: + + { + "hooks-libraries": [ + { + "library": "lib/kea/hooks/libdhcp_lease_query.so", + "parameters": { + "requesters": [ "2001:db8:1::1", "2001:db8:2::1" ], + "advanced" : { + "bulk-query-enabled": true, + "active-query-enabled": false, + + "extended-info-tables-enabled": true, + + "lease-query-ip": "::1", + "lease-query-tcp-port": 547, + + "max-bulk-query-threads": 0, + "max-requester-connections": 10, + "max-concurrent-queries": 4, + "max-requester-idle-time": 300, + "max-leases-per-fetch": 100 + } + } + } + ], + ... + } + +.. _updating-existing-leases: + +Updating Existing Leases in SQL Lease Backends +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Bulk Lease Query required additions to the lease data stored. With SQL lease +backends, leases created prior to the server being configured for Bulk Lease +Query will not contain the new data required. In order to populate this data +it is necessary to run API commands: + +.. isccmd:: extended-info4-upgrade +.. _command-extended-info4-upgrade: + +For DHCPv4 lease data, the command is: + +:: + + { + "command": "extended-info4-upgrade" + } + +For DHCPv6 lease data, the command is: + +.. isccmd:: extended-info6-upgrade +.. _command-extended-info6-upgrade: + +for extended info used for by relay id and by remote id the command is: + +:: + + { + "command": "extended-info6-upgrade" + } + + +In all cases the response will indicate whether it succeeded or failed +and include either the count of leases updated or the nature of the failure: + +:: + + { + "result": 0, + "text": "Upgraded 1000 leases" + } + + +This ``extended-info6-upgrade`` command must be called when: + +- the database schema was upgraded from a previous version + +- Bulk Lease Query was not enabled (tables are maintained only when v6 BLQ is + enabled) + +- data in tables do not seem to be consistent (tables are not maintained in + an atomic way so consistency is not guaranteed. For instance when a database + is shared between several servers races can happen between updates) + +The operation of extended info command is governed by ``extended-info-checks`` +parameter under the sanity-checks element. Please see :ref:`sanity-checks4` +or :ref:`sanity-checks6`. + +For large numbers of leases this command may take some time to complete. + +.. note:: + + Existing leases must have been created by Kea with ``store-extended-info`` + enabled in order for the new data from extended info to be extracted + and stored. + diff --git a/doc/sphinx/arm/hooks-legal-log.rst b/doc/sphinx/arm/hooks-legal-log.rst new file mode 100644 index 0000000..be2a07c --- /dev/null +++ b/doc/sphinx/arm/hooks-legal-log.rst @@ -0,0 +1,1094 @@ +.. ischooklib:: libdhcp_legal_log.so +.. _hooks-legal-log: + +``libdhcp_legal_log.so``: Forensic Logging +========================================== + +The Forensic Logging hook library provides +hooks that record a detailed log of assignments, renewals, releases, and other +lease events into a set of log files. + +.. note:: + + :ischooklib:`libdhcp_legal_log.so` is available as a premium + hook library from ISC. Please visit https://www.isc.org/shop/ to purchase + the premium hook libraries, or contact us at https://www.isc.org/contact for + more information. + +.. note:: + + This library can only be loaded by the :iscman:`kea-dhcp4` or :iscman:`kea-dhcp6` + process. + +In many legal jurisdictions, companies - especially ISPs - must record +information about the addresses they have leased to DHCP clients. This +library is designed to help with that requirement. If the information +that it records is sufficient, it may be used directly. + +If a jurisdiction requires that different information be saved, users +may use the custom formatting capability to extract information from the inbound +request packet, or from the outbound response packet. Administrators are advised +to use this feature with caution, as it may affect server performance. +The custom format cannot be used for control channel commands. + +Alternatively, this library may be used as a template or an example for the +user's own custom logging hook. The logging is done as a set of hooks to allow +it to be customized to any particular need; modifying a hook library is easier +and safer than updating the core code. In addition, by using the hooks features, +users who do not need to log this information can leave it out and avoid +any performance penalties. + +Log File Naming +~~~~~~~~~~~~~~~ + +The names of the log files follow a set pattern. + +If using ``day``, ``month``, or ``year`` as the time unit, the file name follows +the format: + +:: + + path/base-name.CCYYMMDD.txt + +where ``CC`` represents the century, ``YY`` represents the year, +``MM`` represents the month, and ``DD`` represents the day. + +If using ``second`` as the time unit the file name follows the format: + +:: + + path/base-name.TXXXXXXXXXXXXXXXXXXXX.txt + +where ``XXXXXXXXXXXXXXXXXXXX`` represents the time in seconds since the beginning +of the UNIX epoch. + +When using ``second`` as the time unit, the file is rotated when +the ``count`` number of seconds pass. In contrast, when using ``day``, ``month``, +or ``year`` as the time unit, the file is rotated whenever the ``count`` of day, +month, or year starts, as applicable. + +The ``"path"`` and ``"base-name"`` are supplied in the configuration as +described below; see :ref:`forensic-log-configuration`. + +.. note:: + + When running Kea servers for both DHCPv4 and DHCPv6, the log names + must be distinct. See the examples in :ref:`forensic-log-configuration`. + +.. _forensic-log-configuration: + +Configuring the Forensic Logging Hooks +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To use this functionality, the hook library must be included in the +configuration of the desired DHCP server modules. :ischooklib:`libdhcp_legal_log.so` +can save logs to a text file or to a database (created using +:iscman:`kea-admin`; see :ref:`mysql-database-create` and :ref:`pgsql-database-create`). +The library is installed alongside the Kea libraries in +``[kea-install-dir]/var/lib/kea``, where ``kea-install-dir`` is determined +by the ``--prefix`` option of the configure script; it defaults to +``/usr/local``. Assuming the default value, :iscman:`kea-dhcp4` can be configured to load +:ischooklib:`libdhcp_legal_log.so` like this: + +.. code-block:: json + + { + "Dhcp4": { + "hooks-libraries": [ + { + "library": "/usr/local/lib/kea/hooks/libdhcp_legal_log.so", + "parameters": { + "path": "/var/lib/kea/log", + "base-name": "kea-forensic4" + } + } + ] + } + } + +For :iscman:`kea-dhcp6`, the configuration is: + +.. code-block:: json + + { + "Dhcp6": { + "hooks-libraries": [ + { + "library": "/usr/local/lib/kea/hooks/libdhcp_legal_log.so", + "parameters": { + "path": "/var/lib/kea/log", + "base-name": "kea-forensic6" + } + } + ] + } + } + +The hook library parameters for the text file configuration are: + +- ``path`` - the directory in which the forensic file(s) will be written. + The default value is ``[prefix]/var/lib/kea``. The directory must exist. + +- ``base-name`` - an arbitrary value which is used in conjunction with the + current system date to form the current forensic file name. It + defaults to ``kea-legal``. + +- ``time-unit`` - configures the time unit used to rotate the log file. Valid + values are ``second``, ``day``, ``month``, or ``year``. It defaults to + ``day``. + +- ``count`` - configures the number of time units that need to pass until the + log file is rotated. It can be any positive number, or 0, which disables log + rotation. It defaults to 1. + +If log rotation is disabled, a new file is created when the library is +loaded; the new file name is different from any previous file name. + +Additional actions can be performed just before closing the old file and after +opening the new file. These actions must point to an external executable or +script and are configured with the following settings: + +- ``prerotate`` - an external executable or script called with the name of the + file that will be closed. Kea does not wait for the process to finish. + +- ``postrotate`` - an external executable or script called with the name of the + file that was opened. Kea does not wait for the process to finish. + +Custom formatting can be enabled for logging information that can be extracted +either from the client's request packet or from the server's response packet. +Use with caution as this might affect server performance. +The custom format cannot be used for control channel commands. +Two parameters can be used towards this goal, either together or separately: + +- ``request-parser-format`` - an evaluated parsed expression used to extract and + log data from the incoming packet. + +- ``response-parser-format`` - an evaluated parsed expression used to extract and + log data from the server response packet. + +See :ref:`classification-using-expressions` for a list of expressions. +If either ``request-parser-format`` or ``response-parser-format`` is +configured, the default logging format is not used. If both of them are +configured, the resulting log message is constructed by concatenating the +data extracted from the request and the data extracted from the response. + +The custom formatting permits logging on multiple lines using the hexstring 0x0a +(ASCII code for new line). In the log file, each line is prepended +with the log timestamp. For the database backend, the data is stored +(including the newline character) in the same entry. + +Examples: + +.. code-block:: json + + { + "Dhcp6": { + "hooks-libraries": [ + { + "library": "/usr/local/lib/kea/hooks/libdhcp_legal_log.so", + "parameters": { + "path": "/var/lib/kea/log", + "base-name": "kea-forensic6", + "request-parser-format": "'first line' + 0x0a + 'second line'", + "response-parser-format": "'also second line' + 0x0a + 'third line'" + } + } + ] + } + } + +Some data might be available in the request or only in the response; the +data in the request packet might differ from that in the response packet. + +The lease-client context can only be printed using the default format, as this +information is not directly stored in the request packet or in the response +packet. + +The ``timestamp-format`` parameter can be used to change the timestamp logged +at the beginning of each line. Permissible formatting is the one supported by +strftime plus the '%Q' extra format which adds the microseconds subunits. The +default is: "%Y-%m-%d %H:%M:%S %Z". This parameter has no effect for the +database backends, where the timestamp is defined at the schema level. + +Examples: + +.. code-block:: json + + { + "Dhcp6": { + "hooks-libraries": [ + { + "library": "/usr/local/lib/kea/hooks/libdhcp_legal_log.so", + "parameters": { + "path": "/var/lib/kea/log", + "base-name": "kea-forensic6", + "timestamp-format": "%H%t%w %F%%" + } + } + ] + } + } + +Additional parameters for the database connection can be specified, e.g: + +.. code-block:: json + + { + "Dhcp6": { + "hooks-libraries": [ + { + "library": "/usr/local/lib/kea/hooks/libdhcp_legal_log.so", + "parameters": { + "name": "database-name", + "password": "passwd", + "type": "mysql", + "user": "user-name" + } + } + ] + } + } + +For more specific information about database-related parameters, please refer to +:ref:`database-configuration4` and :ref:`database-configuration6`. + +If it is desired to restrict forensic logging to certain subnets, the +``"legal-logging"`` boolean parameter can be specified within a user context +of these subnets. For example: + +.. code-block:: json + + { + "Dhcp4": { + "subnet4": [ + { + "id": 1, + "subnet": "192.0.2.0/24", + "pools": [ + { + "pool": "192.0.2.1 - 192.0.2.200" + } + ], + "user-context": { + "legal-logging": false + } + } + ] + } + } + +This configuration disables legal logging for the subnet "192.0.2.0/24". If the +``"legal-logging"`` parameter is not specified, it defaults to ``true``, which +enables legal logging for the subnet. + +The following example demonstrates how to selectively disable legal +logging for an IPv6 subnet: + +.. code-block:: json + + { + "Dhcp6": { + "subnet6": [ + { + "id": 1, + "subnet": "2001:db8:1::/64", + "pools": [ + { + "pool": "2001:db8:1::1-2001:db8:1::ffff" + } + ], + "user-context": { + "legal-logging": false + } + } + ] + } + } + +See :ref:`dhcp4-user-contexts` and :ref:`dhcp6-user-contexts` to +learn more about user contexts in Kea configuration. + +DHCPv4 Log Entries +~~~~~~~~~~~~~~~~~~ + +For DHCPv4, the library creates entries based on DHCPREQUEST, DHCPDECLINE, +and DHCPRELEASE messages, et al., and their responses. The resulting packets and +leases are taken into account, intercepted through the following hook points: + +* ``pkt4_receive`` +* ``leases4_committed`` +* ``pkt4_send`` +* ``lease4_release`` +* ``lease4_decline`` + +An entry is a single string with no embedded end-of-line markers and a +prepended timestamp, and has the following sections: + +:: + + timestamp address duration device-id {client-info} {relay-info} {user-context} + +Where: + +- ``timestamp`` - the date and time the log entry was written, in + "%Y-%m-%d %H:%M:%S %Z" strftime format ("%Z" is the time zone name). + +- ``address`` - the leased IPv4 address given out, and whether it was + assigned, renewed, or released. + +- ``duration`` - the lease lifetime expressed in days (if present), hours, + minutes, and seconds. A lease lifetime of 0xFFFFFFFF will be denoted + with the text "infinite duration." This information is not given + when the lease is released. + +- ``device-id`` - the client's hardware address shown as a numerical type and + hex-digit string. + +- ``client-info`` - the DHCP client id option (61) if present, shown as a + hex string. When its content is printable it is displayed. + +- ``relay-info`` - for relayed packets, the ``giaddr`` and the RAI ``circuit-id``, + ``remote-id``, and ``subscriber-id`` options (option 82 sub options: 1, 2 and 6), + if present. The ``circuit-id`` and ``remote-id`` are presented as hex + strings. When their content is printable it is displayed. + +- ``user-context`` - the optional user context associated with the lease. + +For instance (line breaks are added here for readability; they are not +present in the log file): + +:: + + 2018-01-06 01:02:03 CET Address: 192.2.1.100 has been renewed for 1 hrs 52 min 15 secs to a device with hardware address: + hwtype=1 08:00:2b:02:3f:4e, client-id: 17:34:e2:ff:09:92:54 connected via relay at address: 192.2.16.33, + identified by circuit-id: 68:6f:77:64:79 (howdy) and remote-id: 87:f6:79:77:ef + +or for a release: + +:: + + 2018-01-06 01:02:03 CET Address: 192.2.1.100 has been released from a device with hardware address: + hwtype=1 08:00:2b:02:3f:4e, client-id: 17:34:e2:ff:09:92:54 connected via relay at address: 192.2.16.33, + identified by circuit-id: 68:6f:77:64:79 (howdy) and remote-id: 87:f6:79:77:ef + +In addition to logging lease activity driven by DHCPv4 client traffic, +the hook library also logs entries for the following lease management control +channel commands: :isccmd:`lease4-add`, :isccmd:`lease4-update`, and :isccmd:`lease4-del`. These cannot have +custom formatting. Each entry is a single string with no embedded end-of-line +markers, and it will typically have the following form: + +``lease4-add:`` + +:: + + *timestamp* Administrator added a lease of address: *address* to a device with hardware address: *device-id* + +Depending on the arguments of the add command, it may also include the +client-id and duration. + +Example: + +:: + + 2018-01-06 01:02:03 CET Administrator added a lease of address: 192.0.2.202 to a device with hardware address: + 1a:1b:1c:1d:1e:1f for 1 days 0 hrs 0 mins 0 secs + +``lease4-update:`` + +:: + + *timestamp* Administrator updated information on the lease of address: *address* to a device with hardware address: *device-id* + +Depending on the arguments of the update command, it may also include +the client-id and lease duration. + +Example: + +:: + + 2018-01-06 01:02:03 CET Administrator updated information on the lease of address: 192.0.2.202 to a device + with hardware address: 1a:1b:1c:1d:1e:1f, client-id: 1234567890 + +``lease4-del:`` deletes have two forms, one by address and one by +identifier and identifier type: + +:: + + *timestamp* Administrator deleted the lease for address: *address* + +or + +:: + + *timestamp* Administrator deleted a lease for a device identified by: *identifier-type* of *identifier* + +Currently only a type of ``@b hw-address`` (hardware address) is supported. + +Examples: + +:: + + 2018-01-06 01:02:03 CET Administrator deleted the lease for address: 192.0.2.202 + + 2018-01-06 01:02:12 CET Administrator deleted a lease for a device identified by: hw-address of 1a:1b:1c:1d:1e:1f + +If High availability module is enabled, the partner will periodically send lease +commands which have a similar format, the only difference is that the issuer of +the command is 'HA partner' instead of 'Administrator'. + +:: + + *timestamp* HA partner added ... + +or + +:: + + *timestamp* HA partner updated ... + +or + +:: + + *timestamp* HA partner deleted ... + +The ``request-parser-format`` and ``response-parser-format`` options can be used to +extract and log data from the incoming packet and server response packet, +respectively. The configured value is an evaluated parsed expression returning a +string. A list of tokens is described in the server classification process. +Use with caution as this might affect server performance. +If either of them is configured, the default logging format is not used. +If both of them are configured, the resulting log message is constructed by +concatenating the logged data extracted from the request and the logged data +extracted from the response. + +The custom formatting permits logging on multiple lines using the hexstring 0x0a +(ASCII code for new line). In the case of the log file, each line is prepended +with the log timestamp. For the database backend, the data is stored +(including the newline character) in the same entry. + +Examples: + +.. code-block:: json + + { + "Dhcp4": { + "hooks-libraries": [ + { + "library": "/usr/local/lib/kea/hooks/libdhcp_legal_log.so", + "parameters": { + "name": "database-name", + "password": "passwd", + "type": "mysql", + "user": "user-name", + "request-parser-format": "'log entry' + 0x0a + 'same log entry'", + "response-parser-format": "'also same log entry' + 0x0a + 'again same log entry'" + } + } + ] + } + } + +Some data might be available in the request or in the response only, and some +data might differ in the incoming packet from the one in the response packet. + +Examples: + +.. code-block:: json + + { + "request-parser-format": "ifelse(pkt4.msgtype == 4 or pkt4.msgtype == 7, 'Address: ' + ifelse(option[50].exists, addrtotext(option[50].hex), addrtotext(pkt4.ciaddr)) + ' has been released from a device with hardware address: hwtype=' + substring(hexstring(pkt4.htype, ''), 7, 1) + ' ' + hexstring(pkt4.mac, ':') + ifelse(option[61].exists, ', client-id: ' + hexstring(option[61].hex, ':'), '') + ifelse(pkt4.giaddr == 0.0.0.0, '', ' connected via relay at address: ' + addrtotext(pkt4.giaddr) + ifelse(option[82].option[1].exists, ', circuit-id: ' + hexstring(option[82].option[1].hex, ':'), '') + ifelse(option[82].option[2].exists, ', remote-id: ' + hexstring(option[82].option[2].hex, ':'), '') + ifelse(option[82].option[6].exists, ', subscriber-id: ' + hexstring(option[82].option[6].hex, ':'), '')), '')", + "response-parser-format": "ifelse(pkt4.msgtype == 5, 'Address: ' + addrtotext(pkt4.yiaddr) + ' has been assigned for ' + uint32totext(option[51].hex) + ' seconds to a device with hardware address: hwtype=' + substring(hexstring(pkt4.htype, ''), 7, 1) + ' ' + hexstring(pkt4.mac, ':') + ifelse(option[61].exists, ', client-id: ' + hexstring(option[61].hex, ':'), '') + ifelse(pkt4.giaddr == 0.0.0.0, '', ' connected via relay at address: ' + addrtotext(pkt4.giaddr) + ifelse(option[82].option[1].exists, ', circuit-id: ' + hexstring(option[82].option[1].hex, ':'), '') + ifelse(option[82].option[2].exists, ', remote-id: ' + hexstring(option[82].option[2].hex, ':'), '') + ifelse(option[82].option[6].exists, ', subscriber-id: ' + hexstring(option[82].option[6].hex, ':'), '')), '')" + } + +Details: + +.. raw:: html + + <details><summary>Expand here!</summary> + <pre>{ + "request-parser-format": + "ifelse(pkt4.msgtype == 4 or pkt4.msgtype == 7, + 'Address: ' + + ifelse(option[50].exists, + addrtotext(option[50].hex), + addrtotext(pkt4.ciaddr)) + + ' has been released from a device with hardware address: hwtype=' + substring(hexstring(pkt4.htype, ''), 7, 1) + ' ' + hexstring(pkt4.mac, ':') + + ifelse(option[61].exists, + ', client-id: ' + hexstring(option[61].hex, ':'), + '') + + ifelse(pkt4.giaddr == 0.0.0.0, + '', + ' connected via relay at address: ' + addrtotext(pkt4.giaddr) + + ifelse(option[82].option[1].exists, + ', circuit-id: ' + hexstring(option[82].option[1].hex, ':'), + '') + + ifelse(option[82].option[2].exists, + ', remote-id: ' + hexstring(option[82].option[2].hex, ':'), + '') + + ifelse(option[82].option[6].exists, + ', subscriber-id: ' + hexstring(option[82].option[6].hex, ':'), + '')), + '')", + "response-parser-format": + "ifelse(pkt4.msgtype == 5, + 'Address: ' + addrtotext(pkt4.yiaddr) + ' has been assigned for ' + uint32totext(option[51].hex) + ' seconds to a device with hardware address: hwtype=' + substring(hexstring(pkt4.htype, ''), 7, 1) + ' ' + hexstring(pkt4.mac, ':') + + ifelse(option[61].exists, + ', client-id: ' + hexstring(option[61].hex, ':'), + '') + + ifelse(pkt4.giaddr == 0.0.0.0, + '', + ' connected via relay at address: ' + addrtotext(pkt4.giaddr) + + ifelse(option[82].option[1].exists, + ', circuit-id: ' + hexstring(option[82].option[1].hex, ':'), + '') + + ifelse(option[82].option[2].exists, + ', remote-id: ' + hexstring(option[82].option[2].hex, ':'), + '') + + ifelse(option[82].option[6].exists, + ', subscriber-id: ' + hexstring(option[82].option[6].hex, ':'), + '')), + '')" + }</pre> + </details><br> + +This will log the following data on request and renew: + +:: + + Address: 192.2.1.100 has been assigned for 6735 seconds to a device with hardware address: hwtype=1 08:00:2b:02:3f:4e, client-id: 17:34:e2:ff:09:92:54 connected via relay at address: 192.2.16.33, circuit-id: 68:6f:77:64:79, remote-id: 87:f6:79:77:ef, subscriber-id: 1a:2b:3c:4d:5e:6f + +This will log the following data on release and decline: + +:: + + Address: 192.2.1.100 has been released from a device with hardware address: hwtype=1 08:00:2b:02:3f:4e, client-id: 17:34:e2:ff:09:92:54 connected via relay at address: 192.2.16.33, circuit-id: 68:6f:77:64:79, remote-id: 87:f6:79:77:ef, subscriber-id: 1a:2b:3c:4d:5e:6f + +A similar result can be obtained by configuring only ``request-parser-format``. + +Examples: + +.. code-block:: json + + { + "request-parser-format": "ifelse(pkt4.msgtype == 3, 'Address: ' + ifelse(option[50].exists, addrtotext(option[50].hex), addrtotext(pkt4.ciaddr)) + ' has been assigned' + ifelse(option[51].exists, ' for ' + uint32totext(option[51].hex) + ' seconds', '') + ' to a device with hardware address: hwtype=' + substring(hexstring(pkt4.htype, ''), 7, 1) + ' ' + hexstring(pkt4.mac, ':') + ifelse(option[61].exists, ', client-id: ' + hexstring(option[61].hex, ':'), '') + ifelse(pkt4.giaddr == 0.0.0.0, '', ' connected via relay at address: ' + addrtotext(pkt4.giaddr) + ifelse(option[82].option[1].exists, ', circuit-id: ' + hexstring(option[82].option[1].hex, ':'), '') + ifelse(option[82].option[2].exists, ', remote-id: ' + hexstring(option[82].option[2].hex, ':'), '') + ifelse(option[82].option[6].exists, ', subscriber-id: ' + hexstring(option[82].option[6].hex, ':'), '')), ifelse(pkt4.msgtype == 4 or pkt4.msgtype == 7, 'Address: ' + ifelse(option[50].exists, addrtotext(option[50].hex), addrtotext(pkt4.ciaddr)) + ' has been released from a device with hardware address: hwtype=' + substring(hexstring(pkt4.htype, ''), 7, 1) + ' ' + hexstring(pkt4.mac, ':') + ifelse(option[61].exists, ', client-id: ' + hexstring(option[61].hex, ':'), '') + ifelse(pkt4.giaddr == 0.0.0.0, '', ' connected via relay at address: ' + addrtotext(pkt4.giaddr) + ifelse(option[82].option[1].exists, ', circuit-id: ' + hexstring(option[82].option[1].hex, ':'), '') + ifelse(option[82].option[2].exists, ', remote-id: ' + hexstring(option[82].option[2].hex, ':'), '') + ifelse(option[82].option[6].exists, ', subscriber-id: ' + hexstring(option[82].option[6].hex, ':'), '')), ''))" + } + +Details: + +.. raw:: html + + <details><summary>Expand here!</summary> + <pre>{ + "request-parser-format": + "ifelse(pkt4.msgtype == 3, + 'Address: ' + + ifelse(option[50].exists, + addrtotext(option[50].hex), + addrtotext(pkt4.ciaddr)) + + ' has been assigned' + + ifelse(option[51].exists, + ' for ' + uint32totext(option[51].hex) + ' seconds', + '') + + ' to a device with hardware address: hwtype=' + substring(hexstring(pkt4.htype, ''), 7, 1) + ' ' + hexstring(pkt4.mac, ':') + + ifelse(option[61].exists, + ', client-id: ' + hexstring(option[61].hex, ':'), + '') + + ifelse(pkt4.giaddr == 0.0.0.0, + '', + ' connected via relay at address: ' + addrtotext(pkt4.giaddr) + + ifelse(option[82].option[1].exists, + ', circuit-id: ' + hexstring(option[82].option[1].hex, ':'), + '') + + ifelse(option[82].option[2].exists, + ', remote-id: ' + hexstring(option[82].option[2].hex, ':'), + '') + + ifelse(option[82].option[6].exists, + ', subscriber-id: ' + hexstring(option[82].option[6].hex, ':'), + '')), + ifelse(pkt4.msgtype == 4 or pkt4.msgtype == 7, + 'Address: ' + + ifelse(option[50].exists, + addrtotext(option[50].hex), + addrtotext(pkt4.ciaddr)) + + ' has been released from a device with hardware address: hwtype=' + substring(hexstring(pkt4.htype, ''), 7, 1) + ' ' + hexstring(pkt4.mac, ':') + + ifelse(option[61].exists, + ', client-id: ' + hexstring(option[61].hex, ':'), + '') + + ifelse(pkt4.giaddr == 0.0.0.0, + '', + ' connected via relay at address: ' + addrtotext(pkt4.giaddr) + + ifelse(option[82].option[1].exists, + ', circuit-id: ' + hexstring(option[82].option[1].hex, ':'), + '') + + ifelse(option[82].option[2].exists, + ', remote-id: ' + hexstring(option[82].option[2].hex, ':'), + '') + + ifelse(option[82].option[6].exists, + ', subscriber-id: ' + hexstring(option[82].option[6].hex, ':'), + '')), + ''))" + }</pre> + </details><br> + +DHCPv6 Log Entries +~~~~~~~~~~~~~~~~~~ + +For DHCPv6, the library creates entries based on REQUEST, RENEW, RELEASE, +and DECLINE messages, et al. and their responses. The resulting packets and leases +are taken into account, intercepted through the following hook points: + +* ``pkt6_receive`` +* ``leases6_committed`` +* ``pkt6_send`` +* ``lease6_release`` +* ``lease6_decline`` + +An entry is a single string with no embedded end-of-line markers and a +prepended timestamp, and has the following sections: + +:: + + timestamp address duration device-id {relay-info}* {user-context} + +Where: + +- ``timestamp`` - the date and time the log entry was written, in + "%Y-%m-%d %H:%M:%S %Z" strftime format ("%Z" is the time zone name). + +- ``address`` - the leased IPv6 address or prefix given out, and whether it + was assigned, renewed, or released. + +- ``duration`` - the lease lifetime expressed in days (if present), hours, + minutes, and seconds. A lease lifetime of 0xFFFFFFFF will be denoted + with the text "infinite duration." This information is not given + when the lease is released. + +- ``device-id`` - the client's DUID and hardware address (if present). + +- ``relay-info`` - for relayed packets the content of relay agent messages, and the + ``remote-id`` (code 37), ``subscriber-id`` (code 38), and ``interface-id`` (code 18) + options, if present. Note that the ``interface-id`` option, if present, + identifies the whole interface on which the relay agent received the message. + This typically translates to a single link in the network, but + it depends on the specific network topology. Nevertheless, this is + useful information to better pinpoint the location of the device, + so it is recorded, if present. + +- ``user-context`` - the optional user context associated with the lease. + +For instance (line breaks are added here for readability; they are not +present in the log file): + +:: + + 2018-01-06 01:02:03 PST Address:2001:db8:1:: has been assigned for 0 hrs 11 mins 53 secs + to a device with DUID: 17:34:e2:ff:09:92:54 and hardware address: hwtype=1 08:00:2b:02:3f:4e + (from Raw Socket) connected via relay at address: fe80::abcd for client on link address: 3001::1, + hop count: 1, identified by remote-id: 01:02:03:04:0a:0b:0c:0d:0e:0f and subscriber-id: 1a:2b:3c:4d:5e:6f + +or for a release: + +:: + + 2018-01-06 01:02:03 PST Address:2001:db8:1:: has been released + from a device with DUID: 17:34:e2:ff:09:92:54 and hardware address: hwtype=1 08:00:2b:02:3f:4e + (from Raw Socket) connected via relay at address: fe80::abcd for client on link address: 3001::1, + hop count: 1, identified by remote-id: 01:02:03:04:0a:0b:0c:0d:0e:0f and subscriber-id: 1a:2b:3c:4d:5e:6f + +In addition to logging lease activity driven by DHCPv6 client traffic, +the hook library also logs entries for the following lease management control channel +commands: :isccmd:`lease6-add`, :isccmd:`lease6-update`, and :isccmd:`lease6-del`. Each entry is a +single string with no embedded end-of-line markers, and it will +typically have the following form: + +``lease6-add:`` + +:: + + *timestamp* Administrator added a lease of address: *address* to a device with DUID: *DUID* + +Depending on the arguments of the add command, it may also include the +hardware address and duration. + +Example: + +:: + + 2018-01-06 01:02:03 PST Administrator added a lease of address: 2001:db8::3 to a device with DUID: + 1a:1b:1c:1d:1e:1f:20:21:22:23:24 for 1 days 0 hrs 0 mins 0 secs + +``lease6-update:`` + +:: + + *timestamp* Administrator updated information on the lease of address: *address* to a device with DUID: *DUID* + +Depending on the arguments of the update command, it may also include +the hardware address and lease duration. + +Example: + +:: + + 2018-01-06 01:02:03 PST Administrator updated information on the lease of address: 2001:db8::3 to a device with + DUID: 1a:1b:1c:1d:1e:1f:20:21:22:23:24, hardware address: 1a:1b:1c:1d:1e:1f + +``lease6-del:`` deletes have two forms, one by address and one by +identifier and identifier type: + +:: + + *timestamp* Administrator deleted the lease for address: *address* + +or + +:: + + *timestamp* Administrator deleted a lease for a device identified by: *identifier-type* of *identifier* + +Currently only a type of ``DUID`` is supported. + +Examples: + +:: + + 2018-01-06 01:02:03 PST Administrator deleted the lease for address: 2001:db8::3 + + 2018-01-06 01:02:11 PST Administrator deleted a lease for a device identified by: duid of 1a:1b:1c:1d:1e:1f:20:21:22:23:24 + +If High availability module is enabled, the partner will periodically send lease +commands which have a similar format, the only difference is that the issuer of +the command is 'HA partner' instead of 'Administrator'. + +:: + + *timestamp* HA partner added ... + +or + +:: + + *timestamp* HA partner updated ... + +or + +:: + + *timestamp* HA partner deleted ... + +The ``request-parser-format`` and ``response-parser-format`` options can be used to +extract and log data from the incoming packet and server response packet, +respectively. The configured value is an evaluated parsed expression returning a +string. A list of tokens is described in the server classification process. +Use with caution as this might affect server performance. +If either of them is configured, the default logging format is not used. +If both of them are configured, the resulting log message is constructed by +concatenating the logged data extracted from the request and the logged data +extracted from the response. + +The custom formatting permits logging on multiple lines using the hexstring 0x0a +(ASCII code for new line). In the case of the log file, each line is prepended +with the log timestamp. For the database backend, the data is stored +(including the newline character) in the same entry. + +Examples: + +.. code-block:: json + + { + "Dhcp6": { + "hooks-libraries": [ + { + "library": "/usr/local/lib/kea/hooks/libdhcp_legal_log.so", + "parameters": { + "name": "database-name", + "password": "passwd", + "type": "mysql", + "user": "user-name", + "request-parser-format": "'log entry' + 0x0a + 'same log entry'", + "response-parser-format": "'also same log entry' + 0x0a + 'again same log entry'" + } + } + ] + } + } + +Some data might be available in the request or in the response only, and some +data might differ in the incoming packet from the one in the response packet. + +Notes: + +In the case of IPv6, the packets can contain multiple IA_NA (3) or IA_PD (25) +options, each containing multiple options, including OPTION_IAADDR (5) or +OPTION_IAPREFIX (25) suboptions. +To be able to print the current lease associated with the log entry, the +forensic log hook library internally isolates the corresponding IA_NA or IA_PD +option and respective suboption matching the current lease. +The hook library will iterate over all new allocated addresses and all deleted +addresses, making each address available for logging as the current lease for +the respective logged entry. + +They are accessible using the following parser expressions: + +Current lease associated with OPTION_IAADDR: + +:: + + addrtotext(substring(option[3].option[5].hex, 0, 16)) + +Current lease associated with OPTION_IAPREFIX: + +:: + + addrtotext(substring(option[25].option[26].hex, 9, 16)) + +All other parameters of the options are available at their respective offsets +in the option. Please read RFC8415 for more details. + +Examples: + +.. code-block:: json + + { + "request-parser-format": "ifelse(pkt6.msgtype == 8 or pkt6.msgtype == 9, ifelse(option[3].option[5].exists, 'Address: ' + addrtotext(substring(option[3].option[5].hex, 0, 16)) + ' has been released from a device with DUID: ' + hexstring(option[1].hex, ':') + ifelse(relay6[0].peeraddr == '', '', ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) + ifelse(relay6[0].option[37].exists, ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'), '') + ifelse(relay6[0].option[38].exists, ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'), '') + ifelse(relay6[0].option[18].exists, ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'), '')), '') + ifelse(option[25].option[26].exists, 'Prefix: ' + addrtotext(substring(option[25].option[26].hex, 9, 16)) + '/' + uint8totext(substring(option[25].option[26].hex, 8, 1)) + ' has been released from a device with DUID: ' + hexstring(option[1].hex, ':') + ifelse(relay6[0].peeraddr == '', '', ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) + ifelse(relay6[0].option[37].exists, ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'), '') + ifelse(relay6[0].option[38].exists, ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'), '') + ifelse(relay6[0].option[18].exists, ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'), '')), ''), '')", + "response-parser-format": "ifelse(pkt6.msgtype == 7, ifelse(option[3].option[5].exists and not (substring(option[3].option[5].hex, 20, 4) == 0), 'Address: ' + addrtotext(substring(option[3].option[5].hex, 0, 16)) + ' has been assigned for ' + uint32totext(substring(option[3].option[5].hex, 20, 4)) + ' seconds to a device with DUID: ' + hexstring(option[1].hex, ':') + ifelse(relay6[0].peeraddr == '', '', ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) + ifelse(relay6[0].option[37].exists, ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'), '') + ifelse(relay6[0].option[38].exists, ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'), '') + ifelse(relay6[0].option[18].exists, ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'), '')), '') + ifelse(option[25].option[26].exists and not (substring(option[25].option[26].hex, 4, 4) == 0), 'Prefix: ' + addrtotext(substring(option[25].option[26].hex, 9, 16)) + '/' + uint8totext(substring(option[25].option[26].hex, 8, 1)) + ' has been assigned for ' + uint32totext(substring(option[25].option[26].hex, 4, 4)) + ' seconds to a device with DUID: ' + hexstring(option[1].hex, ':') + ifelse(relay6[0].peeraddr == '', '', ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) + ifelse(relay6[0].option[37].exists, ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'), '') + ifelse(relay6[0].option[38].exists, ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'), '') + ifelse(relay6[0].option[18].exists, ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'), '')), ''), '')" + } + +Details: + +.. raw:: html + + <details><summary>Expand here!</summary> + <pre>{ + "request-parser-format": + "ifelse(pkt6.msgtype == 8 or pkt6.msgtype == 9, + ifelse(option[3].option[5].exists, + 'Address: ' + addrtotext(substring(option[3].option[5].hex, 0, 16)) + ' has been released from a device with DUID: ' + hexstring(option[1].hex, ':') + + ifelse(relay6[0].peeraddr == '', + '', + ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) + + ifelse(relay6[0].option[37].exists, + ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'), + '') + + ifelse(relay6[0].option[38].exists, + ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'), + '') + + ifelse(relay6[0].option[18].exists, + ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'), + '')), + '') + + ifelse(option[25].option[26].exists, + 'Prefix: ' + addrtotext(substring(option[25].option[26].hex, 9, 16)) + '/' + uint8totext(substring(option[25].option[26].hex, 8, 1)) + ' has been released from a device with DUID: ' + hexstring(option[1].hex, ':') + + ifelse(relay6[0].peeraddr == '', + '', + ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) + + ifelse(relay6[0].option[37].exists, + ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'), + '') + + ifelse(relay6[0].option[38].exists, + ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'), + '') + + ifelse(relay6[0].option[18].exists, + ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'), + '')), + ''), + '')", + "response-parser-format": + "ifelse(pkt6.msgtype == 7, + ifelse(option[3].option[5].exists and not (substring(option[3].option[5].hex, 20, 4) == 0), + 'Address: ' + addrtotext(substring(option[3].option[5].hex, 0, 16)) + ' has been assigned for ' + uint32totext(substring(option[3].option[5].hex, 20, 4)) + ' seconds to a device with DUID: ' + hexstring(option[1].hex, ':') + + ifelse(relay6[0].peeraddr == '', + '', + ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) + + ifelse(relay6[0].option[37].exists, + ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'), + '') + + ifelse(relay6[0].option[38].exists, + ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'), + '') + + ifelse(relay6[0].option[18].exists, + ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'), + '')), + '') + + ifelse(option[25].option[26].exists and not (substring(option[25].option[26].hex, 4, 4) == 0), + 'Prefix: ' + addrtotext(substring(option[25].option[26].hex, 9, 16)) + '/' + uint8totext(substring(option[25].option[26].hex, 8, 1)) + ' has been assigned for ' + uint32totext(substring(option[25].option[26].hex, 4, 4)) + ' seconds to a device with DUID: ' + hexstring(option[1].hex, ':') + + ifelse(relay6[0].peeraddr == '', + '', + ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) + + ifelse(relay6[0].option[37].exists, + ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'), + '') + + ifelse(relay6[0].option[38].exists, + ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'), + '') + + ifelse(relay6[0].option[18].exists, + ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'), + '')), + ''), + '')" + }</pre> + </details><br> + +This will log the following data on request, renew, and rebind for NA: + +:: + + Address: 2001:db8:1:: has been assigned for 713 seconds to a device with DUID: 17:34:e2:ff:09:92:54 connected via relay at address: fe80::abcd for client on link address: 3001::1, remote-id: 01:02:03:04:0a:0b:0c:0d:0e:0f, subscriber-id: 1a:2b:3c:4d:5e:6f, connected at location interface-id: 72:65:6c:61:79:31:3a:65:74:68:30 + +This will log the following data on request, renew and rebind for PD: + +:: + + Prefix: 2001:db8:1::/64 has been assigned for 713 seconds to a device with DUID: 17:34:e2:ff:09:92:54 connected via relay at address: fe80::abcd for client on link address: 3001::1, remote-id: 01:02:03:04:0a:0b:0c:0d:0e:0f, subscriber-id: 1a:2b:3c:4d:5e:6f, connected at location interface-id: 72:65:6c:61:79:31:3a:65:74:68:30 + +This will log the following data on release and decline for NA: + +:: + + Address: 2001:db8:1:: has been released from a device with DUID: 17:34:e2:ff:09:92:54 connected via relay at address: fe80::abcd for client on link address: 3001::1, remote-id: 01:02:03:04:0a:0b:0c:0d:0e:0f, subscriber-id: 1a:2b:3c:4d:5e:6f, connected at location interface-id: 72:65:6c:61:79:31:3a:65:74:68:30 + +This will log the following data on release and decline for PD: + +:: + + Prefix: 2001:db8:1::/64 has been released from a device with DUID: 17:34:e2:ff:09:92:54 connected via relay at address: fe80::abcd for client on link address: 3001::1, remote-id: 01:02:03:04:0a:0b:0c:0d:0e:0f, subscriber-id: 1a:2b:3c:4d:5e:6f, connected at location interface-id: 72:65:6c:61:79:31:3a:65:74:68:30 + +A similar result can be obtained by configuring only ``request-parser-format``. + +Examples: + +.. code-block:: json + + { + "request-parser-format": "ifelse(pkt6.msgtype == 3 or pkt6.msgtype == 5 or pkt6.msgtype == 6, ifelse(option[3].option[5].exists, 'Address: ' + addrtotext(substring(option[3].option[5].hex, 0, 16)) + ' has been assigned for ' + uint32totext(substring(option[3].option[5].hex, 20, 4)) + ' seconds to a device with DUID: ' + hexstring(option[1].hex, ':') + ifelse(relay6[0].peeraddr == '', '', ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) + ifelse(relay6[0].option[37].exists, ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'), '') + ifelse(relay6[0].option[38].exists, ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'), '') + ifelse(relay6[0].option[18].exists, ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'), '')), '') + ifelse(option[25].option[26].exists, 'Prefix: ' + addrtotext(substring(option[25].option[26].hex, 9, 16)) + '/' + uint8totext(substring(option[25].option[26].hex, 8, 1)) + ' has been assigned for ' + uint32totext(substring(option[25].option[26].hex, 4, 4)) + ' seconds to a device with DUID: ' + hexstring(option[1].hex, ':') + ifelse(relay6[0].peeraddr == '', '', ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) + ifelse(relay6[0].option[37].exists, ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'), '') + ifelse(relay6[0].option[38].exists, ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'), '') + ifelse(relay6[0].option[18].exists, ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'), '')), ''), ifelse(pkt6.msgtype == 8 or pkt6.msgtype == 9, ifelse(option[3].option[5].exists, 'Address: ' + addrtotext(substring(option[3].option[5].hex, 0, 16)) + ' has been released from a device with DUID: ' + hexstring(option[1].hex, ':') + ifelse(relay6[0].peeraddr == '', '', ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) + ifelse(relay6[0].option[37].exists, ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'), '') + ifelse(relay6[0].option[38].exists, ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'), '') + ifelse(relay6[0].option[18].exists, ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'), '')), '') + ifelse(option[25].option[26].exists, 'Prefix: ' + addrtotext(substring(option[25].option[26].hex, 9, 16)) + '/' + uint8totext(substring(option[25].option[26].hex, 8, 1)) + ' has been released from a device with DUID: ' + hexstring(option[1].hex, ':') + ifelse(relay6[0].peeraddr == '', '', ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) + ifelse(relay6[0].option[37].exists, ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'), '') + ifelse(relay6[0].option[38].exists, ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'), '') + ifelse(relay6[0].option[18].exists, ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'), '')), ''), ''))" + } + +Details: + +.. raw:: html + + <details><summary>Expand here!</summary> + <pre>{ + "request-parser-format": + "ifelse(pkt6.msgtype == 3 or pkt6.msgtype == 5 or pkt6.msgtype == 6, + ifelse(option[3].option[5].exists, + 'Address: ' + addrtotext(substring(option[3].option[5].hex, 0, 16)) + ' has been assigned for ' + uint32totext(substring(option[3].option[5].hex, 20, 4)) + ' seconds to a device with DUID: ' + hexstring(option[1].hex, ':') + + ifelse(relay6[0].peeraddr == '', + '', + ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) + + ifelse(relay6[0].option[37].exists, + ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'), + '') + + ifelse(relay6[0].option[38].exists, + ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'), + '') + + ifelse(relay6[0].option[18].exists, + ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'), + '')), + '') + + ifelse(option[25].option[26].exists, + 'Prefix: ' + addrtotext(substring(option[25].option[26].hex, 9, 16)) + '/' + uint8totext(substring(option[25].option[26].hex, 8, 1)) + ' has been assigned for ' + uint32totext(substring(option[25].option[26].hex, 4, 4)) + ' seconds to a device with DUID: ' + hexstring(option[1].hex, ':') + + ifelse(relay6[0].peeraddr == '', + '', + ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) + + ifelse(relay6[0].option[37].exists, + ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'), + '') + + ifelse(relay6[0].option[38].exists, + ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'), + '') + + ifelse(relay6[0].option[18].exists, + ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'), + '')), + ''), + ifelse(pkt6.msgtype == 8 or pkt6.msgtype == 9, + ifelse(option[3].option[5].exists, + 'Address: ' + addrtotext(substring(option[3].option[5].hex, 0, 16)) + ' has been released from a device with DUID: ' + hexstring(option[1].hex, ':') + + ifelse(relay6[0].peeraddr == '', + '', + ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) + + ifelse(relay6[0].option[37].exists, + ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'), + '') + + ifelse(relay6[0].option[38].exists, + ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'), + '') + + ifelse(relay6[0].option[18].exists, + ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'), + '')), + '') + + ifelse(option[25].option[26].exists, + 'Prefix: ' + addrtotext(substring(option[25].option[26].hex, 9, 16)) + '/' + uint8totext(substring(option[25].option[26].hex, 8, 1)) + ' has been released from a device with DUID: ' + hexstring(option[1].hex, ':') + + ifelse(relay6[0].peeraddr == '', + '', + ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) + + ifelse(relay6[0].option[37].exists, + ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'), + '') + + ifelse(relay6[0].option[38].exists, + ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'), + '') + + ifelse(relay6[0].option[18].exists, + ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'), + '')), + ''), + ''))" + }</pre> + </details><br> + +.. _forensic-log-database: + +Database Backend +~~~~~~~~~~~~~~~~ + +Log entries can be inserted into a database when Kea is configured with +database backend support. Kea uses a table named ``logs``, that includes a +timestamp generated by the database software, and a text log with the same +format as files without the timestamp. + +Please refer to :ref:`mysql-database` for information on using a MySQL database; +or to :ref:`pgsql-database` for PostgreSQL database information. The ``logs`` +table is part of the Kea database schemas. + +Configuration parameters are extended by standard lease database +parameters as defined in :ref:`database-configuration4`. The ``type`` +parameter should be ``mysql``, ``postgresql`` or ``logfile``; when +it is absent or set to ``logfile``, files are used. + +This database feature is experimental. No specific tools are provided +to operate the database, but standard tools may be used, for example, +to dump the logs table from a MYSQL database: + +:: + + $ mysql --user keatest --password keatest -e "select * from logs;" + +---------------------+--------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------+----+ + | timestamp | address | log | id | + +---------------------+--------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------+----+ + | 2022-03-30 17:38:41 | 192.168.50.1 | Address: 192.168.50.1 has been assigned for 0 hrs 10 mins 0 secs to a device with hardware address: hwtype=1 ff:01:02:03:ff:04, client-id: 00:01:02:03:04:05:06 | 31 | + | 2022-03-30 17:38:43 | 192.168.50.1 | Address: 192.168.50.1 has been assigned for 0 hrs 10 mins 0 secs to a device with hardware address: hwtype=1 ff:01:02:03:ff:04, client-id: 00:01:02:03:04:05:06 | 32 | + | 2022-03-30 17:38:45 | 192.168.50.1 | Address: 192.168.50.1 has been assigned for 0 hrs 10 mins 0 secs to a device with hardware address: hwtype=1 ff:01:02:03:ff:04, client-id: 00:01:02:03:04:05:06 | 33 | + +---------------------+--------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------+----+ + +Like all the other database-centric features, forensic logging supports database +connection recovery, which can be enabled by setting the ``on-fail`` parameter. +If not specified, the ``on-fail`` parameter in forensic logging defaults to +``serve-retry-continue``. This is different than for +:ischooklib:`libdhcp_lease_cmds.so`, :ischooklib:`libdhcp_host_cmds.so`, and +:ischooklib:`libdhcp_cb_cmds.so`, where +``on-fail`` defaults to ``stop-retry-exit``. In this case, the server continues +serving clients and does not shut down even if the recovery mechanism fails. +If ``on-fail`` is set to ``serve-retry-exit``, the server will shut down if +the connection to the database backend is not restored according to the +``max-reconnect-tries`` and ``reconnect-wait-time`` parameters, but it +continues serving clients while this mechanism is activated. + +During server startup, the inability to connect to any of the configured +backends is considered fatal only if ``retry-on-startup`` is set to ``false`` +(the default). A fatal error is logged and the server exits, based on the idea +that the configuration should be valid at startup. Exiting to the operating +system allows nanny scripts to detect the problem. +If ``retry-on-startup`` is set to ``true``, the server will start reconnection +attempts even at server startup or on reconfigure events, and will honor the +action specified in the ``on-fail`` parameter. diff --git a/doc/sphinx/arm/hooks-limits.rst b/doc/sphinx/arm/hooks-limits.rst new file mode 100644 index 0000000..42bb39a --- /dev/null +++ b/doc/sphinx/arm/hooks-limits.rst @@ -0,0 +1,211 @@ +.. ischooklib:: libdhcp_limits.so +.. _hooks-limits: + +``libdhcp_limits.so``: Limits to Manage Lease Allocation and Packet Processing +============================================================================== + +This hook library enables two types of limits: + +1. Lease limiting: allow a maximum of ``n`` leases assigned at any one time. +2. Rate limiting: allow a maximum of ``n`` packets per ``time_unit`` to receive a response. + +.. note:: + + :ischooklib:`libdhcp_limits.so` is available only to ISC customers with + a paid support contract. For more information on subscription options, + please complete the form at https://www.isc.org/contact. + +.. _hooks-limits-configuration: + +Configuration +~~~~~~~~~~~~~ + +The following examples are for :iscman:`kea-dhcp6`, but they apply equally to +:iscman:`kea-dhcp4`. The wildcards ``"<limit-type>"`` and ``"<limit-value>"`` need to be replaced +with the respective keys and values for each limit type described in the sections following this +one. + +The library can be loaded by both :iscman:`kea-dhcp4` and :iscman:`kea-dhcp6` servers by adding its path in the +``"hooks-libraries"`` element of the server's configuration. + +.. code-block:: json + + { + "Dhcp6": { + "hooks-libraries": [ + { + "library": "/usr/local/lib/libdhcp_limits.so" + } + ] + } + } + +This alone does not limit anything. The desired limits are added to the user context in the +configuration portion of the element that identifies the clients to be limited: a client class or a +subnet. Upon reconfiguration, if Kea picked up on the configured limits, it logs one line for +each configured limit. The log message contains ``LIMITS_CONFIGURED`` in its identifier. + +This is how a lease limit is defined for a client class: + +.. code-block:: json + + { + "Dhcp6": { + "client-classes": [ + { + "name": "cable-modem-1", + "test": "option[123].hex == 0x000C4B1E", + "user-context": { + "limits": { + "<limit>": "<limit-value>" + } + } + } + ] + } + } + +This is how a lease limit is defined for a global subnet: + +.. code-block:: json + + { + "Dhcp6": { + "subnet6": [ + { + "id": 1, + "subnet": "2001:db8::/64", + "user-context": { + "limits": { + "<limit>": "<limit-value>" + } + } + } + ] + } + } + +This is how a lease limit is defined for a subnet inside a shared network: + +.. code-block:: json + + { + "Dhcp6": { + "shared-networks": [ + { + "subnet6": [ + { + "id": 1, + "subnet": "2001:db8::/64", + "user-context": { + "limits": { + "<limit>": "<limit-value>" + } + } + } + ] + } + ] + } + } + +.. note:: + + The Limits hook library uses the class name to identify a client class and the subnet ID to + identify a subnet. Changing a test expression in a client class or the network range of a + subnet while leaving the name or ID unchanged does not reset the lease count for the + respective client class or subnet. To reset the lease count, change the client class name + or the subnet ID. + +.. note:: + + Database connection retries are not attempted on startup if the + :ischooklib:`libdhcp_limits.so` is loaded because the hook library requires a + valid connection to the database to check if JSON format is supported and to + recount class limits. + +.. _hooks-limits-lease-limiting: + +Lease Limiting +~~~~~~~~~~~~~~ + +It is possible to limit the number of leases that a group of clients can get from a Kea DHCP server +or from a set of collaborating Kea DHCP servers. + +The value of a lease limit can be specified as an unsigned integer in 32 bits, i.e. between ``0`` and +``4,294,967,295``. Each lease type can be limited individually. IPv4 leases and IPv6 IA_NA leases +are limited through the ``"address-limit"`` configuration entry. IPv6 IA_PD leases are limited +through the ``"prefix-limit"`` configuration entry. Here are some examples: + +* ``"address-limit": 4`` +* ``"prefix-limit": 2`` + +For lease limiting, client classes and the associated lease counts - which are +checked against the configured limits - are updated for each lease in the following hook callouts: + +* ``lease4_select`` +* ``lease4_renew`` +* ``lease6_select`` +* ``lease6_renew`` +* ``lease6_rebind`` + +As a result, classes for which ``"only-if-required"`` is "true" cannot be lease-limited. +Please refer to :ref:`the classification steps <classify-classification-steps>` for more information on which +client classes can be used to limit the number of leases. + +.. note:: + + Under load, a Kea DHCP server may allocate more leases than the limit strictly allows. This only has a chance of + happening during high traffic surges, coming from clients belonging to the same class or the + same subnet, depending on what is limited. Users may be interested in following the development of + `atomic lease limits <https://gitlab.isc.org/isc-projects/kea/-/issues/2449>`__ in ISC's GitLab instance. + +.. _hooks-limits-rate-limiting: + +Rate Limiting +~~~~~~~~~~~~~ + +It is possible to limit the frequency or rate at which inbound packets receive a response. + +The value of a rate limit can be specified in the format ``"<p> packets per <time-unit>"``. ``<p>`` +is any number that can be represented by an unsigned integer in 32 bits, i.e. between ``0`` and +``4,294,967,295``. ``<time-unit>`` can be any of ``second``, ``minute``, ``hour``, ``day``, +``week``, ``month``, or ``year``. A ``month`` is considered to be 30 days for +simplicity; similarly, a ``year`` is 365 days for limiting purposes. This syntax +covers a wide range of rates, from one lease per year to four billion leases per +second. This value is assigned to the ``"rate-limit"`` configuration entry. +Here are some examples: + +* ``"rate-limit": 1 packet per second`` +* ``"rate-limit": 4 packets per minute`` +* ``"rate-limit": 16 packets per hour`` + +The configured value of ``0`` packets is a convenient way of disabling packet processing for certain +clients entirely. As such, it means its literal value and is not a special value for disabling +limiting altogether, as might be imagined. Disabling limiting entirely is achieved by removing +the ``"rate-limit"`` leaf configuration entry, the ``"limits"`` map or user context +around it, or the hook library configuration. The same applies to the value of ``0`` in lease +limiting. However, that use case is best achieved with rate limiting; it puts less computational +strain on Kea, since the action of dropping the request or sending a NAK is decided earlier. + +In terms of rate limiting, client classes are evaluated at the ``pkt4_receive`` and the +``pkt6_receive`` callout, respectively, so that rate limits are checked as early as possible in the +packet-processing cycle. Thus, only those classes which are assigned to the packet solely via an +independent test expression can be used. Classes that depend on host reservations or the special +``BOOTP`` or ``KNOWN`` classes, and classes that are marked with ``"only-if-required": true``, +cannot be rate limited. See :ref:`the classification steps <classify-classification-steps>` for +more details on which client classes can be used to limit the packet rate. + +Rate limits based on subnet are enforced only on the initially selected subnet for a given packet. +If the selected subnet is subsequently changed, as may be the case for subnets in a +shared network or when reselection is enabled in libraries such as the RADIUS hook, rate +limits on the newly selected subnet are ignored. In other words, packets are gated only by +the rate limit on the original subnet. + +.. note:: + + It may seem logical to think that assigning a rate limit of ``n`` packets per time unit results + in ``n`` DORA or ``n`` SARR exchanges. However, by default, all inbound packets are counted - meaning + that a full message exchange accounts for two packets. To achieve the effect of counting an + exchange only once, use client-class rate-limiting with a test expression that binds + ``pkt4.msgtype`` to DHCPDISCOVER messages or ``pkt6.msgtype`` to SOLICIT messages. diff --git a/doc/sphinx/arm/hooks-perfmon.rst b/doc/sphinx/arm/hooks-perfmon.rst new file mode 100644 index 0000000..3c039dc --- /dev/null +++ b/doc/sphinx/arm/hooks-perfmon.rst @@ -0,0 +1,39 @@ +.. ischooklib:: libdhcp_perfmon.so +.. _hooks-perfmon: + +``libdhcp_perfmon.so``: PerfMon +=============================== + +This hook library can be loaded by either kea-dhcp4 or kea-dhcp6 servers +to extend them with the ability to track and report performance related data. + +.. note:: + + This library is currently under development and not yet functional. + +Overview +~~~~~~~~ + +The library, added in Kea 2.5.6, can be loaded by the :iscman:`kea-dhcp4` or +:iscman:`kea-dhcp6` daemon by adding it to the ``hooks-libraries`` element of +the server's configuration: + +.. code-block:: javascript + + { + "hooks-libraries": [ + { + "library": "/usr/local/lib/libdhcp_perfmon.so", + "parameters": { + ... + } + }, + ... + ], + ... + } + +Configuration +~~~~~~~~~~~~~ + + TBD diff --git a/doc/sphinx/arm/hooks-ping-check.rst b/doc/sphinx/arm/hooks-ping-check.rst new file mode 100644 index 0000000..efa2fef --- /dev/null +++ b/doc/sphinx/arm/hooks-ping-check.rst @@ -0,0 +1,169 @@ +.. ischooklib:: libdhcp_ping_check.so +.. _hooks-ping-check: + +``libdhcp_ping_check.so``: Ping Check +===================================== + +This hook library adds the ability to perform a "ping check" of a candidate +IPv4 address prior to offering it to a DHCP client. This feature is similar +to a behavior available in ISC DHCP and one suggested in `RFC +2131 <https://tools.ietf.org/html/rfc2131>`__ , see section 3.1, item 2. + +.. note:: + + :ischooklib:`libdhcp_ping_check.so` is available only to ISC customers + with a paid support contract. For more information on subscription options, + please complete the form at https://www.isc.org/contact. + +Overview +~~~~~~~~ + +The library, added in Kea 2.5.4, can be loaded by the :iscman:`kea-dhcp4` daemon +by adding it to the ``hooks-libraries`` element of the server's configuration: + +.. code-block:: javascript + + { + "hooks-libraries": [ + { + "library": "/usr/local/lib/libdhcp_ping_check.so", + "parameters": { + ... + } + }, + ... + ], + ... + } + +When the library is loaded :iscman:`kea-dhcp4` will conduct a ping-check prior to +offering a lease to client if all of the following conditions are true: + +1. Ping check hook library is loaded. + +2. Ping checking is enabled. + +3. The server is responding to a DHCPDISCOVER. + +4. The candidate lease is neither active nor reserved. + +5. Any of the following are true: + + a. This is the first offer of this lease to this client. This check + can only be done if `offer-lifetime` is greater than zero (i.e. temporary + allocation on DHCPDISCOVER is enabled). If `offer-lifetime` is zero + ping checks are done for every DHCPOFFER as the server has no way to + know it has made prior offers. + + b. The lease is being offered to a client other than its previous owner. + + c. The lease is being offered to its previous owner and more than a + configurable number of seconds, `ping-cltt-secs`, have elapsed since + CLTT of the original lease. + +When the ping check library is loaded, in response to a DHCPDISCOVER the +:iscman:`kea-dhcp4` will: + +1. Select a candidate IPv4 address through normal processes and use it to +construct a DHCPOFFER. + +2. Park the DHCPOFFER and request a ping-check from the ping-check hook +library via its `lease4_offer` callout. + +3. The callout will test conditions described above. If they are not +satisfied it will return without conducting a check, and the server +will send the DHCPOFFER to the client. Otherwise the callout will +initiate a ping-check for the lease address. + +4. Upon conclusion of the ping-check, the server will either send the DHCPOFFER +to the client if the check concluded that the address is available, or discard +the DHCPFOFFER and create a DECLINED lease for the address. + +Each ping-check consists of the following steps: + +1. If the number of ECHO REPLYs sent is less than the configured +minimum number to send, send an ICMP ECHO REQUEST to the lease address. +Otherwise, conclude that the address is available. + +2. If no ECHO REPLY is received within a configurable amount of time +return to step 1. + +3. Upon receipt of an ICMP ECHO REPLY, conclude that the lease is NOT available. + +4. Any of the following occur: + + a. Receipt of an ICMP DESTINATION UNREACHABLE message + b. Send fail of an ICMP ECHO REQUEST due to a network error (e.g. network is unreachable) + c. Send fail of an ICMP ECHO REQUEST due to a permissions error (e.g. lease address is a broadcast address) + d. Send fail of an ICMP ECHO REQUEST with socket buffer full error + + In each of these instances the address could not be checked and is treated as + available. + +.. note:: + + Socket buffer full of errors indicates that the OS rate limits on ICMP are + being exceeded. The server will not retry them as this would likely only + exacerbate the situation. If this occurs continuously then the client load + on the server may be too high to accommodate ping checking. Ping checking is + not recommended for systems with high throughput demands. + +Configuration +~~~~~~~~~~~~~ + +The ping-check hook library currently supports the following configuration parameters +that may be set at the global and subnet levels. Subnet values override global values. + +- `enable-ping-check` - Enables or disables ping checking at a given scope. + +- `min-ping-requests` - The minimum number of ECHO REQUESTs sent without receiving a reply needed to declare an address available. The default is 1, it must be greater than zero. + +- `reply-timeout` - The maximum amount of time to wait for a reply to a single ECHO REQUEST. Specified in milliseconds, it must be greater than zero, it defaults to 100. + +- `ping-cltt-secs` - The number of seconds that must elapse after the lease's CLTT before a ping check will be conducted when the client is the lease's previous owner. The default value is sixty seconds. + +The following parameter is only supported at the global level: + +- `ping-channel-threads` - In multi-threaded mode, this is the number of threads in the channel's thread pool. The default is 0 which instructs the library to use the same number of threads as Kea core. The value is ignored if given when Kea is in single-threaded mode. + +The following configuration excerpt illustrates global level configuration: + +.. code-block:: javascript + + { + "hooks-libraries": [{ + "library": "lib/kea/hooks/libdhcp_ping_check.so", + "parameters": { + "enable-ping-check" : true, + "min-ping-requests" : 1, + "reply-timeout" : 100, + "ping-cltt-secs" : 60, + "ping-channel-threads" : 0 + } + }] + } + +The following excerpt demonstrates subnet level configuration: + +.. code-block:: javascript + + { + "subnet4": [{ + "subnet": "192.0.2.0/24", + "pools": [{ + "pool": "192.0.2.10 - 192.0.2.20" + }], + + "user-context": { + "enable-ping-check" : true, + "min-ping-requests" : 2, + "reply-timeout" : 250, + "ping-cltt-secs" : 120 + } + }] + } + +.. note:: + + Ping checking is an experimental feature. It is not currently recommended for + production environments. diff --git a/doc/sphinx/arm/hooks-radius.rst b/doc/sphinx/arm/hooks-radius.rst new file mode 100644 index 0000000..8f1336d --- /dev/null +++ b/doc/sphinx/arm/hooks-radius.rst @@ -0,0 +1,16 @@ +.. ischooklib:: libdhcp_radius.so +.. _hooks-radius: + +``libdhcp_radius.so``: RADIUS Server Support +============================================ + +This hook library allows the Kea DHCP servers to use the RADIUS protocol to +authorize DHCP clients through the access service or for DHCP lease journaling +through the accounting service. For details on RADIUS in Kea, please see +:ref:`radius`. + +.. note:: + + :ischooklib:`libdhcp_radius.so` is available only to ISC customers with + a paid support contract. For more information on subscription options, + please complete the form at https://www.isc.org/contact. diff --git a/doc/sphinx/arm/hooks-rbac.rst b/doc/sphinx/arm/hooks-rbac.rst new file mode 100644 index 0000000..1df4dd5 --- /dev/null +++ b/doc/sphinx/arm/hooks-rbac.rst @@ -0,0 +1,587 @@ +.. ischooklib:: libca_rbac.so +.. _hooks-RBAC: + +``libca_rbac.so``: Role-Based Access Control +============================================ + +.. _hooks-RBAC-overview: + +Role-Based Access Control (RBAC) Overview +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Before the processing of commands in received HTTP requests, :ischooklib:`libca_rbac.so` +takes specific parameters, e.g. the common-name part of the client +certificate subject name, to assign a role to the request. +The configuration associated with this role is used to accept or reject +the command. After processing, the response can be rewritten, e.g. +parts can be removed. + +Here is a summary of the steps in processing a request: + - The HTTP library records some information to be used later, e.g. + the remote address. + - When TLS is required but the request was not protected by TLS, + the request is rejected by sending an "unauthorized" response. + - The command is extracted from the request. + - A role is assigned using recorded information in the request. + - The role is used to accept (pass through) or reject (send + a forbidden response to) the command. + +Here is a summary of the steps in processing a response: + - The information attached to the request is retrieved during the + request processing (when the request was accepted). + - Request filters are applied to the response. + +.. note:: + + :ischooklib:`libca_rbac.so` is available only to ISC customers with + a paid support contract. For more information on subscription options, + please complete the form at https://www.isc.org/contact. + +.. _hooks-RBAC-config: + +Role-Based Access Control Configuration +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Role Assignment +--------------- + +Role assignment is governed by the configured role-assignment method. + +.. table:: Role assignment methods + + +----------------------+---------------------------------------------------------+ + | Name | Description | + +----------------------+---------------------------------------------------------+ + | remote-address | remote/client IP address | + +----------------------+---------------------------------------------------------+ + | cert-subject | common-name part of the client certificate subject name | + +----------------------+---------------------------------------------------------+ + | cert-issuer | common-name part of the client certificate issuer name | + +----------------------+---------------------------------------------------------+ + | basic-authentication | user ID of basic HTTP authentication | + +----------------------+---------------------------------------------------------+ + | custom-value | another role can be designed in external hooks | + +----------------------+---------------------------------------------------------+ + +Role Configuration +------------------ + +.. table:: Role configuration parameters + + +------------------+----------------------------------------------------+ + | Name | Description | + +------------------+----------------------------------------------------+ + | name | the role name (with the exception of the default | + | | and unknown roles) | + +------------------+----------------------------------------------------+ + | accept-commands | the accept access list | + +------------------+----------------------------------------------------+ + | reject-commands | the reject access list | + +------------------+----------------------------------------------------+ + | other-commands | specifies what to do for commands not matching | + | | accept and reject lists (default: reject) | + +------------------+----------------------------------------------------+ + | list-match-first | specifies what to do for commands matching both | + | | the accept and reject list by giving the list to | + | | check and apply first (default: accept) | + +------------------+----------------------------------------------------+ + | response-filters | the filters to apply to responses | + +------------------+----------------------------------------------------+ + +.. note:: + + The role assignment may fail, for instance with ``cert-subject`` when + the client certificate was not required, or it may have no subject common + name and instead have a DNS alternative subject name. In this case, the role + assignment returns the empty role and the ``default-role`` entry is used. + + The role assignment can return an unexpected value, e.g. with an + unregistered role name or a typing error. In this case the ``unknown-role`` + entry is used. + + The default for both ``default-role`` and ``unknown-role`` is to reject all commands. + +API Commands +------------ + +All commands of the REST API are described in files in the source directory +``src/share/api``, or in installed Kea +in ``.../share/kea/api``. :ischooklib:`libca_rbac.so` reads these files to take the name, +the access right (i.e. ``read`` or ``write``), and the hook name. The access right +can be modified in the file but changes are only applied after the Control Agent +restarts. Removing command definitions from ``.../share/kea/api`` has +consequences: if the access control list is based on ``read`` or ``write`` and +the definition file is missing, the Control Agent always rejects such +a command. If the access controls list is using ``commands`` to specify the +name of a command and the definition file from ``.../share/kea/api`` of this +particular command is missing, the Control Agent logs an error on startup +and exit. + + +.. table:: Extra command-definition parameters + + +--------+---------------------------------------------------------+ + | Name | Description | + +--------+---------------------------------------------------------+ + | name | (mandatory) the command name | + +--------+---------------------------------------------------------+ + | access | (mandatory) the access right i.e. ``read`` or ``write`` | + +--------+---------------------------------------------------------+ + | hook | (optional) the hook name (empty or not-present for | + | | commands of servers or agents) | + +--------+---------------------------------------------------------+ + +.. note:: + + These command description files are security-sensitive, e.g. with + too-permissive access rights a local attacker may modify them and + defeat the RBAC goal. + +Access Control Lists +-------------------- + +Access control lists can be specified using a name (string) or a +single entry map. + +.. table:: Predefined named access list + + +-------+----------------------------------------------+ + | Name | Description | + +-------+----------------------------------------------+ + | ALL | matches everything | + +-------+----------------------------------------------+ + | NONE | matches nothing | + +-------+----------------------------------------------+ + | READ | matches commands with the read-access right | + +-------+----------------------------------------------+ + | WRITE | matches commands with the write-access right | + +-------+----------------------------------------------+ + +Map access list specifications use a list type in the name of the single entry +and parameter in the value. + +.. table:: Access list types + + +---------+-----------------+--------------------------------------+ + | Name | Description | Parameter | + +---------+-----------------+--------------------------------------+ + | not | logical not | access list | + +---------+-----------------+--------------------------------------+ + | and | logical and | list of access lists | + +---------+-----------------+--------------------------------------+ + | or | logical or | list of access lists | + +---------+-----------------+--------------------------------------+ + | command | explicit list | list of command names | + +---------+-----------------+--------------------------------------+ + | access | by access right | access right (``read`` or ``write``) | + +---------+-----------------+--------------------------------------+ + | hook | by hook | hook name (can be empty) | + +---------+-----------------+--------------------------------------+ + +Response Filters +---------------- + +.. table:: Predefined response filters + + +---------------+---------------------------------------+ + | Name | Description | + +---------------+---------------------------------------+ + | list-commands | Removes not-allowed commands from the | + | | list-commands response | + +---------------+---------------------------------------+ + +Global Parameters +----------------- + +The global parameters are: + +- ``assign-role-method``: the name of the method + which is used for role assignment. This parameter is mandatory. + +- ``api-files``: the path of the directory where + the API files describing commands can be found. This parameter is mandatory. + +- ``require-tls``: the specification of whether received requests on HTTP (vs HTTPS) are + rejected. It defaults to ``false`` when the role-assignment method is not + based on certificates. + +- ``commands``: the list of extra command configurations. + +- ``access-control-lists``: the named access control list definitions + (each definition is a single entry map; the name of the entry is + the name of the access list, and the value is the specification). + The name is used in other parts of the configuration, such as "accept-commands". + +- ``roles``: the role configurations. + +- ``default-role``: the configuration of the default role (used + when "" is assigned). + +- ``unknown-role``: the configuration of the unknown role + (used when the not-empty assigned role has no configuration). + +Sample Configuration +~~~~~~~~~~~~~~~~~~~~ + +A sample configuration is available in ``doc/examples/agent/rbac.json`` +in the Kea source and is copied below. + +.. code-block:: javascript + :linenos: + :emphasize-lines: 31-85 + + { + "Control-agent": { + // We need to specify where the agent should listen to incoming HTTP + // queries. + "http-host": "127.0.0.1", + + // If enabling HA and multi-threading, the 8000 port is used by the HA + // hook library http listener. When using HA hook library with + // multi-threading to function, make sure the port used by dedicated + // listener is different (e.g. 8001) than the one used by CA. Note + // the commands should still be sent via CA. The dedicated listener + // is specifically for HA updates only. + "http-port": 8000, + + // TLS trust anchor (Certificate Authority). This is a file name or + // (for OpenSSL only) a directory path. + "trust-anchor": "my-ca", + + // TLS server certificate file name. + "cert-file": "my-cert", + + // TLS server private key file name. + "key-file": "my-key", + + // TLS require client certificates flag. Default is true and means + // require client certificates. False means they are optional. + "cert-required": true, + + // Add hooks here. + "hooks-libraries": [ + { + "library": "/opt/lib/libca_rbac.so", + "parameters": { + // This section configures the RBAC hook library. + // Mandatory parameters. + "assign-role-method": "cert-subject", + "api-files": "/opt/share/kea/api", + // Optional parameters. + "require-tls": true, + "commands": [ + { + "name": "my-command", + "access": "read", + "hook": "my-hook" + } ], + "access-control-lists": [ + { + "my-none": { "not": "ALL" } + },{ + "another-none": { "and": [ "ALL", "NONE" ] } + },{ + "my-read": { "access": "read" } + } ], + "roles": [ + { + "name": "kea-client", + "accept-commands": + { + "commands": [ "list-commands", "status-get" ] + }, + "reject-commands": "NONE", + "other-commands": "reject", + "list-match-first": "accept", + "response-filters": [ "list-commands" ] + },{ + "name": "admin", + "accept-commands": "ALL", + "reject-commands": + { + "hook": "cb_cmds" + }, + "list-match-first": "reject" + } ], + "default-role": + { + "accept-commands": "NONE", + "reject-commands": "ALL" + }, + "unknown-role": + { + "accept-commands": "READ", + "reject-commands": "WRITE" + } + } + } ] + + // Additional parameters, such as logging and others + // omitted for clarity. + + } + } + +Accept/Reject Algorithm +~~~~~~~~~~~~~~~~~~~~~~~ + +This is the pseudo-code of the accept/reject decision algorithm which returns +``true`` (accept) or ``false`` (reject). + +.. code-block:: c + + bool match(command) { + if (list-match-first == accept) { + if (accept_list && accept_list->match(command)) { + return (true); + } + if (reject_list && reject_list->match(command)) { + return (false); + } + } else { + if (reject_list && reject_list->match(command)) { + return (false); + } + if (accept_list && accept_list->match(command)) { + return (true); + } + } + if (others == reject) { + return (false); + } else { + return (true); + } + } + +Custom Hook Commands and Command Redefinition +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +It is possible to have a custom hook with new commands. In this case, +Role Based Access Control can be used to manage a new command in two ways. + +The ``command`` global parameter can be used to define its name, access type, +and hook name: + +.. code-block:: javascript + + { + "commands": [ + { + "name": "my-new-command", + "access": "write", + "hook": "my-custom-hook" + } + ], + ... + } + +The new command can then be specified in ``roles``: + +.. code-block:: javascript + + { + "roles": [ + { + "name": "user1", + "accept-commands": { + "commands": [ "my-new-command" ] }, + "reject-commands": "WRITE", + "list-match-first": "accept" + }, + { + "name": "user2", + "accept-commands": { "hook": "my-custom-hook" }, + "reject-commands": "ALL", + "list-match-first": "accept" + } + ], + ... + } + +The second method is to create a custom file in ``.../share/kea/api`` and define +the access type of the custom command(s). + +It is also possible to redefine an existing command by removing its definition +file from ``.../share/kea/api`` and defining it in the ``commands`` global parameter: + +.. code-block:: javascript + + { + "commands": [ + { + "name": "dhcp-disable", + "access": "read", + "hook": "my-custom-hook-3" + } + ] + } + +With this approach, an administrator can put the configurations of all existing +commands inside the Control Agent's configuration file. + +Extensive Example +~~~~~~~~~~~~~~~~~ + +Here is an extensive example for a role accepting all read commands, with +the exception of :isccmd:`config-get`, e.g. for hiding passwords. For any remote +user who is not recognized as "user1", all commands should be rejected. + +The first option is to put the allowed commands in the "accept-commands" +list and to reject anything else: + +.. code-block:: javascript + + { + "roles": [ + { + "name": "user1", + "accept-commands": + { + "and": [ + "READ", + { "not": + { "commands": [ "config-get" ] } + } + ] + }, + "reject-commands": "ALL", + // This is the default but as the config relies on it + // it is explicitly set. + "list-match-first": "accept" + }, + ... + ], + ... + } + +A common alternative is not to set the "reject-commands" list, i.e. leave +it empty and rely on "other-commands" to reject anything else. + +.. code-block:: javascript + + { + "roles": [ + { + "name": "user2", + "accept-commands": + { + "and": [ + "READ", + { "not": + { "commands": [ "config-get" ] } + } + ] + }, + // This is the default but as the config relies on it + // it is explicitly set. + "other-commands": "reject" + }, + ... + ], + ... + } + +It is also possible to do the opposite, i.e. to set only the "reject-commands" list: + +.. code-block:: javascript + + { + "roles": [ + { + "name": "user3", + "reject-commands": + { + "or": [ + "WRITE", + { "commands": [ "config-get" ] } + ] + }, + "other-commands": "accept" + }, + ... + ], + ... + } + +Or use both lists with the exception in the "reject-commands" list, +which must be checked first as "config-get" has the read-access right. + +.. code-block:: javascript + + { + "roles": [ + { + "name": "user4", + "accept-commands": "READ", + "reject-commands": { "commands": [ "config-get" ] }, + "list-match-first": "reject" + }, + ... + ], + ... + } + +To check any configuration, it is a good idea to use the "list-commands" +response filter, which shows errors such as missing (rejected) commands +and extra (accepted) commands. + +``access-control-lists`` can be used for definitions of access control lists +and later reused in ``roles``: + + .. code-block:: javascript + + { + "access-control-lists":[ + { + "my-list-one":{ + "or":[ + { + "hook": "subnet_cmds" + }, + { + "commands":[ "list-commands" ] + } + ] + } + }, + { + "my-list-two":{ + "and":[ + "READ", + { + "not":{ + "commands":[ "config-get" ] + } + } + ] + } + }, + { + "my-list-three":{ + "or":[ + { "hook":"subnet_cmds" }, + { "hook":"class_cmds" }, + { "hook":"lease_cmds" } + ] + } + } + ], + "roles":[ + { + "name":"admin", + "accept-commands":"my-list-one", + "reject-commands":"ALL", + "list-match-first":"accept" + }, + { + "name":"admin2", + "accept-commands":"my-list-two", + "reject-commands":"ALL", + "list-match-first":"accept" + } + ], + "unknown-role":{ + "accept-commands":"my-list-three", + "reject-commands":"ALL" + }, + ... + } diff --git a/doc/sphinx/arm/hooks-run-script.rst b/doc/sphinx/arm/hooks-run-script.rst new file mode 100644 index 0000000..3d11724 --- /dev/null +++ b/doc/sphinx/arm/hooks-run-script.rst @@ -0,0 +1,626 @@ +.. ischooklib:: libdhcp_run_script.so +.. _hooks-run-script: + +``libdhcp_run_script.so``: Run Script Support for External Hook Scripts +======================================================================= + +The Run Script hook library adds support for calling an external script for specific +packet-processing hook points. + +.. note:: + + :ischooklib:`libdhcp_run_script.so` is part of the open source code and is + available to every Kea user. + +The library, which was added in Kea 1.9.5, can be loaded in a +similar way to other hook libraries by the :iscman:`kea-dhcp4` and +:iscman:`kea-dhcp6` processes. + +.. code-block:: json + + { + "hooks-libraries": [ + { + "library": "/usr/local/lib/libdhcp_run_script.so", + "parameters": { + "name": "/full_path_to/script_name.sh", + "sync": false + } + } + ] + } + +The parameters contain the ``name``, which indicates the full path to the external +script to be called on each hook point, and also the ``sync`` option, to be able +to wait synchronously for the script to finish execution. +If the ``sync`` parameter is ``false``, then the script will launch and Kea +will not wait for the execution to finish, causing all the OUT parameters of +the script (including the next step) to be ignored. + +.. note:: + + The script inherits all privileges from the server which calls it. + +.. note:: + + Currently, enabling synchronous calls to external scripts is not supported. + +.. _hooks-run-script-hook-points: + +This library has several hook-point functions implemented, which are +called at the specific packet-processing stage. + +The dhcpv4 hook points: + +:: + + lease4_renew + lease4_expire + lease4_recover + leases4_committed + lease4_release + lease4_decline + + +The dhcpv6 hook points: + +:: + + lease6_renew + lease6_rebind + lease6_expire + lease6_recover + leases6_committed + lease6_release + lease6_decline + +Each hook point extracts the Kea internal data and exports it as string +environment variables. These parameters are shared with the target script +using the child process environment. +The only parameter passed to the call of the target script is the name of +the hook point. + +An example of a script implementing all hook points is presented below: + +:: + + #!/bin/bash + + unknown_handle() { + echo "Unhandled function call ${*}" + exit 123 + } + + + lease4_renew () { + ... + } + + lease4_expire () { + ... + } + + lease4_recover () { + ... + } + + leases4_committed () { + ... + } + + lease4_release () { + ... + } + + lease4_decline () { + ... + } + + lease6_renew () { + ... + } + + lease6_rebind () { + ... + } + + lease6_expire () { + ... + } + + lease6_recover () { + ... + } + + leases6_committed () { + ... + } + + lease6_release () { + ... + } + + lease6_decline () { + ... + } + + case "$1" in + "lease4_renew") + lease4_renew + ;; + "lease4_expire") + lease4_expire + ;; + "lease4_recover") + lease4_recover + ;; + "leases4_committed") + leases4_committed + ;; + "lease4_release") + lease4_release + ;; + "lease4_decline") + lease4_decline + ;; + "lease6_renew") + lease6_renew + ;; + "lease6_rebind") + lease6_rebind + ;; + "lease6_expire") + lease6_expire + ;; + "lease6_recover") + lease6_recover + ;; + "leases6_committed") + leases6_committed + ;; + "lease6_release") + lease6_release + ;; + "lease6_decline") + lease6_decline + ;; + *) + unknown_handle "${@}" + ;; + esac + + +.. _hooks-run-script-exported-environment-variables: + +Available parameters for each hook point are presented below. + +DHCPv4: + +``lease4_renew`` + +:: + + QUERY4_TYPE + QUERY4_TXID + QUERY4_LOCAL_ADDR + QUERY4_LOCAL_PORT + QUERY4_REMOTE_ADDR + QUERY4_REMOTE_PORT + QUERY4_IFACE_INDEX + QUERY4_IFACE_NAME + QUERY4_HOPS + QUERY4_SECS + QUERY4_FLAGS + QUERY4_CIADDR + QUERY4_SIADDR + QUERY4_YIADDR + QUERY4_GIADDR + QUERY4_RELAYED + QUERY4_HWADDR + QUERY4_HWADDR_TYPE + QUERY4_LOCAL_HWADDR + QUERY4_LOCAL_HWADDR_TYPE + QUERY4_REMOTE_HWADDR + QUERY4_REMOTE_HWADDR_TYPE + QUERY4_OPTION_82 + QUERY4_OPTION_82_SUB_OPTION_1 + QUERY4_OPTION_82_SUB_OPTION_2 + SUBNET4_ID + SUBNET4_NAME + SUBNET4_PREFIX + SUBNET4_PREFIX_LEN + PKT4_CLIENT_ID + PKT4_HWADDR + PKT4_HWADDR_TYPE + LEASE4_ADDRESS + LEASE4_CLTT + LEASE4_HOSTNAME + LEASE4_HWADDR + LEASE4_HWADDR_TYPE + LEASE4_STATE + LEASE4_SUBNET_ID + LEASE4_VALID_LIFETIME + LEASE4_CLIENT_ID + +``lease4_expire`` + +:: + + LEASE4_ADDRESS + LEASE4_CLTT + LEASE4_HOSTNAME + LEASE4_HWADDR + LEASE4_HWADDR_TYPE + LEASE4_STATE + LEASE4_SUBNET_ID + LEASE4_VALID_LIFETIME + LEASE4_CLIENT_ID + REMOVE_LEASE + +``lease4_recover`` + +:: + + LEASE4_ADDRESS + LEASE4_CLTT + LEASE4_HOSTNAME + LEASE4_HWADDR + LEASE4_HWADDR_TYPE + LEASE4_STATE + LEASE4_SUBNET_ID + LEASE4_VALID_LIFETIME + LEASE4_CLIENT_ID + +``leases4_committed`` + +:: + + QUERY4_TYPE + QUERY4_TXID + QUERY4_LOCAL_ADDR + QUERY4_LOCAL_PORT + QUERY4_REMOTE_ADDR + QUERY4_REMOTE_PORT + QUERY4_IFACE_INDEX + QUERY4_IFACE_NAME + QUERY4_HOPS + QUERY4_SECS + QUERY4_FLAGS + QUERY4_CIADDR + QUERY4_SIADDR + QUERY4_YIADDR + QUERY4_GIADDR + QUERY4_RELAYED + QUERY4_HWADDR + QUERY4_HWADDR_TYPE + QUERY4_LOCAL_HWADDR + QUERY4_LOCAL_HWADDR_TYPE + QUERY4_REMOTE_HWADDR + QUERY4_REMOTE_HWADDR_TYPE + QUERY4_OPTION_82 + QUERY4_OPTION_82_SUB_OPTION_1 + QUERY4_OPTION_82_SUB_OPTION_2 + LEASES4_SIZE + DELETED_LEASES4_SIZE + +If ``LEASES4_SIZE`` or ``DELETED_LEASES4_SIZE`` is non-zero, then each lease +has its own unique identifier, as shown below. The first index starts +at 0. + +:: + + LEASES4_AT0_ADDRESS + LEASES4_AT0_CLTT + LEASES4_AT0_HOSTNAME + LEASES4_AT0_HWADDR + LEASES4_AT0_HWADDR_TYPE + LEASES4_AT0_STATE + LEASES4_AT0_SUBNET_ID + LEASES4_AT0_VALID_LIFETIME + LEASES4_AT0_CLIENT_ID + DELETED_LEASES4_AT0_ADDRESS + DELETED_LEASES4_AT0_CLTT + DELETED_LEASES4_AT0_HOSTNAME + DELETED_LEASES4_AT0_HWADDR + DELETED_LEASES4_AT0_HWADDR_TYPE + DELETED_LEASES4_AT0_STATE + DELETED_LEASES4_AT0_SUBNET_ID + DELETED_LEASES4_AT0_VALID_LIFETIME + DELETED_LEASES4_AT0_CLIENT_ID + +``lease4_release`` + +:: + + QUERY4_TYPE + QUERY4_TXID + QUERY4_LOCAL_ADDR + QUERY4_LOCAL_PORT + QUERY4_REMOTE_ADDR + QUERY4_REMOTE_PORT + QUERY4_IFACE_INDEX + QUERY4_IFACE_NAME + QUERY4_HOPS + QUERY4_SECS + QUERY4_FLAGS + QUERY4_CIADDR + QUERY4_SIADDR + QUERY4_YIADDR + QUERY4_GIADDR + QUERY4_RELAYED + QUERY4_HWADDR + QUERY4_HWADDR_TYPE + QUERY4_LOCAL_HWADDR + QUERY4_LOCAL_HWADDR_TYPE + QUERY4_REMOTE_HWADDR + QUERY4_REMOTE_HWADDR_TYPE + QUERY4_OPTION_82 + QUERY4_OPTION_82_SUB_OPTION_1 + QUERY4_OPTION_82_SUB_OPTION_2 + LEASE4_ADDRESS + LEASE4_CLTT + LEASE4_HOSTNAME + LEASE4_HWADDR + LEASE4_HWADDR_TYPE + LEASE4_STATE + LEASE4_SUBNET_ID + LEASE4_VALID_LIFETIME + LEASE4_CLIENT_ID + +``lease4_decline`` + +:: + + QUERY4_TYPE + QUERY4_TXID + QUERY4_LOCAL_ADDR + QUERY4_LOCAL_PORT + QUERY4_REMOTE_ADDR + QUERY4_REMOTE_PORT + QUERY4_IFACE_INDEX + QUERY4_IFACE_NAME + QUERY4_HOPS + QUERY4_SECS + QUERY4_FLAGS + QUERY4_CIADDR + QUERY4_SIADDR + QUERY4_YIADDR + QUERY4_GIADDR + QUERY4_RELAYED + QUERY4_HWADDR + QUERY4_HWADDR_TYPE + QUERY4_LOCAL_HWADDR + QUERY4_LOCAL_HWADDR_TYPE + QUERY4_REMOTE_HWADDR + QUERY4_REMOTE_HWADDR_TYPE + QUERY4_OPTION_82 + QUERY4_OPTION_82_SUB_OPTION_1 + QUERY4_OPTION_82_SUB_OPTION_2 + LEASE4_ADDRESS + LEASE4_CLTT + LEASE4_HOSTNAME + LEASE4_HWADDR + LEASE4_HWADDR_TYPE + LEASE4_STATE + LEASE4_SUBNET_ID + LEASE4_VALID_LIFETIME + LEASE4_CLIENT_ID + +DHCPv6: + +``lease6_renew`` + +:: + + QUERY6_TYPE + QUERY6_TXID + QUERY6_LOCAL_ADDR + QUERY6_LOCAL_PORT + QUERY6_REMOTE_ADDR + QUERY6_REMOTE_PORT + QUERY6_IFACE_INDEX + QUERY6_IFACE_NAME + QUERY6_REMOTE_HWADDR + QUERY6_REMOTE_HWADDR_TYPE + QUERY6_PROTO + QUERY6_CLIENT_ID + LEASE6_ADDRESS + LEASE6_CLTT + LEASE6_HOSTNAME + LEASE6_HWADDR + LEASE6_HWADDR_TYPE + LEASE6_STATE + LEASE6_SUBNET_ID + LEASE6_VALID_LIFETIME + LEASE6_DUID + LEASE6_IAID + LEASE6_PREFERRED_LIFETIME + LEASE6_PREFIX_LEN + LEASE6_TYPE + PKT6_IA_IAID + PKT6_IA_IA_TYPE + PKT6_IA_IA_T1 + PKT6_IA_IA_T2 + +``lease6_rebind`` + +:: + + QUERY6_TYPE + QUERY6_TXID + QUERY6_LOCAL_ADDR + QUERY6_LOCAL_PORT + QUERY6_REMOTE_ADDR + QUERY6_REMOTE_PORT + QUERY6_IFACE_INDEX + QUERY6_IFACE_NAME + QUERY6_REMOTE_HWADDR + QUERY6_REMOTE_HWADDR_TYPE + QUERY6_PROTO + QUERY6_CLIENT_ID + LEASE6_ADDRESS + LEASE6_CLTT + LEASE6_HOSTNAME + LEASE6_HWADDR + LEASE6_HWADDR_TYPE + LEASE6_STATE + LEASE6_SUBNET_ID + LEASE6_VALID_LIFETIME + LEASE6_DUID + LEASE6_IAID + LEASE6_PREFERRED_LIFETIME + LEASE6_PREFIX_LEN + LEASE6_TYPE + PKT6_IA_IAID + PKT6_IA_IA_TYPE + PKT6_IA_IA_T1 + PKT6_IA_IA_T2 + +``lease6_expire`` + +:: + + LEASE6_ADDRESS + LEASE6_CLTT + LEASE6_HOSTNAME + LEASE6_HWADDR + LEASE6_HWADDR_TYPE + LEASE6_STATE + LEASE6_SUBNET_ID + LEASE6_VALID_LIFETIME + LEASE6_DUID + LEASE6_IAID + LEASE6_PREFERRED_LIFETIME + LEASE6_PREFIX_LEN + LEASE6_TYPE + REMOVE_LEASE + +``lease6_recover`` + +:: + + LEASE6_ADDRESS + LEASE6_CLTT + LEASE6_HOSTNAME + LEASE6_HWADDR + LEASE6_HWADDR_TYPE + LEASE6_STATE + LEASE6_SUBNET_ID + LEASE6_VALID_LIFETIME + LEASE6_DUID + LEASE6_IAID + LEASE6_PREFERRED_LIFETIME + LEASE6_PREFIX_LEN + LEASE6_TYPE + +``leases6_committed`` + +:: + + QUERY6_TYPE + QUERY6_TXID + QUERY6_LOCAL_ADDR + QUERY6_LOCAL_PORT + QUERY6_REMOTE_ADDR + QUERY6_REMOTE_PORT + QUERY6_IFACE_INDEX + QUERY6_IFACE_NAME + QUERY6_REMOTE_HWADDR + QUERY6_REMOTE_HWADDR_TYPE + QUERY6_PROTO + QUERY6_CLIENT_ID + LEASES6_SIZE + DELETED_LEASES6_SIZE + +If ``LEASES6_SIZE`` or ``DELETED_LEASES6_SIZE`` is non-zero, then each lease +has its own unique identifier, as shown below. The first index starts +at 0. + +:: + + LEASES6_AT0_ADDRESS + LEASES6_AT0_CLTT + LEASES6_AT0_HOSTNAME + LEASES6_AT0_HWADDR + LEASES6_AT0_HWADDR_TYPE + LEASES6_AT0_STATE + LEASES6_AT0_SUBNET_ID + LEASES6_AT0_VALID_LIFETIME + LEASES6_AT0_DUID + LEASES6_AT0_IAID + LEASES6_AT0_PREFERRED_LIFETIME + LEASES6_AT0_PREFIX_LEN + LEASES6_AT0_TYPE + DELETED_LEASES6_AT0_ADDRESS + DELETED_LEASES6_AT0_CLTT + DELETED_LEASES6_AT0_HOSTNAME + DELETED_LEASES6_AT0_HWADDR + DELETED_LEASES6_AT0_HWADDR_TYPE + DELETED_LEASES6_AT0_STATE + DELETED_LEASES6_AT0_SUBNET_ID + DELETED_LEASES6_AT0_VALID_LIFETIME + DELETED_LEASES6_AT0_DUID + DELETED_LEASES6_AT0_IAID + DELETED_LEASES6_AT0_PREFERRED_LIFETIME + DELETED_LEASES6_AT0_PREFIX_LEN + DELETED_LEASES6_AT0_TYPE + +``lease6_release`` + +:: + + QUERY6_TYPE + QUERY6_TXID + QUERY6_LOCAL_ADDR + QUERY6_LOCAL_PORT + QUERY6_REMOTE_ADDR + QUERY6_REMOTE_PORT + QUERY6_IFACE_INDEX + QUERY6_IFACE_NAME + QUERY6_REMOTE_HWADDR + QUERY6_REMOTE_HWADDR_TYPE + QUERY6_PROTO + QUERY6_CLIENT_ID + LEASE6_ADDRESS + LEASE6_CLTT + LEASE6_HOSTNAME + LEASE6_HWADDR + LEASE6_HWADDR_TYPE + LEASE6_STATE + LEASE6_SUBNET_ID + LEASE6_VALID_LIFETIME + LEASE6_DUID + LEASE6_IAID + LEASE6_PREFERRED_LIFETIME + LEASE6_PREFIX_LEN + LEASE6_TYPE + +``lease6_decline`` + +:: + + QUERY6_TYPE + QUERY6_TXID + QUERY6_LOCAL_ADDR + QUERY6_LOCAL_PORT + QUERY6_REMOTE_ADDR + QUERY6_REMOTE_PORT + QUERY6_IFACE_INDEX + QUERY6_IFACE_NAME + QUERY6_REMOTE_HWADDR + QUERY6_REMOTE_HWADDR_TYPE + QUERY6_PROTO + QUERY6_CLIENT_ID + LEASE6_ADDRESS + LEASE6_CLTT + LEASE6_HOSTNAME + LEASE6_HWADDR + LEASE6_HWADDR_TYPE + LEASE6_STATE + LEASE6_SUBNET_ID + LEASE6_VALID_LIFETIME + LEASE6_DUID + LEASE6_IAID + LEASE6_PREFERRED_LIFETIME + LEASE6_PREFIX_LEN + LEASE6_TYPE diff --git a/doc/sphinx/arm/hooks-stat-cmds.rst b/doc/sphinx/arm/hooks-stat-cmds.rst new file mode 100644 index 0000000..fce8cfa --- /dev/null +++ b/doc/sphinx/arm/hooks-stat-cmds.rst @@ -0,0 +1,252 @@ +.. ischooklib:: libdhcp_stat_cmds.so +.. _hooks-stat-cmds: + +``libdhcp_stat_cmds.so``: Statistics Commands for Supplemental Lease Statistics +=============================================================================== + +This library provides additional commands for retrieving lease +statistics from Kea DHCP servers. These commands were added to address +an issue with obtaining accurate lease statistics in deployments running +multiple Kea servers that use a shared lease backend. The in-memory +statistics kept by individual servers only track lease changes made by +that server; thus, in a deployment with multiple servers (e.g. two +:iscman:`kea-dhcp6` servers using the same PostgreSQL database for lease storage), +these statistics are incomplete. The MySQL and PostgreSQL backends in +Kea track lease allocation changes as they occur via database triggers. +Additionally, all the lease backends were extended to support +retrieving lease statistics for a single subnet, a range +of subnets, or all subnets. Finally, this library provides commands +for retrieving these statistics. + +.. note:: + + :ischooklib:`libdhcp_stat_cmds.so` is part of the open source code and is + available to every Kea user. + +.. note:: + + This library can only be loaded by the :iscman:`kea-dhcp4` or + :iscman:`kea-dhcp6` process. + +The commands provided by this library are: + +- :isccmd:`stat-lease4-get` - fetches DHCPv4 lease statistics. + +- :isccmd:`stat-lease6-get` - fetches DHCPv6 lease statistics. + +The Statistics Commands library is part of the open source code and is +available to every Kea user. + +All commands use JSON syntax and can be issued directly to the servers +via either the control channel (see :ref:`ctrl-channel`) or the +Control Agent (see :ref:`kea-ctrl-agent`). + +This library is loaded in the same way as other libraries and currently has no +parameters: + +:: + + "Dhcp6": { + "hooks-libraries": [ + { + "library": "/path/libdhcp_stat_cmds.so" + }, + ... + ] + } + +In a deployment with multiple Kea DHCP servers sharing a common lease +storage, this hook library can be loaded by any or all of the servers. However, +a server's response to a :isccmd:`stat-lease4-get` / :isccmd:`stat-lease6-get` +command will only contain data for subnets known to +that server. In other words, if a subnet does not appear in a server's +configuration, Kea will not retrieve statistics for it. + +.. isccmd:: stat-lease4-get +.. _command-stat-lease4-get: + +.. isccmd:: stat-lease6-get +.. _command-stat-lease6-get: + +The ``stat-lease4-get``, ``stat-lease6-get`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The :isccmd:`stat-lease4-get` and +:isccmd:`stat-lease6-get` commands fetch lease +statistics for a range of known subnets. The range of subnets is +determined through the use of optional command input parameters: + +- ``subnet-id`` - the ID of the subnet for which lease statistics + should be fetched; used to get statistics for a single subnet. If + the subnet does not exist, the command result code is 3 (i.e. + ``CONTROL_RESULT_EMPTY``). + +- ``subnet-range`` - a pair of subnet IDs which describe an inclusive + range of subnets for which statistics should be retrieved. The range + may include one or more IDs that correspond to no subnet; in this + case, the command only outputs lease statistics for those that + exist. However, if the range does not include any known subnets, the + command result code is 3 (i.e. ``CONTROL_RESULT_EMPTY``). + + - ``first-subnet-id`` - the ID of the first subnet in the range. + + - ``last-subnet-id`` - the ID of the last subnet in the range. + +The use of ``subnet-id`` and ``subnet-range`` are mutually exclusive. If no +parameters are given, the result will contain data for all known +subnets. Note that in configurations with many subnets, this +can result in a large response. + +The following command fetches lease statistics for all known subnets +from a :iscman:`kea-dhcp4` server: + +:: + + { + "command": "stat-lease4-get" + } + +The following command fetches lease statistics for subnet ID 10 from a +:iscman:`kea-dhcp6` server: + +:: + + { + "command": "stat-lease6-get", + "arguments": { + "subnet-id" : 10 + } + } + +The following command fetches lease statistics for all subnets with IDs +in the range 10 through 50 from a :iscman:`kea-dhcp4` server: + +.. code-block:: json + + { + "command": "stat-lease4-get", + "arguments": { + "subnet-range": { + "first-subnet-id": 10, + "last-subnet-id": 50 + } + } + } + +The response to either command will contain three elements: + +- ``result`` - a numeric value indicating the outcome of the command + where: + + - ``0`` - the command was successful; + + - ``1`` - an error occurred, and an explanation is the "text" + element; or + + - ``2`` - the fetch found no matching data. + +- ``text`` - an explanation of the command outcome. When the command + succeeds, it contains the command name along with the number of + rows returned. + +- ``arguments`` - a map containing the data returned by the command as + the element "result-set", which is patterned after SQL statement + responses: + + - ``columns`` - a list of text column labels. + + The columns returned for DHCPv4 are: + + - ``subnet-id`` - the ID of the subnet. + + - ``total-addresses`` - the total number of addresses available for + DHCPv4 management in the subnet. In other words, this is the + count of all addresses in all the configured pools in the subnet. + + - ``cumulative-assigned-addresses`` - the cumulative number of addresses + in the subnet that have been assigned to a client by the server + since it started. + + - ``assigned-addresses`` - the number of addresses in the subnet that + are currently assigned to a client. + + - ``declined-addresses`` - the number of addresses in the subnet that + are currently declined and are thus unavailable for assignment. + + The columns returned for DHCPv6 are: + + - ``subnet-id`` - the ID of the subnet. + + - ``total-nas`` - the number of NA addresses available for DHCPv6 + management in the subnet. In other words, this is the count of + all the NA addresses in all the configured NA pools in the + subnet. + + - ``cumulative-assigned-nas`` - the cumulative number of NA addresses + in the subnet that have been assigned to a client by the server + since it started. + + - ``assigned-nas`` - the number of NA addresses in the subnet that + are currently assigned to a client. + + - ``declined-addresses`` - the number of NA addresses that are currently + declined and are thus unavailable for assignment. + + - ``total-pds`` - the total number of PD prefixes available of DHCPv6 + management in the subnet. In other words, this is the count of + all prefixes in all the configured prefix pools in the subnet. + + - ``cumulative-assigned-pds`` - the cumulative number of PD prefixes + in the subnet that have been assigned to a client by the server + since it started. + + - ``assigned-pds`` - the number of PD prefixes in the subnet that are + currently assigned to a client. + + - ``rows`` - a list of rows, one per subnet ID. Each row contains a + data value corresponding to and in the same order as each column + listed in "columns" for a given subnet. + + - ``timestamp`` - the textual date and time the data were fetched, + expressed as GMT. + +The response to a DHCPv4 command might look as follows: + +:: + + { + "result": 0, + "text": "stat-lease4-get: 2 rows found", + "arguments": { + "result-set": { + "columns": [ "subnet-id", "total-addresses", "cumulative-assigned-addresses", "assigned-addresses", "declined-addresses" ], + "rows": [ + [ 10, 256, 300, 111, 0 ], + [ 20, 4098, 2034, 2034, 4 ] + ], + "timestamp": "2018-05-04 15:03:37.000000" + } + } + } + +The response to a DHCPv6 command might look as follows, assuming subnet 10 has no +prefix pools, subnet 20 has no NA pools, and subnet 30 has both NA and +PD pools: + +:: + + { + "result": 0, + "text": "stat-lease6-get: 2 rows found", + "arguments": { + "result-set": { + "columns": [ "subnet-id", "total-nas", "cumulative-assigned-nas", "assigned-nas", "declined-addresses", "total-pds", "cumulative-assigned-pds", "assigned-pds" ], + "rows": [ + [ 10, 4096, 5000, 2400, 3, 0, 0, 0], + [ 20, 0, 0, 0, 0, 1048, 300, 233 ], + [ 30, 256, 60, 60, 0, 1048, 15, 15 ] + ], + "timestamp": "2018-05-04 15:03:37.000000" + } + } + } diff --git a/doc/sphinx/arm/hooks-subnet-cmds.rst b/doc/sphinx/arm/hooks-subnet-cmds.rst new file mode 100644 index 0000000..63cedfe --- /dev/null +++ b/doc/sphinx/arm/hooks-subnet-cmds.rst @@ -0,0 +1,1326 @@ +.. ischooklib:: libdhcp_subnet_cmds.so +.. _hooks-subnet-cmds: + +``libdhcp_subnet_cmds.so``: Subnet Commands to Manage Subnets and Shared Networks +================================================================================= + +This library offers commands used to query and manipulate subnet and shared network +configurations in Kea. These can be very useful in deployments +with a large number of subnets being managed by the DHCP servers, +when those subnets are frequently updated. The commands offer a lightweight +approach for manipulating subnets without needing to fully reconfigure +the server, and without affecting existing servers' configurations. An +ability to manage shared networks (listing, retrieving details, adding +new ones, removing existing ones, and adding subnets to and removing them from +shared networks) is also provided. + +.. note:: + + :ischooklib:`libdhcp_subnet_cmds.so` is available only to ISC customers with + a paid support contract. For more information on subscription options, + please complete the form at https://www.isc.org/contact. + +.. note:: + + This library can only be loaded by the :iscman:`kea-dhcp4` or :iscman:`kea-dhcp6` + process. + +The following commands are currently supported: + +- :isccmd:`subnet4-list` / :isccmd:`subnet6-list` - lists all configured subnets. + +- :isccmd:`subnet4-get` / :isccmd:`subnet6-get` - retrieves detailed information about a + specified subnet. + +- :isccmd:`subnet4-add` / :isccmd:`subnet6-add` - adds a new subnet into the server's + configuration. + +- :isccmd:`subnet4-update` / :isccmd:`subnet6-update` - updates (replaces) a single subnet in + the server's configuration. + +- :isccmd:`subnet4-del` / :isccmd:`subnet6-del` - removes a subnet from the server's + configuration. + +- :isccmd:`subnet4-delta-add` / :isccmd:`subnet6-delta-add` - updates (replaces) parts of a + single subnet in the server's configuration. + +- :isccmd:`subnet4-delta-del` / :isccmd:`subnet6-delta-del` - removes parts of a single subnet in + the server's configuration. + +- :isccmd:`network4-list` / :isccmd:`network6-list` - lists all configured shared networks. + +- :isccmd:`network4-get` / :isccmd:`network6-get` - retrieves detailed information about a + specified shared network. + +- :isccmd:`network4-add` / :isccmd:`network6-add` - adds a new shared network to the + server's configuration. + +- :isccmd:`network4-del` / :isccmd:`network6-del` - removes a shared network from the + server's configuration. + +- :isccmd:`network4-subnet-add` / :isccmd:`network6-subnet-add` - adds an existing subnet to + an existing shared network. + +- :isccmd:`network4-subnet-del` / :isccmd:`network6-subnet-del` - removes a subnet from + an existing shared network and demotes it to a plain subnet. + +.. isccmd:: subnet4-list +.. _command-subnet4-list: + +The ``subnet4-list`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This command is used to list all currently configured subnets. Each +subnet is returned with a subnet identifier and +subnet prefix. To retrieve +detailed information about the subnet, use the :isccmd:`subnet4-get` command. + +This command has a simple structure: + +:: + + { + "command": "subnet4-list" + } + +The list of subnets is returned in the following format: + +:: + + { + "result": 0, + "text": "2 IPv4 subnets found", + "arguments": { + "subnets": [ + { + "id": 10, + "subnet": "10.0.0.0/8" + }, + { + "id": 100, + "subnet": "192.0.2.0/24" + } + ] + } + } + +If no IPv4 subnets are found, an error code is returned along with the +error description. + +.. isccmd:: subnet6-list +.. _command-subnet6-list: + +The ``subnet6-list`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This command is used to list all currently configured subnets. Each +subnet is returned with a subnet identifier and +subnet prefix. To retrieve +detailed information about the subnet, use the :isccmd:`subnet6-get` command. + +This command has a simple structure: + +:: + + { + "command": "subnet6-list" + } + +The list of subnets is returned in the following format: + +:: + + { + "result": 0, + "text": "2 IPv6 subnets found", + "arguments": { + "subnets": [ + { + "id": 11, + "subnet": "2001:db8:1::/64" + }, + { + "id": 233, + "subnet": "3000::/16" + } + ] + } + } + +If no IPv6 subnets are found, an error code is returned along with the +error description. + +.. isccmd:: subnet4-get +.. _command-subnet4-get: + +The ``subnet4-get`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This command is used to retrieve detailed information about the +specified subnet. This command usually follows :isccmd:`subnet4-list`, +which is used to discover available subnets with their respective subnet +identifiers and prefixes. Any of those parameters can then be used in +:isccmd:`subnet4-get` to fetch subnet information: + +:: + + { + "command": "subnet4-get", + "arguments": { + "id": 10 + } + } + +or + +:: + + { + "command": "subnet4-get", + "arguments": { + "subnet": "10.0.0.0/8" + } + } + +If the subnet exists, the response will be similar to this: + +:: + + { + "result": 0, + "text": "Info about IPv4 subnet 10.0.0.0/8 (id 10) returned", + "arguments": { + "subnets": [ + { + "subnet": "10.0.0.0/8", + "id": 1, + "option-data": [ + { + ... + }, + ... + ], + ... + } + ] + } + } + +.. isccmd:: subnet6-get +.. _command-subnet6-get: + +The ``subnet6-get`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This command is used to retrieve detailed information about the +specified subnet. This command usually follows :isccmd:`subnet6-list`, +which is used to discover available subnets with their respective subnet +identifiers and prefixes. Any of those parameters can be then used in +:isccmd:`subnet6-get` to fetch subnet information: + +:: + + { + "command": "subnet6-get", + "arguments": { + "id": 11 + } + } + +or + +:: + + { + "command": "subnet6-get", + "arguments": { + "subnet": "2001:db8:1::/64" + } + } + +If the subnet exists, the response will be similar to this: + +:: + + { + "result": 0, + "text": "Info about IPv6 subnet 2001:db8:1::/64 (id 11) returned", + "arguments": { + "subnets": [ + { + "subnet": "2001:db8:1::/64", + "id": 1, + "option-data": [ + { + ... + }, + ... + ], + ... + } + ] + } + } + +.. isccmd:: subnet4-add +.. _command-subnet4-add: + +The ``subnet4-add`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This command is used to create and add a new subnet to the existing server +configuration. This operation has no impact on other subnets. The subnet +identifier must be specified and must be unique among all subnets. If +the identifier or a subnet prefix is not unique, an error is reported and +the subnet is not added. + +The subnet information within this command has the same structure as the +subnet information in the server configuration file, with the exception +that static host reservations cannot be specified within +:isccmd:`subnet4-add`. The commands described in :ref:`hooks-host-cmds` should be used to +add, remove, and modify static reservations. + +:: + + { + "command": "subnet4-add", + "arguments": { + "subnet4": [ { + "id": 123, + "subnet": "10.20.30.0/24", + ... + } ] + } + } + +The response to this command has the following structure: + +:: + + { + "result": 0, + "text": "IPv4 subnet added", + "arguments": { + "subnet4": [ + { + "id": 123, + "subnet": "10.20.30.0/24" + } + ] + } + } + +.. isccmd:: subnet6-add +.. _command-subnet6-add: + +The ``subnet6-add`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This command is used to create and add a new subnet to the existing server +configuration. This operation has no impact on other subnets. The subnet +identifier must be specified and must be unique among all subnets. If +the identifier or a subnet prefix is not unique, an error is reported and +the subnet is not added. + +The subnet information within this command has the same structure as the +subnet information in the server configuration file, with the exception +that static host reservations cannot be specified within +:isccmd:`subnet6-add`. The commands described in :ref:`hooks-host-cmds` should be used +to add, remove, and modify static reservations. + +:: + + { + "command": "subnet6-add", + "arguments": { + "subnet6": [ { + "id": 234, + "subnet": "2001:db8:1::/64", + ... + } ] + } + } + +The response to this command has the following structure: + +:: + + { + "result": 0, + "text": "IPv6 subnet added", + "arguments": { + "subnet6": [ + { + "id": 234, + "subnet": "2001:db8:1::/64" + } + ] + } + } + +It is recommended, but not mandatory, to specify the subnet ID. If not +specified, Kea will try to assign the next ``subnet-id`` value. This +automatic ID value generator is simple; it returns the previous +automatically assigned value, increased by 1. This works well, unless +a subnet is manually created with a larger value than one previously used. For +example, if :isccmd:`subnet4-add` is called five times, each without an ID, Kea will +assign IDs 1, 2, 3, 4, and 5 and it will work just fine. However, if +:isccmd:`subnet4-add` is called five times, with the first subnet having the +``subnet-id`` of value 3 and the remaining ones having no ``subnet-id``, the operation will +fail. The first command (with the explicit value) will use ``subnet-id`` 3; the +second command will create a subnet with and ID of 1; the third will use a +value of 2; and finally the fourth will have its ``subnet-id`` value +auto-generated as 3. However, since there is already a subnet with that +ID, the process will fail. + +The general recommendation is either never to use explicit values, so +that auto-generated values will always work; or always use explicit +values, so that auto-generation is never used. The two +approaches can be mixed only if the administrator understands how internal +automatic ``subnet-id`` generation works in Kea. + +.. note:: + + Subnet IDs must be greater than zero and less than 4294967295. + +.. isccmd:: subnet4-update +.. _command-subnet4-update: + +The ``subnet4-update`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This command is used to update (overwrite) a single subnet in the existing +server configuration. This operation has no impact on other subnets. The +subnet identifier is used to identify the subnet to replace; it must be +specified and must be unique among all subnets. The subnet prefix should +not be updated. + +The subnet information within this command has the same structure as the +subnet information in the server configuration file, with the exception +that static host reservations cannot be specified within +:isccmd:`subnet4-update`. The commands described in :ref:`hooks-host-cmds` should be +used to update, remove, and modify static reservations. + +:: + + { + "command": "subnet4-update", + "arguments": { + "subnet4": [ { + "id": 123, + "subnet": "10.20.30.0/24", + ... + } ] + } + } + +The response to this command has the following structure: + +:: + + { + "result": 0, + "text": "IPv4 subnet updated", + "arguments": { + "subnet4": [ + { + "id": 123, + "subnet": "10.20.30.0/24" + } + ] + } + } + +As with other update commands, this command overwrites all the contents of the +entry. If the IPv4 subnet previously had a resource assigned to it, and the +:isccmd:`subnet4-update` command is missing the resource, it is deleted from the +server configuration. If an incremental update of the subnet is desired, then +this can be achieved with :isccmd:`subnet4-delta-add`. + +.. isccmd:: subnet6-update +.. _command-subnet6-update: + +The ``subnet6-update`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This command is used to update (overwrite) a single subnet in the existing +server configuration. This operation has no impact on other subnets. The +subnet identifier is used to identify the subnet to replace; it must be +specified and must be unique among all subnets. The subnet prefix should +not be updated. + +The subnet information within this command has the same structure as the +subnet information in the server configuration file, with the exception +that static host reservations cannot be specified within +:isccmd:`subnet6-update`. The commands described in :ref:`hooks-host-cmds` should be +used to update, remove, and modify static reservations. + +:: + + { + "command": "subnet6-update", + "arguments": { + "subnet6": [ { + "id": 234, + "subnet": "2001:db8:1::/64", + ... + } ] + } + } + +The response to this command has the following structure: + +:: + + { + "result": 0, + "text": "IPv6 subnet updated", + "arguments": { + "subnet6": [ + { + "id": 234, + "subnet": "2001:db8:1::/64" + } + ] + } + } + +As with other update commands, this command overwrites all the contents of the +entry. If the IPv6 subnet previously had a resource assigned to it, and the +:isccmd:`subnet6-update` command is missing the resource, it is deleted from the +server configuration. If an incremental update of the subnet is desired, then +this can be achieved with :isccmd:`subnet6-delta-add`. + +.. isccmd:: subnet4-del +.. _command-subnet4-del: + +The ``subnet4-del`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This command is used to remove a subnet from the server's configuration. +This command has no effect on other configured subnets, but removing a +subnet does have certain implications. + +In most cases the server has assigned some leases to the clients +belonging to the subnet. The server may also be configured with static +host reservations which are associated with this subnet. The current +implementation of the :isccmd:`subnet4-del` command removes neither the leases nor +the host reservations associated with a subnet. This is the safest approach +because the server does not lose track of leases assigned to clients +from this subnet. However, removal of the subnet may still cause +configuration errors and conflicts. For example: after removal of the +subnet, the server administrator may update a new subnet with the ID +used previously for the removed subnet. This means that the existing +leases and static reservations will be in conflict with this new subnet. +Thus, we recommend that this command be used with extreme caution. + +This command can also be used to completely delete an IPv4 subnet that +is part of a shared network. To simply remove the subnet +from a shared network and keep the subnet configuration, use the +:isccmd:`network4-subnet-del` command instead. + +The command has the following structure: + +:: + + { + "command": "subnet4-del", + "arguments": { + "id": 123 + } + } + +A successful response may look like this: + +:: + + { + "result": 0, + "text": "IPv4 subnet 192.0.2.0/24 (id 123) deleted", + "arguments": { + "subnets": [ + { + "id": 123, + "subnet": "192.0.2.0/24" + } + ] + } + } + +.. isccmd:: subnet6-del +.. _command-subnet6-del: + +The ``subnet6-del`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This command is used to remove a subnet from the server's configuration. +This command has no effect on other configured subnets, but removing a +subnet does have certain implications. + +In most cases the server has assigned some leases to the clients +belonging to the subnet. The server may also be configured with static +host reservations which are associated with this subnet. The current +implementation of the :isccmd:`subnet6-del` command removes neither the leases nor +the host reservations associated with a subnet. This is the safest approach +because the server does not lose track of leases assigned to clients +from this subnet. However, removal of the subnet may still cause +configuration errors and conflicts. For example: after removal of the +subnet, the server administrator may add a new subnet with the ID used +previously for the removed subnet. This means that the existing leases +and static reservations will be in conflict with this new subnet. Thus, +we recommend that this command be used with extreme caution. + +This command can also be used to completely delete an IPv6 subnet that +is part of a shared network. To simply remove the subnet +from a shared network and keep the subnet configuration, use the +:isccmd:`network6-subnet-del` command instead. + +The command has the following structure: + +:: + + { + "command": "subnet6-del", + "arguments": { + "id": 234 + } + } + +A successful response may look like this: + +:: + + { + "result": 0, + "text": "IPv6 subnet 2001:db8:1::/64 (id 234) deleted", + "subnets": [ + { + "id": 234, + "subnet": "2001:db8:1::/64" + } + ] + } + +.. isccmd:: subnet4-delta-add +.. _command-subnet4-delta-add: + +The ``subnet4-delta-add`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This command is used to update a subnet by adding or overwriting its parts in +the existing server configuration. This operation has no impact on other +subnets. The subnet identifier is used to identify the subnet to update; it must +be specified and must be unique among all subnets. The subnet prefix should not +be updated. + +The subnet information within this command has the same structure as the +subnet information in the server configuration file, with the exception +that static host reservations cannot be specified within +:isccmd:`subnet4-delta-add`. The commands described in :ref:`hooks-host-cmds` should +be used to update, remove, and modify static reservations. + +:: + + { + "command": "subnet4-delta-add", + "arguments": { + "subnet4": [ { + "valid-lifetime": 120, + "id": 123, + "subnet": "10.20.30.0/24", + "option-data": [ + { + "always-send": false, + "code": 3, + "csv-format": true, + "data": "192.0.3.1", + "name": "routers", + "space": "dhcp4" + } + ], + "pools": [ + { + "pool": "10.20.30.1-10.20.30.10", + "option-data": [ + { + "always-send": false, + "code": 4, + "csv-format": true, + "data": "192.0.4.1", + "name": "time-servers", + "space": "dhcp4" + } + ] + } + ] + } ] + } + } + +The response to this command has the following structure: + +:: + + { + "result": 0, + "text": "IPv4 subnet updated", + "arguments": { + "subnet4": [ + { + "id": 123, + "subnet": "10.20.30.0/24" + } + ] + } + } + +The command updates subnet "10.20.30.0/24" with id 123 by changing the valid +lifetime, adding or changing the subnet level option 3 ("routers"), by adding +or changing the pool "10.20.30.1-10.20.30.10" and by adding or changing the pool +level option 4 ("time-servers"). + +.. isccmd:: subnet6-delta-add +.. _command-subnet6-delta-add: + +The ``subnet6-delta-add`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This command is used to update a subnet by adding or overwriting its parts in +the existing server configuration. This operation has no impact on other +subnets. The subnet identifier is used to identify the subnet to update; it must +be specified and must be unique among all subnets. The subnet prefix should not +be updated. + +The subnet information within this command has the same structure as the +subnet information in the server configuration file, with the exception +that static host reservations cannot be specified within +:isccmd:`subnet6-delta-add`. The commands described in :ref:`hooks-host-cmds` should +be used to update, remove, and modify static reservations. + +:: + + { + "command": "subnet6-delta-add", + "arguments": { + "subnet6": [ { + "valid-lifetime": 120, + "id": 243, + "subnet": "2001:db8:1::/64", + "option-data": [ + { + "always-send": false, + "code": 23, + "csv-format": true, + "data": "3000::3:1", + "name": "dns-servers", + "space": "dhcp6" + } + ], + "pd-pools": [ + { + "prefix": "2001:db8:2::", + "prefix-len": 48, + "delegated-len": 64, + "option-data": [ + { + "always-send": false, + "code": 22, + "csv-format": true, + "data": "3000::4:1", + "name": "sip-server-addr", + "space": "dhcp6" + } + ] + } + ], + "pools": [ + { + "pool": "2001:db8:1::1-2001:db8:1::10", + "option-data": [ + { + "always-send": false, + "code": 31, + "csv-format": true, + "data": "3000::5:1", + "name": "sntp-servers", + "space": "dhcp6" + } + ] + } + ] + } ] + } + } + +The response to this command has the following structure: + +:: + + { + "result": 0, + "text": "IPv6 subnet updated", + "arguments": { + "subnet6": [ + { + "id": 234, + "subnet": "2001:db8:1::/64" + } + ] + } + } + +The command updates subnet "2001:db8:1::/64" with id 243 by changing the valid +lifetime, adding or changing the subnet level option 23 ("dns-servers"), by +adding or changing the pool "2001:db8:1::1-2001:db8:1::10", by adding or +changing the pool level option 31 ("sntp-servers"), by adding or changing the +pd-pool "2001:db8:2::" with prefix-len 48 and by adding or changing the pd-pool +level option 22 ("sip-server-addr"). + +.. isccmd:: subnet4-delta-del +.. _command-subnet4-delta-del: + +The ``subnet4-delta-del`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This command is used to update a subnet by removing its parts in the existing +server configuration. This operation has no impact on other subnets. +The subnet identifier is used to identify the subnet to update; it must be +specified and must be unique among all subnets. The subnet prefix should not be +updated. + +The subnet information within this command has the same structure as the +subnet information in the server configuration file, with the exception +that static host reservations cannot be specified within +:isccmd:`subnet4-delta-del`. The commands described in :ref:`hooks-host-cmds` should +be used to update, remove, and modify static reservations. + +The command is flexible and can delete the part of the subnet by either +specifying the entire object that needs to be deleted, or just the keys +identifying the respective object. The address pools are identified by the +'pool' parameter, the options are identified by the 'name' or 'code' and +'space' parameters. The 'space' parameter can be omitted if the option belongs +to the default 'dhcp4' space. + +:: + + { + "command": "subnet4-delta-del", + "arguments": { + "subnet4": [ { + "valid-lifetime": 0, + "id": 123, + "subnet": "10.20.30.0/24", + "option-data": [ + { "name": "routers" } + ], + "pools": [ + { + "option-data": [ + { "code": 4 } + ], + "pool": "10.20.30.11-10.20.30.20" + }, + { + "pool": "10.20.30.21-10.20.30.30" + } + ] + } ] + } + } + +The response to this command has the following structure: + +:: + + { + "result": 0, + "text": "IPv4 subnet updated", + "arguments": { + "subnet4": [ + { + "id": 123, + "subnet": "10.20.30.0/24" + } + ] + } + } + +The command updates subnet "10.20.30.0/24" with id 123 by removing the valid +lifetime, removing the subnet level option 3 ("routers"), by removing the pool +"10.20.30.21-10.20.30.30" and by removing the pool level option 4 +("time-servers") in pool "10.20.30.11-10.20.30.20". +The scalar values don't need to match what is configured, but still need to be +present to maintain a valid json structure and to be a valid value to be able to +be parsed. + +.. isccmd:: subnet6-delta-del +.. _command-subnet6-delta-del: + +The ``subnet6-delta-del`` Command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This command is used to update a subnet by removing its parts in the existing +server configuration. This operation has no impact on other subnets. +The subnet identifier is used to identify the subnet to update; it must be +specified and must be unique among all subnets. The subnet prefix should not be +updated. + +The subnet information within this command has the same structure as the +subnet information in the server configuration file, with the exception +that static host reservations cannot be specified within +:isccmd:`subnet6-delta-del`. The commands described in :ref:`hooks-host-cmds` should +be used to update, remove, and modify static reservations. + +The command is flexible and can delete the part of the subnet by either +specifying the entire object that needs to be deleted, or just the keys +identifying the respective object. The address pools are identified by the +'pool' parameter, the prefix pools are identified by the "prefix", "prefix-len" +and "delegated-len" parameters, the options are identified by the 'name' or +'code' and 'space' parameters. The 'space' parameter can be omitted if the +option belongs to the default 'dhcp6' space. + +.. code-block:: json + + { + "command": "subnet6-delta-del", + "arguments": { + "subnet6": [ { + "valid-lifetime": 0, + "id": 234, + "subnet": "2001:db8:1::/64", + "option-data": [ + { "name": "dns-servers" } + ], + "pd-pools": [ + { + "prefix": "2001:db8:3::", + "prefix-len": 48, + "delegated-len": 64, + "option-data": [ + { "code": 22 } + ] + }, + { + "prefix": "2001:db8:4::", + "prefix-len": 48, + "delegated-len": 64 + } + ], + "pools": [ + { + "option-data": [ + { "code": 31 } + ], + "pool": "2001:db8:1::11-2001:db8:1::20" + }, + { + "pool": "2001:db8:1::21-2001:db8:1::30" + } + ] + } ] + } + } + +The response to this command has the following structure: + +:: + + { + "result": 0, + "text": "IPv6 subnet updated", + "arguments": { + "subnet6": [ + { + "id": 234, + "subnet": "2001:db8:1::/64" + } + ] + } + } + +The command updates subnet "2001:db8:1::/64" with id 243 by removing the valid +lifetime, removing the subnet level option 23 ("dns-servers"), by removing the +pool "2001:db8:1::21-2001:db8:1::30", by removing the pool level option 31 +("sntp-servers") in pool "2001:db8:1::11-2001:db8:1::20", by removing the +pd-pool "2001:db8:4::" with prefix-len 48, by removing the pd-pool level option +22 ("sip-server-addr") in pd-pool "2001:db8:3::" with prefix-len 48. +The scalar values don't need to match what is configured, but still need to be +present to maintain a valid json structure and to be a valid value to be able to +be parsed. + +.. isccmd:: network4-list +.. _command-network4-list: + +.. isccmd:: network6-list +.. _command-network6-list: + +The ``network4-list``, ``network6-list`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These commands are used to retrieve the full list of currently configured +shared networks. The list contains only very basic information about +each shared network. If more details are needed, please use +:isccmd:`network4-get` or :isccmd:`network6-get` to retrieve all information +available. This command does not require any parameters and its +invocation is very simple: + +:: + + { + "command": "network4-list" + } + +An example response for :isccmd:`network4-list` looks as follows: + +:: + + { + "arguments": { + "shared-networks": [ + { "name": "floor1" }, + { "name": "office" } + ] + }, + "result": 0, + "text": "2 IPv4 network(s) found" + } + +The :isccmd:`network6-list` command uses exactly the same syntax for both the +command and the response. + +.. isccmd:: network4-get +.. _command-network4-get: + +.. isccmd:: network6-get +.. _command-network6-get: + +The ``network4-get``, ``network6-get`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These commands are used to retrieve detailed information about shared +networks, including subnets that are currently part of a given network. +Both commands take one mandatory parameter, ``name``, which specifies the +name of the shared network. An example command to retrieve details about +an IPv4 shared network with the name "floor13" looks as follows: + +:: + + { + "command": "network4-get", + "arguments": { + "name": "floor13" + } + } + +An example response could look as follows: + +:: + + { + "result": 0, + "text": "Info about IPv4 shared network 'floor13' returned", + "arguments": { + "shared-networks": [ + { + "match-client-id": true, + "name": "floor13", + "option-data": [ ], + "rebind-timer": 90, + "relay": { + "ip-address": "0.0.0.0" + }, + "renew-timer": 60, + # "reservation-mode": "all", + # It is replaced by the "reservations-global", + # "reservations-in-subnet", and "reservations-out-of-pool" + # parameters. + # Specify if the server should look up global reservations. + "reservations-global": false, + # Specify if the server should look up in-subnet reservations. + "reservations-in-subnet": true, + # Specify if the server can assume that all reserved addresses + # are out-of-pool. + "reservations-out-of-pool": false, + "subnet4": [ + { + "subnet": "192.0.2.0/24", + "id": 5, + ... + # many other subnet-specific details here + }, + { + "id": 6, + "subnet": "192.0.3.0/31", + ... + # many other subnet-specific details here + } + ], + "valid-lifetime": 120 + } + ] + } + } + +The actual response contains many additional fields that are +omitted here for clarity. The response format is exactly the same as +used in :isccmd:`config-get`, just limited to returning the shared network's +information. + +.. isccmd:: network4-add +.. _command-network4-add: + +.. isccmd:: network6-add +.. _command-network6-add: + +The ``network4-add``, ``network6-add`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These commands are used to add a new shared network, which must +have a unique name. This command requires one parameter, +``shared-networks``, which is a list and should contain exactly one +entry that defines the network. The only mandatory element for a network +is its name. Although it does not make operational sense, it is possible +to add an empty shared network that does not have any subnets in it. +That is allowed for testing purposes, but having empty networks (or networks with +only one subnet) is discouraged in production environments. For details +regarding syntax, see :ref:`shared-network4` and +:ref:`shared-network6`. + +.. note:: + + As opposed to parameter inheritance during the processing of a full new + configuration, this command does not fully handle parameter inheritance. + Any missing parameters will be filled with default values, rather + than inherited from the global scope. + +An example that showcases how to add a new IPv4 shared network looks as +follows: + +:: + + { + "command": "network4-add", + "arguments": { + "shared-networks": [ { + "name": "floor13", + "subnet4": [ + { + "id": 100, + "pools": [ { "pool": "192.0.2.2-192.0.2.99" } ], + "subnet": "192.0.2.0/24", + "option-data": [ + { + "name": "routers", + "data": "192.0.2.1" + } + ] + }, + { + "id": 101, + "pools": [ { "pool": "192.0.3.2-192.0.3.99" } ], + "subnet": "192.0.3.0/24", + "option-data": [ + { + "name": "routers", + "data": "192.0.3.1" + } + ] + } ] + } ] + } + } + +Assuming there was no shared network with a name "floor13" and no subnets +with IDs 100 and 101 previously configured, the command will be +successful and will return the following response: + +:: + + { + "arguments": { + "shared-networks": [ { "name": "floor13" } ] + }, + "result": 0, + "text": "A new IPv4 shared network 'floor13' added" + } + +The :isccmd:`network6-add` command uses the same syntax for both the query and the +response. However, there are some parameters that are IPv4-only (e.g. +``match-client-id``) and some that are IPv6-only (e.g. ``interface-id``). The same +applies to subnets within the network. + +.. isccmd:: network4-del +.. _command-network4-del: + +.. isccmd:: network6-del +.. _command-network6-del: + +The ``network4-del``, ``network6-del`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These commands are used to delete existing shared networks. Both +commands take exactly one parameter, ``name``, that specifies the name of +the network to be removed. An example invocation of the :isccmd:`network4-del` +command looks as follows: + +:: + + { + "command": "network4-del", + "arguments": { + "name": "floor13" + } + } + +Assuming there was such a network configured, the response will look +similar to the following: + +:: + + { + "arguments": { + "shared-networks": [ + { + "name": "floor13" + } + ] + }, + "result": 0, + "text": "IPv4 shared network 'floor13' deleted" + } + +The :isccmd:`network6-del` command uses exactly the same syntax for both the +command and the response. + +If there are any subnets belonging to the shared network being deleted, +they will be demoted to a plain subnet. There is an optional parameter +called ``subnets-action`` that, if specified, takes one of two possible +values: ``keep`` (which is the default) and ``delete``. It controls +whether the subnets are demoted to plain subnets or removed. An example +usage in the :isccmd:`network6-del` command that deletes the shared network and all +subnets in it could look as follows: + +:: + + { + "command": "network4-del", + "arguments": { + "name": "floor13", + "subnets-action": "delete" + } + } + +Alternatively, to completely remove the subnets, it is possible to use the +:isccmd:`subnet4-del` or :isccmd:`subnet6-del` commands. + +.. isccmd:: network4-subnet-add +.. _command-network4-subnet-add: + +.. isccmd:: network6-subnet-add +.. _command-network6-subnet-add: + +The ``network4-subnet-add``, ``network6-subnet-add`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These commands are used to add existing subnets to existing shared +networks. There are several ways to add a new shared network. The system +administrator can add the whole shared network at once, either by +editing a configuration file or by calling the :isccmd:`network4-add` or +:isccmd:`network6-add` command with the desired subnets in it. This approach +works well for completely new shared subnets. However, there may be +cases when an existing subnet is running out of addresses and needs to +be extended with additional address space; in other words, another subnet +needs to be added on top of it. For this scenario, a system administrator +can use :isccmd:`network4-add` or :isccmd:`network6-add`, and then add an existing +subnet to this newly created shared network using +:isccmd:`network4-subnet-add` or :isccmd:`network6-subnet-add`. + +The :isccmd:`network4-subnet-add` and +:isccmd:`network6-subnet-add` commands take +two parameters: ``id``, which is an integer and specifies the ID of +an existing subnet to be added to a shared network; and ``name``, which +specifies the name of the shared network to which the subnet will be added. The +subnet must not belong to any existing network; to +reassign a subnet from one shared network to another, use the +:isccmd:`network4-subnet-del` or +:isccmd:`network6-subnet-del` command commands first. + +An example invocation of the :isccmd:`network4-subnet-add` command looks as +follows: + +:: + + { + "command": "network4-subnet-add", + "arguments": { + "name": "floor13", + "id": 5 + } + } + +Assuming there is a network named "floor13", and there is a subnet with +``subnet-id`` 5 that is not a part of the existing network, the command will +return a response similar to the following: + +:: + + { + "result": 0, + "text": "IPv4 subnet 10.0.0.0/8 (id 5) is now part of shared network 'floor13'" + } + +The :isccmd:`network6-subnet-add` command uses exactly the same syntax for both the +command and the response. + +.. note:: + + As opposed to parameter inheritance during the processing of a full new + configuration or when adding a new shared network with new subnets, + this command does not fully handle parameter inheritance. + Any missing parameters will be filled with default values, rather + than inherited from the global scope or from the shared network. + +.. isccmd:: network4-subnet-del +.. _command-network4-subnet-del: + +.. isccmd:: network6-subnet-del +.. _command-network6-subnet-del: + +The ``network4-subnet-del``, ``network6-subnet-del`` Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These commands are used to remove a subnet that is part of an existing +shared network and demote it to a plain, stand-alone subnet. +To remove a subnet completely, use the :isccmd:`subnet4-del` or :isccmd:`subnet6-del` +commands instead. The :isccmd:`network4-subnet-del` and +:isccmd:`network6-subnet-del` commands take two parameters: ``id``, which is +an integer and specifies the ID of an existing subnet to be removed from +a shared network; and ``name``, which specifies the name of the shared +network from which the subnet will be removed. + +An example invocation of the :isccmd:`network4-subnet-del` command looks as +follows: + +:: + + { + "command": "network4-subnet-del", + "arguments": { + "name": "floor13", + "id": 5 + } + } + +Assuming there was a subnet with ``subnet-id`` 5, that was part of a +shared network named "floor13", the response would look similar to the +following: + +:: + + { + "result": 0, + "text": "IPv4 subnet 10.0.0.0/8 (id 5) is now removed from shared network 'floor13'" + } + +The :isccmd:`network6-subnet-del` command uses exactly the same syntax for both the +command and the response. diff --git a/doc/sphinx/arm/hooks-user-chk.rst b/doc/sphinx/arm/hooks-user-chk.rst new file mode 100644 index 0000000..37f94b4 --- /dev/null +++ b/doc/sphinx/arm/hooks-user-chk.rst @@ -0,0 +1,83 @@ +.. ischooklib:: libdhcp_user_chk.so +.. _hooks-user-chk: + +``libdhcp_user_chk.so``: User Check +=================================== + +This library serves several purposes: + +- To assign "new" or "unregistered" users to a restricted subnet, while + "known" or "registered" users are assigned to unrestricted subnets. + +- To allow DHCP response options or vendor option values to be + customized based on user identity. + +- To provide a real-time record of user registration activity, which + can be sampled by an external consumer. + +- To serve as a demonstration of various capabilities possible using + the hooks interface. + +.. note:: + + :ischooklib:`libdhcp_user_chk.so` is part of the open source code and is + available to every Kea user. + +Once loaded, the library allows the separation of incoming requests into known +and unknown clients. For known clients, packets are processed +as usual, although it is possible to override the sending of certain options +on a per-host basis. Clients that are not on the known +hosts list are treated as unknown and are assigned to the last +subnet defined in the configuration file. + +As an example of a use case, this behavior may be implemented to put unknown users +into a separate subnet that leads to a "walled garden," where they can +only access a registration portal. Once they fill in necessary data, +their details are added to the known clients file and they get a proper +address after their device is restarted. + +.. note:: + + This library was developed several years before the host reservation + mechanism became available. Host reservation is much + more powerful and flexible, but the ability of ``user_chk`` + to consult an external source of information about clients and alter + Kea's behavior remains useful and of educational value. + +The library reads the ``/tmp/user_chk_registry.txt`` file while being loaded +and each time an incoming packet is processed. Each line of the file is expected to +contain a self-contained JSON snippet which must have the +following two entries: + +- ``type`` - whose value is ``"HW_ADDR"`` for IPv4 users or ``"DUID"`` for IPv6 + users. + +- ``id`` - whose value is either the hardware address or the DUID from + the request formatted as a string of hex digits, with or without ":" + delimiters. + +and may have zero or more of the following entries: + +- ``bootfile`` - whose value is the pathname of the desired file. + +- ``tftp_server`` - whose value is the hostname or IP address of the + desired server. + +A sample user registry file is shown below: + +:: + + { "type" : "HW_ADDR", "id" : "0c:0e:0a:01:ff:04", "bootfile" : "/tmp/v4bootfile" } + { "type" : "HW_ADDR", "id" : "0c:0e:0a:01:ff:06", "tftp_server" : "tftp.v4.example.com" } + { "type" : "DUID", "id" : "00:01:00:01:19:ef:e6:3b:00:0c:01:02:03:04", "bootfile" : "/tmp/v6bootfile" } + { "type" : "DUID", "id" : "00:01:00:01:19:ef:e6:3b:00:0c:01:02:03:06", "tftp_server" : "tftp.v6.example.com" } + +As with any other hook libraries provided by ISC, internals of the +``user_chk`` code are well-documented. Users may refer to the `user_chk +library section of the Kea Developer's Guide +<https://reports.kea.isc.org/dev_guide/d8/db2/libdhcp_user_chk.html>`__ +for information on how the code works internally. That, together with the +`Hooks Framework section of the Kea Developer's Guide +<https://reports.kea.isc.org/dev_guide/index.html#hooksFramework>`__ should give users +some pointers on how to extend this library and perhaps even write one +from scratch. diff --git a/doc/sphinx/arm/hooks.rst b/doc/sphinx/arm/hooks.rst new file mode 100644 index 0000000..73a26b9 --- /dev/null +++ b/doc/sphinx/arm/hooks.rst @@ -0,0 +1,626 @@ +.. _hooks-libraries: + +************** +Hook Libraries +************** + +.. _hooks-libraries-introduction: + +Introduction +============ + +Kea is both flexible and customizable, via the use of "hooks." This feature +lets Kea load one or more +dynamically linked libraries (known as "hook libraries") and call functions +in them at various points in its processing ("hook points"). +Those functions perform whatever custom processing is required. + +The hooks concept allows the core Kea code to remain reasonably small +by moving features that only some, but not all, users find useful to +external libraries. Those with no need for certain functions can simply choose not +to load those libraries. + +Hook libraries are loaded by individual Kea processes, not by Kea as a +whole. This means, among other things, that it is possible to associate one set +of libraries with the DHCPv4 server and a different set with the DHCPv6 +server. + +It is also possible for a process to load +multiple libraries. When processing reaches a hook point, Kea calls the +hook library functions attached to it. If multiple libraries have +attached a function to a given hook point, Kea calls all of them, in the +order in which the libraries are specified in the configuration file. +The order may be important; consult the documentation of the libraries +for specifics. + +When a Kea process unloads a library, it expects the ``dlclose`` function +to remove all library symbols, as well as the library code, from address space. +Although most OSes implement the ``dlclose`` function, this behavior is not +required by the POSIX standard and not all systems support it; for example, the musl +library, used by default by Alpine Linux, implements the ``dlclose`` function +as a no operation. On such systems a library actually remains loaded for the +lifetime of the process, which means that it must be restarted +to update libraries with newer versions; it is not sufficient to simply +reconfigure or reload the Kea process. + +The next sections describe how to install and configure hook libraries. Users who are +interested in writing their own hook library can find information +in the `Hooks Developer's Guide section of the Kea Developer's +Guide <https://reports.kea.isc.org/dev_guide/df/d46/hooksdgDevelopersGuide.html>`__. + +Note that some libraries are available under different licenses. + +Please also note that some libraries may require additional dependencies and/or +compilation switches to be enabled. + + +Installing Hook Packages +======================== + +.. note:: + + For more details about installing the Kea Premium Hooks package, please read + `this Knowledgebase article <https://kb.isc.org/docs/aa-01587>`__. + +Some hook packages are included in the base Kea sources. There is no +need to do anything special to compile or install them, as they are covered +by the usual building and installation procedures. Please +refer to :ref:`installation` for a general overview of the installation process. + +ISC provides several additional premium hooks in the form of packages, which +follow a similar installation procedure but with several additional steps. +For our users' convenience, the premium hooks installation procedure is described in this section. + +1. Download the package; detailed instructions are provided in the KB article +above. The package will be a file with a name similar to +``kea-premium-|release|.tar.gz``. (The name may vary depending on the package +purchased.) + +2. Administrators who have the sources for the corresponding version of the +open-source Kea package on their system from the initial Kea installation +should skip this step. Otherwise, extract the Kea source from the original +tarball that was downloaded. For example, with a download of Kea |release|, +there should be a tarball called ``kea-|release|.tar.gz`` on the system. +Unpack this tarball: + +.. parsed-literal:: + + $ tar -zxvf kea-|release|.tar.gz + +This will unpack the tarball into the ``kea-|release|`` subdirectory of +the current working directory. + +3. Unpack the Kea premium hooks tarball into the same directory where the +original Kea source is located. Once Kea |release| has been unpacked into a ``kea-|release|`` +subdirectory and the Kea premium tarball is in the current directory, the following +steps will unpack the premium tarball into the correct location: + +.. parsed-literal:: + + $ cd kea-|release| + $ tar -xvf ../kea-premium-|release|.tar.gz + +Note that unpacking the Kea premium package puts the files into a +directory named ``premium``. Regardless of the name of the package, the +directory is always called ``premium``, although its contents will vary +depending on the hooks package. + +4. Run the ``autoreconf`` tools. This step is necessary to update Kea's build +script to include the additional directory. If this tool is not already +available on the system, install the ``automake`` and ``autoconf`` +tools. To generate the configure script, please use: + +:: + + $ autoreconf -i + +5. Rerun ``configure``, using the same configuration options that were used when +originally building Kea. It is possible to verify that ``configure`` has detected the +premium package by inspecting the summary printed when it exits. The +first section of the output should look something like this: + +.. parsed-literal:: + + Package: + Name: kea + Version: |release| + Extended version: |release| (tarball) + OS Family: Linux + Using GNU sed: yes + Premium package: yes + Included Hooks: forensic_log flex_id host_cmds + +The last line indicates which specific hooks were detected. Note that +some hooks may require their own dedicated switches. +Please consult later sections of this chapter for details. + +6. Rebuild Kea. + +:: + + $ make + +If the machine has multiple CPU cores, an interesting option to consider +here is using the argument ``-j X``, where ``X`` is the number of available cores. + +7. Install Kea sources along with the hooks: + +:: + + $ sudo make install + +Note that as part of the installation procedure, the install script +places additional hook libraries and associated files into the ``premium/`` directory. + +The installation location of the hook libraries depends on whether the +``--prefix`` parameter was specified in the ``configure`` script. If not, +the default location is ``/usr/local/lib/kea/hooks``. The proper installation +of the libraries can be verified with this command: + +:: + + $ ls -l /usr/local/lib/kea/hooks/*.so + /usr/local/lib/kea/hooks/libdhcp_class_cmds.so + /usr/local/lib/kea/hooks/libdhcp_flex_id.so + /usr/local/lib/kea/hooks/libdhcp_flex_option.so + /usr/local/lib/kea/hooks/libdhcp_host_cmds.so + /usr/local/lib/kea/hooks/libdhcp_lease_cmds.so + /usr/local/lib/kea/hooks/libdhcp_legal_log.so + /usr/local/lib/kea/hooks/libdhcp_subnet_cmds.so + +The exact list returned depends on the packages installed. If the +directory was specified via ``--prefix``, the hook libraries will be located in +``{prefix directory}/lib/kea/hooks``. + +Configuring Hook Libraries +=========================== + +The hook libraries for a given process are configured using the +``hooks-libraries`` keyword in the configuration for that process. (Note +that the word "hooks" is plural.) The value of the keyword is an array +of map structures, with each structure corresponding to a hook library. For +example, to set up two hook libraries for the DHCPv4 server, the +configuration would be: + +:: + + "Dhcp4": { + : + "hooks-libraries": [ + { + "library": "/opt/first_custom_hooks_example.so" + }, + { + "library": "/opt/local/second_custom_hooks_example.so", + "parameters": { + "mail": "spam@example.com", + "floor": 13, + "debug": false, + "users": [ "alice", "bob", "charlie" ], + "languages": { + "french": "bonjour", + "klingon": "yl'el" + } + } + } + ] + : + } + +.. note:: + + Libraries are reloaded even if their lists have not changed, + because the parameters specified for the library (or the files those + parameters point to) may have changed. + +Libraries may have additional parameters that are not mandatory, in the +sense that there may be libraries that do not require them. However, for any +given library there is often a requirement to specify a certain +set of parameters. Please consult the documentation for each individual library for +details. In the example above, the first library (``/opt/first_custom_hooks_example.so``) +has no parameters. The second library (``/opt/local/second_custom_hooks_example.so``) +has five parameters: specifying mail (string parameter), floor (integer parameter), +debug (boolean parameter), lists (list of strings), and maps (containing strings). +Nested parameters can be used if the library supports it. This topic is explained in detail +in the `Hooks Developer's Guide section of the Kea Developer's Guide +<https://reports.kea.isc.org/dev_guide/df/d46/hooksdgDevelopersGuide.html>`__. + +Some hooks use user context to set the parameters. See :ref:`user-context-hooks`. + +Notes: + +- The full path to each library should be given. + +- As noted above, the order in which the hooks are called may be important; + consult the documentation for each library for specifics. + +- An empty list has the same effect as omitting the ``hooks-libraries`` + configuration element altogether. + + .. note:: + + There is one case where this is not true: if Kea is running with a + configuration that contains a ``hooks-libraries`` item, and that + item is removed and the configuration reloaded, the removal will + be ignored and the libraries remain loaded. As a workaround, + instead of removing the ``hooks-libraries`` item, change it to an + empty list. + +At the moment, only the :iscman:`kea-dhcp4` and :iscman:`kea-dhcp6` processes support +hook libraries. + +.. _order-of-configuration-hooks: + +Order of Configuration: +~~~~~~~~~~~~~~~~~~~~~~~ + +It is important to recognize that the order in which hook libraries are +configured determines the order in which their callouts will be executed, +in cases where more than one hook library implements the same callout. For +example, if you wish to use the flex-id hook library to formulate the client +IDs in conjunction with HA hook library for load-balanced HA, it is essential +that the flex-id library be specified first in your server's ``hooks-libraries`` +section. This ensures that the client ID is formulated by the flex-id library +before the HA library uses it for load-balancing. Similarly it would be best to +specify forensic logging last, to ensure any other install hooks have made +their contributions to the packet processing. + +.. _user-context-hooks: + +User Contexts in Hooks +~~~~~~~~~~~~~~~~~~~~~~ + +Hook libraries can have their own configuration parameters, which is +convenient if the parameter applies to the whole library. However, +sometimes it is useful to extend certain configuration entities +with additional configuration data. This is where the concept +of user contexts comes in. A system administrator can define an arbitrary set of +data and attach it to Kea structures, as long as the data is specified +as a JSON map. In particular, it is possible to define fields that are +integers, strings, boolean, lists, or maps. It is possible to define +nested structures of arbitrary complexity. Kea does not use that data on +its own; it simply stores it and makes it available for the hook libraries. + +Another use case for user contexts may be storing comments and other +information that will be retained by Kea. Regular comments are discarded +when the configuration is loaded, but user contexts are retained. This is +useful if administrators want their comments to survive :isccmd:`config-set` or :isccmd:`config-get` +operations, for example. + +If user context is supported in a given context, the parser translates +"comment" entries into user context with a "comment" entry. + +User context can store configuration for multiple hooks and comments at once. + +Some hooks use user context for a configuration that can be easily edited +without the need to restart the server. + +The DDNS-Tuning Hook uses user-context to configure per subnet behavior. Example: + +:: + + "subnet4": [{ + "id": 1, + "subnet": "192.0.2.0/24", + "pools": [{ + "pool": "192.0.2.10 - 192.0.2.20" + } ], + "user-context": { + "ddns-tuning": { + "hostname-expr": "'guest-'+int8totext(substring(pkt4.yiaddr, 0,1))+'-' \ + +int8totext(substring(pkt4.yiaddr, 1,2))+'-' \ + +int8totext(substring(pkt4.yiaddr, 2,3))+'-' \ + +int8totext(substring(pkt4.yiaddr, 3,4))" + }, + "last-modified": "2017-09-04 13:32", + "phones": [ "x1234", "x2345" ], + "devices-registered": 42, + "billing": false + } + }] + + +The Limits hook uses user-context in classes and subnets to set parameters. For example: + +.. code-block:: json + + { + "Dhcp6": { + "client-classes": [ + { + "name": "gold", + "user-context": { + "limits": { + "address-limit": 2, + "prefix-limit": 1, + "rate-limit": "1000 packets per second" + } + } + } + ], + "hooks-libraries": [ + { + "library": "/usr/local/lib/libdhcp_limits.so" + } + ], + "subnet6": [ + { + "id": 1, + "pools": [ + { + "pool": "2001:db8::/64" + } + ], + "subnet": "2001:db8::/64", + "user-context": { + "limits": { + "address-limit": 4, + "prefix-limit": 2, + "rate-limit": "10 packets per minute" + } + } + } + ] + } + } + +Available Hook Libraries +======================== + +As described above, the hook functionality provides a way to customize +a Kea server without modifying the core code. ISC has chosen to take +advantage of this feature to provide functions that may only be useful +to a subset of Kea users. To this end, ISC has created some hook +libraries, discussed in the following sections. + +.. note:: + + Some of these libraries are available with the base code, while others are + premium libraries available for purchase, or only shared with organizations + who contribute to Kea's development through paid ISC support contracts. Paid support + includes professional engineering assistance, advance security notifications, input + into ISC's roadmap planning, and many other benefits, while helping + keep Kea sustainable in the long term. ISC encourages companies and organizations + to consider purchasing a paid support contract; further information can be + obtained by completing the form at https://www.isc.org/contact. + +The following table provides a list of hook libraries currently available +from ISC. It is important to pay attention to which libraries may be +loaded by which Kea processes. It is a common mistake to configure the +:iscman:`kea-ctrl-agent` process to load libraries that should, in fact, be +loaded by the :iscman:`kea-dhcp4` or :iscman:`kea-dhcp6` processes. If a library +from ISC does not work as expected, please make sure that it has been +loaded by the correct process per the table below. + +.. tabularcolumns:: |p{0.1\linewidth}|p{0.1\linewidth}|p{0.8\linewidth}| + +.. table:: List of available hook libraries + :class: longtable + :widths: 10 10 80 + + +-----------------------------------------------------------+--------------+--------------------------------------------------------------+ + | Name | Availability | Description | + +===========================================================+==============+==============================================================+ + | :ref:`BOOTP <hooks-bootp>` | Kea open | This hook library adds BOOTP support, as defined in | + | | source | RFC 1497. It recognizes received BOOTP requests: | + | | | they are translated into DHCPREQUEST packets, put into the | + | | | BOOTP client class, and receive infinite lifetime leases. | + +-----------------------------------------------------------+--------------+--------------------------------------------------------------+ + | :ref:`Class Commands <hooks-class-cmds>` | ISC support | This hook library allows configured DHCP client classes to | + | | customers | be added, updated, deleted, and fetched without | + | | | needing to restart the DHCP server. | + +-----------------------------------------------------------+--------------+--------------------------------------------------------------+ + | :ref:`Configuration Backend Commands <hooks-cb-cmds>` | ISC support | This hook | + | | customers | library implements a collection of commands to manage | + | | | Kea configuration information in a | + | | | database. This library may only be used in conjunction with | + | | | one of the supported Configuration Backend implementations. | + +-----------------------------------------------------------+--------------+--------------------------------------------------------------+ + | :ref:`DDNS Tuning <hooks-ddns-tuning>` | ISC premium | This hook library adds custom behaviors related to Dynamic | + | | library | DNS updates on a per-client basis. Its primary feature is to | + | | | allow the host name used for DNS to be | + | | | calculated using an expression. | + +-----------------------------------------------------------+--------------+--------------------------------------------------------------+ + | :ref:`Flexible Identifier <hooks-flex-id>` | ISC premium | Kea software provides a way to handle host reservations that | + | | library | include addresses, prefixes, options, client classes and | + | | | other features. The reservation can be based on hardware | + | | | address, DUID, circuit-id, or client-id in DHCPv4 and on | + | | | hardware address or DUID in DHCPv6. However, there are | + | | | sometimes scenarios where the reservation is more complex, | + | | | e.g. uses other options than mentioned above, uses parts of | + | | | specific options, or perhaps uses a combination of several | + | | | options and fields to uniquely identify a client. Those | + | | | scenarios are addressed by the Flexible Identifier hook | + | | | application. It allows defining an expression, similar to | + | | | the one used in client classification, | + | | | e.g. ``substring(relay6[0].option[37],0,6)``. Each incoming | + | | | packet is evaluated against that expression and its value is | + | | | then searched in the reservations database. | + +-----------------------------------------------------------+--------------+--------------------------------------------------------------+ + | :ref:`Flexible Option <hooks-flex-option>` | Kea open | This library provides hooks that compute option values | + | | source | instead of static configured values. An expression is | + | | | evaluated on the query packet. Defined add, supersede, and | + | | | remove actions are applied on the response packet before | + | | | it is sent using the evaluation result. | + +-----------------------------------------------------------+--------------+--------------------------------------------------------------+ + | :ref:`Forensic Logging <hooks-legal-log>` | ISC premium | This library provides hooks that record a detailed log of | + | | library | lease assignments and renewals in a set of log files. In | + | | | many legal jurisdictions, companies - especially ISPs - must | + | | | record information about the addresses they have leased to | + | | | DHCP clients. This library is designed to help with that | + | | | requirement. If the information that it records is | + | | | sufficient, it may be used directly. If a jurisdiction | + | | | requires a different set of information to be saved, it can | + | | | be used as a template or example to create | + | | | custom logging hooks. In Kea 1.9.8, additional parameters | + | | | were added to give users more flexibility regarding | + | | | what information should be logged. | + +-----------------------------------------------------------+--------------+--------------------------------------------------------------+ + | :ref:`GSS-TSIG <hooks-gss-tsig>` | ISC support | This hook library adds support to the Kea D2 server | + | | customers | (kea-dhcp-ddns) for using GSS-TSIG to sign DNS updates. | + +-----------------------------------------------------------+--------------+--------------------------------------------------------------+ + | :ref:`High Availability <hooks-high-availability>` | Kea open | The risk of DHCP service unavailability can be minimized | + | | source | by setting up a pair of DHCP servers in a network. Two | + | | | modes of operation are supported. The first one is called | + | | | load-balancing, and is sometimes referred to as | + | | | "active-active." Each server can handle selected groups of | + | | | clients in this network, or all clients if it detects that | + | | | its partner has become unavailable. It is also possible to | + | | | designate one server to serve all DHCP clients, and leave | + | | | another server as standby. This mode is called "hot standby" | + | | | and is sometimes referred to as "active-passive." This | + | | | server activates its DHCP function only when it detects that | + | | | its partner is not available. Such cooperation between the | + | | | DHCP servers requires that these servers constantly | + | | | communicate with each other to send updates about allocated | + | | | leases, and to periodically test whether their partners are | + | | | still operational. The hook library also provides an ability | + | | | to send lease updates to external backup servers, making it | + | | | much easier to have a replacement that is up to date. | + +-----------------------------------------------------------+--------------+--------------------------------------------------------------+ + | :ref:`Host Cache <hooks-host-cache>` | ISC support | Some database backends, such as RADIUS, | + | | customers | may take a long time to respond. Since | + | | | Kea in general is synchronous, backend performance | + | | | directly affects DHCP performance. To minimize | + | | | performance impact, this library | + | | | provides a way to cache responses from other hosts. This | + | | | includes negative caching, i.e. the ability to remember that | + | | | there is no client information in the database. | + +-----------------------------------------------------------+--------------+--------------------------------------------------------------+ + | :ref:`Host Commands <hooks-host-cmds>` | ISC premium | Kea provides a way to store host reservations in a | + | | library | database. In many larger deployments it is useful to be able | + | | | to manage that information while the server is running. This | + | | | library provides management commands for adding, querying, | + | | | and deleting host reservations in a safe way without | + | | | restarting the server. In particular, it validates the | + | | | parameters, so an attempt to insert incorrect data, e.g. add | + | | | a host with conflicting identifier in the same subnet, is | + | | | rejected. Those commands are exposed via the command channel | + | | | (JSON over UNIX sockets) and the Control Agent (JSON over | + | | | RESTful interface). | + +-----------------------------------------------------------+--------------+--------------------------------------------------------------+ + | :ref:`Lease Commands <hooks-lease-cmds>` | Kea open | This hook library offers a number of commands used to | + | | source | manage leases. Kea can store lease information in various | + | | | backends: memfile, MySQL, PostgreSQL. This library provides | + | | | a unified interface to manipulate leases in an unified, safe | + | | | way. In particular, it allows manipulation of memfile leases | + | | | while Kea is running, sanity check changes, lease existence | + | | | checks, and removal of all leases belonging to a specific | + | | | subnet. It can also catch obscure errors, like the addition | + | | | of a lease with subnet-id that does not exist in the | + | | | configuration, or configuration of a lease to use an address | + | | | that is outside of the subnet to which it is supposed to | + | | | belong. This library allows easy management of user contexts | + | | | associated with leases. | + +-----------------------------------------------------------+--------------+--------------------------------------------------------------+ + | :ref:`Leasequery <hooks-lease-query>` | ISC support | This library adds support for DHCPv4 | + | | customers | Leasequery as described in RFC 4388; and for DHCPv6 | + | | | Leasequery as described in RFC 5007. | + +-----------------------------------------------------------+--------------+--------------------------------------------------------------+ + | :ref:`Limits <hooks-limits>` | ISC support | With this hook library, :iscman:`kea-dhcp4` and | + | | customers | :iscman:`kea-dhcp6` servers can apply a limit to the rate at | + | | | which packets receive a response. The limit can be applied | + | | | per-client class or per-subnet. | + +-----------------------------------------------------------+--------------+--------------------------------------------------------------+ + | :ref:`MySQL Configuration Backend <hooks-cb-mysql>` | Kea open | This hook library is an implementation of the Kea | + | | source | Configuration Backend for MySQL. It uses a MySQL database as | + | | | a repository for the Kea configuration information. Kea | + | | | servers use this library to fetch their configurations. | + +-----------------------------------------------------------+--------------+--------------------------------------------------------------+ + | :ref:`PerfMon <hooks-perfmon>` | Kea open | With this hook library, :iscman:`kea-dhcp4` server and | + | | source | :iscman:`kea-dhcp6` servers can track and report performance | + | | | data. CURRENTLY UNDER DEVELOPMENT | + +-----------------------------------------------------------+--------------+--------------------------------------------------------------+ + | :ref:`Ping Check <hooks-ping-check>` | ISC support | With this hook library, :iscman:`kea-dhcp4` server can | + | | customers | perform ping checks of candidate lease addresses before | + | | | offering them to clients. | + +-----------------------------------------------------------+--------------+--------------------------------------------------------------+ + | :ref:`PostgreSQL Configuration Backend <hooks-cb-pgsql>` | Kea open | This hook library is an implementation of the Kea | + | | source | Configuration Backend for PostgreSQL. It uses a PostgreSQL | + | | | database as a repository for the Kea configuration | + | | | information. Kea servers use this library to fetch their | + | | | configurations. | + +-----------------------------------------------------------+--------------+--------------------------------------------------------------+ + | :ref:`RADIUS <hooks-radius>` | ISC support | The RADIUS hook library allows Kea to interact with | + | | customers | RADIUS servers using access and accounting mechanisms. The | + | | | access mechanism may be used for access control, assigning | + | | | specific IPv4 or IPv6 addresses reserved by RADIUS, | + | | | dynamically assigning addresses from designated pools chosen | + | | | by RADIUS, or rejecting the client's messages altogether. | + | | | The accounting mechanism allows a RADIUS server to keep | + | | | track of device activity over time. | + +-----------------------------------------------------------+--------------+--------------------------------------------------------------+ + | :ref:`RBAC <hooks-rbac>` | ISC support | This hook library adds support to the Kea Control Agent | + | | customers | (kea-ctrl-agent) for Role-Based Access Control filtering | + | | | of commands. | + +-----------------------------------------------------------+--------------+--------------------------------------------------------------+ + | :ref:`Run Script <hooks-run-script>` | Kea open | This hook library adds support to run external | + | | source | scripts for specific packet-processing hook points. There | + | | | are several exported environment variables available for | + | | | the script. | + +-----------------------------------------------------------+--------------+--------------------------------------------------------------+ + | :ref:`Statistics Commands <hooks-stat-cmds>` | Kea open | This library provides additional | + | | source | commands for retrieving accurate DHCP lease statistics, for | + | | | Kea DHCP servers that share the same lease database. This | + | | | setup is common in deployments where DHCP service redundancy | + | | | is required and a shared lease database is used to avoid | + | | | lease-data replication between the DHCP servers. | + | | | This hook library returns lease statistics | + | | | for each subnet. | + +-----------------------------------------------------------+--------------+--------------------------------------------------------------+ + | :ref:`Subnet Commands <hooks-subnet-cmds>` | ISC support | In deployments in which subnet configuration needs to be | + | | customers | frequently updated, it is a hard requirement that such | + | | | updates be performed without the need for a full DHCP server | + | | | reconfiguration or restart. This hook library allows for | + | | | incremental changes to the subnet configuration such as | + | | | adding or removing a subnet. It also allows for | + | | | listing all available subnets and fetching detailed | + | | | information about a selected subnet. The commands exposed by | + | | | this library do not affect other subnets or configuration | + | | | parameters currently used by the server. | + +-----------------------------------------------------------+--------------+--------------------------------------------------------------+ + | :ref:`User Check <hooks-user-chk>` | Kea open | Reads known users list from a file. Unknown users will be | + | | source | assigned a lease from the last subnet defined in the | + | | | configuration file, e.g. to redirect them to a captive | + | | | portal. This demonstrates how an external source of | + | | | information can be used to influence the Kea allocation | + | | | engine. This hook is part of the Kea source code and is | + | | | available in the ``src/hooks/dhcp/user_chk`` directory. | + +-----------------------------------------------------------+--------------+--------------------------------------------------------------+ + +ISC hopes to see more hook libraries become available as time +progresses, developed both internally and externally. Since this list +may evolve dynamically, it is maintained on a wiki page, available +at https://gitlab.isc.org/isc-projects/kea/wikis/Hooks-available. +Developers or others who are aware of any hook libraries not listed there +are asked to please send a note to the kea-users or kea-dev mailing lists for +updating. (Information on all of ISC's public mailing lists can be found +at https://www.isc.org/mailinglists/.) + +The libraries developed by ISC are described in detail in the following +sections. + +.. include:: hooks-bootp.rst +.. include:: hooks-cb-cmds.rst +.. include:: hooks-class-cmds.rst +.. include:: hooks-ddns-tuning.rst +.. include:: hooks-flex-id.rst +.. include:: hooks-flex-option.rst +.. include:: hooks-gss-tsig.rst +.. include:: hooks-ha.rst +.. include:: hooks-host-cache.rst +.. include:: hooks-host-cmds.rst +.. include:: hooks-lease-cmds.rst +.. include:: hooks-lease-query.rst +.. include:: hooks-legal-log.rst +.. include:: hooks-limits.rst +.. include:: hooks-cb-mysql.rst +.. include:: hooks-perfmon.rst +.. include:: hooks-ping-check.rst +.. include:: hooks-cb-pgsql.rst +.. include:: hooks-radius.rst +.. include:: hooks-rbac.rst +.. include:: hooks-run-script.rst +.. include:: hooks-stat-cmds.rst +.. include:: hooks-subnet-cmds.rst +.. include:: hooks-user-chk.rst diff --git a/doc/sphinx/arm/install.rst b/doc/sphinx/arm/install.rst new file mode 100644 index 0000000..c9b24ea --- /dev/null +++ b/doc/sphinx/arm/install.rst @@ -0,0 +1,633 @@ +.. _installation: + +************ +Installation +************ + +Packages +======== + +ISC publishes native RPM, deb, and APK packages, along with the tarballs +with the source code. The packages are available on +`Cloudsmith <https://cloudsmith.io/~isc/repos/>`_ at +https://cloudsmith.io/~isc/repos. The native packages can be downloaded +and installed using the system available in a specific distribution (such +as dpkg or rpm). The Kea repository can also be added to the system, +making it easier to install updates. For details, please +go to https://cloudsmith.io/~isc/repos, choose the repository of +interest, and then click the ``Set Me Up`` button. For detailed +instructions or refer to ISC `KB article <https://kb.isc.org/docs/isc-kea-packages>`_. + +Installation From Cloudsmith Packages +------------------------------------- +ISC provides Kea packages for Alpine, Debian, Fedora, RHEL, and Ubuntu. +The recommended method for installing Kea on any of these systems, from the +Cloudsmith repository for Kea release 2.3.1 or later, is to install the ``isc-kea`` +metapackage. This metapackage is included on all supported distros and +installs all of the services offered by the Kea software suite. + +Specific Kea components +can be installed individually, with any of the following packages: + +- ``isc-kea-dhcp4`` — Kea DHCPv4 server package + +- ``isc-kea-dhcp6`` — Kea DHCPv6 server package + +- ``isc-kea-dhcp-ddns`` — Kea DHCP DDNS server + +- ``isc-kea-ctrl-agent`` — Kea Control Agent for remote configuration + +- ``isc-kea-admin`` — Kea database administration tools + +- ``isc-kea-hooks`` — Kea open source DHCP hooks + +Kea Premium hook packages are not included in the ``isc-kea-hooks`` package. +For ISC customers with access to the premium hooks, those packages have the +``isc-kea-premium-`` prefix. + +Once installed, the services can be managed through the distribution's +service manager. The services are named: :iscman:`kea-dhcp4`, :iscman:`kea-dhcp6`, +:iscman:`kea-dhcp-ddns`, and :iscman:`kea-ctrl-agent`. + +.. note:: + The real service names on Debian and Ubuntu follow the names of the older + packages, to maintain compatibility with pre-existing scripts. A + systemd service alias is used to allow users to refer to them with shorter + names. Calling ``systemctl enable`` on these services requires + the real service names, which are: ``isc-kea-dhcp4-server``, + ``isc-kea-dhcp6-server``, ``isc-kea-dhcp-ddns-server``, and + ``isc-kea-ctrl-agent``. + +Caveats When Upgrading Kea Packages +----------------------------------- + +To upgrade to Kea 2.3.2 or later from an earlier version of Kea on Debian +and Ubuntu systems, run ``apt dist-upgrade`` instead of the usual ``apt upgrade``. +Once this upgrade has been completed, it is possible to upgrade to later versions +normally using ``apt upgrade`` on Debian and Ubuntu systems. + +Users may notice differences in the packages distributed in Kea versions prior to +2.3.2 and those distributed with 2.3.2 and later. As a result of an overhaul of our +package design with that release, some packages were renamed or removed. +To ensure that upgrades go as smoothly as possible, pay attention to +which packages are being removed and installed by the upgrade transaction, +and ensure that all required packages are reinstalled. + +Specifically, there is a possibility for the following packages to be removed +during the upgrade, depending on which packages were originally installed: + +- ``isc-kea-dhcp4`` + +- ``isc-kea-dhcp6`` + +- ``isc-kea-dhcp-ddns`` + +- ``isc-kea-hooks`` + +To install the entire Kea software suite, simply run +``apt install isc-kea`` after upgrading, which +will install all of the relevant subpackages that make up Kea. + +This upgrade path issue does not apply to RPM and Alpine systems; however, +customers with ISC support contracts who experience difficulties with upgrading +past 2.3.1 are invited to open a ticket in their support queue. Other users +are encouraged to describe their situation on the kea-users mailing list for +best-effort support from other list members. + +.. _install-hierarchy: + +Installation Hierarchy +====================== + +The following is the directory layout of the complete Kea installation. +(All directory paths are relative to the installation directory.) + +- ``etc/kea/`` — configuration files. + +- ``include/`` — C++ development header files. + +- ``lib/`` — libraries. + +- ``lib/kea/hooks`` — additional hook libraries. + +- ``sbin/`` — server software and commands used by the system administrator. + +- ``share/doc/kea/`` — this guide, other supplementary documentation, and examples. + +- ``share/kea/`` — API command examples and database schema scripts. + +- ``share/man/`` — manual pages (online documentation). + +- ``var/lib/kea/`` — server identification and lease database files. + +- ``var/log/`` - log files. + +- ``var/run/kea`` - PID file and logger lock file. + +.. _build-requirements: + +Build Requirements +================== + +In addition to the runtime requirements (listed in +:ref:`required-software`), building Kea from source code requires +various development include headers and program development tools. + +.. note:: + + Some operating systems have split their distribution packages into a + runtime and a development package. The + development package versions, which include header files and + libraries, must be installed to build Kea from the source code. + +Building from source code requires the following software installed on +the system: + +- Boost C++ libraries (https://www.boost.org/). The oldest Boost version + used for testing is 1.57 (although Kea may also work with older + versions). The Boost system library must also be installed. + Installing a header-only version of Boost is not recommended. + +- OpenSSL (at least version 1.0.2) or Botan (at least version 2). + OpenSSL version 1.1.1 or later is strongly recommended. + +- log4cplus (at least version 1.0.3) development include headers. + +- A C++ compiler (with C++14 support) and standard development headers. + +- The development tools automake, libtool, and pkg-config. + +- The MySQL client and the client development libraries, when using the + ``--with-mysql`` configuration flag to build the Kea MySQL database + backend. In this case, an instance of the MySQL server running locally + or on a machine reachable over a network is required. Note that running + the unit tests requires a local MySQL server. + +- The PostgreSQL client and the client development libraries, when using the + ``--with-pgsql`` configuration flag to build the Kea PostgreSQL database + backend. In this case an instance of the PostgreSQL server running locally + or on a machine reachable over a network is required. Note that running + the unit tests requires a local PostgreSQL server. + +- Sysrepo v1.4.140 and libyang v1.0.240 are needed to connect to a Sysrepo + datastore. Earlier versions are no longer supported. When compiling from + sources, the configure switches that can be used are ``--with-libyang`` and + ``--with-sysrepo`` without any parameters. If these dependencies were + installed in custom paths, point the switches to them. + +- The MIT Kerberos 5 or Heimdal libraries are needed by Kea DDNS server to sign + and verify DNS updates using GSS-TSIG. The configuration switch which enables + this functionality is ``--with-gssapi`` without any parameters. If these + dependencies were installed in custom paths, point the switch to them. + +- googletest (version 1.8 or later) is required when using the ``--with-gtest`` + configuration option to build the unit tests. + +- The documentation generation tools `Sphinx <https://www.sphinx-doc.org/>`_, + texlive with its extensions, and Doxygen, if using the + ``--enable-generate-docs`` configuration option to create the documentation. + Specifically, with Fedora, ``python3-sphinx``, ``python3-sphinx_rtd_theme``, + ``texlive``, and ``texlive-collection-latexextra`` are necessary. + With Ubuntu, ``python3-sphinx``, ``python3-sphinx-rtd-theme``, + ``texlive``, and ``texlive-latex-extra`` are needed. + If LaTeX packages are missing, Kea skips PDF generation and produces only + HTML documents. + +Visit ISC's Knowledgebase at https://kb.isc.org/docs/installing-kea for +system-specific installation tips. + +.. _install: + +Installation From Source +======================== + +Although Kea may be available in pre-compiled, ready-to-use packages +from operating system vendors, it is open source software written in +C++. As such, it is freely available in source code form from ISC as a +downloadable tar file. The source code can also be obtained from the Kea +GitLab repository at https://gitlab.isc.org/isc-projects/kea. This +section describes how to build Kea from the source code. + +Download Tar File +----------------- + +The Kea release tarballs may be downloaded from: +https://downloads.isc.org/isc/kea/. + +Retrieve From Git +----------------- + +The latest development code is available on GitLab (see +https://gitlab.isc.org/isc-projects/kea). The Kea source is public and +development is done in the “master” branch. + +Downloading this "bleeding edge" code is recommended only for developers +or advanced users. Using development code in a production environment is +not recommended. + +.. note:: + + When building from source code retrieved via git, additional software + is required: automake (v1.11 or later), libtoolize, and autoconf + (v2.69 or later). These may need to be installed. + +The code can be checked out from +``https://gitlab.isc.org/isc-projects/kea.git``: + +.. code-block:: console + + $ git clone https://gitlab.isc.org/isc-projects/kea.git + +The code checked out from the git repository does not include the +generated configure script or the Makefile.in files, nor their related build +files. They can be created by running ``autoreconf`` with the +``--install`` switch. This will run ``autoconf``, ``aclocal``, +``libtoolize``, ``autoheader``, ``automake``, and related commands. + +Write access to the Kea repository is only granted to ISC staff. +Developers planning to contribute to Kea should check our +`Contributor's +Guide <https://gitlab.isc.org/isc-projects/kea/blob/master/contributors-guide.md>`__. +The `Kea Developer's +Guide <https://reports.kea.isc.org/dev_guide/>`__ contains more +information about the process, and describes the requirements for +contributed code to be accepted by ISC. + +.. _configure: + +Configure Before the Build +-------------------------- + +Kea uses the GNU Build System to discover build environment details. To +generate the makefiles using the defaults, simply run: + +.. code-block:: console + + $ ./configure + +Run ``./configure`` with the ``--help`` switch to view the different +options. Some commonly used options are: + + - ``--prefix`` + Define the installation location (the default is ``/usr/local``). + + - ``--with-mysql`` + Build Kea with code to allow it to store leases and host reservations + in a MySQL database. + + - ``--with-pgsql`` + Build Kea with code to allow it to store leases and host reservations + in a PostgreSQL database. + + - ``--with-log4cplus`` + Define the path to find the Log4cplus headers and libraries. Normally + this is not necessary. + + - ``--with-boost-include`` + Define the path to find the Boost headers. Normally this is not + necessary. + + - ``--with-botan-config`` + Specify the path to the botan-config script to build with Botan for + cryptographic functions. It is preferable to use OpenSSL (see below). + + - ``--with-openssl`` + Use the OpenSSL cryptographic library instead of Botan. By default + ``configure`` searches for a valid Botan installation; if one is not + found, Kea searches for OpenSSL. Normally this is not necessary. + + - ``--enable-shell`` + Build the optional :iscman:`kea-shell` tool (more in :ref:`kea-shell`). + The default is to not build it. + + - ``--with-site-packages`` + Only useful when :iscman:`kea-shell` is enabled, this switch causes the kea-shell + Python packages to be installed in the specified directory. This is + mostly useful for Debian-related distributions. While most systems store + Python packages in ``${prefix}/usr/lib/pythonX/site-packages``, Debian + introduced a separate directory for packages installed from DEB. Such + Python packages are expected to be installed in + ``/usr/lib/python3/dist-packages``. + + - ``--enable-perfdhcp`` + Build the optional :iscman:`perfdhcp` DHCP benchmarking tool. The default + is to not build it. + +.. note:: + + For instructions concerning the installation and configuration of + database backends for Kea, see :ref:`dhcp-install-configure`. + +There are many options that are typically not necessary for +regular users. However, they may be useful for package maintainers, +developers, or people who want to extend Kea code or send patches: + + - ``--with-gtest``, ``--with-gtest-source`` + Enable the building of C++ unit tests using the Google Test + framework. This option specifies the path to the gtest source. (If + the framework is not installed on the system, it can be downloaded + from https://github.com/google/googletest.) + + - ``--enable-generate-docs`` + Enable the rebuilding of Kea documentation. ISC publishes Kea + documentation for each release; however, in some cases it may be + desirable to rebuild it: for example, to change something in the + docs, or to generate new ones from git sources that are not yet + released. + + - ``--enable-generate-parser`` + Enable the generation of parsers using flex or bison. Kea sources include + .cc and .h parser files, pre-generated for users' convenience. By + default Kea does not use flex or bison, to avoid + requiring installation of unnecessary dependencies for users. + However, if anything in the parsers is changed (such as adding a new + parameter), flex and bison are required to regenerate + parsers. This option permits that. + + - ``--enable-generate-messages`` + Enable the regeneration of messages files from their messages source + files, e.g. regenerate xxx_messages.h and xxx_messages.cc from + xxx_messages.mes using the Kea message compiler. By default Kea is + built using these .h and .cc files from the distribution. However, if + anything in a .mes file is changed (such as adding a new message), + the Kea message compiler needs to be built and used. This option + permits that. + +As an example, the following command configures Kea to find the Boost +headers in /usr/pkg/include, specifies that PostgreSQL support should be +enabled, and sets the installation location to /opt/kea: + +.. code-block:: console + + $ ./configure \ + --with-boost-include=/usr/pkg/include \ + --with-pgsql=/usr/local/bin/pg_config \ + --prefix=/opt/kea + +Users who have any problems with building Kea using the header-only Boost +code, or who would like to use the Boost system library (assumed for the +sake of this example to be located in /usr/pkg/lib), should issue these +commands: + +.. code-block:: console + + $ ./configure \ + --with-boost-libs=-lboost_system \ + --with-boost-lib-dir=/usr/pkg/lib + +If ``configure`` fails, it may be due to missing or old dependencies. + +When ``configure`` succeeds, it displays a report with the parameters used +to build the code. This report is saved into the file ``config.report`` +and is also embedded into the executable binaries, e.g., :iscman:`kea-dhcp4`. + +Build +----- + +After the configure step is complete, build the executables from the C++ +code and prepare the Python scripts by running the command: + +.. code-block:: console + + $ make + +Install +------- + +To install the Kea executables, support files, and documentation, issue +the command: + +.. code-block:: console + + $ make install + +Do not use any form of parallel or job server options (such as GNU +make's ``-j`` option) when performing this step; doing so may cause +errors. + +.. note:: + + The install step may require superuser privileges. + +If required, run ``ldconfig`` as root with ``/usr/local/lib`` (or with +prefix/lib if configured with ``--prefix``) in ``/etc/ld.so.conf`` (or the +relevant linker cache configuration file for the OS): + +.. code-block:: console + + $ ldconfig + +.. note:: + + If ``ldconfig`` is not run where required, users may see + errors like the following: + + :: + + program: error while loading shared libraries: libkea-something.so.1: + cannot open shared object file: No such file or directory + + +Cross-Building +-------------- + +It is possible to cross-build Kea, i.e. to create binaries in a separate +system (the ``build`` system) from the one where Kea runs +(the ``host`` system). + +It is outside of the scope of common administrator operations and requires +some developer skills, but the Developer Guide explains how to do that +using an x86_64 Linux system to build Kea for a Raspberry Pi box running +Raspbian: `Kea Cross-Compiling Example +<https://reports.kea.isc.org/dev_guide/de/d9a/crossCompile.html>`__. + +.. _dhcp-install-configure: + +DHCP Database Installation and Configuration +============================================ + +Kea stores its leases in a lease database. The software has been written +in a way that makes it possible to choose which database product should +be used to store the lease information. Kea supports three +database backends: MySQL, PostgreSQL and memfile. To limit external +dependencies, MySQL and PostgreSQL support are disabled by default and only +memfile is available. Support for the optional external database backend must +be explicitly included when Kea is built. +This section covers the building of Kea with one of the optional backends and +the creation of the lease database. + +.. note:: + + When unit tests are built with Kea (i.e. the ``--with-gtest`` configuration + option is specified), the databases must be manually pre-configured + for the unit tests to run. The details of this configuration can be + found in the `Kea Developer's + Guide <https://reports.kea.isc.org/dev_guide/>`__. + +Building with MySQL Support +--------------------------- + +Install MySQL according to the instructions for the system. The client +development libraries must be installed. + +Build and install Kea as described in :ref:`installation`, +with the following modification. To enable the MySQL database code, at the +"configure" step (see :ref:`configure`), the ``--with-mysql`` switch should be +specified: + +.. code-block:: console + + $ ./configure [other-options] --with-mysql + +If MySQL was not installed in the default location, the location of the +MySQL configuration program "mysql_config" should be included with the +switch: + +.. code-block:: console + + $ ./configure [other-options] --with-mysql=path-to-mysql_config + +See :ref:`mysql-database-create` for details regarding MySQL +database configuration. + +Building with PostgreSQL support +-------------------------------- + +Install PostgreSQL according to the instructions for the system. The +client development libraries must be installed. Client development +libraries are often packaged as "libpq". + +Build and install Kea as described in :ref:`installation`, +with the following modification. To enable the PostgreSQL database code, at the +"configure" step (see :ref:`configure`), the ``--with-pgsql`` switch should be +specified: + +.. code-block:: console + + $ ./configure [other-options] --with-pgsql + +If PostgreSQL was not installed in the default location, the location of +the PostgreSQL configuration program "pg_config" should be included with +the switch: + +.. code-block:: console + + $ ./configure [other-options] --with-pgsql=path-to-pg_config + +See :ref:`pgsql-database-create` for details regarding PostgreSQL +database configuration. + + + +.. include:: hammer.rst + +.. _non-root: + +Running Kea From a Non-root Account on Linux +============================================ + +Both Kea DHCPv4 and DHCPv6 servers perform operations that in general require root access +privileges. In particular, DHCPv4 opens raw sockets and both DHCPv4 and DHCPv6 open UDP sockets on +privileged ports. However, with some extra system configuration, it is possible to run Kea from +non-root accounts. + +First, a regular user account must be created: + +.. code-block:: console + + useradd admin + +Then, change the binaries' ownership and group to the new user. Note that +the specific path may be different. Please refer to the ``--prefix`` +parameter passed to the configure script: + +.. code-block:: console + + chown -R admin /opt/kea + chgrp -R admin /opt/kea + chown -R admin /var/log/kea-dhcp4.log + chgrp -R admin /var/log/kea-dhcp4.log + chown -R admin /var/log/kea-dhcp6.log + chgrp -R admin /var/log/kea-dhcp6.log + +If using systemd, modify its service file +(e.g. /etc/systemd/system/kea-dhcp6.service): + +.. code-block:: console + + User=admin + Group=admin + +The most important step is to set the capabilities of the binaries. Refer to `man capabilities` to get +more information. + +.. code-block:: console + + setcap 'cap_net_bind_service,cap_net_raw=+ep' /opt/kea/sbin/kea-dhcp4 + setcap 'cap_net_bind_service=+ep' /opt/kea/sbin/kea-dhcp6 + +If using systemd, also add this to the service file +(e.g. /etc/systemd/system/kea-dhcp6.service): + +.. code-block:: console + + ExecStartPre=setcap 'cap_net_bind_service=+ep' /opt/kea/sbin/kea-dhcp6 + +After this step is complete, the admin user should be able to run Kea. Note that the DHCPv4 server by +default opens raw sockets. If the network is only using relayed traffic, Kea can be instructed to +use regular UDP sockets (refer to ``dhcp-socket-type`` parameter in the +:ref:`dhcp4-interface-configuration` section) and the ``cap_net_raw`` capability can be skipped. + +.. note:: + + It is possible to avoid running Kea with root privileges by instructing Kea to + use non-privileged (greater than 1024) ports and redirecting traffic. This, however, only works + for relayed traffic. This approach in general is considered experimental and has not been tested + for deployment in production environments. Use with caution! + + To use this approach, configure the server to listen on other non-privileged ports (e.g. 1547 + and 1548) by running the process with the ``-p`` option in ``/etc/systemd/system/kea-dhcp4.service``: + +.. code-block:: console + + ExecStart=/opt/kea/sbin/kea-dhcp4 -d -c /etc/kea/kea-dhcp4.conf -p 2067 + +and ``/etc/systemd/system/kea-dhcp4.service``: + +.. code-block:: console + + ExecStart=/opt/kea/sbin/kea-dhcp6 -d -c /etc/kea/kea-dhcp6.conf -p 1547 + +Then configure port redirection with iptables and ip6tables for new ports (e.g. 1547 +and 1548). Be sure to replace ``ens4`` with the specific interface name. + +.. code-block:: console + + iptables -t nat -A PREROUTING -i ens4 -p udp --dport 67 -j REDIRECT --to-port 2067 + iptables -t nat -A PREROUTING -i ens4 -p udp --dport 2068 -j REDIRECT --to-port 68 + ip6tables -t nat -A PREROUTING -i ens4 -p udp --dport 547 -j REDIRECT --to-port 1547 + ip6tables -t nat -A PREROUTING -i ens4 -p udp --dport 1548 -j REDIRECT --to-port 548 + +.. _deprecated: + +Deprecated Features +=================== + +This section lists significant features that have been or will be removed. We try to +deprecate features before removing them to signal +to current users to plan a migration. New users should not rely on deprecated features. + +Sysrepo 0.x or 1.x +------------------ + +Kea 2.3.2 introduced support for Sysrepo 2.x. Unfortunately, +Sysrepo continues to undergo major changes that are backward-incompatible, +and Kea versions 2.3.2 do not support Sysrepo earlier than versions 2.x. + +:isccmd:`libreload` command +---------------------------------------- + +The :isccmd:`libreload` command was deprecated in Kea 2.3.4. The code to handle this command is +still there, but there are reports of it being buggy and not really usable. +Kea 2.3 and 2.4 versions will produce a warning when this command +is used, and it will be removed entirely sometime in the 2.5 branch. diff --git a/doc/sphinx/arm/integrations.rst b/doc/sphinx/arm/integrations.rst new file mode 100644 index 0000000..57f5734 --- /dev/null +++ b/doc/sphinx/arm/integrations.rst @@ -0,0 +1,11 @@ +********************************* +Integration With External Systems +********************************* + +Kea provides optional support for a variety of external systems, such as RADIUS, NETCONF, +YANG, and GSS-TSIG. The following sections describe how to compile Kea with those additional +capabilities and how to configure them. + +.. include:: ext-netconf.rst +.. include:: ext-gss-tsig.rst +.. include:: ext-radius.rst diff --git a/doc/sphinx/arm/intro.rst b/doc/sphinx/arm/intro.rst new file mode 100644 index 0000000..f5c82f5 --- /dev/null +++ b/doc/sphinx/arm/intro.rst @@ -0,0 +1,64 @@ +.. _intro: + +************ +Introduction +************ + +Kea is the next generation of DHCP software, developed by Internet Systems Consortium (ISC). It +supports both the DHCPv4 and DHCPv6 protocols along with their extensions, +e.g. prefix delegation and dynamic updates to DNS. + +This guide covers Kea version |release|. + +For information about supported platforms see :ref:`platforms`. + +.. include:: platforms.rst + +.. _kea_software: + +Kea Software +============ + +Kea is a modular DHCP server solution. This modularity is accomplished using multiple +cooperating processes which, together, provide the server functionality. +The following software is included with Kea: + +- :iscman:`keactrl` — This tool starts, stops, reconfigures, and reports the status of + the Kea servers. + +- :iscman:`kea-dhcp4` — The DHCPv4 server process. This process responds to + DHCPv4 queries from clients. + +- :iscman:`kea-dhcp6` — The DHCPv6 server process. This process responds to + DHCPv6 queries from clients. + +- :iscman:`kea-dhcp-ddns` — The DHCP Dynamic DNS process. This process acts + as an intermediary between the DHCP servers and external DNS servers. It + receives name update requests from the DHCP servers and sends DNS + update messages to the DNS servers. + +- :iscman:`kea-admin` — This is a useful tool for database backend maintenance + (creating a new database, checking versions, upgrading, etc.). + +- :iscman:`kea-lfc` — This process removes redundant information from the + files used to provide persistent storage for the memfile database + backend. While it can be run standalone, it is normally run as and + when required by the Kea DHCP servers. + +- :iscman:`kea-ctrl-agent` — The Kea Control Agent (CA) is a daemon that exposes + a RESTful control interface for managing Kea servers. + +- :iscman:`kea-netconf` - kea-netconf is an agent that provides a + YANG/NETCONF interface for configuring Kea. + +- :iscman:`kea-shell` — This simple text client uses the REST interface to + connect to the Kea Control Agent. + +- :iscman:`perfdhcp` — This is a DHCP benchmarking tool which simulates multiple + clients to test both DHCPv4 and DHCPv6 server performance. + +The tools and modules are covered in full detail in this guide. In +addition, manual pages are also provided in the default installation. + +Kea also provides C++ libraries and programmer interfaces for DHCP. +These include detailed developer documentation and code examples. diff --git a/doc/sphinx/arm/keactrl.rst b/doc/sphinx/arm/keactrl.rst new file mode 100644 index 0000000..93768c3 --- /dev/null +++ b/doc/sphinx/arm/keactrl.rst @@ -0,0 +1,364 @@ +.. _keactrl: + +*********************************** +Managing Kea with :iscman:`keactrl` +*********************************** + +.. _keactrl-overview: + +Overview +======== + +:iscman:`keactrl` is a shell script which controls the startup, shutdown, and +reconfiguration of the Kea servers (:iscman:`kea-dhcp4`, :iscman:`kea-dhcp6`, +:iscman:`kea-dhcp-ddns`, :iscman:`kea-ctrl-agent`, and :iscman:`kea-netconf`). It also +provides the means for checking the current status of the servers and +determining the configuration files in use. + +:iscman:`keactrl` is available only when Kea is built from sources. When installing +Kea using native packages, the native ``systemd`` scripts are provided. See +:ref:`systemd` Section for details. + +.. _keactrl-usage: + +Command Line Options +==================== + +:iscman:`keactrl` is run as follows: + +.. code-block:: console + + # keactrl <command> [-c keactrl-config-file] [-s server[,server,...]] + +``<command>`` is one of the commands described in :ref:`keactrl-commands`. + +The optional ``-c keactrl-config-file`` switch allows specification of +an alternate :iscman:`keactrl` configuration file. (``--ctrl-config`` is a +synonym for ``-c``.) In the absence of ``-c``, :iscman:`keactrl` uses the +default configuration file ``[kea-install-dir]/etc/kea/keactrl.conf``. + +The optional ``-s server[,server,...]`` switch selects the servers to +which the command is issued. (``--server`` is a synonym for ``-s``.) If +absent, the command is sent to all servers enabled in the :iscman:`keactrl` +configuration file. If multiple servers are specified, they should be +separated by commas with no intervening spaces. + +.. _keactrl-config-file: + +The :iscman:`keactrl` Configuration File +======================================== + +Depending on the administrator's requirements, it may not be +necessary to run all of the available servers. +The :iscman:`keactrl` configuration file sets which servers are enabled and +which are disabled. The default configuration file is +``[kea-install-dir]/etc/kea/keactrl.conf``, but this can be overridden +on a per-command basis using the ``-c`` switch. + +The contents of ``keactrl.conf`` are: + +.. code-block:: bash + + # This is a configuration file for keactrl script which controls + # the startup, shutdown, reconfiguration and gathering the status + # of the Kea processes. + + # prefix holds the location where the Kea is installed. + prefix=@prefix@ + + # Location of Kea configuration file. + kea_dhcp4_config_file=@sysconfdir@/@PACKAGE@/kea-dhcp4.conf + kea_dhcp6_config_file=@sysconfdir@/@PACKAGE@/kea-dhcp6.conf + kea_dhcp_ddns_config_file=@sysconfdir@/@PACKAGE@/kea-dhcp-ddns.conf + kea_ctrl_agent_config_file=@sysconfdir@/@PACKAGE@/kea-ctrl-agent.conf + kea_netconf_config_file=@sysconfdir@/@PACKAGE@/kea-netconf.conf + + # Location of Kea binaries. + exec_prefix=@exec_prefix@ + dhcp4_srv=@sbindir@/kea-dhcp4 + dhcp6_srv=@sbindir@/kea-dhcp6 + dhcp_ddns_srv=@sbindir@/kea-dhcp-ddns + ctrl_agent_srv=@sbindir@/kea-ctrl-agent + netconf_srv=@sbindir@/kea-netconf + + # Start DHCPv4 server? + dhcp4=yes + + # Start DHCPv6 server? + dhcp6=yes + + # Start DHCP DDNS server? + dhcp_ddns=no + + # Start Control Agent? + ctrl_agent=yes + + # Start Netconf? + netconf=no + + # Be verbose? + kea_verbose=no + +.. note:: + + In the example above, strings of the form @something@ are replaced by + the appropriate values when Kea is installed. + +Setting the ``dhcp4``, ``dhcp6``, ``dhcp_ddns``, ``ctrl_agent``, and ``netconf`` +parameters set to "yes" configures :iscman:`keactrl` to manage (start, +reconfigure) all servers, i.e. :iscman:`kea-dhcp4`, :iscman:`kea-dhcp6`, +:iscman:`kea-dhcp-ddns`, :iscman:`kea-ctrl-agent`, and :iscman:`kea-netconf`. When any of +these parameters is set to "no", :iscman:`keactrl` ignores the +corresponding server when starting or reconfiguring Kea. Some daemons +(dhcp_ddns and netconf) are disabled by default. + +By default, Kea servers managed by :iscman:`keactrl` are located in +``[kea-install-dir]/sbin``. This should work for most installations. If +the default location needs to be altered, the paths +specified with the ``dhcp4_srv``, ``dhcp6_srv``, ``dhcp_ddns_srv``, +``ctrl_agent_srv``, and ``netconf_srv`` parameters should be modified. + +The ``kea_verbose`` parameter specifies the verbosity of the servers +being started. When ``kea_verbose`` is set to ``yes``, the logging level of +the server is set to DEBUG. Modification of the logging severity in a +configuration file, as described in :ref:`logging`, will have no +effect as long as ``kea_verbose`` is set to "yes." Setting it to +"no" causes the server to use the logging levels specified in the +Kea configuration file. If no logging configuration is specified, the +default settings are used. + +.. note:: + + The verbosity for the server is set when it is started. Once started, + the verbosity can only be changed by stopping the server and starting + it again with the new value of the ``kea_verbose`` parameter. + +.. _keactrl-commands: + +Commands +======== + +The following commands are supported by :iscman:`keactrl`: + +- ``start`` - starts the selected servers. + +- ``stop`` - stops all running servers. + +- ``reload`` - triggers reconfiguration of the selected servers by + sending the SIGHUP signal to them. + +- ``status`` - returns the status of the servers (active or inactive) + and the names of the configuration files in use. + +- ``version`` - prints out the version of the :iscman:`keactrl` tool itself, + together with the versions of the Kea daemons. + +Typical output from :iscman:`keactrl` when starting the servers looks similar +to the following: + +.. code-block:: console + + $ keactrl start + INFO/keactrl: Starting kea-dhcp4 -c /usr/local/etc/kea/kea-dhcp4.conf -d + INFO/keactrl: Starting kea-dhcp6 -c /usr/local/etc/kea/kea-dhcp6.conf -d + INFO/keactrl: Starting kea-dhcp-ddns -c /usr/local/etc/kea/kea-dhcp-ddns.conf -d + INFO/keactrl: Starting kea-ctrl-agent -c /usr/local/etc/kea/kea-ctrl-agent.conf -d + INFO/keactrl: Starting kea-netconf -c /usr/local/etc/kea/kea-netconf.conf -d + +Kea's servers create PID files upon startup. These files are used by +:iscman:`keactrl` to determine whether a given server is running. If one or more +servers are running when the start command is issued, the output +looks similar to the following: + +.. code-block:: console + + $ keactrl start + INFO/keactrl: kea-dhcp4 appears to be running, see: PID 10918, PID file: /usr/local/var/run/kea/kea.kea-dhcp4.pid. + INFO/keactrl: kea-dhcp6 appears to be running, see: PID 10924, PID file: /usr/local/var/run/kea/kea.kea-dhcp6.pid. + INFO/keactrl: kea-dhcp-ddns appears to be running, see: PID 10930, PID file: /usr/local/var/run/kea/kea.kea-dhcp-ddns.pid. + INFO/keactrl: kea-ctrl-agent appears to be running, see: PID 10931, PID file: /usr/local/var/run/kea/kea.kea-ctrl-agent.pid. + INFO/keactrl: kea-netconf appears to be running, see: PID 10123, PID file: /usr/local/var/run/kea/kea.kea-netconf.pid. + +During normal shutdowns, these PID files are deleted; they may, however, +be left over as remnants following a system crash. It is possible, +though highly unlikely, that upon system restart the PIDs they contain +may actually refer to processes unrelated to Kea. This condition will +cause :iscman:`keactrl` to decide that the servers are running, when in fact they +are not. In such a case the PID files listed in the :iscman:`keactrl` output +must be manually deleted. + +The following command stops all servers: + +.. code-block:: console + + $ keactrl stop + INFO/keactrl: Stopping kea-dhcp4... + INFO/keactrl: Stopping kea-dhcp6... + INFO/keactrl: Stopping kea-dhcp-ddns... + INFO/keactrl: Stopping kea-ctrl-agent... + INFO/keactrl: Stopping kea-netconf... + +Note that the ``stop`` command attempts to stop all servers +regardless of whether they are "enabled" in ``keactrl.conf``. If any +of the servers are not running, an informational message is displayed as +in the ``stop`` command output below. + +.. code-block:: console + + $ keactrl stop + INFO/keactrl: kea-dhcp4 isn't running. + INFO/keactrl: kea-dhcp6 isn't running. + INFO/keactrl: kea-dhcp-ddns isn't running. + INFO/keactrl: kea-ctrl-agent isn't running. + INFO/keactrl: kea-netconf isn't running. + +As already mentioned, the reconfiguration of each Kea server is +triggered by the SIGHUP signal. The ``reload`` command sends the SIGHUP +signal to any servers that are enabled in the :iscman:`keactrl` configuration +file and that are currently running. When a server receives the SIGHUP signal +it rereads its configuration file and, if the new configuration is +valid, uses the new configuration. +If the new configuration proves to be invalid, the server retains its +current configuration; however, in some cases a fatal error message is logged +indicating that the server is no longer providing any service: a working +configuration must be loaded as soon as possible. + +A reload is executed as follows: + +.. code-block:: console + + $ keactrl reload + INFO/keactrl: Reloading kea-dhcp4... + INFO/keactrl: Reloading kea-dhcp6... + INFO/keactrl: Reloading kea-dhcp-ddns... + INFO/keactrl: Reloading kea-ctrl-agent... + +If any of the servers are not running, an informational message is +displayed as in the ``reload`` command output below. +:iscman:`kea-netconf` does not support the SIGHUP signal. If its +configuration has changed, please stop and restart it for the change to +take effect. + +.. code-block:: console + + $ keactrl stop + INFO/keactrl: kea-dhcp4 isn't running. + INFO/keactrl: kea-dhcp6 isn't running. + INFO/keactrl: kea-dhcp-ddns isn't running. + INFO/keactrl: kea-ctrl-agent isn't running. + INFO/keactrl: kea-netconf isn't running. + +.. note:: + + NETCONF is an optional feature that is disabled by default and can be + enabled during compilation. If Kea was compiled without NETCONF + support, :iscman:`keactrl` does not provide + information about it. The NETCONF entries are still present in + the ``keactrl.conf`` file, but NETCONF status is not shown and other + commands ignore it. + +.. note:: + + Currently :iscman:`keactrl` does not report configuration failures when the + server is started or reconfigured. To check if the server's + configuration succeeded, the Kea log must be examined for errors. By + default, the log is written to the `syslog` file. + +Sometimes it is useful to check which servers are running. The +``status`` command reports this, with typical output that looks like: + +.. code-block:: console + + $ keactrl status + DHCPv4 server: active + DHCPv6 server: inactive + DHCP DDNS: active + Control Agent: active + Netconf agent: inactive + Kea configuration file: /usr/local/etc/kea/kea.conf + Kea DHCPv4 configuration file: /usr/local/etc/kea/kea-dhcp4.conf + Kea DHCPv6 configuration file: /usr/local/etc/kea/kea-dhcp6.conf + Kea DHCP DDNS configuration file: /usr/local/etc/kea/kea-dhcp-ddns.conf + Kea Control Agent configuration file: /usr/local/etc/kea/kea-ctrl-agent.conf + Kea Netconf configuration file: /usr/local/etc/kea/kea-netconf.conf + keactrl configuration file: /usr/local/etc/kea/keactrl.conf + +``keactrl status`` offers basic reporting capabilities. For more extensive insight +into Kea's health and status, consider deploying Stork. For details, see :ref:`stork`. + +.. _keactrl-overriding-servers: + +Overriding the Server Selection +=============================== + +The optional ``-s`` switch allows the selection of the server(s) to which +the :iscman:`keactrl` command is issued. For example, the following instructs +:iscman:`keactrl` to stop the :iscman:`kea-dhcp4` and :iscman:`kea-dhcp6` servers and +leave the :iscman:`kea-dhcp-ddns` and :iscman:`kea-ctrl-agent` running: + +.. code-block:: console + + $ keactrl stop -s dhcp4,dhcp6 + +Similarly, the following starts only the :iscman:`kea-dhcp4` and +:iscman:`kea-dhcp-ddns` servers, but not :iscman:`kea-dhcp6` or :iscman:`kea-ctrl-agent`. + +.. code-block:: console + + $ keactrl start -s dhcp4,dhcp_ddns + +Note that the behavior of the ``-s`` switch with the ``start`` and +``reload`` commands is different from its behavior with the ``stop`` +command. On ``start`` and ``reload``, :iscman:`keactrl` checks whether the +servers given as parameters to the ``-s`` switch are enabled in the +:iscman:`keactrl` configuration file; if not, the server is ignored. For +``stop``, however, this check is not made; the command is applied to all +listed servers, regardless of whether they have been enabled in the +file. + +The following keywords can be used with the ``-s`` command-line option: + +- ``dhcp4`` for :iscman:`kea-dhcp4`. + +- ``dhcp6`` for :iscman:`kea-dhcp6`. + +- ``dhcp_ddns`` for :iscman:`kea-dhcp-ddns`. + +- ``ctrl_agent`` for :iscman:`kea-ctrl-agent`. + +- ``netconf`` for :iscman:`kea-netconf`. + +- ``all`` for all servers (default). + +.. _systemd: + +Native Packages and ``systemd`` +=============================== + +:iscman:`keactrl` is a script that was developed to assist in managing Kea processes. +However, all modern operating systems have their own process-management scripts, +such as ``systemd``. In general, these native scripts should be used, +as they have several advantages. ``systemd`` scripts handle processes in a uniform +way, so Kea is handled in a similar fashion to HTTP or a mail +server. Second and more importantly, ``systemd`` allows dependencies to be defined +between services. For example, it is easy to specify that the Kea server should not start +until the network interfaces are operational. Using native scripts also has other benefits, such as +the ability to enable or disable services using commands, and the ability to temporarily start a disabled +service. + +Thus, it is recommended to use ``systemctl`` commands if they are available. Native +Kea packages do not provide :iscman:`keactrl`; ``systemctl`` service definitions are +provided instead. Consult the system documentation for details. + +Briefly, here are example commands to check status, start, stop, and restart various Kea daemons: + +.. code-block:: console + + # systemctl status kea-ctrl-agent + # systemctl start kea-dhcp4 + # systemctl stop kea-dhcp6 + # systemctl restart kea-dhcp-ddns + +Note that the service names may be slightly different between Linux distributions; in general, +we have followed the naming conventions in third-party packages. In particular, +some systems may not have the `isc-` prefix. diff --git a/doc/sphinx/arm/lease-expiration.rst b/doc/sphinx/arm/lease-expiration.rst new file mode 100644 index 0000000..a6ebd51 --- /dev/null +++ b/doc/sphinx/arm/lease-expiration.rst @@ -0,0 +1,328 @@ +.. _lease-expiration: + +**************** +Lease Expiration +**************** + +The primary role of the DHCP server is to assign addresses and/or +delegate prefixes to DHCP clients. These addresses and prefixes are +often referred to as "leases." Leases are typically assigned to clients +for a finite amount of time, known as the "valid lifetime." DHCP clients +who wish to continue using their assigned leases periodically renew +them by sending the appropriate message to the DHCP server. The DHCP +server records the time when these leases are renewed and calculates new +expiration times for them. + +If the client does not renew a lease before its valid lifetime elapses, +the lease is considered expired. There are many situations when the +client may cease lease renewals; common scenarios include when the machine +running the client shuts down for an extended period of time, or when a +mobile device leaves the vicinity of a network. + +The process through which the DHCP server makes expired leases available +for reassignment is referred to as "lease reclamation," and expired +leases returned to availability through this process are referred to as +"reclaimed." The DHCP server attempts to reclaim an expired lease as +soon as it detects that it has expired. The server has several possible +ways to detect expiration: it may attempt to allocate a lease to a +client but find this lease already present in the database and expired; +or it can periodically query the lease database for expired leases. +Regardless of how an expired lease is detected, it must be reclaimed +before it can be assigned to a client. + +This chapter explains how to configure the server to periodically query +for the expired leases, and how to minimize the impact of the periodic +lease-reclamation process on the server's responsiveness. Finally, it +explains "lease affinity," which provides the means to assign the same +lease to a returning client after its lease has expired. + +Although all configuration examples in this section are provided for the +DHCPv4 server, the same parameters may be used for DHCPv6 server +configuration. + +.. _lease-reclamation: + +Lease Reclamation +================= + +Lease reclamation is the process through which an expired lease becomes +available for assignment to the same or a different client. This process +involves the following steps for each reclaimed lease: + +- Invoke callouts for the ``lease4_expire`` or ``lease6_expire`` hook + points, if hook libraries supporting those callouts are currently + loaded. + +- Update the DNS, i.e. remove any DNS entries associated with the + expired lease. + +- Update lease information in the lease database to indicate that the + lease is now available for reassignment. + +- Update counters on the server, a process that includes increasing the + number of reclaimed leases and decreasing the number of assigned + addresses or delegated prefixes. + +Please refer to :ref:`dhcp-ddns-server` to see how to configure DNS +updates in Kea, and to :ref:`hooks-libraries` for information about +using hook libraries. + +.. _lease-reclamation-defaults: + +Lease Reclamation Configuration Parameters +========================================== + +The following list presents all the configuration parameters pertaining to +processing expired leases, with their default values: + +- ``reclaim-timer-wait-time`` - this parameter governs intervals + between the completion of the previous reclamation cycle and the start of the + next one. Specified in seconds; the default value is 10. + +- ``flush-reclaimed-timer-wait-time`` - this parameter controls how + often the server initiates the lease reclamation procedure. Expressed in + seconds; the default value is 25. If both ``flush-reclaimed-timer-wait-time`` + and ``hold-reclaimed-time`` are not 0, when the client sends a release + message the lease is expired instead of being deleted from lease storage. + +- ``hold-reclaimed-time`` - this parameter governs how long the lease + should be kept after it is reclaimed. This enables lease affinity + when set to a non-zero value. Expressed in seconds; the default value + is 3600. If both ``flush-reclaimed-timer-wait-time`` and + ``hold-reclaimed-time`` are not 0, when the client sends a release message + the lease is expired instead of being deleted from lease storage. + +- ``max-reclaim-leases`` - this parameter specifies the maximum number + of reclaimed leases that can be processed at one time. Zero means + unlimited (i.e. process all reclaimed leases). The default value is + 100. + +- ``max-reclaim-time`` - this parameter specifies an upper limit to the + length of time a lease reclamation procedure can take. Zero means no time + limit. Expressed in milliseconds; the default value is 250. + +- ``unwarned-reclaim-cycles`` - if lease reclamation limits are + specified (``max-reclaim-leases`` and/or ``max-reclaim-time``), then + under certain circumstances the server may not be able to deal with + the leases to be reclaimed fast enough. This parameter specifies how many + consecutive clean-up cycles must end with remaining leases to be + processed before a warning is printed. The default is 5 cycles. + +The parameters are explained in more detail in the rest of this chapter. + +The default value for any parameter is used when the parameter is not +explicitly specified in the configuration. If the +``expired-leases-processing`` map is omitted entirely in the +configuration, the default values are used for all +parameters listed above. + +.. _lease-reclaim-config: + +Configuring Lease Reclamation +============================= + +Kea can be configured to periodically detect and reclaim expired leases. +During this process the lease entries in the database are modified or +removed. While this is happening the server does not process incoming +DHCP messages, to avoid issues with concurrent access to database +information. As a result, the server is unresponsive while lease +reclamation is performed and DHCP queries will accumulate; responses +will be sent once the lease-reclamation cycle is complete. + +In deployments where response time is critical, administrators may wish +to minimize the interruptions in service caused by lease reclamation. +To this end, Kea provides configuration parameters to control the +frequency of lease reclamation cycles, the maximum number of leases +processed in a single reclamation cycle, and the maximum amount of time +a single reclamation cycle is allowed to run before being interrupted. +The following examples demonstrate how these parameters can be used: + +.. code-block:: json + + { + "Dhcp4": { + "expired-leases-processing": { + "reclaim-timer-wait-time": 5, + "max-reclaim-leases": 0, + "max-reclaim-time": 0 + } + } + } + +The first parameter is expressed in seconds and specifies an interval +between the two consecutive lease reclamation cycles. This is explained +by the following diagram: + +:: + + + | c1 | | c2 | |c3| | c4 | + |<---->|<---------->|<-->|<---------->|<>|<---------->|<-->|<-- + ------------------------------------------------------------------> + | | 5s | | 5s | | 5s | | time + +This diagram shows four lease-reclamation cycles (c1 through c4) of +variable duration. The duration of the reclamation cycle +depends on the number of expired leases detected and processed in a +particular cycle. This duration is usually significantly shorter than +the interval between the cycles. + +According to the ``reclaim-timer-wait-time``, the server keeps fixed +intervals of five seconds between the end of one cycle and the start of +the next cycle. This guarantees the presence of 5-second-long periods during +which the server remains responsive to DHCP queries and does not perform +lease reclamation. The ``max-reclaim-leases`` and ``max-reclaim-time`` +are set to 0, which sets no restriction on the maximum number of leases +reclaimed in the particular cycle, or on the maximum duration of each +cycle. + +In deployments with high lease-pool utilization, relatively short valid +lifetimes, and frequently disconnecting clients which allow leases to +expire, the number of expired leases requiring reclamation at any given +time may rise significantly. In this case, it is often desirable to +apply restrictions to the maximum duration of a reclamation cycle or the +maximum number of leases reclaimed in a cycle. The following +configuration demonstrates how this can be done: + +.. code-block:: json + + { + "Dhcp4": { + "expired-leases-processing": { + "reclaim-timer-wait-time": 3, + "max-reclaim-leases": 100, + "max-reclaim-time": 50, + "unwarned-reclaim-cycles": 10 + } + } + } + +In this example, the ``max-reclaim-leases`` parameter limits the number of leases +reclaimed in a single cycle to 100, and the ``max-reclaim-time`` limits the +maximum duration of each cycle to 50ms. The lease-reclamation cycle will +be interrupted if either of these limitations is reached. The +reclamation of any unreclaimed leases will be attempted in subsequent +cycles. + +The following diagram illustrates the behavior of the system in the +presence of many expired leases, when the limits are applied for the +reclamation cycles: + +:: + + + | c1 | | c2 | | c3 | | c4 | + |<-->|<-------------->|<-->|<-------------->|<-->|<-------------->|<-->|<-- + ------------------------------------------------------------------------------> + |50ms| 3s |50ms| 3s |50ms| 3s |50ms| time + +In this case, if any reclamation cycle takes +more than 50ms, it is interrupted according to the value of the +``max-reclaim-time``. This results in equal durations of all reclamation +cycles over time. In this example, the limitation of the +maximum 100 leases is not reached. This may be the case when database +transactions or callouts in the hook libraries attached to the +server are slow. Regardless, the chosen values for either the maximum +number of leases or a maximum cycle time strongly depend on the +particular deployment, the lease database backend being used, any +hook libraries, etc. Administrators may need to experiment to tune the +system to suit the dynamics of their deployment. + +It is important to realize that with the use of these limits, there is a +risk that expired leases will accumulate faster than the server can +reclaim them. This should not be a problem if the server is dealing with +a temporary burst of expirations, because it should be able to +eventually deal with them over time. However, if leases expire at a high +rate for a long period of time, the unreclaimed leases will pile up in +the database. To notify the administrator that the current configuration +does not satisfy the needs for reclamation of expired leases, the server +issues a warning message in the log if it is unable to reclaim all +leases within several reclamation cycles. The number of cycles after +which such a warning is issued is specified with the +``unwarned-reclaim-cycles`` configuration parameter. + +Setting the ``reclaim-timer-wait-time`` to 0 disables periodic +reclamation of the expired leases. + +.. _lease-affinity: + +Configuring Lease Affinity +========================== + +Suppose that a laptop goes into sleep mode after a period of user +inactivity. While the laptop is in sleep mode, its DHCP client does not +renew leases obtained from the server and these leases will eventually +expire. When the laptop wakes up, it is often desirable for it to +continue using its previous assigned IP addresses. To facilitate this, +the server needs to correlate returning clients with their expired +leases. When the client returns, the server first checks for those +leases and reassigns them if they have not been assigned to another +client. The ability of the server to reassign the same lease to a +returning client is referred to as "lease affinity." + +When lease affinity is enabled (i.e. when ``hold-reclaimed-time`` is configured +to a value greater than zero), the server still reclaims leases according to the +parameters described in :ref:`lease-reclaim-config`, but the reclaimed leases +are held in the database for a specified amount of time rather than removed. +If both ``flush-reclaimed-timer-wait-time`` and ``hold-reclaimed-time`` are +greater than zero, the lease is expired immediately when the client sends a +release message, instead of being deleted from lease storage. When the client +returns, the server first verifies whether there are any reclaimed leases +associated with this client and then reassigns them if possible. However, it is +important to note that any reclaimed lease may be assigned to another client if +that client specifically asks for it. Therefore, lease affinity does not +guarantee that the reclaimed lease will be available for the client who used it +before; it merely increases the chances of the client being assigned the same +lease. If the lease pool is small - namely, in DHCPv4, for which address space +is limited - there is an increased likelihood that the expired lease will be +assigned to another client. + +Consider the following configuration: + +:: + + "Dhcp4": { + "expired-leases-processing": { + "reclaim-timer-wait-time": 3, + "hold-reclaimed-time": 1800, + "flush-reclaimed-timer-wait-time": 5 + }, + ... + } + +The ``hold-reclaim-time`` specifies how many seconds after an expiration +a reclaimed lease should be held in the database for reassignment to +the same client. In the example given above, reclaimed leases are +held for 30 minutes (1800 seconds) after their expiration. During this time, +the server will likely be able to reassign the same lease to the +returning client, unless another client specifically requests this lease and the +server assigns it. + +The server must periodically remove reclaimed leases for which the time +indicated by ``hold-reclaim-time`` has elapsed. The +``flush-reclaimed-timer-wait-time`` parameter controls how often the +server removes such leases. In the example provided above, the server +initiates removal of such leases five seconds after the previous +removal attempt was completed. Setting this value to 0 disables lease +affinity, meaning leases are removed from the lease database +when they are reclaimed. If lease affinity is enabled, it is recommended +that the ``hold-reclaim-time`` be set to a value significantly higher than +the ``reclaim-timer-wait-time``, as timely removal of expired-reclaimed +leases is less critical than the removal process, which may impact +server responsiveness. + +There is no guarantee that lease affinity will work every time; if a +server is running out of addresses, it will reassign expired addresses +to new clients. Also, clients can request specific addresses and the +server tries to honor such requests if possible. Administrators who want to +ensure a client keeps its address, even after periods of inactivity, +should consider using host reservations or leases with very long lifetimes. + +.. _leases-reclamation-using-command: + +Reclaiming Expired Leases via Command +===================================== + +The :isccmd:`leases-reclaim` command can be used to trigger lease reclamation at +any time. Please consult the :ref:`command-leases-reclaim` section +for details about using this command. diff --git a/doc/sphinx/arm/lfc.rst b/doc/sphinx/arm/lfc.rst new file mode 100644 index 0000000..f28756a --- /dev/null +++ b/doc/sphinx/arm/lfc.rst @@ -0,0 +1,73 @@ +.. _kea-lfc: + +*************** +The LFC Process +*************** + +.. _kea-lfc-overview: + +Overview +======== + +:iscman:`kea-lfc` is a service process that removes redundant information from +the files used to provide persistent storage for the memfile database +backend. This service is written to run as a standalone process. + +While :iscman:`kea-lfc` can be started externally, there is usually no need to +do so. :iscman:`kea-lfc` is run on a periodic basis by the Kea DHCP servers. + +The process operates on a set of files, using them to receive input and +output of the lease entries and to indicate what stage the process is +in, in the event of an interruption. Currently the caller must supply +names for all of the files. + +.. _kea-lfc-usage: + +Command-Line Options +==================== + +:iscman:`kea-lfc` is run as follows: + +:: + + kea-lfc [-4 | -6] -c config-file -p pid-file -x previous-file -i copy-file -o output-file -f finish-file + +The argument ``-4`` or ``-6`` selects the protocol version of the lease +files. + +The ``-c`` argument specifies the configuration file. This is required, +but is not currently used by the process. + +The ``-p`` argument specifies the PID file. When the :iscman:`kea-lfc` process +starts, it attempts to determine whether another instance of the process +is already running by examining the PID file. If one is already running, +the new process is terminated; if one is not running, Kea writes its PID +into the PID file. + +The other filenames specify where the :iscman:`kea-lfc` process should look +for input, write its output, and perform its bookkeeping: + +- ``previous`` — when :iscman:`kea-lfc` starts, this is the result of any + previous run of :iscman:`kea-lfc`. When :iscman:`kea-lfc` finishes, it is the + result of this run. If :iscman:`kea-lfc` is interrupted before completing, + this file may not exist. + +- ``input`` — before the DHCP server invokes :iscman:`kea-lfc`, it moves + the current lease file here and then calls :iscman:`kea-lfc` with this file. + +- ``output`` — this is the temporary file where :iscman:`kea-lfc` writes the + leases. Once the file has finished writing, it is moved to the + ``finish`` file (see below). + +- ``finish`` — this is another temporary file :iscman:`kea-lfc` uses for + bookkeeping. When :iscman:`kea-lfc` completes writing the ``output`` file, it + moves the contents to the file of this name. After :iscman:`kea-lfc` finishes deleting the + other files (``previous`` and ``input``), it moves this file to the ``previous`` + lease file. By moving the files in this fashion, :iscman:`kea-lfc` and + the DHCP server processes can determine the correct file to use even + if one of the processes is interrupted before completing its task. + +There are several additional arguments, mostly for debugging purposes. +``-d`` sets the logging level to debug. ``-v`` and ``-V`` print out +version stamps, with ``-V`` providing a longer form. ``-h`` prints out +the usage string. diff --git a/doc/sphinx/arm/logging.rst b/doc/sphinx/arm/logging.rst new file mode 100644 index 0000000..897cf9e --- /dev/null +++ b/doc/sphinx/arm/logging.rst @@ -0,0 +1,1077 @@ +.. _logging: + +******* +Logging +******* + +Logging Configuration +===================== + +During its operation Kea may produce many log messages. They differ in +severity (some are more important than others) and source (different +components, like hooks, produce different messages). It is useful to +understand which log messages are critical and which are not, and to +configure logging appropriately. For example, debug-level messages +can be safely ignored in a typical deployment. They are, however, very +useful when debugging a problem. + +The logging system in Kea is configured through the ``loggers`` entry in the +server section of the configuration file. + +Loggers +------- + +Within Kea, a message is logged through an entity called a "logger." +Different components log messages through different loggers, and each +logger can be configured independently of the others. Some components, +in particular the DHCP server processes, may use multiple loggers to log +messages pertaining to different logical functions of the component. For +example, the DHCPv4 server uses one logger for messages about packet +reception and transmission, another logger for messages related to lease +allocation, and so on. Some of the libraries used by the Kea server, +such as libdhcpsrv, use their own loggers. + +Users implementing hook libraries (code attached to the server at +runtime) are responsible for creating the loggers used by those +libraries. Such loggers should have unique names, different from the +logger names used by Kea. That way, the messages produced by the hook +library can be distinguished from messages issued by the core Kea code. +Unique names also allow the hook loggers to be configured independently of +loggers used by Kea. Whenever it makes sense, a hook library can use +multiple loggers to log messages pertaining to different logical parts +of the library. + +In the server section of a configuration file, the +configuration for zero or more loggers (including loggers used by the +proprietary hook libraries) can be specified. If there are no loggers specified, the +code uses default values; these cause Kea to log messages of INFO +severity or greater to standard output. There is a small time window +after Kea has been started but before it has read its configuration; +logging in this short period can be controlled using environment +variables. For details, see :ref:`logging-during-startup`. + +The three main elements of a logger configuration are: ``name`` (the +component that is generating the messages), ``severity`` (what to log), +and ``output_commands`` (where to log). There is also a ``debuglevel`` +element, which is only relevant if debug-level logging has been +selected. + +The ``name`` (string) Logger +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Each logger in the system has a name: that of the component binary file +using it to log messages. For instance, to configure logging +for the DHCPv4 server, add an entry for a logger named “kea-dhcp4”. +This configuration will then be used by the loggers in the DHCPv4 +server and all the libraries used by it, unless a library defines its +own logger and there is a specific logger configuration that applies to +that logger. + +When tracking down an issue with the server's operation, use of DEBUG +logging is required to obtain the verbose output needed for problem +diagnosis. However, the high verbosity is likely to overwhelm the +logging system in cases where the server is processing high-volume +traffic. To mitigate this problem, Kea can use multiple loggers, for +different functional parts of the server, that can each be configured +independently. If the user is reasonably confident that a problem +originates in a specific function of the server, or that the problem is +related to a specific type of operation, they may enable high verbosity +only for the relevant logger, thereby limiting the DEBUG messages to the +required minimum. + +The loggers are associated with a particular library or binary of Kea. +However, each library or binary may (and usually does) include multiple +loggers. For example, the DHCPv4 server binary contains separate loggers +for packet parsing, dropped packets, callouts, etc. + +The loggers form a hierarchy. For each program in Kea, there is a "root" +logger, named after the program (e.g. the root logger for :iscman:`kea-dhcp4`, the +DHCPv4 server, is named :iscman:`kea-dhcp4`). All other loggers are children of +this logger and are named accordingly, e.g. the allocation engine in the +DHCPv4 server logs messages using a logger called +``kea-dhcp4.alloc-engine``. + +This relationship is important, as each child logger derives its default +configuration from its parent root logger. In the typical case, the root +logger configuration is the only logging configuration specified in the +configuration file and so applies to all loggers. If an entry is made +for a given logger, any attributes specified override those of the root +logger, whereas any not specified are inherited from it. + +To illustrate this, suppose we are using the DHCPv4 server with the +root logger :iscman:`kea-dhcp4` logging at the INFO level. In order to enable +DEBUG verbosity for DHCPv4 packet drops, we must create a configuration +entry for the logger with ``"name": "kea-dhcp4.bad-packets”``, +``"severity": "DEBUG"``, and an explicit debug level. All other configuration +parameters may be omitted for this logger if it should use the default values +specified in the root logger's configuration. + +``debuglevel`` is inherited only if ``severity`` is missing as well. For +predictable results, if ``severity`` is ``"DEBUG"``, these two attributes +should always be explicitly specified or omitted together. An entry with an +explicit ``"DEBUG"`` severity does not inherit ``debuglevel`` from the root +logger and defaults to ``0`` if missing, resulting in no debug messages +being logged. This is a consequence of relying on the log4cplus inheritance +mechanism. + +If there are multiple logger specifications in the configuration that +might match a particular logger, the specification with the more +specific logger name takes precedence. For example, if there are entries +for both :iscman:`kea-dhcp4` and ``kea-dhcp4.dhcpsrv``, the main DHCPv4 server +program — and all libraries it uses other than the ``dhcpsrv`` library +(libdhcpsrv) — logs messages according to the configuration in the +first entry (:iscman:`kea-dhcp4`). Messages generated by the ``dhcpsrv`` library +are logged according to the configuration set by the second entry. + +Currently defined loggers are listed in the following table. The +"Software Package" column of this table specifies whether the particular +loggers belong to the core Kea code (open source Kea binaries and +libraries), or hook libraries (open source or premium). + +.. tabularcolumns:: |p{0.2\linewidth}|p{0.2\linewidth}|p{0.6\linewidth}| + +.. table:: List of loggers supported by Kea servers and hook libraries shipped with Kea/premium packages + :class: longtable + :widths: 20 20 60 + + +----------------------------------+---------------------------------------+--------------------------------+ + | Logger Name | Software Package | Description | + +==================================+=======================================+================================+ + | ``kea-ctrl-agent`` | core | The root logger for | + | | | the Control Agent | + | | | exposing the RESTful | + | | | control API. All | + | | | components used by | + | | | the Control Agent | + | | | inherit the settings | + | | | from this logger. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-ctrl-agent.auth`` | core | A logger which covers | + | | | access control details, such as| + | | | a result of the basic HTTP | + | | | authentication. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-ctrl-agent.ctrl-agent`` | core | Used to log results of | + | | | configuration checks, | + | | | information about services | + | | | starting or failing to start, | + | | | command receival and | + | | | forwarding. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-ctrl-agent.http`` | core | A logger which | + | | | outputs log messages | + | | | related to receiving, | + | | | parsing, and sending | + | | | HTTP messages. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-ctrl-agent.rbac-hooks`` | :ischooklib:`libca_rbac.so` | Used to log messages related | + | | enterprise hook library | to the operation of the RBAC | + | | | hook library. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp4`` | core | The root logger for | + | | | the DHCPv4 server. | + | | | All components used | + | | | by the DHCPv4 server | + | | | inherit the settings | + | | | from this logger. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp6`` | core | The root logger for | + | | | the DHCPv6 server. | + | | | All components used | + | | | by the DHCPv6 server | + | | | inherit the settings | + | | | from this logger. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp4.alloc-engine``, | core | Used by the lease | + | ``kea-dhcp6.alloc-engine`` | | allocation engine, | + | | | which is responsible | + | | | for managing leases | + | | | in the lease | + | | | database, i.e. | + | | | creating, modifying, | + | | | and removing DHCP | + | | | leases as a result of | + | | | processing messages | + | | | from clients. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-ctrl-agent.auth``, | core | Used to log malformed HTTP | + | ``kea-dhcp4.auth``, | | packets when using basic | + | ``kea-dhcp6.auth`` | | authentication. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp4.bad-packets``, | core | Used by the DHCP | + | ``kea-dhcp6.bad-packets`` | | servers for logging | + | | | inbound client | + | | | packets that were | + | | | dropped or to which | + | | | the server responded | + | | | with a DHCPNAK. It | + | | | allows administrators | + | | | to configure a | + | | | separate log output | + | | | that contains only | + | | | packet drop and | + | | | reject entries. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp4.bootp-hooks`` | :ischooklib:`libdhcp_bootp.so` | This logger is used to log | + | | open-source hook library | messages related to the | + | | | operation of the BOOTP hook | + | | | library. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-ctrl-agent.callouts``, | core | Used to log messages | + | ``kea-dhcp4.callouts``, | | pertaining to the | + | ``kea-dhcp6.callouts``, | | callouts registation and | + | ``kea-dhcp-ddns.callouts`` | | execution for a particular | + | | | hook point. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp4.cb-cmds-hooks``, | :ischooklib:`libdhcp_cb_cmds.so` | Used to log messages related | + | ``kea-dhcp6.cb-cmds-hooks`` | subscription hook library | to the operation of the | + | | | Config Backend Commands | + | | | hook library. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp4.class-cmds-hooks``, | :ischooklib:`libdhcp_class_cmds.so` | Used to log messages related | + | ``kea-dhcp6.class-cmds-hooks`` | subscription hook library | to the operation of the | + | | | Class Commands | + | | | hook library. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp4.commands``, | core | Used to log messages | + | ``kea-dhcp6.commands`` | | relating to the | + | | | handling of commands | + | | | received by the DHCP | + | | | server over the | + | | | command channel. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp4.database``, | core | Used to log messages | + | ``kea-dhcp6.database`` | | relating to general | + | | | operations on the | + | | | relational databases. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp4.ddns-tuning-hooks``, | :ischooklib:`libdhcp_ddns_tuning.so` | Used to log messages related | + | ``kea-dhcp6.ddns-tuning-hooks`` | premium hook library | to the operation of the | + | | | DDNS Tuning hook library. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp4.ddns``, | core | Used by the DHCP | + | ``kea-dhcp6.ddns`` | | server to log | + | | | messages related to | + | | | Client FQDN and | + | | | Hostname option | + | | | processing. It also | + | | | includes log messages | + | | | related to the | + | | | relevant DNS updates. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp4.dhcp4``, | core | Used to log basic operations. | + | ``kea-dhcp6.dhcp6`` | | | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp4.dhcpsrv``, | core | The base loggers for the | + | ``kea-dhcp6.dhcpsrv`` | | ``libkea-dhcpsrv.so`` library. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp4.eval``, | core | Used to log messages | + | ``kea-dhcp6.eval`` | | relating to the | + | | | client classification | + | | | expression evaluation | + | | | code. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp4.flex-id-hooks``, | :ischooklib:`libdhcp_flex_id.so` | Used | + | ``kea-dhcp6.flex-id-hooks`` | premium hook library | to log messages | + | | | related to the | + | | | operation of the | + | | | Flexible Identifier | + | | | hook library. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp4.flex-option-hooks``, | :ischooklib:`libdhcp_flex_option.so` | Used to log messages related | + | ``kea-dhcp6.flex-option-hooks`` | open-source hook library | to the operaton of | + | | | the Flexible Option | + | | | hook library. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp4.ha-hooks``, | :ischooklib:`libdhcp_ha.so` | Used | + | ``kea-dhcp6.ha-hooks`` | open-source hook library | to log messages | + | | | related to the | + | | | operation of the High | + | | | Availability hook | + | | | library. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-ctrl-agent.hooks``, | core | Used to log messages related | + | ``kea-dhcp4.hooks``, | | to the maagemet of hook | + | ``kea-dhcp6.hooks``, | | libraries, e.g. | + | ``kea-dhcp-ddns.hooks`` | | registatin and | + | | | deregistration of the | + | | | libraries, and to the | + | | | initialization of the | + | | | callouts execution | + | | | for various hook | + | | | points within the | + | | | DHCP server. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp4.host-cache-hooks``, | :ischooklib:`libdhcp_host_cache.so` | Used | + | ``kea-dhcp6.host-cache-hooks`` | subscription hook library | to log messages | + | | | related to the | + | | | operation of the Host | + | | | Cache hook library. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp4.host-cmds-hooks``, | :ischooklib:`libdhcp_host_cmds.so` | Used | + | ``kea-dhcp6.host-cmds-hooks`` | premium hook library | to log messages | + | | | related to the | + | | | operation of the Host | + | | | Commands hook | + | | | library. In general, | + | | | these pertain to | + | | | the loading and | + | | | unloading of the | + | | | library and the | + | | | execution of commands | + | | | by the library. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp4.hosts``, | core | Used within | + | ``kea-dhcp6.hosts`` | | ``libdhcpsrv``, it logs | + | | | messages related to | + | | | the management of | + | | | DHCP host | + | | | reservations, i.e. | + | | | retrieving | + | | | reservations and | + | | | adding new | + | | | reservations. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp4.lease-cmds-hooks``, | :ischooklib:`libdhcp_lease_cmds.so` | Used | + | ``kea-dhcp6.lease-cmds-hooks`` | open-source hook library | to log messages | + | | | related to the | + | | | operation of the | + | | | Lease Commands hook | + | | | library. In general, | + | | | these pertain to | + | | | the loading and | + | | | unloading of the | + | | | library and the | + | | | execution of commands | + | | | by the library. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp4.limits-hooks``, | :ischooklib:`libdhcp_limits.so` | Used to log messages related | + | ``kea-dhcp6.limits-hooks`` | subscription hook library | to the operation of the | + | | | Limits hook library. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp4.lease-query-hooks``, | :ischooklib:`libdhcp_lease_query.so` | Used | + | ``kea-dhcp6.lease-query-hooks`` | premium hook library | to log messages | + | | | related to the | + | | | operation of the | + | | | Leasequery hook library. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp4.leases``, | core | Used by the DHCP | + | ``kea-dhcp6.leases`` | | server to log | + | | | messages related to | + | | | lease allocation. The | + | | | messages include | + | | | detailed information | + | | | about the allocated | + | | | or offered leases, | + | | | errors during the | + | | | lease allocation, | + | | | etc. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp4.legal-log-hooks``, | :ischooklib:`libdhcp_legal_log.so` | Used | + | ``kea-dhcp6.legal-log-hooks`` | premium hook library | to log messages | + | | | related to the | + | | | operation of the | + | | | Forensic Logging | + | | | hook library. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp4.mysql-cb-hooks``, | :ischooklib:`libdhcp_mysql_cb.so` | Used | + | ``kea-dhcp6.mysql-cb-hooks`` | open-source hook library | to log messages | + | | | related to the | + | | | operation of the | + | | | MySQL Configuration | + | | | Backend hook | + | | | library. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp4.options``, | core | Used by the DHCP | + | ``kea-dhcp6.options`` | | server to log | + | | | messages related to | + | | | the processing of | + | | | options in the DHCP | + | | | messages, i.e. | + | | | parsing options, | + | | | encoding options into | + | | | on-wire format, and | + | | | packet classification | + | | | using options | + | | | contained in the | + | | | received packets. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp4.packets``, | core | Mostly | + | ``kea-dhcp6.packets`` | | used to log messages | + | | | related to | + | | | transmission of the | + | | | DHCP packets, i.e. | + | | | packet reception and | + | | | the sending of a | + | | | response. Such | + | | | messages include | + | | | information about the | + | | | source and | + | | | destination IP | + | | | addresses and | + | | | interfaces used to | + | | | transmit packets. The | + | | | logger is also used | + | | | to log messages | + | | | related to subnet | + | | | selection, as this | + | | | selection is usually | + | | | based on the IP | + | | | addresses, relay | + | | | addresses, and/or | + | | | interface names, | + | | | which can be | + | | | retrieved from the | + | | | received packet even | + | | | before the DHCP | + | | | message carried in | + | | | the packet is parsed. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp4.perfmon-hooks``, | :ischooklib:`libdhcp_perfmon.so` | Used to log messages related | + | ``kea-dhcp6.perfmon-hooks`` | open-source hook library | to performance monitoring. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp4.ping-check-hooks`` | :ischooklib:`libdhcp_ping_check.so` | Used | + | | subscription hook library | to log messages related to | + | | | carrying out pre-offer ping | + | | | checks of candidate leases. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp4.pgsql-cb-hooks``, | :ischooklib:`libdhcp_pgsql_cb.so` | Used | + | ``kea-dhcp6.pgsql-cb-hooks`` | open-source hook library | to log messages | + | | | related to the | + | | | operation of the | + | | | PostgreSQL Configuration | + | | | Backend hook | + | | | library. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp4.run-script-hooks``, | :ischooklib:`libdhcp_run_script.so` | Used to log messages related | + | ``kea-dhcp6.run-script-hooks`` | open-source hook library | to the operation of the | + | | | Run Script hook library. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp4.radius-hooks``, | :ischooklib:`libdhcp_radius.so` | Used | + | ``kea-dhcp6.radius-hooks`` | premium hook library | to log messages | + | | | related to the | + | | | operation of the | + | | | RADIUS hook library. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp4.stat-cmds-hooks``, | :ischooklib:`libdhcp_stat_cmds.so` | Used | + | ``kea-dhcp6.stat-cmds-hooks`` | opens-source hook library | to log messages | + | | | related to the | + | | | operation of the | + | | | Statistics Commands | + | | | hook library. In | + | | | general, these | + | | | pertain to loading | + | | | and unloading the | + | | | library and the | + | | | execution of commands | + | | | by the library. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp4.subnet-cmds-hooks``, | :ischooklib:`libdhcp_subnet_cmds.so` | Used | + | ``kea-dhcp6.subnet-cmds-hooks`` | premium hook library | to log messages | + | | | related to the | + | | | operation of the | + | | | Subnet Commands hook | + | | | library. In general, | + | | | these pertain to | + | | | loading and unloading | + | | | the library and the | + | | | execution of commands | + | | | by the library. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp4.tcp``, | core | Used to log messages related | + | ``kea-dhcp6.tcp`` | | to TCP traffic. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp4.user_chk``, | :ischooklib:`libdhcp_user_chk.so` | Used to log messages related | + | ``kea-dhcp6.user_chk`` | hook library | to the operaton of the | + | | | User Check hook library. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp-ddns`` | core | The root logger for | + | | | the :iscman:`kea-dhcp-ddns` | + | | | daemon. All | + | | | components used by | + | | | this daemon inherit | + | | | the settings from | + | | | this logger unless | + | | | there are | + | | | configurations for | + | | | more specialized | + | | | loggers. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-ctrl-agent.dctl``, | core | Used to log basic inofrmaton | + | ``kea-dhcp-ddns.dctl`` | | about the process, | + | | | received signals, and | + | | | triggered | + | | | reconfigurations. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp-ddns.asiodns``, | core | Used to log messages about | + | | | network events in DDNS | + | | | operations. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp-ddns.dhcpddns`` | core | Used by | + | | | the :iscman:`kea-dhcp-ddns` | + | | | daemon to log | + | | | events related to | + | | | DDNS operations. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp-ddns.dhcp-to-d2`` | core | Used by the | + | | | :iscman:`kea-dhcp-ddns` daemon | + | | | to log | + | | | information about | + | | | events dealing with | + | | | receiving messages | + | | | from the DHCP servers | + | | | and adding them to | + | | | the queue for | + | | | processing. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp-ddns.d2-to-dns`` | core | Used by the | + | | | :iscman:`kea-dhcp-ddns` daemon | + | | | to log | + | | | information about | + | | | events dealing with | + | | | sending and receiving | + | | | messages to and from | + | | | the DNS servers. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp-ddns.gss-tsig-hooks`` | :ischooklib:`libddns_gss_tsig.so` | Used to log messages related | + | | subscription hook library | to the operation of the | + | | | GSS-TSIG hook library. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-dhcp-ddns.libdhcp-ddns`` | core | Used to log events related to | + | | | DDNS operations. | + +----------------------------------+---------------------------------------+--------------------------------+ + | ``kea-netconf`` | core | The root logger for | + | | | the NETCONF agent. | + | | | All components used | + | | | by NETCONF inherit | + | | | the settings from | + | | | this logger if there | + | | | is no specialized | + | | | logger provided. | + +----------------------------------+---------------------------------------+--------------------------------+ + +Note that user-defined hook libraries should not use any of the loggers +mentioned above, but should instead define new loggers with names that +correspond to the libraries using them. Suppose that a user created +a library called “libdhcp-packet-capture” to dump packets received and +transmitted by the server to a file. An appropriate name for the +logger could be ``kea-dhcp4.packet-capture-hooks``. (Note that the hook +library implementer only specifies the second part of this name, i.e. +“packet-capture”. The first part is a root-logger name and is prepended +by the Kea logging system.) It is also important to note that since this +new logger is a child of a root logger, it inherits the configuration +from the root logger, something that can be overridden by an entry in +the configuration file. + +The easiest way to find a logger name is to configure all logging to go +to a single destination and look there for specific logger names. See +:ref:`logging-message-format` for details. + +The ``severity`` (string) Logger +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This specifies the category of messages logged. Each message is logged +with an associated severity, which may be one of the following (in +descending order of severity): + +- FATAL - associated with messages generated by a condition that is so + serious that the server cannot continue executing. + +- ERROR - associated with messages generated by an error condition. The + server continues executing, but the results may not be as + expected. + +- WARN - indicates an out-of-the-ordinary condition. However, the + server continues executing normally. + +- INFO - an informational message marking some event. + +- DEBUG - messages produced for debugging purposes. + +When the severity of a logger is set to one of these values, it +only logs messages of that severity and above (e.g. setting the logging +severity to INFO logs INFO, WARN, ERROR, and FATAL messages). The +severity may also be set to NONE, in which case all messages from that +logger are inhibited. + +.. note:: + + The :iscman:`keactrl` tool, described in :ref:`keactrl`, can be configured + to start the servers in verbose mode. If this is the case, the + settings of the logging severity in the configuration file have + no effect; the servers use a logging severity of DEBUG + regardless of the logging settings specified in the configuration + file. To control severity via the configuration file, + please make sure that the ``kea_verbose`` value is set to "no" within + the :iscman:`keactrl` configuration. + +.. _debuglevel: + +The ``debuglevel`` (integer) Logger +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When a logger's severity is set to DEBUG, this value specifies the +level of debug messages to be printed. It ranges from 0 (least +verbose) to 99 (most verbose). If severity for the logger is not DEBUG, +this value is ignored. + +The ``output-options`` (list) Logger +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Each logger can have zero or more ``output-options``. These specify +where log messages are sent and are explained in detail below. + +.. note:: + + As of Kea 2.5.1, alias ``output-options`` was added that can be used + interchangeably with previous ``output_options`` configuration key. + The reason behind this was to keep all configuration keys consistent i.e. + to use "dash" instead of "underscore" in the key name. For the time being + both configuration keys are considered correct and mean the same to Kea parsers. + + As of Kea 2.5.2, the ``output-options`` becomes the default configuration key + and ``output_options`` can be used as an alias. + +The ``output`` (string) Option +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This value determines the type of output. There are several special +values allowed here: ``stdout`` (messages are printed on standard +output), ``stderr`` (messages are printed on stderr), ``syslog`` +(messages are logged to syslog using the default name), ``syslog:name`` +(messages are logged to syslog using a specified name). Any other value is +interpreted as a filename to which messages should be written. + +The ``flush`` (boolean) Option +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This flushes the buffers after each log message. Doing this reduces performance +but ensures that if the program terminates abnormally, all messages +up to the point of termination are output. The default is ``true``. + +The ``maxsize`` (integer) Option +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This option is only relevant when the destination is a file; this is the maximum size +in bytes that a log file may reach. When the maximum size is reached, +the file is renamed and a new file created. Initially, a ".1" is +appended to the name; if a ".1" file exists, it is renamed ".2", etc. +This is referred to as rotation. + +The default value is 10240000 (10MB). The smallest value that can be +specified without disabling rotation is 204800. Any value less than +this, including 0, disables rotation. The greatest possible value is INT_MAX MB, which is +approximately 2PB. + +.. note:: + + Due to a limitation of the underlying logging library (log4cplus), + rolling over the log files (from ".1" to ".2", etc.) may show odd + results; there can be multiple small files at the timing of rollover. + This can happen when multiple processes try to roll over the + files simultaneously. Version 1.1.0 of log4cplus solved this problem, + so if this version or later of log4cplus is used to build Kea, the + issue should not occur. Even with older versions, it is normally + expected to happen rarely unless the log messages are produced very + frequently by multiple different processes. + +The ``maxver`` (integer) Option +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This option is only relevant when the destination is a file and rotation is enabled +(i.e. maxsize is large enough). This is the maximum number of rotated +versions that will be kept. Once that number of files has been reached, +the oldest file, "log-name.maxver", is discarded each time the log +rotates. In other words, at most there will be the active log file plus +maxver rotated files. The minimum and default value is 1. + +The ``pattern`` (string) Option +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This option can be used to specify the layout pattern of messages for +a logger. Kea logging is implemented using the log4cplus library and its +output formatting is based, conceptually, on the printf formatting from C; +this is discussed in detail in the next section, +:ref:`logging-message-format`. + +Each output type (``stdout``, file, or ``syslog``) has a default ``pattern`` which +describes the content of its log messages. This parameter can be used to +specify a desired pattern. The pattern for each logger is governed +individually, so each configured logger can have its own pattern. Omitting +the ``pattern`` parameter or setting it to an empty string, "", causes +Kea to use the default pattern for that logger's output type. + +In addition to the log text itself, the default patterns used for ``stdout`` +and files contain information such as date and time, logger level, and +process information. The default pattern for ``syslog`` is limited primarily +to log level, source, and the log text. This avoids duplicating information +which is usually supplied by syslog. + +.. warning:: + Users are strongly encouraged to test their pattern(s) on a local, + non-production instance of Kea, running in the foreground and + logging to ``stdout``. + +.. _logging-message-format: + +Logging Message Format +---------------------- + +As mentioned above, Kea log message content is controlled via a scheme similar +to the C language's printf formatting. The "pattern" used for each message is +described by a string containing one or more format components as part of a +text string. In addition to the components, the string may contain any other +useful text for the administrator. + +The behavior of Kea's format strings is determined by log4cplus. The following +time format options are possible enclosed in ``%D{}`` or ``%d{}``: + +.. table:: List of supported time format string components by Kea's logger + :class: longtable + :widths: 8 40 + + +-----------+-----------------------------------------------+ + | Component | Value | + +===========+===============================================+ + | ``%a`` | Abbreviated weekday name | + +-----------+-----------------------------------------------+ + | ``%A`` | Full weekday name | + +-----------+-----------------------------------------------+ + | ``%b`` | Abbreviated month name | + +-----------+-----------------------------------------------+ + | ``%B`` | Full month name | + +-----------+-----------------------------------------------+ + | ``%c`` | Standard date and time string | + +-----------+-----------------------------------------------+ + | ``%d`` | Day of month as a decimal(1-31) | + +-----------+-----------------------------------------------+ + | ``%H`` | Hour(0-23) | + +-----------+-----------------------------------------------+ + | ``%I`` | Hour(1-12) | + +-----------+-----------------------------------------------+ + | ``%j`` | Day of year as a decimal(1-366) | + +-----------+-----------------------------------------------+ + | ``%m`` | Month as decimal(1-12) | + +-----------+-----------------------------------------------+ + | ``%M`` | Minute as decimal(0-59) | + +-----------+-----------------------------------------------+ + | ``%p`` | Locale's equivalent of AM or PM | + +-----------+-----------------------------------------------+ + | ``%q`` | milliseconds as decimal(0-999) | + +-----------+-----------------------------------------------+ + | ``%Q`` | microseconds as decimal(0-999.999) | + +-----------+-----------------------------------------------+ + | ``%S`` | Second as decimal(0-59) | + +-----------+-----------------------------------------------+ + | ``%U`` | Week of year, Sunday being first day(0-53) | + +-----------+-----------------------------------------------+ + | ``%w`` | Weekday as a decimal(0-6, Sunday being 0) | + +-----------+-----------------------------------------------+ + | ``%W`` | Week of year, Monday being first day(0-53) | + +-----------+-----------------------------------------------+ + | ``%x`` | Standard date string | + +-----------+-----------------------------------------------+ + | ``%X`` | Standard time string | + +-----------+-----------------------------------------------+ + | ``%y`` | Year in decimal without century(0-99) | + +-----------+-----------------------------------------------+ + | ``%Y`` | Year including century as decimal | + +-----------+-----------------------------------------------+ + | ``%Z`` | Time zone name | + +-----------+-----------------------------------------------+ + | ``%%`` | The percent sign | + +-----------+-----------------------------------------------+ + +Refer to the documentation for the ``strftime()`` function found in the +``<ctime>`` header or the ``strftime(3)`` UNIX manual page for more +information. + +It is probably easiest to understand this by examining the default pattern +for stdout and files; currently they are the same. That pattern is shown +below: + +:: + + "%D{%Y-%m-%d %H:%M:%S.%q} %-5p [%c/%i.%t] %m\n" + +and a typical log produced by this pattern looks something like this: + +:: + + 2019-08-05 14:27:45.871 DEBUG [kea-dhcp4.dhcpsrv/8475.12345] DHCPSRV_TIMERMGR_START_TIMER starting timer: reclaim-expired-leases + +That breaks down to: + + - ``%D{%Y-%m-%d %H:%M:%S.%q}`` + "%D" is the local date and time when the log message is generated, + while everything between the curly braces, "{}", are date and time components. + From the example log above this produces: + ``2019-08-05 14:27:45.871`` + + - ``%-5p`` + The severity of the message, output as a minimum of five characters, + using right-padding with spaces. In our example log: ``DEBUG`` + + - ``%c`` + The log source. This includes two elements: the Kea process generating the + message, in this case, :iscman:`kea-dhcp4`; and the component within the program + from which the message originated, ``dhcpsrv`` (e.g. the name of the + library used by DHCP server implementations). + + - ``%i`` + The process ID. From the example log: ``8475``. + + - ``%t`` + The thread ID. From the example log: ``12345``. + The format of the thread ID is OS-dependent: e.g. on some systems + it is an address, so it is displayed in hexadecimal. + + - ``%m`` + The log message itself. Kea log messages all begin with a message identifier + followed by arbitrary log text. Every message in Kea has a unique + identifier, which can be used as an index to the :ref:`kea-messages`, where + more information can be obtained. In our example log above, the identifier + is ``DHCPSRV_TIMERMGR_START_TIMER``. The log text is typically a brief + description detailing the condition that caused the message to be logged. In + our example, the information logged, + ``starting timer: reclaim-expired-leases``, explains that the timer for the + expired lease reclamation cycle has been started. + +.. Warning:: + + Omitting ``%m`` omits the log message text from the output, making it + rather useless. ``%m`` should be considered mandatory. + +Finally, note that spacing between components, the square brackets around the +log source and PID, and the final carriage return ``\n`` are all literal text +specified as part of the pattern. + +.. Warning:: + + To ensure that each log entry is a separate line, patterns + must end with an ``\n``. There may be use cases where it is not desired + so we do not enforce its inclusion. If it is omitted from + the pattern, the log entries will run together in one long "line". + +The default pattern for ``syslog`` output is: + +:: + + "%-5p [%c.%t] %m\n" + +It omits the date and time as well as the process ID, as this +information is typically output by ``syslog``. Note that Kea uses the pattern +to construct the text it sends to ``syslog`` (or any other destination). It has +no influence on the content ``syslog`` may add or formatting it may do. + +Consult the OS documentation for ``syslog`` behavior, as there are multiple +implementations. + +A complete list of logging parameters supported by Kea is shown in the table below: + +.. table:: List of supported format string components by Kea's logger + :class: longtable + :widths: 8 40 + + +-----------+------------------------------------------------------------------------+ + | Component | Value | + +===========+========================================================================+ + | ``%b`` | Outputs file that called the log e.g., logger_impl.cc | + +-----------+------------------------------------------------------------------------+ + | ``%c`` | Outputs the logger of the event e.g., kea-dhcp4.hosts | + +-----------+------------------------------------------------------------------------+ + | ``%d`` | ``%d{}`` formats UTC time output e.g., ``%d{%Y-%m-%d %H:%M:%S.%q}`` | + +-----------+------------------------------------------------------------------------+ + | ``%D`` | ``%D{}`` formats LOCAL time output e.g., ``%D{%Y-%m-%d %H:%M:%S.%q}`` | + +-----------+------------------------------------------------------------------------+ + | ``%E`` | Outputs environment variables e.g., ``%E{PATH}`` | + +-----------+------------------------------------------------------------------------+ + | ``%F`` | Outputs filename where logging request was issued e.g., logger_impl.cc | + +-----------+------------------------------------------------------------------------+ + | ``%h`` | Outputs hostname of the system e.g., host-1 | + +-----------+------------------------------------------------------------------------+ + | ``%H`` | Outputs fully qualified domain name e.g., host-1.example.com | + +-----------+------------------------------------------------------------------------+ + | ``%l`` | Equivalent to ``%F:%L`` e.g., logger_impl.cc:179 | + +-----------+------------------------------------------------------------------------+ + | ``%L`` | Outputs the line number where the log was called e.g., 179 | + +-----------+------------------------------------------------------------------------+ + | ``%m`` | Outputs the actual log message | + +-----------+------------------------------------------------------------------------+ + | ``%M`` | Outputs caller (function name) of the log message | + +-----------+------------------------------------------------------------------------+ + | ``%n`` | Outputs line separator suppored by platform e.g., ``\n`` in Linux | + +-----------+------------------------------------------------------------------------+ + | ``%p`` | Outputs log severity e.g., INFO | + +-----------+------------------------------------------------------------------------+ + | ``%r`` | Outputs milliseconds since program start e.g., 1235 | + +-----------+------------------------------------------------------------------------+ + | ``%t`` | Outputs thread id that generated the log message e.g., 281472855306256 | + +-----------+------------------------------------------------------------------------+ + | ``%T`` | Outputs thread name that generated the log message e.g., 168005 | + +-----------+------------------------------------------------------------------------+ + | ``%i`` | Outputs process id that generated the log message e.g., 168030 | + +-----------+------------------------------------------------------------------------+ + | ``%%`` | Outputs a literal percent sign | + +-----------+------------------------------------------------------------------------+ + +Padding and truncation are also possible with modifiers preceeding the component. This is +done by placing a number and other modifier characters between the component and the % +sign. There are five ways of modifying the output shown by example here. + + - ``%20p`` + Left pads with spaces (align right) if the severity is shorter than 20 characters. + + - ``%-15r`` + Right pads with spaces (align left) if the milliseconds since program start is shorter + than 15 characters. + + - ``%.30m`` + Truncates from the beginning of the message if the message is longer than 30 + characters. + + - ``%10.35E{PATH}`` + Left pad with spaces (align right) if the environment variable "PATH" is shorter than + 10 characters. If the content is longer than 35 characters, then truncate from the + beginning of the string. + + - ``%-15.40m`` + Right pad with spaces (align left) if the log message is shorter than 15 characters. + If the message is longer than 40 characters, truncate from the beginning. + +Supported parameters depend on the liblog4cplus version used to compile Kea. This can +be checked by executing ``kea-dhcp4 -W | grep -i log4cplus`` which will produce output +like this: ``LOG4CPLUS_VERSION: 2.0.5``. Consult the documentation in the +`log4cplus wiki <https://github.com/log4cplus/log4cplus/wiki>`__ for further information +about the version you have installed. + +Example Logger Configurations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In this example, we want to set the server logging to write to the +console using standard output. + +:: + + "Server": { + "loggers": [ + { + "name": "kea-dhcp4", + "output-options": [ + { + "output": "stdout" + } + ], + "severity": "WARN" + } + ] + } + +As a second example, we want to store DEBUG log messages in a file +that is at most 2MB and keep up to eight copies of old log files. Once the +logfile grows to 2MB, it should be renamed and a new file should be created. + +:: + + "Server": { + "loggers": [ + { + "name": "kea-dhcp6", + "output-options": [ + { + "output": "/var/log/kea-debug.log", + "maxver": 8, + "maxsize": 204800, + "flush": true, + "pattern": "%d{%j %H:%M:%S.%q} %c %m\n" + } + ], + "severity": "DEBUG", + "debuglevel": 99 + } + ] + } + +Notice that the above configuration uses a custom pattern which produces output like this: + +:: + + 220 13:50:31.783 kea-dhcp4.dhcp4 DHCP4_STARTED Kea DHCPv4 server version 1.6.0-beta2-git started + + +.. _logging-during-startup: + +Logging During Kea Startup +-------------------------- + +The logging configuration is specified in the configuration file. +However, when Kea starts, the configuration file is not read until partway into the +initialization process. Prior to that, the logging settings are set to +default values, although it is possible to modify some aspects of the +settings by means of environment variables. In the absence of +any logging configuration in the configuration file, the settings of the +(possibly modified) default configuration will persist while the program +is running. + +The following environment variables can be used to control the behavior +of logging during startup: + +``KEA_LOCKFILE_DIR`` + + Specifies a directory where the logging system should create its lock + file. If not specified, it is prefix/var/run/kea, where "prefix" + defaults to /usr/local. This variable must not end with a slash. + There is one special value: "none", which instructs Kea not to create + a lock file at all. This may cause issues if several processes log to + the same file. + +``KEA_LOGGER_DESTINATION`` + + Specifies logging output. There are several special values: + + ``stdout`` + Log to standard output. + + ``stderr`` + Log to standard error. + + ``syslog[:fac]`` + Log via syslog. The optional "fac" (which is separated from the word + "syslog" by a colon) specifies the facility to be used for the log + messages. Unless specified, messages are logged using the + facility "local0". + + Any other value is treated as a name of the output file. If not + otherwise specified, Kea logs to standard output. + +Logging Levels +============== + +All Kea servers follow the overall intention to let the user +know what is going on while not overloading the logging system with too much information, as that +could easily be used as a denial-of-service attack. + +Unlike the FATAL, ERROR, WARN and +INFO levels, DEBUG has additional parameters. The following list details +the basic information that is logged on each level. Sometimes the circumstances +determine whether a piece of information is logged on a higher +or lower level. For example, if a packet is being dropped due to configured classification, that +is an execution of the configured policy and would be logged on debuglevel 15. However, if the +packet is dropped due to an exception being thrown, it is much more important, as it may indicate +a software bug, serious problems with memory, or database connectivity problems. As such it may +be logged on much higher levels, such as WARN or even ERROR. + +- 0 - singular messages printed during startup or shutdown of the server. +- 10 - log information about received API commands. +- 15 - information about reasons why a packet was dropped. +- 40 - tracing information, including processing decisions, results + of expression evaluations, and more. +- 45 - similar to level 40, but with more details, e.g. the subnet being + selected for an incoming packet. +- 50 - evaluations of expressions, status received from hook points, lease + processing, packet processing details, including unpacking, packing, sending, etc. +- 55 - includes all details available, including full packet contents + with all options printed. + +The debug levels apply only to messages logged on DEBUG, and are configured using +the ``debuglevel`` option. See the :ref:`debuglevel` section for details. diff --git a/doc/sphinx/arm/quickstart.rst b/doc/sphinx/arm/quickstart.rst new file mode 100644 index 0000000..81cc316 --- /dev/null +++ b/doc/sphinx/arm/quickstart.rst @@ -0,0 +1,382 @@ +.. _quickstart: + +*********** +Quick Start +*********** + +This section describes the basic steps needed to get Kea up and running. +For further details, full customizations, and troubleshooting, see the +respective chapters elsewhere in this Kea Administrator Reference Manual (ARM). + +.. _quick-start-tarball: + +Quick Start Guide Using tarball +=============================== + +1. Install required runtime and build dependencies. See + :ref:`build-requirements` for details. + +2. Download the Kea source tarball from + `the ISC.org downloads page <https://www.isc.org/download/>`__ or + `the ISC downloads site <https://downloads.isc.org/isc/kea/>`__ or + `the ISC Cloudsmith page <https://cloudsmith.io/~isc/packages/?q=format%3Araw>`__. + +3. Extract the tarball. For example: + + .. parsed-literal:: + + $ tar -xvzf kea-|release|.tar.gz + +4. Go into the source directory and run the configure script: + + .. parsed-literal:: + + $ cd kea-|release| + $ ./configure [your extra parameters] + +5. Build it: + + .. code-block:: console + + $ make + +6. Install it (by default it will be placed in ``/usr/local/``, so + root privileges are likely required for this step): + + .. code-block:: console + + $ make install + +.. _quick-start-repo: + +Quick Start Guide Using Native Packages +======================================= + +ISC provides native Alpine, deb, and RPM packages, which make Kea installation +much easier. Unless specific compilation options are desired, it is usually +easier to install Kea using native packages. + +1. Go to `Kea on cloudsmith.io <https://cloudsmith.io/~isc/repos/>`__. + +2. Choose the Cloudsmith repository e.g. |cloudsmith_repo| for Kea |version|. + +3. Click on the arrow besides the ``Set Me Up`` button and select your OS flavor + out of: ``Alpine``, ``Debian``, ``RedHat``. + +4. Follow the instructions written there. + +.. note:: + For example, the Debian setup instructions for Kea 2.4 can be found here: + https://cloudsmith.io/~isc/repos/kea-2-4/setup/#formats-deb + + The dropdown near the top of the page offers instructions for + other operating systems. + +5. Kea is split into various packages. The entire list is available on the + Cloudsmith repository page under ``Packages``, or it can be retrieved + using ``apk``/``apt``/``dnf``. + +.. list-table:: + :stub-columns: 1 + :widths: 10 90 + + * - Debian/Ubuntu + + - .. code-block:: console + + $ apt search isc-kea + + .. note:: + ``isc-kea-dhcp4-server`` and ``isc-kea-dhcp6-server`` are empty + transitional packages. The working server packages are + ``isc-kea-dhcp4`` and ``isc-kea-dhcp6``. + + * - Fedora/RedHat + + - .. code-block:: console + + $ dnf search 'isc-kea*' + + * - Alpine + + - .. code-block:: console + + $ apk search isc-kea + +6. Install the metapackage containing all the tools, libraries, servers, + documentation, and open source hooks: + +.. list-table:: + :stub-columns: 1 + :widths: 10 90 + + * - Debian/Ubuntu + + - .. code-block:: console + + $ sudo apt install isc-kea + + * - Fedora/RedHat + + - .. code-block:: console + + $ sudo dnf install isc-kea + + * - Alpine + + - .. code-block:: console + + # apk add isc-kea + +or specific packages: + +.. list-table:: + :stub-columns: 1 + :widths: 10 90 + + * - Debian/Ubuntu + + - .. code-block:: console + + $ sudo apt install isc-kea-dhcp6 + + * - Fedora/RedHat + + - .. code-block:: console + + $ sudo dnf install isc-kea-dhcp6 + + * - Alpine + + - .. code-block:: console + + $ apk add isc-kea-dhcp6 + +or every single Kea-related package, including development headers, debug +symbols, and premium hooks (if available): + +.. list-table:: + :stub-columns: 1 + :widths: 10 90 + + * - Debian/Ubuntu + + - .. code-block:: console + + $ sudo apt install 'isc-kea*' + + * - Fedora/RedHat + + - .. code-block:: console + + $ sudo dnf install 'isc-kea*' + + * - Alpine + + - Installing packages via globbing (``*``) is not available for Alpine, + but it can be simulated with the following command: + + .. code-block:: console + + # apk search isc-kea | sed 's/-[0-9].*//g' | xargs apk add + +or all packages with a specified version number: + +.. list-table:: + :stub-columns: 1 + :widths: 10 90 + + * - Debian/Ubuntu + + - .. code-block:: console + + $ sudo apt install 'isc-kea*=2.4.0-isc20230921141113' + + * - Fedora/RedHat + + - .. code-block:: console + + $ sudo dnf install 'isc-kea*2.4.0-isc20230921141113*' + + * - Alpine + + - Installing packages via globbing (``*``) is not available for Alpine, + but it can be simulated with the following command: + + .. code-block:: console + + # apk search isc-kea | sed 's/-[0-9].*//g' | grep r20230921141113 | xargs apk add + +8. All installed packages should be now available directly. + + You can start a server up manually: + + .. code-block:: console + + # kea-dhcp6 -c /etc/kea/kea-dhcp6.conf + + or using systemd: + + .. code-block:: console + + # systemctl restart kea-dhcp6 + + or using OpenRC on Alpine: + + .. code-block:: console + + # service kea-dhcp6 restart + +.. note:: + :iscman:`keactrl` is not available in packages, as similar functionality is provided + by the native systemctl scripts. + +9. On Debian/Ubuntu systems, the service is enabled at boot time automatically + when the package is installed. On Fedora/RHEL and Alpine, the service is not + enabled automatically, so, if desired, it must be enabled manually. + + With systemd on Fedora/RedHat: + + .. code-block:: console + + # systemctl enable kea-dhcp6 + + With OpenRC on Alpine: + + .. code-block:: console + + # rc-update add kea-dhcp6 + + +.. _quick-start-docker: + +Quick Start Guide Using Docker Containers +========================================= + +1. Go to `ISC docker repository on cloudsmith.io <https://cloudsmith.io/~isc/repos/docker/packages/>`__. + +2. Create an ipvlan network attached to the client-facing host interface and + assigned to the subnet that is served by Kea. + +.. code-block:: console + + $ docker network create --driver ipvlan --ipv6 --subnet 2001:db8::/64 --opt parent=eth0 ipvlan0 + +3. Pick the desired image and pull it locally. + +.. code-block:: console + + $ docker pull docker.cloudsmith.io/isc/docker/kea-dhcp6 + + +4. Create a container out of the image. Mount the configuration volume and the + data volume if needed. + +.. code-block:: console + + $ docker create \ + --name kea-dhcp6 \ + --network ipvlan0 \ + --volume /local/kea/config:/etc/kea \ + --volume /local/kea/data:/var/lib/kea \ + docker.cloudsmith.io/isc/docker/kea-dhcp6 + +5. Start the docker container. + +.. code-block:: console + + $ docker start kea-dhcp6 + +6. To stop the docker container, run: + +.. code-block:: console + + $ docker stop kea-dhcp6 + +.. note:: + + Refer to the `kea-docker readme <https://gitlab.isc.org/isc-projects/kea-docker#user-content-docker-files-for-building-kea-containers>`__ for more complex scenarios. + + +.. _quick-start-services: + +Quick Start Guide for DHCPv4 and DHCPv6 Services +================================================ + +1. Edit the Kea configuration files, which by default are installed in + the ``[kea-install-dir]/etc/kea/`` directory. These are: + ``kea-dhcp4.conf``, ``kea-dhcp6.conf``, ``kea-dhcp-ddns.conf`` and + ``kea-ctrl-agent.conf``, ``keactrl.conf`` for DHCPv4 server, DHCPv6 server, + D2, Control Agent, and the keactrl script, respectively. + +2. To start the DHCPv4 server in the background, run the + following command (as root): + + .. code-block:: console + + # keactrl start -s dhcp4 + + Or run the following command to start the DHCPv6 server: + + .. code-block:: console + + # keactrl start -s dhcp6 + + Note that it is also possible to start all servers simultaneously: + + .. code-block:: console + + # keactrl start + +3. Verify that the Kea server(s) is/are running: + + .. code-block:: console + + # keactrl status + + A server status of "inactive" may indicate a configuration error. + Please check the log file (by default named + ``[kea-install-dir]/var/log/kea-dhcp4.log``, + ``[kea-install-dir]/var/log/kea-dhcp6.log``, + ``[kea-install-dir]/var/log/kea-ddns.log``, or + ``[kea-install-dir]/var/log/kea-ctrl-agent.log``) for the details of + any errors. + +4. If the server has started successfully, test that it is + responding to DHCP queries and that the client receives a + configuration from the server; for example, use the `ISC DHCP + client <https://www.isc.org/download/>`__. + +5. To stop running the server(s): + + .. code-block:: console + + # keactrl stop + +For system-specific instructions, please read the +`system-specific notes <https://kb.isc.org/docs/installing-kea>`__, +available in the Kea section of `ISC's +Knowledgebase <https://kb.isc.org/docs>`__. + +The details of :iscman:`keactrl` script usage can be found in :ref:`keactrl`. + +Once Kea services are up and running, consider deploying a dashboard solution +to monitor running services. For more details, see :ref:`stork`. + +.. _quick-start-direct-run: + +Running the Kea Servers Directly +================================ + +The Kea servers can be started directly, without the need to use +:iscman:`keactrl` or ``systemctl``. To start the DHCPv4 server run the following command: + +.. code-block:: console + + # kea-dhcp4 -c /path/to/your/kea4/config/file.json + +Similarly, to start the DHCPv6 server, run the following command: + +.. code-block:: console + + # kea-dhcp6 -c /path/to/your/kea6/config/file.json diff --git a/doc/sphinx/arm/rst_arm_sources.mk b/doc/sphinx/arm/rst_arm_sources.mk new file mode 100644 index 0000000..dc2cf45 --- /dev/null +++ b/doc/sphinx/arm/rst_arm_sources.mk @@ -0,0 +1,54 @@ +rst_arm_sources += arm/acknowledgments.rst +rst_arm_sources += arm/admin.rst +rst_arm_sources += arm/agent.rst +rst_arm_sources += arm/classify.rst +rst_arm_sources += arm/config-backend.rst +rst_arm_sources += arm/config-templates.rst +rst_arm_sources += arm/config.rst +rst_arm_sources += arm/congestion-handling.rst +rst_arm_sources += arm/ctrl-channel.rst +rst_arm_sources += arm/database-connectivity.rst +rst_arm_sources += arm/ddns.rst +rst_arm_sources += arm/dhcp4-srv.rst +rst_arm_sources += arm/dhcp6-srv.rst +rst_arm_sources += arm/ext-gss-tsig.rst +rst_arm_sources += arm/ext-netconf.rst +rst_arm_sources += arm/ext-radius.rst +rst_arm_sources += arm/hammer.rst +rst_arm_sources += arm/hooks-bootp.rst +rst_arm_sources += arm/hooks-cb-cmds.rst +rst_arm_sources += arm/hooks-class-cmds.rst +rst_arm_sources += arm/hooks-ddns-tuning.rst +rst_arm_sources += arm/hooks-flex-id.rst +rst_arm_sources += arm/hooks-flex-option.rst +rst_arm_sources += arm/hooks-gss-tsig.rst +rst_arm_sources += arm/hooks-ha.rst +rst_arm_sources += arm/hooks-host-cache.rst +rst_arm_sources += arm/hooks-host-cmds.rst +rst_arm_sources += arm/hooks-lease-cmds.rst +rst_arm_sources += arm/hooks-lease-query.rst +rst_arm_sources += arm/hooks-limits.rst +rst_arm_sources += arm/hooks-cb-mysql.rst +rst_arm_sources += arm/hooks-cb-pgsql.rst +rst_arm_sources += arm/hooks-legal-log.rst +rst_arm_sources += arm/hooks-perfmon.rst +rst_arm_sources += arm/hooks-ping-check.rst +rst_arm_sources += arm/hooks-radius.rst +rst_arm_sources += arm/hooks-rbac.rst +rst_arm_sources += arm/hooks-run-script.rst +rst_arm_sources += arm/hooks-stat-cmds.rst +rst_arm_sources += arm/hooks-subnet-cmds.rst +rst_arm_sources += arm/hooks-user-chk.rst +rst_arm_sources += arm/hooks.rst +rst_arm_sources += arm/install.rst +rst_arm_sources += arm/integrations.rst +rst_arm_sources += arm/intro.rst +rst_arm_sources += arm/keactrl.rst +rst_arm_sources += arm/lease-expiration.rst +rst_arm_sources += arm/lfc.rst +rst_arm_sources += arm/logging.rst +rst_arm_sources += arm/quickstart.rst +rst_arm_sources += arm/security.rst +rst_arm_sources += arm/shell.rst +rst_arm_sources += arm/stats.rst +rst_arm_sources += arm/stork.rst diff --git a/doc/sphinx/arm/security.rst b/doc/sphinx/arm/security.rst new file mode 100644 index 0000000..3063fb0 --- /dev/null +++ b/doc/sphinx/arm/security.rst @@ -0,0 +1,445 @@ +.. _security: + +************ +Kea Security +************ + +Kea was originally designed to be installed in a protected environment, in a network +datacenter; it did not offer hardened security features. However, due to customer demand +and evolving network requirements, support for basic HTTP authentication and Transport +Layer Security (TLS) have been added to Kea. + +.. _tls: + +TLS/HTTPS Support +================= + +Since Kea 1.9.6, TLS can be used to secure HTTP communication. There are three levels of +protection possible: + +- No TLS. The connection is plain-text, unencrypted HTTP. (This is + the only option available in versions prior to Kea 1.9.6.) + +- Encryption, which protects against passive attacks and + eavesdropping. In this case, the server is authenticated but the client is + not. This is the typical mode when securing a website, where + clients and servers are not under the control of a common entity. + +- Mutual authentication between the client and the server. This is the + strictest security mode and is the default when TLS is + enabled. + +.. note:: + + TLS mutual authentication is for TLS entities only. When TLS and + an HTTP authentication scheme are used together, there is no binding between + the two security mechanisms, and therefore no proof that the TLS client and server + are the same as the HTTP authentication client and server. + +.. _tls_config: + +Building Kea with TLS/HTTPS Support +----------------------------------- + +TLS/HTTPS support is available with either the OpenSSL or the Botan +cryptographic library. There are some constraints on the Boost library +that must be used: + +- OpenSSL versions older than 1.0.2 are obsolete and should not be used. + Kea TLS support has not been tested with and is not supported on these versions. + +- OpenSSL version 1.0.2 has extended support, but only for OpenSSL premium + customers. Kea TLS support has been tested but is not supported on this version. + +- OpenSSL versions 1.1.x and later have been tested and are supported. Many + recent operating system versions include TLS 1.3 support. + +- OpenSSL 3.x has been released and Kea will build with it. + +- LibreSSL 3.2.4 has been tested. LibreSSL shares the OpenSSL 1.0.2 API, so + it should work, but is not supported. + +- Botan 1.x versions are obsolete and should not be used. + Kea TLS support has not been tested and is not supported with these versions. + +- Botan versions 2.14.0 and later have been tested and are supported. Kea TLS + support requires the four Asio header files which are included in Botan + packages and which are installed only if Botan is configured with the + ``--with-boost`` option. + + Many packages provided by operating systems, such as Ubuntu 20.10, + do not build Botan with Boost support, making those packages + unusable for Kea with TLS. + + It is still possible to take these files from the corresponding + Botan distribution and install them manually in the Botan include + directory, but this should be a last-resort procedure. + + Without these header files, or with a Botan version prior + to 2.14.0, Kea can still build, but the TLS/HTTPS support is disabled; + any attempt to use it will fail with a fatal error. + +- Very old Boost versions provide SSL support (based on OpenSSL) + without offering a choice of the TLS version; Kea can still use them, + but they are not recommended. + +- Boost versions prior to 1.64 provide SSL support with a fixed + choice of the TLS version; Kea enforces the use of TLS 1.2 with them. + +- Boost versions 1.64 or newer provide SSL support with a generic + TLS version; the best (highest) version available on both peers is + selected. + +TLS/HTTPS Configuration +----------------------- + +The TLS configuration parameters are: + +- ``trust-anchor`` - this string parameter specifies the name of a file + or directory where the certification authority (CA) certificate of + the other peer can be found. With OpenSSL, the directory must include + hash symbolic links. With Botan, the directory is recursively + searched for certificates. + +- ``cert-file`` - this string parameter specifies the name of the file + containing the end-entity certificate of the Kea instance + being configured. + +- ``key-file`` - this string parameter specifies the private key of the + end-entity certificate of the Kea instance being configured. + The file must not be encrypted; it is highly recommended to + restrict its access. + +The three string parameters must be either all unspecified (TLS disabled) +or all specified (TLS enabled). + +TLS is asymmetric: the authentication of the server by the client is +mandatory but the authentication of the client by the server is optional. +In TLS terms, this means the server may require the client certificate, or +may not; there is a server-specific TLS parameter. + +- ``cert-required`` - this boolean parameter allows a server to not + require the client certificate. Its default value is ``true``, which + means the client certificate is required and the + client must be authenticated. This flag has no meaning on the client side; the server + always provides a certificate which is validated by the client. + +Objects in files must be in the PEM format. Files can contain more +than one certificate, but this has not been tested and is not supported. + +Botan requires CA certificates to have the standard CA certificate +attributes, verifies that end-entity certificates are version 3 +certificates (as required by the TLS standard), and supports only PKCS 8 +files for the private key. + +.. note:: + + Some cryptographic libraries (e.g. Botan and recent OpenSSL) enforce + minimal strength (i.e. key length), e.g. at least 2048 for RSA. + +A sample set of certificates and associated objects is available at +``src/lib/asiolink/testutils/ca`` in the Kea sources, with a ``doc.txt`` file +explaining how they were generated using the ``openssl`` command. These +files are for testing purposes only. **Do not use them in production.** + +TLS handshake, the phase where the cryptographic parameters are exchanged +and authentication is verified, can fail in multiple ways. Error messages +often do not help to pinpoint the source of the problem. +Both OpenSSL and Botan provide a command-line tool with a ``verify`` command +which can be used to understand and fix handshake issues. + +OpenSSL Tuning +-------------- + +Kea accepts the default OpenSSL configuration parameters, but administrators can +also fine-tune the OpenSSL settings. For example, it may be desirable to limit +the TLS version. + +The default OpenSSL configuration file is named ``openssl.cnf``. It can +be found in a system-dependent ``etc`` directory, and the location can be overridden +using the ``OPENSSL_CONF`` environment variable. For OpenSSL versions greater than +1.0.2, the minimum acceptable protocol can be set via the ``MinProtocol`` variable. + +For these examples, we assume that no variables are already set and no sections already +exist; it is, of course, possible to reuse existing variables and sections. + +In the default application, ``openssl_conf``, the corresponding variable +must be set to the name of the section that handles defaults: in this example, +``default_conf``. If ``openssl_conf`` is not yet set, add this command +at the beginning of the OpenSSL configuration file (before the first +section): + +.. code-block:: ini + + openssl_conf = default_conf + +In the ``default_conf`` section, the ``ssl_conf`` variable must be set +to the name of the section that handles SSL/TLS defaults: in this +example, ``ssl_sect``. + +.. code-block:: ini + + [ default_conf ] + ssl_conf = ssl_sect + +In the ``ssl_sect`` section, the ``system_default`` variable must be +set to the name of the section that handles system defaults: in +this example, ``system_default_sect``. + +.. code-block:: ini + + [ ssl_sect ] + system_default = system_default_sect + +In the ``system_default_sect`` section, the ``MinProtocol`` variable must be +set to the desired minimal SSL/TLS version: in this example, ``TLSv1.2``. + +.. code-block:: ini + + [ system_default_sect ] + MinProtocol = TLSv1.2 + +The same steps can be used to enforce other crypto parameters if +desired. + +It is highly recommended to read the ``openssl.cnf`` manual page, +normally called ``config.5ssl`` and displayed using ``man config``. + +Securing a Kea Deployment +========================= + +Below is a list of considerations for administrators wishing to improve Kea's +security. In many cases, there are trade-offs between convenience and security. + +Component-Based Design +---------------------- + +The Kea architecture is modular, with separate daemons for separate tasks. +A Kea deployment may include DHCPv4, DHCPv6, and Dynamic DNS daemons; a Control Agent +daemon run on each application server; the ``kea-lfc utility`` for doing periodic lease +file cleanup; MySQL and or PostgreSQL databases, run either locally on the application +servers or accessed over the internal network; and a Stork monitoring system. +This modular architecture allows the administrator to minimize the attack surface +by minimizing the code that is loaded and running. +For example, :iscman:`kea-dhcp-ddns` should not be run unless DNS updates are required. +Similarly, :iscman:`kea-lfc` is never triggered (and can be safely removed or never installed) if memfile is not used. +Potential Kea security issues can be minimized by running only those processes required in the local environment. + +Limiting Application Permissions +-------------------------------- + +The DHCPv4 and DHCPv6 protocols assume the server opens privileged UDP port 67 +(DHCPv4) or 547 (DHCPv6), which requires root access under normal circumstances. However, via the +capabilities mechanism on Linux systems, Kea can run from an unprivileged account. See +:ref:`non-root` for details on how to run Kea without root access. + +The Control Agent (CA) can accept incoming HTTP or HTTPS connections. The default port is 8000, which +does not require privileged access. + +Securing Kea Administrative Access +---------------------------------- + +The three primary Kea daemons (:iscman:`kea-dhcp4`, :iscman:`kea-dhcp6` and :iscman:`kea-dhcp-ddns`) all support a control +channel, which is implemented as a UNIX socket. The control channel, which opens a UNIX socket, is disabled by default; +however, many configuration examples have it enabled, as it is a very popular feature. To +read from or write to this socket, root access is generally required, although if Kea is configured +to run as non-root, the owner of the process can write to it. Access can be controlled using normal +file-access control on POSIX systems (owner, group, others, read/write). + +Kea configuration is controlled by a JSON file on the Kea server. This file can be viewed or edited +by anyone with file permissions (which are controlled by the operating system). Note that +passwords are stored in clear text in the configuration file, so anyone with access to read the +configuration file can find this information. As a practical matter, anyone with permission to edit +the configuration file has control over Kea. +Limiting user permission to read or write the Kea configuration file is an important security step. + +Securing Database Connections +----------------------------- + +Kea can use an external MySQL or PostgreSQL database to store configuration, host reservations, +or/and leases, or/and for forensic logging. The use of databases is a popular feature, but it is optional; +it is also possible to store data in a flat file on disk. + +When using a database, Kea stores and uses the following credentials to authenticate with the database: +username, password, host, port, and database name. **These are stored in clear text +in the configuration file.** + +Depending on the database configuration, it is also possible to verify whether the system user matches the +database username. Consult the MySQL or PostgreSQL manual for details. + +Information Leakage Through Logging +----------------------------------- + +It is possible for Kea to log an entire configuration file, including passwords and secrets. +Since Kea 1.9.7, this issue has been resolved by replacing the value of all entries ending in +``password`` or ``secret`` with asterisks, as was already done for database logs. + +Logs are sent to stdout, stderr, files, or syslog; system file permissions system apply to +stdout/stderr and files. Syslog may export the logs over the network, exposing them further to possible snooping. + +Cryptography Components +----------------------- + +Kea supports the use of either of two cryptographic libraries: Botan or OpenSSL. +The choice is made at compile time, and creates both compile and runtime dependencies +between the Kea and the selected library. While OpenSSL is the most popular choice for +deployments, Botan remains a fully supported alternative. + +The primary use cases for the cryptographic libraries are: + +- TLS support for the Control Agent (CA), introduced in Kea 1.9.6. +- TSIG signatures when sending DNS updates. +- calculating DHCID records when sending DNS updates. +- random number generation (but not for usage requiring a crypto grade generator). + +For OpenSSL and Botan, only the low-level crypto interface is used (e.g. libcrypto). Kea does not link +with libssl. Some dependent software systems, such as database client libraries, can also depend on a crypto +library. + +One way to limit exposure for potential OpenSSL or Botan vulnerabilities is not to use DDNS. The +libraries would still be needed to build and run Kea, but the code would never be used, so any +potential bugs in the libraries would not be exploitable. + +TSIG Signatures +--------------- + +Kea supports the following algorithms when signing DNS updates with TSIG signatures: + +- HMAC-MD5 +- HMAC-SHA1 +- HMAC-SHA224 +- HMAC-SHA256 +- HMAC-SHA384 +- HMAC-SHA512 + +See :ref:`d2-tsig-key-list-config` for an up-to-date list. + +Kea uses SHA256 to calculate DHCID records. This is irrelevant from the cryptography perspective, as +the DHCID record is only used to generate unique identifiers for two devices that may have been +assigned the same IP address at different times. + +Raw Socket Support +------------------ + +In principle, Kea DHCPv4 uses raw sockets to receive traffic from clients. The difficulty is with +receiving packets from devices that do not yet have an IPv4 address. When dealing with direct traffic +(where both client and server are connected to the same link, not separated by relays), the kernel +normally drops the packet as the source IP address is 0.0.0.0. Therefore, Kea needs to open raw +sockets to be able to receive this traffic. + +However, this is not necessary if all the traffic is coming via relays, which is often the case in +many networks. In that case normal UDP sockets can be used instead. There is a ``dhcp-socket-type`` +parameter that controls this behavior. + +The default is to permit raw socket usage, as it is more versatile. + +When using raw sockets, Kea is able to receive raw layer 2 packets, bypassing most firewalls +(including iptables). This effectively means that when raw sockets are used, the iptables cannot be +used to block DHCP traffic. This is a design choice of the Linux kernel. + +Kea can be switched to use UDP sockets. This is an option when all traffic is relayed. +However, it does not work for directly connected devices. If Kea is limited to UDP sockets, +iptables should work properly. + +If raw sockets are not required, disabling this access can improve security. + +Remote Administrative Access +---------------------------- + +Kea's Control Agent (CA) exposes a RESTful API over HTTP or HTTPS (HTTP over TLS). The CA is an +optional feature that is disabled by default, but it is very popular. When enabled, it listens on the +loopback address (127.0.0.1 or ::1) by default, unless configured otherwise. See :ref:`tls` +for information about protecting the TLS traffic. Limiting the incoming connections with a firewall, such as +iptables, is generally a good idea. + +Note that in High Availability (HA) deployments, DHCP partners connect to each other using a CA +connection. + +Authentication for Kea's RESTful API +------------------------------------ + +Kea 1.9.0 added support for basic HTTP authentication (`RFC 7617 <https://tools.ietf.org/html/rfc7617>`_), +to control access for incoming REST commands over HTTP. The credentials (username, password) are +stored in a local Kea configuration file on disk. The username is logged with the API command, so it +is possible to determine which authenticated user performed each command. The access control details +are logged using a dedicated ``auth`` logger. Basic HTTP +authentication is weak on its own as there are known dictionary attacks, but those attacks require +a "man in the middle" to get access to the HTTP traffic. That can be eliminated by using basic HTTP +authentication exclusively over TLS. In fact, if possible, using client certificates for TLS is better than +using basic HTTP authentication. + +Kea 1.9.2 introduced a new ``auth`` hook point. With this new hook point, it is possible to develop an external +hook library to extend the access controls, integrate with another authentication authority, or add role-based +access control to the Control Agent. + +Kea Security Processes +====================== + +The following sections discuss how the Kea DHCP development team ensures code quality and handles vulnerabilities. + +Vulnerability Handling +---------------------- + +ISC is an experienced and active participant in the industry-standard vulnerability disclosure +process and maintains accurate documentation on our process and vulnerabilities in ISC software. +See https://kb.isc.org/docs/aa-00861 for ISC's Software Defect and Security Vulnerability Disclosure Policy. + +In case of a security vulnerability in Kea, ISC notifies support customers ahead of any public +disclosure, and provides a patch and/or updated installer package to remediate the +vulnerability. + +When a security update is published, both the source tarballs and the ISC-maintained packages are +published on the same day. This enables users of the native Linux update mechanisms (such as +Debian's and Ubuntu's apt or RedHat's dnf) to update their systems promptly. + +Code Quality and Testing +------------------------ + +Kea undergoes extensive tests during its development. The following are some of the +processes that are used to ensure adequate code quality: + +- Each line of code goes through a formal review before it is accepted. The review process is + documented and available publicly. +- Roughly 50% of the source code is dedicated to unit tests. As of December 2020, there were over 6000 + unit tests and the number is increasing with time. Unit tests are required to commit any new feature. +- There are around 1500 system tests for Kea. These simulate both correct and invalid + situations, covering network packets (mostly DHCP, but also DNS, HTTP, HTTPS and others), + command-line usage, API calls, database interactions, scripts, and more. +- There are performance tests with over 80 scenarios that test Kea overall performance and + resiliency to various levels of traffic, and measuring various metrics (latency, leases per seconds, + packets per seconds, CPU usage, memory utilization, and others). +- Kea uses Continuous Integration (CI). This means that the great majority of tests (all unit and system + tests, and in some cases also performance tests) are run for every commit. Many "lighter" tests are + run on branches, before the code is even accepted. +- Many unit and system tests check for negative scenarios, such as incomplete, + broken, or truncated packets, API commands, and configuration files, as well as incorrect sequences (such as sending + packets in an invalid order) and more. +- The Kea development team uses many tools that perform automatic code quality checks, such as danger, as well as + internally developed sanity checkers. +- The Kea team uses the following static code analyzers: Coverity Scan, shellcheck, and danger. +- The Kea team uses the following dynamic code analyzers: Valgrind and Thread Sanitizer (TSAN). + +Fuzz Testing +------------ + +The Kea team has a process for running fuzz testing, using `AFL <https://github.com/google/AFL>`_. There +are two modes which are run: the first mode fuzzes incoming packets, effectively throwing millions of mostly +broken packets at Kea per day, while the second mode fuzzes configuration structures and forces Kea to +attempt to load them. Kea has been fuzzed since around 2018 in both modes. The input seeds +(the data being used to generate or "fuzz" other input) are changed periodically. + +Release Integrity +----------------- + +All ISC software releases are signed with PGP and distributed via the ISC website, which is itself +DNSSEC-signed, so users can be confident the software has not been tampered with. + +Bus Factor +---------- + +According to the `Core Infrastructure project <https://bestpractices.coreinfrastructure.org/>`_, a "bus +factor" or "truck factor" is the minimum number of project members that have to suddenly disappear +from a project ("be hit by a bus") before the project stalls due to lack of knowledgeable or competent +personnel. It is hard to estimate precisely, but the bus factor for Kea is somewhere around five. As of +2021, there are six core developers and two quality assurance engineers, with many additional casual +contributors (product manager, support team, IT, etc.). The team is geographically dispersed. diff --git a/doc/sphinx/arm/shell.rst b/doc/sphinx/arm/shell.rst new file mode 100644 index 0000000..62a9900 --- /dev/null +++ b/doc/sphinx/arm/shell.rst @@ -0,0 +1,165 @@ +.. _kea-shell: + +************* +The Kea Shell +************* + +.. _shell-overview: + +Overview of the Kea Shell +========================= + +The Kea Control Agent (CA, see +:ref:`kea-ctrl-agent`) provides a RESTful control interface +over HTTP. That API is typically expected to be used by various IPAMs +and similar management systems. Nevertheless, there may be cases when an +administrator wants to send a command to the CA directly, and the Kea shell +provides a way to do this. It is a simple command-line, +scripting-friendly, text client that is able to connect to the CA, send +it commands with parameters, retrieve the responses, and display them. + +As the primary purpose of the Kea shell is as a tool in a scripting +environment, it is not interactive. However, by following simple guidelines it can +be run manually. + +Kea 1.9.0 introduced basic HTTP authentication support. + +Shell Usage +=========== + +:iscman:`kea-shell` is run as follows: + +.. code-block:: console + + $ kea-shell [--host hostname] [--port number] [--path path] [--auth-user] [--auth-password] [--timeout seconds] [--service service-name] [command] + +where: + +- ``--host hostname`` specifies the hostname of the CA. If not + specified, "localhost" is used. + +- ``--port number`` specifies the TCP port on which the CA listens. If + not specified, 8000 is used. + +- ``--path path`` specifies the path in the URL to connect to. If not + specified, an empty path is used. As the CA listens at the empty + path, this parameter is useful only with a reverse proxy. + +- ``--auth-user`` specifies the user ID for basic HTTP authentication. + If not specified or specified as the empty string, authentication is + not used. + +- ``--auth-password`` specifies the password for basic HTTP authentication. + If not specified but the user ID is specified, an empty password is used. + +- ``--timeout seconds`` specifies the timeout (in seconds) for the + connection. If not given, 10 seconds is used. + +- ``--service service-name`` specifies the target of a command. If not + given, the CA is used as the target. This may be used more than once + to specify multiple targets. + +- ``command`` specifies the command to be sent. If not specified, the + :isccmd:`list-commands` command is used. + +Other switches are: + +- ``-h`` - prints a help message. + +- ``-v`` - prints the software version. + +See :ref:`shell-tls` for new command-line arguments associated with TLS/HTTPS support. + +Once started, the shell reads the parameters for the command from standard +input, which are expected to be in JSON format. When all have been read, +the shell establishes a connection with the CA using HTTP, sends the +command, and awaits a response. Once that is received, it is displayed +on standard output. + +For a list of available commands, see :ref:`ctrl-channel`; +additional commands may be provided by hook libraries. For a list of +all supported commands from the CA, use the :isccmd:`list-commands` command. + +The following shows a simple example of usage: + +.. code-block:: console + + $ kea-shell --host 192.0.2.1 --port 8001 --service dhcp4 list-commands + ^D + +After the command line is entered, the program waits for command +parameters to be entered. Since :isccmd:`list-commands` does not take any +arguments, Ctrl-D (represented in the above example by "^D") +indicates end-of-file and terminates the parameter input. The shell +then contacts the CA and prints out the list of available commands +returned for the service named ``dhcp4``. + +The Kea shell will likely be most frequently used in +scripts; the next example shows a simple scripted execution. It sends +the command :isccmd:`config-write` to the CA (the ``--service`` parameter has not +been used), along with the parameters specified in param.json. The +result will be stored in result.json. + +.. code-block:: console + + $ cat param.json + "filename": "my-config-file.json" + $ cat param.json | kea-shell --host 192.0.2.1 config-write > result.json + +When a reverse proxy is used to de-multiplex requests to different +servers, the default empty path in the URL is not enough, so the +``--path`` parameter should be used. For instance, if requests to the +"/kea" path are forwarded to the CA this can be used: + +.. code-block:: console + + $ kea-shell --host 192.0.2.1 --port 8001 --path kea ... + +The Kea shell requires Python to be installed on the system. It has been +tested with various versions of Python 3, up to 3.5. +Since not every Kea deployment uses this feature and there are +deployments that do not have Python, the Kea shell is not enabled by +default. To use it, specify ``--enable-shell`` when running ``configure`` +during the installation of Kea. When building on Debian systems, +``--with-site-packages=...`` may also be useful. + +.. note:: + + From Kea 2.4.0 version, the :iscman:`kea-shell` no longer supports Python 2.7. + +The Kea shell is intended to serve more as a demonstration of the +RESTful interface's capabilities (and, perhaps, an illustration for +people interested in integrating their management environments with Kea) +than as a serious management client. It is not likely to be +significantly expanded in the future; it is, and will remain, a simple +tool. + +.. note:: + + When using this tool with basic HTTP authentication, please keep in + mind that command-line arguments are not hidden from local users. + +.. _shell-tls: + +TLS Support +=========== + +Since Kea 1.9.6, :iscman:`kea-shell` supports HTTPS connections. The TLS/HTTPS +support requires Python 3. The additional command-line arguments are: + +- ``--ca`` specifies the file or directory name of the Certification + Authority. If not specified, HTTPS is not used. + +- ``--cert`` specifies the file name of the user end-entity public key + certificate. If specified, the file name of the user key must also be specified. + +- ``--key`` specifies the file name of the user key file. If specified, + the file name of the user certificate must also be specified. + Encrypted key files are not supported. + +For example, a basic HTTPS request to get a list of commands could +look like this: + +.. code-block:: console + + $ kea-shell --host 127.0.0.1 --port 8000 --ca ./kea-ca.crt list-commands diff --git a/doc/sphinx/arm/stats.rst b/doc/sphinx/arm/stats.rst new file mode 100644 index 0000000..b37b37a --- /dev/null +++ b/doc/sphinx/arm/stats.rst @@ -0,0 +1,1043 @@ +.. _stats: + +********** +Statistics +********** + +Statistics Overview +=================== + +Both Kea DHCP servers support statistics gathering. A working DHCP +server encounters various events that can cause certain statistics to be +collected. For example, a DHCPv4 server may receive a packet +(the ``pkt4-received`` statistic increases by one) that after parsing is +identified as a DHCPDISCOVER (``pkt4-discover-received``). The server +processes it and decides to send a DHCPOFFER representing its answer +(the ``pkt4-offer-sent`` and ``pkt4-sent statistics`` increase by one). Such +events happen frequently, so it is not uncommon for the statistics to have +values in the high thousands. They can serve as an easy and powerful +tool for observing a server's and a network's health. For example, if +the ``pkt4-received`` statistic stops growing, it means that the clients' +packets are not reaching the server. + +There are four types of statistics: + +- *integer* - this is the most common type. It is implemented as a + 64-bit integer (int64_t in C++), so it can hold any value between + -2^63 to 2^63-1. + +- *big integer* - this type is inteded for holding large numbers. It is + implemented as a 128-bit integer (boost::multiprecision::int128_t in C++), so + it can hold any value between -2^127 to 2^127-1. + +- *floating point* - this type is intended to store floating-point + precision. It is implemented as a C++ double type. + +- *duration* - this type is intended for recording time periods. It + uses the \`boost::posix_time::time_duration type, which stores hours, + minutes, seconds, and microseconds. + +- *string* - this type is intended for recording statistics in text + form. It uses the C++ std::string type. + +During normal operation, the DHCPv4 and DHCPv6 servers gather +statistics. For a list of DHCPv4 and DHCPv6 statistics, see +:ref:`dhcp4-stats` and :ref:`dhcp6-stats`, respectively. + +To extract data from the statistics module, the control channel can be +used. See :ref:`ctrl-channel` for details. It is possible to +retrieve a single statistic or all statistics, reset the statistics (i.e. +set them to a neutral value, typically zero), or even completely remove a +single statistic or all statistics. See the section :ref:`command-stats` +for a list of statistics-oriented commands. + +Statistics can be used by external tools to monitor Kea. One example of such a tool is Stork. +See :ref:`stork` for details on how to use it and other data sources to retrieve statistics periodically +to get better insight into Kea's health and operational status. + +.. _stats-lifecycle: + +Statistics Lifecycle +==================== + +All of the statistics supported by Kea's servers are initialized upon the servers' startup +and are returned in response to the commands such as +:isccmd:`statistic-get-all`. The runtime statistics concerning DHCP packets +processed are initially set to 0 and are reset upon the server +restart. + +Per-subnet statistics are recalculated when reconfiguration takes place. + +In general, once a statistic is initialized it is held in the manager until +explicitly removed, via :isccmd:`statistic-remove` or +:isccmd:`statistic-remove-all`, +or when the server is shut down. + +Removing a statistic that is updated frequently makes little sense, as +it will be re-added when the server code next records that statistic. +The :isccmd:`statistic-remove` and +:isccmd:`statistic-remove-all` commands are +intended to remove statistics that are not expected to be observed in +the near future. For example, a misconfigured device in a network may +cause clients to report duplicate addresses, so the server will report +increasing values of ``pkt4-decline-received``. Once the problem is found +and the device is removed, the system administrator may want to remove +the ``pkt4-decline-received`` statistic so that it is no longer reported, until +and unless a duplicate address is again detected. + +.. isccmd:: stats +.. _command-stats: + +Commands for Manipulating Statistics +==================================== + +There are several commands defined that can be used for accessing +(``-get``), resetting to zero or a neutral value (``-reset``), or removing a +statistic completely (``-remove``). The statistics time-based +limit (``-sample-age-set``) and size-based limit (``-sample-count-set``), which +control how long or how many samples of a given statistic are retained, can also +be changed. + +The difference between ``-reset`` and ``-remove`` is somewhat subtle. +The ``-reset`` command sets the value of the statistic to zero or a neutral value, +so that after this operation, the statistic has a value of 0 (integer), +0.0 (float), 0h0m0s0us (duration), or "" (string). +When requested, a statistic with the values mentioned is returned. +``-remove`` removes a statistic completely, so the statistic is no longer +reported. However, the server code may add it back if there is a reason +to record it. + +.. note:: + + The following sections describe commands that can be sent to the + server; the examples are not fragments of a configuration file. For + more information on sending commands to Kea, see + :ref:`ctrl-channel`. + +.. isccmd:: statistic-get +.. _command-statistic-get: + +The ``statistic-get`` Command +----------------------------- + +The :isccmd:`statistic-get` command retrieves a single statistic. It takes a +single-string parameter called ``name``, which specifies the statistic +name. An example command may look like this: + +:: + + { + "command": "statistic-get", + "arguments": { + "name": "pkt4-received" + } + } + +The server returns details of the requested statistic, with a result of +0 indicating success and the specified statistic as the value of the +``arguments`` parameter. If the requested statistic is not found, the +response contains an empty map, i.e. only { } as an argument, but +the status code still indicates success (0). + +Here is an example response: + +:: + + { + "command": "statistic-get", + "arguments": { + "pkt4-received": [ [ 125, "2019-07-30 10:11:19.498739" ], [ 100, "2019-07-30 10:11:19.498662" ] ] + }, + "result": 0 + } + +.. isccmd:: statistic-reset +.. _command-statistic-reset: + +The ``statistic-reset`` Command +------------------------------- + +The :isccmd:`statistic-reset` command sets the specified statistic to its +neutral value: 0 for integer, 0.0 for float, 0h0m0s0us for time +duration, and "" for string type. It takes a single-string parameter +called ``name``, which specifies the statistic name. An example command +may look like this: + +:: + + { + "command": "statistic-reset", + "arguments": { + "name": "pkt4-received" + } + } + +If the specific statistic is found and the reset is successful, the +server responds with a status of 0, indicating success, and an empty +parameters field. If an error is encountered (e.g. the requested +statistic was not found), the server returns a status code of 1 (error) +and the text field contains the error description. + +.. isccmd:: statistic-remove +.. _command-statistic-remove: + +The ``statistic-remove`` Command +-------------------------------- + +The :isccmd:`statistic-remove` command deletes a single statistic. It +takes a single-string parameter called ``name``, which specifies the +statistic name. An example command may look like this: + +:: + + { + "command": "statistic-remove", + "arguments": { + "name": "pkt4-received" + } + } + +If the specific statistic is found and its removal is successful, the +server responds with a status of 0, indicating success, and an empty +parameters field. If an error is encountered (e.g. the requested +statistic was not found), the server returns a status code of 1 (error) +and the text field contains the error description. + +.. isccmd:: statistic-get-all +.. _command-statistic-get-all: + +The ``statistic-get-all`` Command +--------------------------------- + +The :isccmd:`statistic-get-all` command retrieves all statistics recorded. An +example command may look like this: + +:: + + { + "command": "statistic-get-all", + "arguments": { } + } + +The server responds with details of all recorded statistics, with a +result set to 0 to indicate that it iterated over all statistics (even +when the total number of statistics is zero). + +Here is an example response returning all collected statistics: + +:: + + { + "command": "statistic-get-all", + "arguments": { + "cumulative-assigned-addresses": [ + [ + 0, + "2023-06-13 20:42:46.836166" + ] + ], + "declined-addresses": [ + [ + 0, + "2023-06-13 20:42:46.836156" + ] + ], + "pkt4-ack-received": [ + [ + 0, + "2023-06-13 20:42:46.616247" + ] + ], + "pkt4-ack-sent": [ + [ + 0, + "2023-06-13 20:42:46.616290" + ] + ], + "pkt4-decline-received": [ + [ + 0, + "2023-06-13 20:42:46.616296" + ] + ], + "pkt4-discover-received": [ + [ + 0, + "2023-06-13 20:42:46.616303" + ] + ], + "pkt4-inform-received": [ + [ + 0, + "2023-06-13 20:42:46.616308" + ] + ], + "pkt4-nak-received": [ + [ + 0, + "2023-06-13 20:42:46.616312" + ] + ], + "pkt4-nak-sent": [ + [ + 0, + "2023-06-13 20:42:46.616314" + ] + ], + "pkt4-offer-received": [ + [ + 0, + "2023-06-13 20:42:46.616318" + ] + ], + "pkt4-offer-sent": [ + [ + 0, + "2023-06-13 20:42:46.616323" + ] + ], + "pkt4-parse-failed": [ + [ + 0, + "2023-06-13 20:42:46.616326" + ] + ], + "pkt4-receive-drop": [ + [ + 0, + "2023-06-13 20:42:46.616330" + ] + ], + "pkt4-received": [ + [ + 0, + "2023-06-13 20:42:46.616335" + ] + ], + "pkt4-release-received": [ + [ + 0, + "2023-06-13 20:42:46.616339" + ] + ], + "pkt4-request-received": [ + [ + 0, + "2023-06-13 20:42:46.616343" + ] + ], + "pkt4-sent": [ + [ + 0, + "2023-06-13 20:42:46.616348" + ] + ], + "pkt4-unknown-received": [ + [ + 0, + "2023-06-13 20:42:46.616354" + ] + ], + "reclaimed-declined-addresses": [ + [ + 0, + "2023-06-13 20:42:46.836159" + ] + ], + "reclaimed-leases": [ + [ + 0, + "2023-06-13 20:42:46.836163" + ] + ], + "subnet[1].assigned-addresses": [ + [ + 0, + "2023-06-13 20:42:46.836173" + ] + ], + "subnet[1].cumulative-assigned-addresses": [ + [ + 0, + "2023-06-13 20:42:46.836098" + ] + ], + "subnet[1].declined-addresses": [ + [ + 0, + "2023-06-13 20:42:46.836178" + ] + ], + "subnet[1].pool[0].assigned-addresses": [ + [ + 0, + "2023-06-13 20:42:46.836205" + ] + ], + "subnet[1].pool[0].cumulative-assigned-addresses": [ + [ + 0, + "2023-06-13 20:42:46.836137" + ] + ], + "subnet[1].pool[0].declined-addresses": [ + [ + 0, + "2023-06-13 20:42:46.836213" + ] + ], + "subnet[1].pool[0].reclaimed-declined-addresses": [ + [ + 0, + "2023-06-13 20:42:46.836225" + ] + ], + "subnet[1].pool[0].reclaimed-leases": [ + [ + 0, + "2023-06-13 20:42:46.836236" + ] + ], + "subnet[1].pool[0].total-addresses": [ + [ + 11010049, + "2023-06-13 20:42:46.836128" + ] + ], + "subnet[1].reclaimed-declined-addresses": [ + [ + 0, + "2023-06-13 20:42:46.836186" + ] + ], + "subnet[1].reclaimed-leases": [ + [ + 0, + "2023-06-13 20:42:46.836194" + ] + ], + "subnet[1].total-addresses": [ + [ + 11010049, + "2023-06-13 20:42:46.836083" + ] + ], + "subnet[1].v4-lease-reuses": [ + [ + 0, + "2023-06-13 20:42:46.836105" + ] + ], + "subnet[1].v4-reservation-conflicts": [ + [ + 0, + "2023-06-13 20:42:46.836111" + ] + ], + "v4-allocation-fail": [ + [ + 0, + "2023-06-13 20:42:46.616358" + ] + ], + "v4-allocation-fail-classes": [ + [ + 0, + "2023-06-13 20:42:46.616363" + ] + ], + "v4-allocation-fail-no-pools": [ + [ + 0, + "2023-06-13 20:42:46.616368" + ] + ], + "v4-allocation-fail-shared-network": [ + [ + 0, + "2023-06-13 20:42:46.616372" + ] + ], + "v4-allocation-fail-subnet": [ + [ + 0, + "2023-06-13 20:42:46.616376" + ] + ], + "v4-lease-reuses": [ + [ + 0, + "2023-06-13 20:42:46.616410" + ] + ], + "v4-reservation-conflicts": [ + [ + 0, + "2023-06-13 20:42:46.616412" + ] + ] + }, + "result": 0 + } + +or + +:: + + { + "command": "statistic-get-all", + "arguments": { + "cumulative-assigned-nas": [ + [ + 0, + "2023-06-13 21:28:57.196757" + ] + ], + "cumulative-assigned-pds": [ + [ + 0, + "2023-06-13 21:28:57.196758" + ] + ], + "declined-addresses": [ + [ + 0, + "2023-06-13 21:28:57.196754" + ] + ], + "pkt6-advertise-received": [ + [ + 0, + "2023-06-13 21:28:57.177731" + ] + ], + "pkt6-advertise-sent": [ + [ + 0, + "2023-06-13 21:28:57.177739" + ] + ], + "pkt6-decline-received": [ + [ + 0, + "2023-06-13 21:28:57.177739" + ] + ], + "pkt6-dhcpv4-query-received": [ + [ + 0, + "2023-06-13 21:28:57.177740" + ] + ], + "pkt6-dhcpv4-response-received": [ + [ + 0, + "2023-06-13 21:28:57.177740" + ] + ], + "pkt6-dhcpv4-response-sent": [ + [ + 0, + "2023-06-13 21:28:57.177741" + ] + ], + "pkt6-infrequest-received": [ + [ + 0, + "2023-06-13 21:28:57.177742" + ] + ], + "pkt6-parse-failed": [ + [ + 0, + "2023-06-13 21:28:57.177742" + ] + ], + "pkt6-rebind-received": [ + [ + 0, + "2023-06-13 21:28:57.177743" + ] + ], + "pkt6-receive-drop": [ + [ + 0, + "2023-06-13 21:28:57.177743" + ] + ], + "pkt6-received": [ + [ + 0, + "2023-06-13 21:28:57.177744" + ] + ], + "pkt6-release-received": [ + [ + 0, + "2023-06-13 21:28:57.177744" + ] + ], + "pkt6-renew-received": [ + [ + 0, + "2023-06-13 21:28:57.177745" + ] + ], + "pkt6-reply-received": [ + [ + 0, + "2023-06-13 21:28:57.177745" + ] + ], + "pkt6-reply-sent": [ + [ + 0, + "2023-06-13 21:28:57.177746" + ] + ], + "pkt6-request-received": [ + [ + 0, + "2023-06-13 21:28:57.177747" + ] + ], + "pkt6-sent": [ + [ + 0, + "2023-06-13 21:28:57.177747" + ] + ], + "pkt6-solicit-received": [ + [ + 0, + "2023-06-13 21:28:57.177748" + ] + ], + "pkt6-unknown-received": [ + [ + 0, + "2023-06-13 21:28:57.177748" + ] + ], + "reclaimed-declined-addresses": [ + [ + 0, + "2023-06-13 21:28:57.196755" + ] + ], + "reclaimed-leases": [ + [ + 0, + "2023-06-13 21:28:57.196756" + ] + ], + "subnet[1].assigned-nas": [ + [ + 0, + "2023-06-13 21:28:57.196760" + ] + ], + "subnet[1].assigned-pds": [ + [ + 0, + "2023-06-13 21:28:57.196761" + ] + ], + "subnet[1].cumulative-assigned-nas": [ + [ + 0, + "2023-06-13 21:28:57.196727" + ] + ], + "subnet[1].cumulative-assigned-pds": [ + [ + 0, + "2023-06-13 21:28:57.196729" + ] + ], + "subnet[1].declined-addresses": [ + [ + 0, + "2023-06-13 21:28:57.196763" + ] + ], + "subnet[1].pd-pool[0].assigned-pds": [ + [ + 0, + "2023-06-13 21:28:57.196785" + ] + ], + "subnet[1].pd-pool[0].cumulative-assigned-pds": [ + [ + 0, + "2023-06-13 21:28:57.196744" + ] + ], + "subnet[1].pd-pool[0].reclaimed-leases": [ + [ + 0, + "2023-06-13 21:28:57.196789" + ] + ], + "subnet[1].pd-pool[0].total-pds": [ + [ + 256, + "2023-06-13 21:28:57.196741" + ] + ], + "subnet[1].pool[0].assigned-nas": [ + [ + 0, + "2023-06-13 21:28:57.196773" + ] + ], + "subnet[1].pool[0].cumulative-assigned-nas": [ + [ + 0, + "2023-06-13 21:28:57.196739" + ] + ], + "subnet[1].pool[0].declined-addresses": [ + [ + 0, + "2023-06-13 21:28:57.196775" + ] + ], + "subnet[1].pool[0].reclaimed-declined-addresses": [ + [ + 0, + "2023-06-13 21:28:57.196779" + ] + ], + "subnet[1].pool[0].reclaimed-leases": [ + [ + 0, + "2023-06-13 21:28:57.196783" + ] + ], + "subnet[1].pool[0].total-nas": [ + [ + 281474976710656, + "2023-06-13 21:28:57.196736" + ] + ], + "subnet[1].reclaimed-declined-addresses": [ + [ + 0, + "2023-06-13 21:28:57.196766" + ] + ], + "subnet[1].reclaimed-leases": [ + [ + 0, + "2023-06-13 21:28:57.196770" + ] + ], + "subnet[1].total-nas": [ + [ + 281474976710656, + "2023-06-13 21:28:57.196720" + ] + ], + "subnet[1].total-pds": [ + [ + 256, + "2023-06-13 21:28:57.196724" + ] + ], + "subnet[1].v6-ia-na-lease-reuses": [ + [ + 0, + "2023-06-13 21:28:57.196731" + ] + ], + "subnet[1].v6-ia-pd-lease-reuses": [ + [ + 0, + "2023-06-13 21:28:57.196733" + ] + ], + "v6-allocation-fail": [ + [ + 0, + "2023-06-13 21:28:57.177749" + ] + ], + "v6-allocation-fail-classes": [ + [ + 0, + "2023-06-13 21:28:57.177755" + ] + ], + "v6-allocation-fail-no-pools": [ + [ + 0, + "2023-06-13 21:28:57.177756" + ] + ], + "v6-allocation-fail-shared-network": [ + [ + 0, + "2023-06-13 21:28:57.177756" + ] + ], + "v6-allocation-fail-subnet": [ + [ + 0, + "2023-06-13 21:28:57.177757" + ] + ], + "v6-ia-na-lease-reuses": [ + [ + 0, + "2023-06-13 21:28:57.177757" + ] + ], + "v6-ia-pd-lease-reuses": [ + [ + 0, + "2023-06-13 21:28:57.177758" + ] + ] + }, + "result": 0 + } + +or + +:: + + { + "command": "statistic-get-all", + "arguments": { + "ncr-error": [ + [ + 0, + "2023-06-13 21:42:54.627751" + ] + ], + "ncr-invalid": [ + [ + 0, + "2023-06-13 21:42:54.627749" + ] + ], + "ncr-received": [ + [ + 0, + "2023-06-13 21:42:54.627737" + ] + ], + "update-error": [ + [ + 0, + "2023-06-13 21:42:54.627759" + ] + ], + "update-sent": [ + [ + 0, + "2023-06-13 21:42:54.627752" + ] + ], + "update-signed": [ + [ + 0, + "2023-06-13 21:42:54.627753" + ] + ], + "update-success": [ + [ + 0, + "2023-06-13 21:42:54.627755" + ] + ], + "update-timeout": [ + [ + 0, + "2023-06-13 21:42:54.627757" + ] + ], + "update-unsigned": [ + [ + 0, + "2023-06-13 21:42:54.627754" + ] + ] + }, + "result": 0 + } + +.. isccmd:: statistic-reset-all +.. _command-statistic-reset-all: + +The ``statistic-reset-all`` Command +----------------------------------- + +The :isccmd:`statistic-reset` command sets all statistics to their neutral +values: 0 for integer, 0.0 for float, 0h0m0s0us for time duration, and +"" for string type. An example command may look like this: + +:: + + { + "command": "statistic-reset-all", + "arguments": { } + } + +If the operation is successful, the server responds with a status of 0, +indicating success, and an empty parameters field. If an error is +encountered, the server returns a status code of 1 (error) and the text +field contains the error description. + +.. isccmd:: statistic-remove-all +.. _command-statistic-remove-all: + +The ``statistic-remove-all`` Command +------------------------------------ + +The :isccmd:`statistic-remove-all` command attempts to delete all statistics. An +example command may look like this: + +:: + + { + "command": "statistic-remove-all", + "arguments": { } + } + +If the removal of all statistics is successful, the server responds with +a status of 0, indicating success, and an empty parameters field. If an +error is encountered, the server returns a status code of 1 (error) and +the text field contains the error description. + +.. isccmd:: statistic-sample-age-set +.. _command-statistic-sample-age-set: + +The ``statistic-sample-age-set`` Command +---------------------------------------- + +The :isccmd:`statistic-sample-age-set` command sets a time-based limit +on samples for a given statistic. It takes two parameters: a string +called ``name``, which specifies the statistic name, and an integer value called +``duration``, which specifies the time limit for the given statistic in seconds. +An example command may look like this: + +:: + + { + "command": "statistic-sample-age-set", + "arguments": { + "name": "pkt4-received", + "duration": 1245 + } + + } + +If the command is successful, the server responds with a status of +0, indicating success, +and an empty parameters field. If an error is encountered (e.g. the +requested statistic was not found), the server returns a status code +of 1 (error) and the text field contains the error description. + +.. isccmd:: statistic-sample-age-set-all +.. _command-statistic-sample-age-set-all: + +The ``statistic-sample-age-set-all`` Command +-------------------------------------------- + +The :isccmd:`statistic-sample-age-set-all` command sets time-based limits +on samples for all statistics. It takes a single-integer parameter +called ``duration``, which specifies the time limit for the statistic +in seconds. An example command may look like this: + +:: + + { + "command": "statistic-sample-age-set-all", + "arguments": { + "duration": 1245 + } + + } + +If the command is successful, the server responds with a status of +0, indicating success, +and an empty parameters field. If an error is encountered, the server returns +a status code of 1 (error) and the text field contains the error description. + +.. isccmd:: statistic-sample-count-set +.. _command-statistic-sample-count-set: + +The ``statistic-sample-count-set`` Command +------------------------------------------ + +The :isccmd:`statistic-sample-count-set` command sets a size-based limit +on samples for a given statistic. An example command may look +like this: + +:: + + { + "command": "statistic-sample-count-set", + "arguments": { + "name": "pkt4-received", + "max-samples": 100 + } + + } + +If the command is successful, the server responds with a status of +0, indicating success, +and an empty parameters field. If an error is encountered (e.g. the +requested statistic was not found), the server returns a status code +of 1 (error) and the text field contains the error description. + +.. isccmd:: statistic-sample-count-set-all +.. _command-statistic-sample-count-set-all: + +The ``statistic-sample-count-set-all`` Command +---------------------------------------------- + +The :isccmd:`statistic-sample-count-set-all` command sets size-based limits +on samples for all statistics. An example command may look +like this: + +:: + + { + "command": "statistic-sample-count-set-all", + "arguments": { + "max-samples": 100 + } + + } + +If the command is successful, the server responds with a status of +0, indicating success, +and an empty parameters field. If an error is encountered, the server returns +a status code of 1 (error) and the text field contains the error description. + +.. _time-series: + +Time Series +=========== + +With certain statistics, a single isolated data point may be useful. However, +some statistics, such as received +packet size, packet processing time, or number of database queries needed to +process a packet, are not cumulative and it is useful to keep many data +points, perhaps to do some statistical analysis afterwards. + + +Each Kea statistic holds 20 data points; setting such +a limit prevents unlimited memory growth. +There are two ways to define the limits: time-based (e.g. keep samples from +the last 5 minutes) and size-based. The size-based +limit can be changed using one of two commands: :isccmd:`statistic-sample-count-set`, +to set a size limit for a single statistic, and :isccmd:`statistic-sample-count-set-all`, +to set size-based limits for all statistics. To set time-based +limits for a single statistic, use :isccmd:`statistic-sample-age-set`; use +:isccmd:`statistic-sample-age-set-all` to set time-based limits for all statistics. +For a given statistic only one type of limit can be active; storage +is limited by either time or size, not both. diff --git a/doc/sphinx/arm/stork.rst b/doc/sphinx/arm/stork.rst new file mode 100644 index 0000000..bfa4a06 --- /dev/null +++ b/doc/sphinx/arm/stork.rst @@ -0,0 +1,50 @@ +.. _stork: + +************************* +Monitoring Kea With Stork +************************* + +Most administrators want to be able to monitor any Kea services that are running. Kea offers so many +pieces of information - configuration files, API, statistics, logs, open database content, and more - +that it may sometimes +be overwhelming to keep up. ISC's Stork project is intended to address this problem for both Kea +and BIND 9. Stork is useful in a variety of ways: + +- Stork can be used as a dashboard. It provides insight into what exactly is happening + on the servers. In particular, it allows users to: see up-to-date details regarding pool + utilization in subnets and shared networks; monitor the state of the HA pair (and + provide extra insight in case of failover and recovery events); list, filter, and + search for specific host reservations; and more. Only + a single Stork server needs to be deployed, and one Stork agent on each machine to be monitored. + +- The Stork agent can integrate Kea with Prometheus and Grafana. Once the Stork + agent is active on the server, it serves as a Prometheus exporter. Users who have deployed + Prometheus in their networks can visualize statistics as time series using Grafana. + +- Stork can act as both a dashboard and an integrator for Prometheus/Grafana. Once Stork + is linked to where Grafana is deployed on the network, users can inspect the current status and + visit a customized link to Grafana to see how a given property behaves over time. + +Stork is available as source code, but also as native deb and RPM packages, which makes it easy +to install on most popular systems. For more details, please see the +`Stork ARM <https://stork.readthedocs.io>`_ or the `Stork project page <https://gitlab.isc.org/isc-projects/stork>`_. +The ARM has a nice collection of screenshots that is frequently updated, to give users +an idea of what is currently available. Stork is in the midst of full development with +monthly releases, so please check back frequently. + +.. _grafana: +.. _prometheus: + +Kea Statistics in Grafana +========================= + +The ISC Stork project provides an agent that can be deployed alongside Kea. It +exposes Kea statistics in a format that is accepted by Prometheus. +One of the major benefits of Prometheus is that it turns repeated one-time observations into time series, +which lets users monitor how certain behaviors change over time. It is easy to use other tools +to visualize data available in Prometheus; the most common approach is to use +Grafana to provide visual dashboards. The Stork project provides dashboard +definitions for Kea that can be imported into Grafana very easily. + +Learn more about Prometheus and Grafana on their websites: `Prometheus <https://prometheus.io/>` +and `Grafana <https://grafana.com/>`. |