16. Hook Libraries¶
16.1. 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, at various points in its processing (“hook points”), call functions in them. Those functions perform whatever custom processing is required.
The hooks concept allows the core Kea code to remain reasonably small by moving features to external libraries that some, but not all, users find useful. Those with no need for specific functions can simply choose not to load the 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 DHCP4 server and a different set with the DHCP6 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 section describes how to 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.
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, e.g. the RADIUS library
requires the FreeRadius-client library to be present. If
the --with-freeradius
option is not specified, the RADIUS library is not
built.
16.2. Installing Hook Packages¶
Note
For more details about installing the Kea Premium Hooks package, please read this Knowledge Base article.
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 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 2.1.6.,
there should be a tarball called kea-|release|.tar.gz
on the system.
Unpack this tarball:
$ tar -zxvf kea-2.1.6.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 2.1.6 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:
$ cd kea-2.1.6 $ tar -xvf ../kea-premium-2.1.6.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 will always be 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:
Package: Name: kea Version: 2.1.6 Extended version: 2.1.6 (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, e.g. the RADIUS hook requires extra switches for FreeRADIUS. Please consult later sections of this chapter for details.
- 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.
- 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/libca_rbac.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
.
16.3. 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/charging.so"
},
{
"library": "/opt/local/notification.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/charging.so
) has no parameters. The
second library (/opt/local/notification.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.
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 thehooks-libraries
item, change it to an empty list.
At the moment, only the kea-dhcp4
and kea-dhcp6
processes support
hook libraries.
16.4. 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 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.
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
kea-ctrl-agent
process to load libraries that should, in fact, be
loaded by the kea-dhcp4
or 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.
Warning
While the Kea Control Agent includes the “hooks” functionality, (i.e. hook libraries can be loaded by this process), none of ISC’s current hook libraries should be loaded by the Control Agent.
Name | Availability | Description |
---|---|---|
User Check | Kea open source | Reads known users list from a file. Unknown users will be
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. |
Forensic Logging | ISC support customers | This library provides hooks that record a detailed log of lease assignments and renewals into 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. |
Flexible Identifier | ISC support customers | 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 using
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. |
Flexible Option | Kea open source | This library provides hooks that compute option values 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. |
Host Commands | ISC support customers | Kea provides a way to 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. 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). |
Subnet Commands | ISC support customers | In deployments in which subnet configuration needs to be 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. |
Lease Commands | Kea open source | This hook library offers a number of commands used to 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. |
High Availability | Kea open source | The risk of DHCP service unavailability can be minimized 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. |
Statistics Commands | Kea open source | This library provides additional 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. |
RADIUS | ISC support customers | The RADIUS hook library allows Kea to interact with 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. |
Host Cache | ISC support customers | Some database backends, such as RADIUS, 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. |
Class Commands | ISC support customers | This hook library allows configured DHCP client classes to be added, updated, deleted, and fetched without needing to restart the DHCP server. |
MySQL Configuration Backend | Kea open source | This hook library is an implementation of the Kea 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. |
PostgreSQL Configuration Backend | Kea open source | This hook library is an implementation of the Kea 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. |
Configuration Backend Commands | ISC support customers | This hook 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. |
BOOTP | Kea open source | This hook library adds BOOTP support, as defined in RFC 1497. It recognizes received BOOTP requests: they are translated into DHCPREQUEST packets, put into the BOOTP client class, and receive infinite lifetime leases. |
Leasequery | ISC support customers | This library adds support for DHCPv4 Leasequery as described in RFC 4388; and for DHCPv6 Leasequery as described in RFC 5007. |
Run Script | Kea open source | This hook library adds support to run external scripts for specific packet-processing hook points. There are several exported environment variables available for the script. |
GSS-TSIG | ISC support customers | This hook library adds support to the Kea D2 server (kea-dhcp-ddns) for using GSS-TSIG to sign DNS updates. |
RBAC | ISC support customers | This hook library adds support to the Kea Control Agent (kea-ctrl-agent) for Role Based Access Control filtering of commands. |
DDNS-Tuning | ISC support customers | This hook library adds support for fine tuning various DDNS update aspects such as generating hostnames via expressions and skipping DDNS updates for select clients. |
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 this link: 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.
16.5. user_chk
: Checking User Access¶
The user_chk
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.
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
for information on how the code works internally. That, together with the
Hooks Framework section of the Kea Developer’s Guide should give users
some pointers on how to extend this library and perhaps even write one
from scratch.
16.6. legal_log
: Forensic Logging Hooks¶
This section describes the forensic log hook library. This library provides hooks that record a detailed log of assignments, renewals, releases, and other lease events into a set of log files.
Currently this library is only available to ISC customers with a paid support contract.
Note
This library may only be loaded by the kea-dhcp4
or 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.
16.6.1. 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 Configuring the Forensic Log Hooks.
Note
When running Kea servers for both DHCPv4 and DHCPv6, the log names must be distinct. See the examples in Configuring the Forensic Log Hooks.
16.6.2. Configuring the Forensic Log Hooks¶
To use this functionality, the hook library must be included in the
configuration of the desired DHCP server modules. The legal_log
library
can save logs to a text file or to a database (created using
kea-admin
; see First-Time Creation of the MySQL Database and First-Time Creation of the PostgreSQL Database).
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, kea-dhcp4
can be configured to load
the legal_log
library like this:
{
"Dhcp4": {
"hooks-libraries": [
{
"library": "/usr/local/lib/kea/hooks/libdhcp_legal_log.so",
"parameters": {
"path": "/var/lib/kea/log",
"base-name": "kea-forensic4"
}
}
]
}
}
For kea-dhcp6
, the configuration is:
{
"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 tokea-legal
.time-unit
- configures the time unit used to rotate the log file. Valid values aresecond
,day
,month
, oryear
. It defaults today
.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 Using Expressions in Classification 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:
{
"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:
{
"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:
{
"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 Lease Database Configuration and Lease Database Configuration.
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:
{
"Dhcp4": {
"subnet4": [
{
"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:
{
"Dhcp6": {
"subnet6": [
{
"subnet": "2001:db8:1::/64",
"pools": [
{
"pool": "2001:db8:1::1-2001:db8:1::ffff"
}
],
"user-context": {
"legal-logging": false
}
}
]
}
}
See User Contexts in IPv4 and User Contexts in IPv6 to learn more about user contexts in Kea configuration.
16.6.3. 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, thegiaddr
and the RAIcircuit-id
,remote-id
, andsubscriber-id
options (option 82 sub options: 1, 2 and 6), if present. Thecircuit-id
andremote-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: lease4-add
, lease4-update
, and 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
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:
{
"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:
{
"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, ':'), '')), '')"
}
Expand here!
{ "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, ':'), '')), '')" }
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:
{
"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, ':'), '')), ''))"
}
Expand here!
{ "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, ':'), '')), ''))" }
16.6.4. 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 theremote-id
(code 37),subscriber-id
(code 38), andinterface-id
(code 18) options, if present. Note that theinterface-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: lease6-add
, lease6-update
, and 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
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:
{
"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:
{
"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, ':'), '')), ''), '')"
}
Expand here!
{ "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, ':'), '')), ''), '')" }
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:
{
"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, ':'), '')), ''), ''))"
}
Expand here!
{ "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, ':'), '')), ''), ''))" }
16.6.5. 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 MySQL for information on using a MySQL database;
or to PostgreSQL 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 Lease Database Configuration. 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 a change from its behavior in the Lease Commands, Host Commands, and
Configuration Backend hook libraries, 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.
16.7. flex_id
: Flexible Identifiers 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.
Currently this library is only available to ISC customers with a paid support contract.
Note
This library may only be loaded by the kea-dhcp4
or kea-dhcp6
process.
The library allows the definition of an expression, using notation initially
used only for client classification. (See
Using Expressions in Classification 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 an optional boolean
parameter replace-client-id
:
"Dhcp6": {
"hooks-libraries": [
{
"library": "/path/libdhcp_flex_id.so",
"parameters": {
"identifier-expression": "expression",
"replace-client-id": 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"
}
},
...
]
}
When replace-client-id
is set to false
(which is the default setting),
the flex-id
hook library 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).
The flex-id
library 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
Using Client Identifier and Hardware Address 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 lease_cmds: Lease Commands section describes commands used to retrieve,
update, and delete leases using various identifiers, such as hw-address
and
client-id
. The lease_cmds
library 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
}
}
16.8. flex_option
Flexible Option 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
.
The syntax used for the action expressions is the same syntax used for client classification and the Flexible Identifier hook library; see either Using Expressions in Classification or flex_id: Flexible Identifiers for Host Reservations 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 does the same 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, the flex_option
library can be loaded
by either the kea-dhcp4
or 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.
"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.
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 thecode
orname
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 thecode
orname
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 DHCPv4vivso-suboptions
and for the DHCPv6vendor-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 theadd
andsupersede
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 theremove
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 wholesub-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.
"Dhcp4": {
"hooks-libraries": [
{ "library": "/usr/local/lib/libdhcp_flex_option.so",
"parameters": {
"options": [
{
"code": 43,
"sub-options": [
{
"code": 1,
"add": "'foobar'"
}
]
}
]
}
},
...
]
}
16.9. host_cmds
: 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. 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 - 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).
Currently this library is only available to ISC customers with a paid support contract.
Note
This library can only be loaded by the kea-dhcp4
or kea-dhcp6
process.
Currently, the following commands are supported:
reservation-add
, which adds a new host reservation.reservation-get
, which returns an existing reservation if specified criteria are matched.reservation-get-all
, which returns all reservations in a specified subnet.reservation-get-page
, a variant ofreservation-get-all
that returns reservations by pages, either all or in a specified subnet.reservation-get-by-hostname
, which returns all reservations with a specified hostname and optionally in a subnet.reservation-get-by-id
, which returns all reservations with a specified identifier (since Kea version 1.9.0).reservation-del
, which attempts to delete a reservation matching specified criteria.
To use the commands that change reservation information
(i.e. reservation-add
and reservation-del
), the hosts database must be
specified and it must not operate in read-only mode (for details, see
the hosts-databases
descriptions in DHCPv4 Hosts Database Configuration
and DHCPv6 Hosts Database Configuration). If the hosts-databases
are not specified or are
running in read-only mode, the host_cmds
library will load, but any
attempts to use reservation-add
or reservation-del
will fail.
For a description of proposed future commands, see the Control API Requirements document.
All host commands use JSON syntax. They can be issued either using the control channel (see Management API) or via the Control Agent (see The Kea Control 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"
}
...
]
}
16.9.1. 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
reservation-get-by-hostname
, where it is optional. Since Kea 1.9.0,
subnet-id
is also optional in reservation-get-page
, and
it is forbidden in 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.
16.9.2. The reservation-add
Command¶
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 Host Reservations in DHCPv4; for IPv6 reservations, see
Host Reservations in DHCPv6. 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. An example command can be as
simple as:
{
"command": "reservation-add",
"arguments": {
"reservation": {
"subnet-id": 1,
"hw-address": "1a:1b:1c:1d:1e:1f",
"ip-address": "192.0.2.202"
}
}
}
but it can also take many more parameters, for example:
{
"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:
{
"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 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:
{ "result": 0, "text": "Host added." }
And here’s an example of a failure:
{ "result": 1, "text": "Mandatory 'subnet-id' parameter missing." }
As 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.
16.9.3. The reservation-get
Command¶
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"
}
}
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"
},
"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." }
16.9.4. The reservation-get-all
Command¶
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"
},
...
{
"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"
}
]
},
"result": 0,
"text": "72 IPv4 host(s) found."
}
The response returned by reservation-get-all
can be very long. The
DHCP server does not handle DHCP traffic while preparing a response to
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 reservation-get-page
instead (see
The reservation-get-page command).
For more information, see The reservation-get-all Command.
16.9.5. The reservation-get-page
command¶
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:
{
"arguments": {
"count": 0,
"hosts": [ ],
},
"result": 3,
"0 IPv4 host(s) found."
}
This command is more complex than 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
reservation-get-all
(see The reservation-get-all Command).
16.9.6. The reservation-get-by-hostname
Command¶
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 reservation-get-by-hostname
can be long,
particularly when responses are not limited to a subnet.
For more information, see The reservation-get-by-hostname Command.
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 MySQL section of Kea Database Administration.
16.9.7. The reservation-get-by-id
Command¶
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 ref:command-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 reservation-get-by-id
can be long,
particularly when responses are not limited to a subnet.
For more information, see The reservation-get-by-id Command.
16.9.8. The reservation-del
Command¶
reservation-del
can be used to delete a reservation from the host
database. 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"
}
}
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)."
}
{
"result": 0,
"text": "Host deleted."
}
{
"result": 1,
"text": "Unable to delete a host because there is no hosts-database
configured."
}
16.10. lease_cmds
: Lease Commands¶
Kea allows users to store lease information in several
backends (memfile, MySQL and PostgreSQL), and this 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.
The lease commands library is part of the open source code and is available to every Kea user.
Note
This library may only be loaded by the kea-dhcp4
or the
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:
lease4-add
- adds a new IPv4 lease.lease6-add
- adds a new IPv6 lease.lease6-bulk-apply
- creates, updates, and/or deletes multiple IPv6 leases in a single transaction.lease4-get
- checks whether an IPv4 lease with the specified parameters exists and returns it if it does.lease6-get
- checks whether an IPv6 lease with the specified parameters exists and returns it if it does.lease4-get-all
- returns all IPv4 leases or all IPv4 leases for the specified subnets.lease6-get-all
- returns all IPv6 leases or all IPv6 leases for the specified subnets.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.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.lease4-get-by-hw-address
- returns all IPv4 leases with the specified hardware address.lease4-get-by-client-id
- returns all IPv4 leases with the specifiedclient-id
.lease6-get-by-duid
- returns all IPv6 leases with the specified DUID.lease4-get-by-hostname
- returns all IPv4 leases with the specified hostname.lease6-get-by-hostname
- returns all IPv6 leases with the specified hostname.lease4-del
- deletes an IPv4 lease with the specified parameters.lease6-del
- deletes an IPv6 lease with the specified parameters.lease4-update
- updates an IPv4 lease.lease6-update
- updates an IPv6 lease.lease4-wipe
- removes all leases from a specific IPv4 subnet or from all subnets.lease6-wipe
- removes all leases from a specific IPv6 subnet or from all subnets.lease4-resend-ddns
- resends a request to update DNS entries for an existing lease.lease6-resend-ddns
- resends a request to update DNS entries for an existing lease.
All commands use JSON syntax and can be issued either using the control channel (see Management API) or Control Agent (see The Kea Control 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"
}
...
]
}
16.10.1. The lease4-add
, lease6-add
Commands¶
The lease4-add
and 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 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 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 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
}
}
lease6-add
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 specifiedsubnet-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 ofvalid-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 isfalse
. The hostname parameter must be specified iffqdn-fwd
is set totrue
.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 isfalse
. The hostname parameter must be specified iffqdn-fwd
is set totrue
.hostname
- specifies the hostname to be associated with this lease. Its value must be non-empty if eitherfqdn-fwd
orfqdn-rev
are set totrue
. 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 specifiedsubnet-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 fordefault
, 1 fordeclined
, and 2 for theexpired-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)" }
16.10.2. The lease6-bulk-apply
Command¶
The 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 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 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).
16.10.3. The lease4-get
, lease6-get
Commands¶
lease4-get
and lease6-get
can be used to query the lease database
and retrieve existing leases. There are two types of parameters the
lease4-get
command supports: (address
) or (subnet-id
,
identifier-type
, identifier
). There are also two types for
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 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 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.
lease4-get
and 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.
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
\(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. \(cltt = expire\) when \(valid\_lft = 4294967295\) and the lease backend is MySQL or PostgreSQL.
16.10.4. The lease4-get-all
, lease6-get-all
Commands¶
lease4-get-all
and 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 lease4-get-all
and 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.
16.10.5. The lease4-get-page
, lease6-get-page
Commands¶
The lease4-get-all
and 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.
lease4-get-page
and 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
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 lease4-get-page
or
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.
16.10.6. 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 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 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 lease4-get-all
or lease6-get-all
. This list can be
empty and is usually not large.
16.10.7. The lease4-del
, lease6-del
Commands¶
lease4-del
and 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
lease4-get``and ``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 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
orfqdn_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
}
}
lease4-del
and 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.
16.10.8. The lease4-update
, lease6-update
Commands¶
The lease4-update
and 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
lease4-del
/lease6-del
followed by lease4-add
/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 lease4-update
/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
}
}
16.10.9. The lease4-wipe
, lease6-wipe
Commands¶
lease4-wipe
and 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 lease4-wipe
is:
{
"command": "lease4-wipe",
"arguments": {
"subnet-id": 44
}
}
An example of 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.
16.10.10. The lease4-resend-ddns
, lease6-resend-ddns
Commands¶
lease4-resend-ddns
and lease6-resend-ddns
can be used to generate
a request to 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
orfqdn_rev
) must be true.
An example 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 lease6-resend-ddns
query is:
{
"command": "lease6-resend-ddns",
"arguments": {
"ip-address": "2001:db8:1::1"
}
}
lease4-resend-ddns
and 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 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."
}
16.11. subnet_cmds
: Subnet Commands¶
This application 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.
Currently this library is only available to ISC customers with a paid support contract.
Note
This library may only be loaded by the kea-dhcp4
or kea-dhcp6
process.
The following commands are currently supported:
subnet4-list/subnet6-list
- lists all configured subnets.subnet4-get/subnet6-get
- retrieves detailed information about a specified subnet.subnet4-add/subnet6-add
- adds a new subnet into the server’s configuration.subnet4-update/subnet6-update
- updates (replaces) a single subnet in the server’s configuration.subnet4-del/subnet6-del
- removes a subnet from the server’s configuration.network4-list/network6-list
- lists all configured shared networks.network4-get/network6-get
- retrieves detailed information about a specified shared network.network4-add/network6-add
- adds a new shared network to the server’s configuration.network4-del/network6-del
- removes a shared network from the server’s configuration.network4-subnet-add/network6-subnet-add
- adds an existing subnet to an existing shared network.network4-subnet-del/network6-subnet-del
- removes a subnet from an existing shared network and demotes it to a plain subnet.
16.11.1. 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 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.
16.11.2. 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 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.
16.11.3. The subnet4-get
Command¶
This command is used to retrieve detailed information about the
specified subnet. This command usually follows 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
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": [
....
]
...
}
]
}
}
16.11.4. The subnet6-get
Command¶
This command is used to retrieve detailed information about the
specified subnet. This command usually follows 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
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": [
...
]
....
}
]
}
}
16.11.5. 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
subnet4-add
. The commands described in host_cmds: Host Commands 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"
}
]
}
}
16.11.6. 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
subnet6-add
. The commands described in host_cmds: Host Commands 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 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
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.
16.11.7. 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
subnet4-update
. The commands described in host_cmds: Host Commands 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"
}
]
}
}
16.11.8. 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
subnet6-update
. The commands described in host_cmds: Host Commands 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"
}
]
}
}
16.11.9. 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 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 the 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
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"
}
]
}
}
16.11.10. 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 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 the 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
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"
}
]
}
16.11.11. 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
network4-get
or 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 network4-list
looks as follows:
{
"arguments": {
"shared-networks": [
{ "name": "floor1" },
{ "name": "office" }
]
},
"result": 0,
"text": "2 IPv4 network(s) found"
}
network6-list
follows exactly the same syntax for both the query and
the response.
16.11.12. 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 lookup global reservations.
"reservations-global": false,
# Specify if the server should lookup 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 config-get
, just limited to returning the shared network’s
information.
16.11.13. 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 Shared Networks in DHCPv4 and
Shared Networks in DHCPv6.
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 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.
16.11.14. 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 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 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 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
subnet4-del
or subnet6-del
commands.
16.11.15. 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 network4-add
or
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 network4-add
or network6-add
, and then add an existing
subnet to this newly created shared network using
network4-subnet-add
or network6-subnet-add
.
The network4-subnet-add
and 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
network4-subnet-del
or network6-subnet-del
commands first.
An example invocation of the 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 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.
16.11.16. 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 subnet4-del
or subnet6-del
commands instead. The network4-subnet-del
and
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 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 network6-subnet-del
command uses exactly the same syntax for
both the command and the response.
16.12. BOOTP Support¶
This hook library adds support for BOOTP with vendor-information extensions
(RFC 1497). 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.
This open source library is loaded
similarly to other hook libraries by the kea-dhcp4
process, and
it takes no parameters.
"Dhcp4": {
"hooks-libraries": [
{ "library": "/usr/local/lib/libdhcp_bootp.so" },
...
]
}
Note
This library can only be loaded by the kea-dhcp4
process,
as there is no BOOTP protocol for IPv6.
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).
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"
}],
...
},
...
],
...
}
16.13. class_cmds
: Class Commands¶
This section describes the Class Commands hooks library, which 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
This library may only be loaded by the kea-dhcp4
or
kea-dhcp6
process.
The Class Commands hooks library is currently available only to ISC customers with a paid support contract.
16.13.1. The class-add
Command¶
The 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 class-add
command in our example:
{
"result": 0,
"text": "Class 'ipxe_efi_x64' added."
}
16.13.2. The class-update
Command¶
The 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 class-add
command must be used instead to create the new
client class.
The class-update
command has the same argument structure as the
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 class-del
command and then added again with a
different name using class-add
. Note, however, that the class with
the new name will be added at the end of the list of configured classes.
16.13.3. The class-del
Command¶
The 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 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.
16.13.4. The class-list
Command¶
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
class-get
command should be used.
16.13.5. The class-get
Command¶
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.
16.14. cb_cmds: Configuration Backend Commands¶
This section describes the cb_cmds
hooks library, used to manage Kea
servers’ configurations in the Configuration Backends. This library must
be used in conjunction with the available CB hooks libraries implementing
the common APIs to create, read, update, and delete (CRUD) the
configuration information in the respective databases. For example:
the mysql_cb
hooks library implements this API for MySQL while the
pgsql_cg
hooks library implements this API for PostgreSQL.
To manage the configuration information in a MySQL database, both the
mysql_cb
and cb_cmds
libraries must be loaded by the server used for the
configuration management.
To manage the configuration information in a PostgreSQL database, both the
pgsql_cb
and cb_cmds
libraries must be loaded by the server used for the
configuration management.
The cb_cmds
library is only available to ISC customers with a paid
support contract.
Note
This library may only be loaded by the kea-dhcp4
or
kea-dhcp6
process.
Note
Please read about CB Capabilities and Limitations before using the commands described in this section.
16.14.1. Commands Structure¶
There are 5 types of commands supported by this library:
del
- delete the selected object from the database, e.g.remote-global-parameter4-del
.get
- fetch the selected object from the database, e.g.remote-subnet4-get
.get-all
- fetch all objects of the particular type from the database, e.g.remote-option-def4-get-all
.list
- list all objects of the particular type in the database, e.g.remote-network4-list
; this class of commands returns brief information about each object compared to the output ofget-all
.set
- creates or replaces an object of the given type in the database, e.g.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:
{
"command": "remote-subnet4-list",
"arguments": {
"remote": {
"type": "mysql",
"host": "192.0.2.33",
"port": 3302
}
}
}
The cb_cmds
library is only available to ISC customers with a paid
support contract.
Note
This library may only be loaded by the kea-dhcp4
or
kea-dhcp6
process.
Note
Please read about CB Capabilities and Limitations before using the commands described in this section.
16.14.2. Commands Structure¶
There are 5 types of commands supported by this library:
del
- delete the selected object from the database, e.g.remote-global-parameter4-del
.get
- fetch the selected object from the database, e.g.remote-subnet4-get
.get-all
- fetch all objects of the particular type from the database, e.g.remote-option-def4-get-all
.list
- list all objects of the particular type in the database, e.g.remote-network4-list
; this class of commands returns brief information about each object compared to the output ofget-all
.set
- creates or replaces an object of the given type in the database, e.g.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:
{
"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 present Kea release, it is possible to configure the Kea server
to use only one 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. That’s why the remote
parameter may be omitted in the commands and the cb_cmds hooks library will
use the sole backend by default. The example command below most often show a
value of “mysql” for the type
parameter. It should be assumed that a
value would be “postgresql” for installations using a PostgreSQL database.
16.14.3. Control Commands for DHCP Servers¶
This section describes and gives some examples of the control commands
implemented by the cb_cmds
hooks library, 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 the following sections, various commands are described and some usage
examples are provided. In the sections jointly describing the DHCPv4 and
DHCPv6 variants of the particular command, we sometimes use the following
notation: the remote-subnet[46]-set
is the wildcard name for the
two commands: remote-subnet4-set
and remote-subnet6-set
.
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.
16.14.4. 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 remote-network4-list
command, which includes the metadata:
{
"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, this map will be
extended with additional information, e.g. object modification time, log
message created during the last modification, etc.
16.14.5. 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:
{
"command": "remote-server4-del",
"arguments": {
"servers": [
{
"server-tag": "server1"
}
],
"remote": {
"type": "postgresql"
}
}
}
As a result of this command, the user defined server called server1 is removed from the database. All associations of the configuration information with this server are automatically removed from the database. The non-shareable configuration information, such as: global parameters, option definitions and global options associated with the server are removed from the database. The 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 the server1 using the remote-subnet4-set command and the server1 is subsequently deleted, the subnet remains in the database but none of the servers can use this subnet. The subnet can be updated using the remote-subnet4-set and associated with some other server or with all servers using the special server tag “all”. Such subnet can be also deleted from the database using the remote-subnet4-del-by-id or remote-subnet4-del-by-prefix, if it is no longer needed.
The following is the successful response to the remote-server4-del command:
{
"result": 0,
"text": "1 DHCPv4 server(s) deleted."
"arguments": {
"count": 1
}
}
Note
The remote-server4-del and remote-server6-del commands must be used with care, because an accidental deletion of the server causes 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.
16.14.6. 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:
{
"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 server tag and the user’s description of the server:
{
"result": 0,
"text": "DHCP server server1 found.",
"arguments": {
"servers": [
{
"server-tag": "server1",
"description": "A DHCPv6 server located on the first floor."
}
],
"count": 1
}
}
16.14.7. 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:
{
"command": "remote-server4-get-all"
"arguments": {
"remote": {
"type": "mysql"
}
}
}
The response includes basic information about each server, such as its server tag and description:
{
"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
}
}
16.14.8. 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 remote-server4-set or remote-server6-set commands. The following command creates a new (or updates an existing) DHCPv6 server in the database:
{
"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 must not be used as server tags: “all” and “any”.
The following is the example response to the above command:
{
"result": 0,
"text": "DHCPv6 server successfully set.",
"arguments": {
"servers": [
{
"server-tag": "server1",
"description": "A DHCP server on the ground floor."
}
]
}
}
16.14.9. 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 will use 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:
{
"command": "remote-global-parameter4-del",
"arguments": {
"parameters": [ "renew-timer" ],
"remote": {
"type": "mysql"
},
"server-tags": [ "all" ]
}
}
If the 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.
16.14.10. 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 the “server1”:
{
"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.:
{
"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. Therefore, the value shared by all servers is returned. If there was the server1 specific value in the database this value would be returned instead.
The example response for the integer value is:
{
"result": 0,
"text": "1 DHCPv4 global parameter found.",
"arguments": {
"parameters": {
"renew-timer": 2000,
"metadata": {
"server-tags": [ "server1" ]
}
},
"count": 1
}
}
The real value:
{
"result": 0,
"text": "1 DHCPv4 global parameter found.",
"arguments": {
"parameters": {
"t1-percent": 0.85,
"metadata": {
"server-tags": [ "all" ]
}
},
"count": 1
}
}
Finally, the boolean value:
{
"result": 0,
"text": "1 DHCPv4 global parameter found.",
"arguments": {
"parameters": {
"match-client-id": true,
"metadata": {
"server-tags": [ "server2" ]
}
},
"count": 1
}
}
16.14.11. 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”:
{
"command": "remote-global-parameter4-get-all",
"arguments": {
"remote": {
"type": "mysql"
},
"server-tags": [ "server1" ]
}
}
The example response may look as follows:
{
"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 if this parameter is specific to the “server1” or 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 the 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.
16.14.12. 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:
{
"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 are stored successfully and some fail. If an error occurs when
processing this command, it is recommended to use
remote-global-parameter[46]-get-all
to check which of the parameters have
been stored/updated successfully and which have failed.
The server-tags list is mandatory and it must contain a single server tag or the keyword “all”. In the example above, all specified parameters are associated with the “server1” server.
16.14.13. 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:
{
"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
network[46]-del
commands with respect to the subnets-action
parameter.
Note that the server-tags parameter must not be used for this command.
16.14.14. 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:
{
"command": "remote-network6-get",
"arguments": {
"shared-networks": [
{
"name": "level3"
}
],
"subnets-include": "full",
"remote": {
"type": "mysql"
}
}
}
Note that the server-tags parameter must not be used for this command.
16.14.15. 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 the “server1” and “server2”:
{
"command": "remote-network4-list"
"arguments": {
"remote": {
"type": "mysql"
},
"server-tags": [ "server1", "server2" ]
}
}
The server-tags parameter is mandatory and it 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:
{
"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:
{
"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. In order to fetch the detailed information about the selected shared network, use the remote-network[46]-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 the “server1” and another one is associated with the “server2”.
When listing unassigned shared networks, the response will look similar to this:
{
"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.
16.14.16. 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
Shared Networks in DHCPv4 and Shared Networks in DHCPv6 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 will result in an error.
These commands are intended to be used for managing the shared
network-specific information and DHCP options. In order to associate and
disassociate the subnets with the shared networks, the
remote-subnet[46]-set
commands should be used.
The following command adds the IPv6 shared network “level3” to the database:
{
"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 will use the global
values for unspecified parameters or, if the global values are not
specified, the default values will be used.
The server-tags list is mandatory for this command and it 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.
16.14.17. 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:
{
"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 the “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 the server1, no option is deleted. In order 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. It must not include the null value.
16.14.18. 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”:
{
"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”. It must not contain the null value.
16.14.19. 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 particular server or all servers. For example:
{
"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 it must include exactly one server tag or the keyword “all”. It must not include the null value.</para>
The following is the example response to this command:
{
"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.
16.14.20. 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 Custom DHCPv4 Options and Custom DHCPv6 Options). The following command creates the DHCPv4 option definition at the top-level “dhcp4” option space and associates it with the “server1”:
{
"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”. It must not contain the null value.
16.14.21. 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:
{
"command": "remote-option4-global-del",
"arguments": {
"options": [
{
"code": 5
"space": "dhcp4"
}
],
"remote": {
"type": "mysql"
},
"server-tags": [ "server1" ]
}
}
The “dhcp4” is the top-level option space where the standard DHCPv4 options belong. The server-tags is mandatory and it must include a single option tag or the keyword “all”. If the explicit server tag is specified then 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. In order to delete the option associated with all servers, the keyword “all” must be specified.
16.14.22. 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:
{
"command": "remote-option6-global-get",
"arguments": {
"options": [
{
"code": 23,
"space": "dhcp6"
}
],
"remote": {
"type": "mysql"
},
"server-tags": [ "all" ]
}
}
The server-tags is mandatory and it must include exactly one server tag or the keyword “all”. It must not contain the null value.
16.14.23. 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 particular server or for all servers. The following command fetches all global DHCPv4 options for the “server1”:
{
"command": "remote-option6-global-get-all",
"arguments": {
"remote": {
"type": "mysql"
},
"server-tags": [ "server1" ]
}
}
The server-tags list is mandatory for this command and it must contain exactly one server tag or a keyword “all”. It must not contain the null value. The following is the example response to this command with a single option being associated with the “server1” returned:
{
"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
}
}
16.14.24. 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 Standard DHCPv4 Options and Standard DHCPv6 Options). For example:
{
"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 it must include exactly one server tag or the keyword “all”. It must not 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 the standard DHCP options. When specifying a value for the user-defined DHCP option, the option code should be specified instead of the name. For example:
{
"command": "remote-option6-global-set",
"arguments": {
"options": [
{
"code": 1,
"space": "isc",
"data": "2001:db8:1::1"
}
],
"server-tags": [ "server1" ]
}
}
16.14.25. 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. In order to delete a subnet level option the remote-option[46]-subnet-del command 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”.
{
"command": "remote-option4-network-del",
"arguments": {
"shared-networks": [
{
"name": "fancy"
}
],
"options": [
{
"code": 5,
"space": "dhcp4"
}
],
"remote": {
"type": "mysql"
}
}
}
The “dhcp4” is the top-level option space where the standard DHCPv4 options belong. The server-tags parameter must not be specified for this command.
16.14.26. 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 Standard DHCPv4 Options and Standard DHCPv6 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.
{
"command": "remote-option6-network-set",
"arguments": {
"shared-networks": [
{
"name": "fancy"
}
],
"options": [
{
"name": "dns-servers",
"data": "2001:db8:1::1"
}
],
"remote": {
"type": "mysql"
}
}
}
The sever-tags parameter must not 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 specified instead of the name.
16.14.27. 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. In order to delete a subnet level option the remote-option6-subnet-del command must be used instead.
{
"command": "remote-option6-pd-pool-del",
"arguments": {
"pd-pools": [
{
"prefix": "3000::",
"prefix-len": 64
}
],
"options": [
{
"code": 23,
"space": "dhcp6"
}
],
"remote": {
"type": "mysql"
}
}
}
The “dhcp6” is the top-level option space where the standard DHCPv6 options belong. The server-tags parameter must not be specified for this command.
16.14.28. 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 Standard DHCPv4 Options and Standard DHCPv6 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:
{
"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 sever-tags parameter must not 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 specified instead of the name.
16.14.29. 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 option instance is not affected by this command as this command merely deletes a pool level option. In order to delete subnet level option the remote-option[46]-subnet-del command 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:
{
"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” is the top-level option space where the standard DHCPv4 options belong. The server-tags parameter must not be specified for this command.
16.14.30. 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 Standard DHCPv4 Options and Standard DHCPv6 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:
{
"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 sever-tags parameter must not 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 specified instead of the name.
16.14.31. 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.
{
"command": "remote-option4-subnet-del",
"arguments": {
"subnets": [
{
"id": 123
}
],
"options": [
{
"code": 5,
"space": "dhcp4"
}
],
"remote": {
"type": "mysql"
}
}
}
The “dhcp4” is the top-level option space where the standard DHCPv4 options belong. The server-tags parameter must not be specified for this command.
16.14.32. 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 Standard DHCPv4 Options and Standard DHCPv6 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.
{
"command": "remote-option6-subnet-set",
"arguments": {
"subnets": [
{
"id": 123
}
],
"options": [
{
"name": "dns-servers",
"data": "2001:db8:1::1"
}
],
"remote": {
"type": "mysql"
}
}
}
The sever-tags parameter must not 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 specified instead of the name.
16.14.33. 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:
{
"command": "remote-subnet4-del-by-id",
"arguments": {
"subnets": [
{
"id": 5
}
],
"remote": {
"type": "mysql"
}
}
}
The server-tags parameter must not be used with this command.
16.14.34. 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:
{
"command": "remote-subnet6-del-by-prefix",
"arguments": {
"subnets": [
{
"subnet": "2001:db8:1::/64"
}
],
"remote": {
"type": "mysql"
}
}
}
The server-tags parameter must not be used with this command.
16.14.35. 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:
{
"command": "remote-subnet4-get-by-id",
"arguments": {
"subnets": [
{
"id": 5
}
],
"remote": {
"type": "mysql"
}
}
}
The server-tags parameter must not be used with this command.
16.14.36. 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:
{
"command": "remote-subnet6-get-by-prefix",
"arguments": {
"subnets": [
{
"subnet": "2001:db8:1::/64"
}
],
"remote": {
"type": "mysql"
}
}
}
The server-tags parameter must not be used with this command.
16.14.37. 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 the “server1” and “server2”:
{
"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:
{
"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:
{
"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 subnet identifier, prefix and associated shared network name. In order to retrieve full information about the selected subnet use the remote-subnet[46]-get-by-id or remote-subnet[46]-get-by-prefix.
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, thus it is also present in the configuration for the “server1” and “server2”.
When listing unassigned subnets, the response will look similar to this:
{
"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.
16.14.38. 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 DHCPv4 Server Configuration and
DHCPv6 Server Configuration). The subnet information conveyed in the
remote-subnet[46]-set
command must include the additional parameter
shared-network-name
, which denotes whether the subnet belongs to a
shared network.
Consider the following example:
{
"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 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
:
{
"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
remote-subnet4-set
command. The server-tags list is mandatory and it 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.</para>
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.
16.14.39. 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
remote-class4-get-all
command to fetch all client classes and find
the dependent ones.
{
"command": "remote-class4-del",
"arguments": {
"client-classes": [
{
"name": "foo"
}
],
"remote": {
"type": "mysql"
}
}
}
The server-tags parameter must not be used for this command because client classes are uniquely identified by name.
16.14.40. The remote-class4-get, remote-class6-get Commands¶
These commands retrieve DHCPv4 or DHCPv6 client class information by a client class name.
{
"command": "remote-class4-get",
"arguments": {
"client-classes": [
{
"name": "foo"
}
],
"remote": {
"type": "mysql"
}
}
}
The server-tags parameter must not be used for this command because client classes are uniquely identified by name.
A response to the command looks similar to this:
{
"result": 0,
"text": "DHCPv4 client class 'foo' found.",
"arguments": {
"client-classes": [
{
"name": "foo",
"metadata": {
"server-tags": [ "all" ]
}
}
],
"count": 1
}
}
16.14.41. 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, or all servers. For example, the following command retrieves all client classes defined for a server having the server tag of server1 and all servers. In other words, it returns all client classes used by that server.
{
"command": "remote-class4-get-all",
"arguments": {
"remote": {
"type": "mysql"
},
"server-tags": [ "server1" ]
}
}
The server-tags parameter is mandatory and it contains one or more server tags. It may contain the keyword “all” to fetch the client classes associated with all servers. 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:
{
"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
}
}
16.14.42. 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 Client Classification in DHCPv4 and Client Classification in DHCPv6 for details).
{
"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 Using Expressions in Classification apply to the classes inserted into the database. It implies 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 for specifying a position of the inserted or updated client class. The optional follow-class-name parameter can be included in the command to specify 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 the command similar to the following:
{
"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 the third-class can depend on the first-class because it is placed after the first-class. The third-class must not depend on the second-class because it is placed before it. However, the second-class could now be updated to depend on the third-class.
The follow-class-name parameter can be explicitly set to null, e.g.:
{
"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 is 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.
16.15. ha
: High Availability¶
The High Availability 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 of one of the servers. This library was previously only available to ISC’s paid subscribers, but is now part of the open source Kea, available to all users.
Note
This library may only be loaded by the kea-dhcp4
or
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, difficult to use, has significant operational constraints, and is different than its v4 counterpart. Although it may be useful for some users to use a “standard” failover protocol, it seems that 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.
16.15.1. 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, 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.” However, 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
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 the hot-standby
over the load-balancing
mode is that the former
has a simpler configuration. Conversely, load-balancing
has higher
performance potential at the cost of more complex configuration.
See Load-Balancing Configuration 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 servers as an additional storage for leases without a need for 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 start 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.
16.15.2. 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 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 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.
16.15.3. HTTPS Support¶
Since Kea 1.9.7, the High Availability hook library supports HTTPS via TLS, as described in TLS/HTTPS Support.
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 Control Agent to require and verify client certificate
in Client-Server communication. It does not affect communication
between HA peers.
Currently using HTTPS in HA setup requires use of Control Agent on all peers. (See TLS/HTTPS Support for Control Agent TLS configuration).
Following is an example of HA server pair and Control Agent configuration for Hot-Standby with TLS.
Server 1:
"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": [{
"subnet": "192.0.3.0/24",
"pools": [{
"pool": "192.0.3.100 - 192.0.3.250",
}]
}]
}
Server 2:
"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": [{
"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
}
}
16.15.4. 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
ha-heartbeat
command sent over the RESTful API. If the partner
server does not respond to the 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
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 theload-balancing
andpartner-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 thepartner-down
state. Thecommunication-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 thedelayed-updates-limit
to 0. (Please refer to Load-Balancing Configuration, later in this chapter, for details on this parameter.) Disabling entry into thecommunication-recovery
state causes the server to begin testing for thepartner-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 theha-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 thein-maintenance
state it can be safely shut down. The partner is in thepartner-in-maintenance
state, from which it transitions to thepartner-down
state immediately after it discovers 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 thepartner-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 aha-maintenance-start
command from the administrator. The server in this state becomes responsible for responding to all DHCP requests. The server sends aha-maintenance-notify
command to the partner, which should enter thein-maintenance
state. The server remaining in thepartner-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 thepartner-in-maintenance
state transitions to thepartner-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 thewait-backup-ack
configuration parameter totrue
, 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 thepartner-down
state - that it should return to normal operation. If and when it does, the server in theready
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 thedhcp-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 theha-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 thepartner-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 thesync-leases
configuration parameter is set tofalse
, will never transition to this state. Instead, it transitions directly from thewaiting
state to theready
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 theterminated
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 thebackup
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 thepartner-down
state. If the partner is available, the server transitions to thesyncing
orready
state, depending on the setting of thesync-leases
configuration parameter. If both servers appear to be in thewaiting
state (concurrent startup), the primary server transitions to the next state first. The secondary or standby server remains in thewaiting
state until the primary transitions to theready
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.
State | Server Type | DHCP Service | DHCP Service Scopes |
---|---|---|---|
backup | backup server | disabled | none |
communication-recovery | primary or secondary (load-balancing mode only) | enabled | “HA_server1” or “HA_server2” |
hot-standby | primary or standby (hot-standby mode) | enabled | “HA_server1” if primary, none otherwise |
load-balancing | primary or secondary (load-balancing mode) | enabled | “HA_server1” or “HA_server2” |
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 Load Balancing with Advanced Classification for more details).
16.15.5. 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.
16.15.6. 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 will only use the pool fragments owned by the partner when
the partner is not running. See the notes in
Supported Configurations highlighting differences between
the load-balancing
and hot-standby
modes. The semantics of pool
partitioning is explained further in this section.
The Load Balancing with Advanced Classification 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,
"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": [{
"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:
libdhcp_lease_cmds.so
and 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 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 with one of the servers specified within thepeers
list.mode
- specifies an HA mode of operation. The currently supported modes areload-balancing
andhot-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 theheartbeat-delay
; typically it should be a multiple ofheartbeat-delay
. When the server detects that communication is interrupted, it may transition to thepartner-down
state (whenmax-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 thesecs
field (DHCPv4) orElapsed 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 (seemax-ack-delay
) before this server assumes that the partner is offline and transitions to thepartner-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 thepartner-down
state immediately. The default value of this parameter is 10.delayed-updates-limit
- specifies the maximum number of lease updates which can be queued while the server is in thecommunication-recovery
state. This parameter was introduced in Kea 1.9.4. The special value of 0 configures the server to never transition to thecommunication-recovery
state and the server behaves as in earlier Kea versions, i.e. if the server cannot reach its partner, it goes straight into thepartner-down
state. The default value of this parameter is 100.
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 fail),
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 the respective 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 will be 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 tobasic-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
, andbackup
. 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 istrue
.
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.
16.15.7. 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.
"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": [{
"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
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 Client Classification for details on how to use the member
expression and class dependencies.
16.15.8. 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,
"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": [{
"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 Load-Balancing Configuration, 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.
16.15.9. Passive-Backup Configuration¶
The following is an example configuration file for the primary server in a passive-backup 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": "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": [{
"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
, and others related to the automatic failover mechanism
should not be specified in the passive-backup mode.
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_CILENT_QUEUE_SIZE_GROWING in Kea Messages Manual) 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.
16.15.10. 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.
16.15.11. Controlling Lease-Page Size Limit¶
An HA-enabled server initiates synchronization of the lease database
after downtime or upon receiving the ha-sync
command. The server
uses commands described in The lease4-get-page, lease6-get-page Commands and
The lease4-get-page, lease6-get-page Commands 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.
16.15.12. 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 Controlling Lease-Page Size Limit. Before the page of leases is fetched,
the synchronizing server sends a 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
.
16.15.13. Pausing the HA State Machine¶
The high-availability
state machine includes many different states
described in detail in 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 ha-continue
command
must be sent to the paused server. This command does not take any
arguments. See Control Commands for High Availability for details about commands
specific to the HA hook library.
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 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.
16.15.14. Control Agent Configuration¶
The Kea Control 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.
16.15.15. 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 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. Whenfalse
(the default), the server operates as in earlier versions, relying onkea-ctrl-agent
and using single-threaded HTTP client processing.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 ofkea-ctrl-agent
traffic, allowing peers to send their HA commands directly to each other. The listener listens on the peer’surl
. When false (the default), the server relies onkea-ctrl-agent
. This parameter has been provided largely for flexibility and testing; running HA+MT without dedicated listeners enabled will substantially limit HA throughput.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 direct connection, the DHCPv4 server open its own
// socket. Note 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 direct connection, the DHCPv4 server open its own
// socket. Note 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. Our is primary.
"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.
16.15.16. 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.
16.15.17. 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 Scope Transition in a Partner-Down Case 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 ha-maintenance-start
command was introduced to allow
the administrator to put the pair of the active servers in states 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 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 ha-maintenance-start
request was already sent to the other server.
Upon receiving the ha-maintenance-start
command, server1
sends the 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 ha-maintenance-start
command to server2
.
If the 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 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 allowing it to complete its normal state negotiation process.
16.15.18. 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 and start serving all DHCP clients. Once the hook
library on the first server is upgraded to a current version, the
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 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 ha-maintenance-start
command while the server
running the old hook library is still online. The server receiving
this command will return an error.
16.15.19. 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.
16.15.19.1. The ha-sync
Command¶
The 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 ha-sync
command must be issued to that peer.
Database synchronization may be triggered for both active and backup
server types. The 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
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 lease4-get-page
commands. When the lease-database
synchronization is complete, the synchronizing server sends the
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.
16.15.19.2. The ha-scopes
Command¶
This command allows an administrator to modify the HA scopes being
served. Consult Load-Balancing Configuration and
Hot-Standby Configuration to learn which scopes are
available for the different HA modes of operation. The ha-scopes
command
has the following structure (in a DHCPv4 example):
{
"command": "ha-scopes",
"service": [ "dhcp4" ],
"arguments": {
"scopes": [ "HA_server1", "HA_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": [ ]
}
}
16.15.19.3. The ha-continue
Command¶
This command is used to resume the operation of the paused HA state machine, as described in Pausing the HA State Machine. It takes no arguments, so the command structure is simply:
{
"command": "ha-continue",
"service": [ "dhcp4" ]
}
16.15.19.4. The ha-heartbeat
Command¶
The Server States section describes how the 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 ha-heartbeat
command takes no
arguments:
{
"command": "ha-heartbeat",
"service": [ "dhcp4" ]
}
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 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 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 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 Scope Transition in a Partner-Down Case
section describes the algorithm which the surviving server follows before
it transitions to the partner-down
state. If the 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.
16.15.19.5. The status-get
Command¶
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 status-get
command, including
the HA status of two load-balancing servers:
{
"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"
},
"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
}
}
}
],
"multi-threading-enabled": true,
"thread-pool-size": 4,
"packet-queue-size": 64,
"packet-queue-statistics": [ 0.2, 0.1, 0.1 ]
}
}
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 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 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 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 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 Load-Balancing Configuration.
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 themax-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 themax-response-delay
setting.unacked-clients-left
- this indicates the number of additional clients which have to be considered “unacked” before the server enters thepartner-down
state. This value decreases when theunacked-clients
value increases. The local server enters thepartner-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 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.
16.15.19.6. The ha-maintenance-start
Command¶
This command is used to initiate transition of the server’s partner into
the in-maintenance
state and the transition of the server receiving the
command into the partner-in-maintenance
state. See the
Controlled Shutdown and Maintenance of DHCP servers section for details.
{
"command": "ha-maintenance-start",
"service": [ "dhcp4" ]
}
16.15.19.7. The ha-maintenance-cancel
Command¶
This command is used to cancel the maintenance previously initiated using
the ha-maintenance-start
command. The server receiving this command
will first send ha-maintenance-notify
, with the cancel
flag set
to true
, to its partner. Next, the server reverts from the
partner-in-maintenance
state to its previous state. See the
Controlled Shutdown and Maintenance of DHCP servers section for details.
{
"command": "ha-maintenance-cancel",
"service": [ "dhcp4" ]
}
16.15.19.8. The ha-maintenance-notify
Command¶
This command is sent by the server receiving the ha-maintenance-start
or the 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 Controlled Shutdown and Maintenance of DHCP servers section for details.
{
"command": "ha-maintenance-notify",
"service": [ "dhcp4" ],
"arguments": {
"cancel": false
}
}
Warning
The 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.
16.15.19.9. 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 the command to reset a misbehaving state machine.
This command includes no arguments:
{
"command": "ha-reset",
"service": [ "dhcp4" ]
}
And 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.
16.15.19.10. 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
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.
This command includes no arguments:
{
"command": "ha-sync-complete-notify",
"service": [ "dhcp4" ]
}
And elicits the response:
{
"result": 0,
"text": "Server successfully notified about the synchronization completion."
}
Warning
The 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.
16.16. stat_cmds
: Supplemental Statistics Commands¶
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
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
This library may only be loaded by the kea-dhcp4
or
kea-dhcp6
process.
The commands currently provided by this library are:
stat-lease4-get
- fetches DHCPv4 lease statistics.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 Management API) or the Control Agent (see The Kea Control Agent).
This library may be loaded by both the kea-dhcp4
and kea-dhcp6
servers. It
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 may be loaded by any or all of the servers. However,
a server’s response to a
stat-lease[46]-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.
16.16.1. The stat-lease4-get
, stat-lease6-get
Commands¶
The stat-lease4-get
and 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 kea-dhcp4
server:
{
"command": "stat-lease4-get"
}
The following command fetches lease statistics for subnet ID 10 from a
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 kea-dhcp4
server:
{
"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; or2
- 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 sum 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 sum 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-nas
- 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 sum 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-nas", "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"
}
}
}
16.17. radius
: RADIUS Server Support¶
The RADIUS hook library allows Kea to interact with two types of RADIUS servers: 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 kea-dhcp4
or the
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 Configuring Pools With Class Information), 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.
16.17.1. Compilation and Installation of the RADIUS Hook¶
The following section describes how to compile and install the software on CentOS 7.0. Other systems may differ slightly.
Note
ISC provides Kea software and hooks in convenient-to-use native Alpine, deb, and RPM packages. This includes the RADIUS hook and the required patched version of the FreeRADIUS client library. The software compilation for RADIUS is complicated; unless there are specific reasons to compile it, administrators should seriously consider using native packages.
STEP 1: Install dependencies
Several tools are needed to build the dependencies and Kea itself. The following commands should install them:
$ sudo rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
$ sudo yum install gcc-g++ openssl-devel log4cplus-devel wget git
STEP 2: Install FreeRADIUS
The Kea RADIUS hook library uses the FreeRADIUS client library to conduct RADIUS communication. Unfortunately, the standard 1.1.7 release available from the project website https://freeradius.org/sub_projects/ has several serious deficiencies; ISC engineers observed a segmentation fault during testing. Also, the base version of the library does not offer asynchronous transmissions, which are essential for effective accounting implementation. Both of these issues were addressed by ISC engineers, and the changes have been reported to the FreeRADIUS client project. Acceptance of those changes is outside of ISC’s control, so until those are processed, it is strongly recommended to use the FreeRADIUS client with ISC’s patches. To download and compile this version, please use the following steps:
$ git clone https://github.com/fxdupont/freeradius-client.git
$ cd freeradius-client/
$ git checkout iscdev
$ ./configure
$ make
$ sudo make install
Additional parameters may be passed to the configure script, if needed. The FreeRADIUS client will be installed in /usr/local, which is the default path where Kea will look for it. It can be installed in a different directory; if so, make sure to add that path to the configure script when compiling Kea.
STEP 3: Install a recent Boost version
Kea requires a reasonably recent Boost version. Unfortunately, the version available in CentOS 7 is too old, so a newer Boost version is necessary. Furthermore, CentOS 7 has an old version of the g++ compiler that does not handle the latest Boost versions. Fortunately, Boost 1.65 meets both requirements; it is both recent enough for Kea and can be compiled using the g++ 4.8 version in CentOS.
To download and compile Boost 1.65, please use the following commands:
$ wget -nd https://boostorg.jfrog.io/artifactory/main/release/1.65.1/source/boost_1_65_1.tar.gz
$ tar -zxvf boost_1_65_1.tar.gz
$ cd boost_1_65_1/
$ ./bootstrap.sh
$ ./b2 --without-python
$ sudo ./b2 install
Note that the b2
script may optionally take extra parameters; one of
them specifies the destination path where the sources are to be
compiled.
Alternatively, some systems provide newer Boost packages. For example,
CentOS 7 provides boost169-devel
. If it is installed with
yum install boost169-devel
, Kea must be pointed to it with:
$ ./configure --with-boost-include=/usr/include/boost169 --with-boost-lib-dir=/usr/lib64/boost169
STEP 4: Compile and install Kea
Obtain the Kea sources either by downloading them from the git repository or extracting the tarball. Use one of these commands to obtain the Kea sources.
Choice 1: Retrieve from GitHub
$ git clone https://github.com/isc-projects/kea.git
Choice 2: Retrieve a tarball and extract it
$ tar -zxvf kea-2.1.6.tar.gz
The next step is to extract the premium Kea package that contains the RADIUS repository into the Kea sources. After the tarball is extracted, the Kea sources should have a premium/ subdirectory.
$ cd kea $ tar -zxvf ../kea-premium-radius-2.1.6.tar.gz
Once this is done, verify that the Kea sources look similar to this:
$ ls -l
total 952
-rw-r--r-- 1 thomson staff 6192 Apr 25 17:38 AUTHORS
-rw-r--r-- 1 thomson staff 29227 Apr 25 17:38 COPYING
-rw-r--r-- 1 thomson staff 360298 Apr 25 20:00 ChangeLog
-rw-r--r-- 1 thomson staff 645 Apr 25 17:38 INSTALL
-rw-r--r-- 1 thomson staff 5015 Apr 25 17:38 Makefile.am
-rw-r--r-- 1 thomson staff 587 Apr 25 17:38 README
-rw-r--r-- 1 thomson staff 62323 Apr 25 17:38 configure.ac
drwxr-xr-x 12 thomson staff 408 Apr 26 19:04 doc
drwxr-xr-x 7 thomson staff 238 Apr 25 17:38 examples
drwxr-xr-x 5 thomson staff 170 Apr 26 19:04 ext
drwxr-xr-x 8 thomson staff 272 Apr 26 19:04 m4macros
drwxr-xr-x 20 thomson staff 680 Apr 26 11:22 premium
drwxr-xr-x 10 thomson staff 340 Apr 26 19:04 src
drwxr-xr-x 14 thomson staff 476 Apr 26 19:04 tools
The makefiles must be regenerated using autoreconf
.
The next step is to configure Kea, and there are several essential steps
necessary here. Running autoreconf -if
is necessary to compile the
premium package that contains RADIUS. Also, the --with-freeradius
option
is necessary to tell Kea where the FreeRADIUS client sources can be
found. Also, since the non-standard Boost is used, the path to it must
be specified.
$ autoreconf -i
$ ./configure --with-freeradius=/path/to/freeradius --with-boost-include=/path/to/boost --with-boost-lib-dir=/path/to/boost/state/lib
For example, assuming the FreeRADIUS client was installed in the default directory (/usr/local) and the Boost 1.65 sources were compiled in /home/thomson/devel/boost1_65_1, the configure path should look as follows:
$ ./configure --with-freeradius=/usr/local \
--with-boost-include=/home/thomson/devel/boost_1_65_1 \
--with-boost-lib-dir=/home/thomson/devel/boost_1_65_1/stage/lib
After some checks, the configure script should print a report similar to the following:
Kea source configure results: -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- Package: Name: kea Version: 2.1.6 Extended version: 2.1.6 (tarball) OS Family: Linux Hooks directory: /usr/local/lib/kea/hooks Premium hooks: yes Included Hooks: forensic_log flex_id host_cmds subnet_cmds radius host_cache C++ Compiler: CXX: g++ --std=c++11 CXX_VERSION: g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-16) CXX_STANDARD: 201103 DEFS: -DHAVE_CONFIG_H CPPFLAGS: -DOS_LINUX -DBOOST_ASIO_HEADER_ONLY CXXFLAGS: -g -O2 LDFLAGS: -lpthread KEA_CXXFLAGS: -Wall -Wextra -Wnon-virtual-dtor -Wwrite-strings -Woverloaded-virtual -Wno-sign-compare -pthread -Wno-missing-field-initializers -fPIC Python: PYTHON_VERSION: not needed (because kea-shell is disabled) Boost: BOOST_VERSION: 1.65.1 BOOST_INCLUDES: -I/home/thomson/devel/boost_1_65_1 BOOST_LIBS: -L/home/thomson/devel/boost_1_65_1/stage/lib -lboost_system OpenSSL: CRYPTO_VERSION: OpenSSL 1.0.2k 26 Jan 2017 CRYPTO_CFLAGS: CRYPTO_INCLUDES: CRYPTO_LDFLAGS: CRYPTO_LIBS: -lcrypto Botan: no Log4cplus: LOG4CPLUS_VERSION: 1.1.3 LOG4CPLUS_INCLUDES: -I/usr/include LOG4CPLUS_LIBS: -L/usr/lib -L/usr/lib64 -llog4cplus Flex/bison: FLEX: flex BISON: bison -y MySQL: no PostgreSQL: no Google Test: no FreeRADIUS client: FREERADIUS_INCLUDE: -I/usr/local/include FREERADIUS_LIB: -L/usr/local/lib -lfreeradius-client FREERADIUS_DICTIONARY: /usr/local/etc/radiusclient/dictionary Developer: Enable Debugging: no Google Tests: no Valgrind: not found C++ Code Coverage: no Logger checks: no Generate Documentation: no Parser Generation: no Kea-shell: no Perfdhcp: no
Please make sure that the compilation includes the following:
- RADIUS listed in Included Hooks;
- FreeRADIUS client directories printed and pointing to the right directories;
- Boost version at least 1.65.1. The versions available in CentOS 7 (1.48 and 1.53) are too old.
Once the configuration is complete, compile Kea using make
. If the
system has more than one core, using the -jN
option is recommended to speed up the build.
$ make -j5
$ sudo make install
16.17.2. RADIUS Hook Configuration¶
The RADIUS hook is a library that must be loaded by either DHCPv4 or DHCPv6 Kea servers. Unlike some other available hook libraries, this one takes many parameters. For example, this configuration could be used:
"Dhcp4": {
# Your regular DHCPv4 configuration parameters 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/libdhc_radius.so",
"parameters": {
# Specify where FreeRADIUS dictionary could be located
"dictionary": "/usr/local/etc/freeradius/dictionary",
# Specify which address to use to communicate with RADIUS servers
"bindaddr": "*",
# more RADIUS parameters 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, which correspond to FreeRADIUS client library options:
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.canonical-mac-address
(defaultfalse
) - specifies whether MAC addresses in attributes follow the canonical RADIUS format (lowercase pairs of hexadecimal digits separated by-
).client-id-pop0
(defaultfalse
) - used withflex-id
, removes the leading zero (or pair of zeroes in DHCPv6) type inclient-id
(duid
in DHCPv6). Implied byclient-id-printable
.client-id-printable
(defaultfalse
) - checks whether theclient-id
/duid
content is printable and uses it as is instead of in hexadecimal. Impliesclient-id-pop0
andextract-duid
as 0 and 255 are not printable.deadtime
(default0
) - is a mechanism to try unresponsive servers after responsive servers. Its value specifies the number of seconds after which a server is considered not to have answered, so 0 disables the mechanism. As the asynchronous communication does not use locks or atomics, it is recommended not to use this feature when running in this mode.dictionary
(default set by configure at build time) - is the attribute and value dictionary. Note that it is a critical parameter. Dictionary examples can be found in the FreeRADIUS repository under the etc/ directory.extract-duid
(defaulttrue
) - extracts the embeddedduid
from an RFC 4361-compliant DHCPv4client-id
. Implied byclient-id-printable
.identifier-type4
(defaultclient-id
) - specifies the identifier type to build the User-Name attribute. It should be the same as the host identifier, and when theflex-id
hook library is used thereplace-client-id
must be set totrue
;client-id
is used withclient-id-pop0
.identifier-type6
(defaultduid
) - specifies the identifier type to build the User-Name attribute. It should be the same as the host identifier, and when theflex-id
hook library is used thereplace-client-id
must be set totrue
;duid
is used withclient-id-pop0
.realm
(default""
) - is the default realm.reselect-subnet-address
(defaultfalse
) - uses the Kea reserved address/RADIUS Framed-IP-Address or Framed-IPv6-Address to reselect subnets where the address is not in the subnet range.reselect-subnet-pool
(defaultfalse
) - uses the Keaclient-class
/RADIUS Frame-Pool to reselect subnets where no available pool can be found.retries
(default3
) - is the number of retries before trying the next server. Note that it is not supported for asynchronous communication.session-history
(default""
) - is the name of the file providing persistent storage for accounting session history.timeout
(default10
) - is the number of seconds during which a response is awaited.
When reselect-subnet-pool
or reselect-subnet-address
is set to
true
at the reception of RADIUS Access-Accept, the selected subnet is
checked against the client-class
name or the reserved address; if it
does not match, another subnet is selected among matching subnets.
Two services are supported:
access
- the authentication service.accounting
- the accounting service.
Configuration of services is divided into two parts:
Servers that define RADIUS servers that the library is expected to contact. Each server may have the following items specified:
name
- specifies the IP address of the server (it is possible to use a name which will be resolved, but it is not recommended).port
(default RADIUS authentication or accounting service) - specifies the UDP port of the server. Note that the FreeRADIUS client library by default uses ports 1812 (authorization) and 1813 (accounting). Some server implementations use 1645 (authorization) and 1646 (accounting). Theport
parameter may be used to adjust as needed.secret
- authenticates messages.
There may be up to eight servers. Note that 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), orexpr
(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. The data entry is parsed by the FreeRADIUS library, so values defined in the dictionary of the attribute may be used.raw
- the second of three ways to specify the attribute content; it specifies the content in hexadecimal. Note that it does not work with integer-content attributes (date, integer, and IPv4 address); a string-content attribute (string, IPv6 address, and IPv6 prefix) is required.expr
- the last way to specify the attribute content. It specifies an evaluation expression which must return a not-empty string when evaluated with the DHCP query packet. Currently this is restricted to the access service.
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 (Password, Connect-Info, and Configuration-Token), the following snippet could be used:
"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": "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 Section 13) 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-Name 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:
{
"parameters": {
"access": {
"attributes": [
{
"name": "User-Name",
"expr": "hexstring(pkt4.mac, '-')"
}
]
}
}
}
And here’s how to specify period-separated hexadecimal notation (dead.beef.cafe
), preferred by Cisco devices:
{
"parameters": {
"access": {
"attributes": [
{
"name": "User-Name",
"expr": "concat(concat(concat(substring(hexstring(pkt4.mac, ''), 0, 4), '.'), concat(substring(hexstring(pkt4.mac, ''), 4, 4), '.'), concat(substring(hexstring(pkt4.mac, ''), 8, 4), '.'))"
}
]
}
}
}
For the RADIUS hook library to operate properly in DHCPv4,
the Host Cache hook library 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 Comments and User Context and User Contexts in Hooks for details.) The host-cache mechanism allows the information retrieved by RADIUS to be stored and later used for sending accounting and access 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.
16.18. host_cache
: Caching Host Reservations¶
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
This library can only be loaded by the kea-dhcp4
or
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/libdhc_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 Using the Control Channel) or the RESTful API (see Overview of the Kea Control Agent). An example RESTful API client is described in Overview of the Kea Shell. The following sections describe the commands available.
16.18.1. 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 cache-clear
instead. The hosts are stored in FIFO
(first-in, first-out) order, so the oldest entries are always removed.
16.18.2. 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 cache-flush
instead.
16.18.3. The cache-size
Command¶
This command returns the number of host entries. An example usage looks as follows:
{
"command": "cache-size"
}
16.18.4. 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 cache-load
command or
processed by any other tool that is able to understand JSON format.
16.18.5. 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 cache-load
command or
processed by any other tool that is able to understand JSON format.
16.18.6. The cache-get
Command¶
This command is similar to 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.
16.18.7. The cache-get-by-id
Command¶
This command is similar to 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.
16.18.8. 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 Host Reservations in DHCPv4 or
Host Reservations in DHCPv6), 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
}
}
16.18.9. 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
cache-remove
command can solve this problem by removing a cached entry
after administrative changes.
The cache-remove
command works similarly to the 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
}
}
16.19. lease_query
: Leasequery¶
This library provides support for DHCPv4 Leasequery as described in RFC 4388; and for DHCPv6 Leasequery (RFC 5007).
Note
This library can only be loaded by the kea-dhcp4
or
kea-dhcp6
process.
The Leasequery library is only available to ISC customers with a paid support contract.
16.19.1. 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 addresschaddr
- set to the lease’s hardware address
In addition, one or more of the following options are included:
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 Storing Extended Lease Information) |
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.
16.19.2. 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.
16.19.3. 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) orquery-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 singleclientid
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 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 is not currently implemented. Leases for delegated prefixes may only be returned when querying by client ID. See GitLab issue #1275
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:
Query Outcome | Status Label | Status Code | Status Text |
---|---|---|---|
Invalid query type field | STATUS_UnknownQueryType | 7 | “unknown query-type” |
Query by IP address that does not contain an address option | STATUS_Malformed | 10 | “missing D6O_IAADDR” |
Query by IP address for an address that does fall within any configured pools | STATUS_NotConfigured | 9 | “address not in a configured pool” |
Query by IP address which found only an inactive lease (e.g. expired, declined, reclaimed-expired) | STATUS_Success | 0 | “inactive lease exists” |
Query by IP address that found no leases (active or otherwise) | STATUS_Success | 0 | “no active lease” |
Query by IP address that found an active lease for the address | STATUS_Success | 0 | “active lease found” |
Query by Client ID that does not contain a client ID option | STATUS_Malformed | 10 | “missing D6O_CLIENTID” |
Query by Client ID with a link address that does not match any configured subnets | STATUS_NotConfigured | 9 | “not a configured link” |
Query by client ID which found no matching leases | STATUS_Success | 0 | “no active leases” |
Query by client ID which found one or more active leases | STATUS_Success | 0 | “active lease(s) found” |
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)
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).
The client-data option encapsulates the following options:
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
Storing Extended Lease Information), then an OPTION_LQ_RELAY_DATA
option is
added to the reply (see
RFC 5007, 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.
16.19.4. 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" ]
}
}
],
:
Note
For security purposes, there is no way to specify wildcards. Each requester address must be explicitly listed.
16.20. Run Script Support¶
This hook library adds support for calling an external script for specific packet-processing hook points.
The library, which was added in Kea 1.9.5, can be loaded in a
similar way to other hook libraries by the kea-dhcp4
and
kea-dhcp6
processes.
{
"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.
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
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
16.21. ddns_tuning
: Tuning DDNS updates¶
This hook library adds support for fine tuning various DNS update aspects. Currently it supports procedural host name generation and the ability to skip performing DDNS updates for select clients. The DDNS Tuning hook is a premium feature.
The library, which was added in Kea 2.1.5, can be loaded by the kea-dhcp4
and kea-dhcp6
daemons by adding it to hooks-libraries
element of the
server’s configuration:
{
"hooks-libraries": [
:
,
{
"library": "/usr/local/lib/libdhcp_ddns_tuning.so",
"parameters": {
:
}
},
:
]
}
16.21.1. 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 will apply to all hosts in all subnets. The expressions can use all tokens defined in Client Classification. An example of a global expression is shown below:
{
"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 user-context mechanism. If defined at the subnet level, the expression applies to 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:
"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 slash, ‘’, to show line continuation. This is for clarity only and is not valid JSON supported by Kea parsing. The actual value has to be expressed in 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 MAC address, are usually a very bad idea. The global expression example used MAC address for simplicity.
16.21.1.1. DHCPv4 host name generation¶
With this library installed the behavior for 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 along with the DDNS behavioral parameters to form the final host name. Goto step 4.
2. If the client supplied an FQDN option (option 81) use the domain name value specified within it along with the DDNS behavioral parameters to form the final host name. Goto step 4.
3. If the client supplied a host name option (option 12) use the host name specified within it along with the DDNS behavioral parameters to form the final host name.
4. If there is an 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 the prior steps (1 or 2), the calculated value becomes the final host name.
16.21.1.2. DHCPv6 host name generation¶
With this library installed the behavior for 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 along with the DDNS behavioral parameters to form the final host name. Goto step 4.
2. If the client did not supply an FQDN but ddns-replace-client-name is either
always
orwhen-not-present
, then calculate the final form of the host name and use it to create an outbound FQDN. Goto 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, and 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 the prior steps (1 or 2), the calculated value becomes the final host name.
16.21.2. Skipping DDNS Updates¶
The ddns-tuning library 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, kea servers (kea-dhcp4 and kea-dhcp6) will not send DDNS update requests (NCRs) to 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:
{
"reservations": [
{
"hw-address": "01:02:03:04:05:06",
"ip-address": "192.0.2.1",
"client-classes": [ "SKIP_DDNS", "foo", "bar" ]
}]
}
The ddns-tuning library will spot the presence of the “SKIP_DDNS” class in the client’s class list each time the client requests, renews, or releases its lease, and instruct kea-dhcp4 to bypass sending DDNS updates. A similar work flow is supported for kea-dhcp6:
{
"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:
{
"client-classes":[
{
"name": "SKIP_DDNS",
"test": "member('KNOWN')"
}]
}
Note
In order for the SKIP_DDNS class to have an effect, the DDNS-tuning hook library must be loaded.
16.22. limits
: Rate Limiting¶
This hook library enables limiting the rate at which packets are being processed. The limits hook library is part of the subscription package.
16.22.1. Configuration¶
The library can be loaded by both kea-dhcp4
and kea-dhcp6
servers by adding its path in the
"hooks-libraries"
element of the server’s configuration.
The 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 on 32 bits i.e. between 0
and
4,294,967,295
. <time-unit>
can be any of second
, minute
, hour
, day
,
week
, month
, year
. month
is considered to be 30 days for simplicity. Similarly,
year
is 365 days for all intents and purposes of limiting. This syntax covers a high range of
rates from one lease per year to four billion leases per second.
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 it might be imagined. Disabling limiting altogether is achieved by removing
the “rate-limit” leaf configuration entry, the “limits” map around it or the user context around
it or the hook library configuration.
There are two ways to configure which packets get limited. One is through the client classes that are initially assigned to the packet. In this case, the limit is configured in the user context in the client class definition. Class rate limits are checked early in packet processing cycle and is thus limited to those classes which are assigned to the packet via test expression and that do not depend on host reservations, the special “BOOTP” or “KNOWN” classes, and is not marked with “only-if-required”.
Note
It can be tempting to think that assigning a rate limit of n packets per time unit results in n DORA or n SARR exchanges. By default, all inbound packets are counted. That means that a full message exchange accounts for 2 packets. To achieve the desired effect of counting an exchange only once, you may use client class rate limiting with a test expression that binds pkt4.msgtype to DHCPDISCOVER messages or pkt6.msgtype to SOLICIT messages.
The other way is through the subnet that the Kea selects for the packet. To achieve this, the limit is added to the user context of the subnet definition.
Note
Subnet rate limits 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 will be ignored. In other words, packets are gated only by the rate limit on the original subnet.
The following is an example that adds one rate limit on a client class and another one in a subnet in kea-dhcp6. A valid configuration for kea-dhcp4 can be easily extrapolated.
{
"Dhcp6": {
"client-classes": [
{
"name": "gold",
"user-context": {
"limits": {
"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": {
"rate-limit": "10 packets per minute"
}
}
}
]
}
16.23. Role Based Access Control¶
16.23.1. Role Based Access Control Overview¶
Before the processing of commands in received HTTP requests, the hook takes some parameters e.g. the common name part of the client certificate subject name to assign a role to the request. The configuration associated to this role is used to accept or reject the command. After the processing the response can be rewritten e.g. removing parts.
- Summary of the request processing:
- 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, reject the request by sending an unauthorized response.
- extract the command from the request.
- assign a role using recorded information in the request.
- use the role to accept (i.e. pass through) or reject (i.e. send a forbidden response) the command.
- Summary of response processing:
- retrieve some information attached to the request during the request processing (when the request was accepted).
- applies request filters to the response.
16.23.1.1. Role Based Access Control Configuration¶
16.23.2. Role Assignment¶
The role assignment is governed by the configured role assignment method.
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 | for extension |
16.23.3. Role Configuration¶
If the role assignment returns the empty role the configuration of the
default
role is used: by default the request is rejected.
If the role assignment returns a not empty role without a configuration,
the configuration of the unknown
role is used.
Name | Description |
name | the role name (at 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 accept and reject list by giving the list to check and apply first (default accept) |
response-filters | filters to apply to responses |
16.23.4. API Commands¶
All commands of the REST API are described in files in a directory
which can be found in sources in src/share/api
or in installed Kea
in .../share/kea/api
. The hook reads these files to take the name,
access right (i.e. read
or write
) and the hook name.
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.
16.23.5. Access Control Lists¶
Access control lists can be specified using a name (string) or a single entry map.
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 kind in the name of the single entry and parameter in the value.
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) |
16.23.6. Response Filters¶
Name | Description |
list-commands | Removes not allowed commands from the list-commands response |
16.23.7. Global Parameters¶
Global parameters are:
assign-role-method
: (mandatory) the name of the method which is used for role assignment.api-files
: (mandatory) the path of the directory where the API files describing commands can be found.require-tls
: specifies if received requests on HTTP vs HTTPS are rejected. Default to false when the role assignment method is not based on certificates.commands
: the list of extra command configurations.access-control-lists
: named access control list definitions (each definition is a single entry map: the name of the entry is the name of the access list, the value is the specification).roles
: role configurations.default-role
: the configuration of the default role (used when “” is assigned).unknown-role
: takes the configuration of the unknown role (used when the not empty assigned role has no configuration).
16.23.8. Sample Configuration¶
A sample configuration is available in doc/examples/agent/rbac.json
in the Kea source and is copied below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | {
"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.
}
}
|
16.23.9. Accept/Reject Algorithm¶
Here is the pseudo-code of the accept/reject decision algorithm which returns true i.e. accept or false i.e. reject.
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);
}
}
16.23.10. Extensive Example¶
Here is an extensive example for a role accepting all read commands at the exception of “config-get”, e.g. for hiding passwords or this access list to a remote user (if the user is local “config-write” should be rejected too.
The first option is to put the allowed commands in the “accept-commands” list and to reject anything else:
...
"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 to not set the “reject-commands” list i.e. leaving it empty and to rely on the “other-commands” to reject anything else.
...
"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"
},
...
],
...
One can do the opposite i.e. setting only the “reject-commands” list.
...
"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.
...
"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 i.e. missing (rejected) commands and extra (accepted) commands.
16.24. 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 config-set
or 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.
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, and server ID. These are supported in both DHCPv4 and DHCPv6, with the exception of server ID, which is DHCPv6 only.