1.. _hooks-libraries:
2
3***************
4Hooks Libraries
5***************
6
7.. _hooks-libraries-introduction:
8
9Introduction
10============
11
12Kea is both flexible and customizable, via the use of "hooks." This feature
13lets Kea load one or more
14dynamically linked libraries (known as "hooks libraries") and, at
15various points in its processing ("hook points"), call functions in
16them. Those functions perform whatever custom processing is required.
17
18The hooks concept allows the core Kea code to remain reasonably small
19by moving features to external libraries that some, but not all, users
20find useful. Those with no need for specific functions can simply choose not
21to load the libraries.
22
23Hooks libraries are loaded by individual Kea processes, not by Kea as a
24whole. This means, among other things, that it is possible to associate one set
25of libraries with the DHCP4 server and a different set with the DHCP6
26server.
27
28Another point to note is that it is possible for a process to load
29multiple libraries. When processing reaches a hook point, Kea calls the
30hooks library functions attached to it. If multiple libraries have
31attached a function to a given hook point, Kea calls all of them, in the
32order in which the libraries are specified in the configuration file.
33The order may be important; consult the documentation of the libraries
34for specifics.
35
36When a Kea process unloads a library, it expects the ``dlclose`` function
37removes all library symbols and removes the library code from address space
38on the last reference. This behavior is not required by the POSIX standard
39and at least the musl library used by default by Alpine Linux implements
40the ``dlclose`` function as a no operation. On such systems a library
41is loaded forever in a process, for instance it is not possible to
42replace a library binary by another version using configuration change
43or reload: the process must be stopped and relaunched.
44
45The next section describes how to configure hooks libraries. Users who are
46interested in writing their own hooks library can find information
47in the `Hooks Developer's Guide section of the Kea Developer's
48Guide <https://reports.kea.isc.org/dev_guide/df/d46/hooksdgDevelopersGuide.html>`__.
49
50Note that some libraries are available under different licenses.
51
52Please also note that some libraries may require additional dependencies and/or
53compilation switches to be enabled, e.g. the RADIUS library introduced in
54Kea 1.4 requires the FreeRadius-client library to be present. If
55--with-freeradius option is not specified, the RADIUS library will not
56be built.
57
58Installing Hook Packages
59========================
60
61.. note::
62
63   For more details about installing the Kea Premium Hooks package, please read
64   `this Knowledge Base article <https://kb.isc.org/docs/aa-01587>`__.
65
66Some hook packages are included in the base Kea sources. There is no
67need to do anything special to compile or install them, as they are covered
68by the usual building and installation procedures. Please
69refer to :ref:`installation` for a general overview of the installation process.
70
71ISC provides several additional premium hooks in the form of packages, which
72follow a similar installation procedure but with several additional steps.
73For our users' convenience, the premium hooks installation procedure is described in this section.
74
751. Download the package; detailed instructions are provided separately on how
76to get it. The package will be a file with a name similar to
77kea-premium-|release|.tar.gz. (The name may vary depending on the package
78purchased.)
79
802. Administrators who still have the sources for the corresponding version of the
81open-source Kea package still on their system from the initial Kea installation
82should skip this step. Otherwise, extract the Kea source from the original
83tarball that was downloaded. For example, with a download of Kea |release|.,
84there should be a tarball called kea-|release|.tar.gz on the system.
85Unpack this tarball:
86
87.. parsed-literal::
88
89   $ tar -zxvf kea-|release|.tar.gz
90
91This will unpack the tarball into the kea-|release| subdirectory of
92the current working directory.
93
943. Unpack the Kea premium tarball into the directory into which Kea was
95unpacked. Once Kea |release| has been unpacked into a kea-|release|
96subdirectory and the Kea premium tarball is in the current directory, the following
97steps will unpack the premium tarball into the correct location:
98
99.. parsed-literal::
100
101     $ cd kea-|release|
102     $ tar -xvf ../kea-premium-|release|.tar.gz
103
104Note that unpacking the Kea premium package will put the files into a
105directory named "premium". Regardless of the name of the package, the
106directory will always be called "premium", although its contents will vary
107depending on the premium package.
108
1094. Run ``autoreconf`` tools. This step is necessary to update Kea's build
110script to include the additional directory. If this tool is not already
111available on the system, install the ``automake`` and ``autoconf``
112tools. To generate the configure script, please use:
113
114::
115
116     $ autoreconf -i
117
1185. Rerun configure, using the same configure options that were used when
119originally building Kea. It is possible to verify that configure has detected the
120premium package by inspecting the summary printed when it exits. The
121first section of the output should look something like this:
122
123.. parsed-literal::
124
125   Package:
126     Name:             kea
127     Version:          |release|
128     Extended version: |release| (tarball)
129     OS Family:        Linux
130     Using GNU sed:    yes
131     Premium package:  yes
132     Included Hooks:   forensic_log flex_id host_cmds subnet_cmds radius host_cache class_cmds cb_cmds lease_query
133
134The last line indicates which specific hooks were detected. Note that
135some hooks may require their own dedicated switches, e.g. the RADIUS hook
136requires extra switches for FreeRADIUS. Please consult later sections of
137this chapter for details.
138
1396. Rebuild Kea.
140
141::
142
143     $ make
144
145If the machine has multiple CPU cores, an interesting option to consider
146here is using the argument -j X, where X is the number of available cores.
147
1487. Install Kea sources along with the hooks:
149
150::
151
152   $ sudo make install
153
154Note that as part of the installation procedure, the install script will
155eventually venture into the premium/ directory and will install additional
156hook libraries and associated files.
157
158The installation location of the hooks libraries depends on whether the
159--prefix parameter was specified in the configure script. If not,
160the default location will be /usr/local/lib/kea/hooks. The proper installation
161of the libraries can be verified with this command:
162
163::
164
165   $ ls -l /usr/local/lib/kea/hooks/*.so
166   /usr/local/lib/kea/hooks/libdhcp_class_cmds.so
167   /usr/local/lib/kea/hooks/libdhcp_flex_id.so
168   /usr/local/lib/kea/hooks/libdhcp_flex_option.so
169   /usr/local/lib/kea/hooks/libdhcp_host_cmds.so
170   /usr/local/lib/kea/hooks/libdhcp_lease_cmds.so
171   /usr/local/lib/kea/hooks/libdhcp_legal_log.so
172   /usr/local/lib/kea/hooks/libdhcp_subnet_cmds.so
173
174The exact list returned will depend on the packages installed. If the
175directory was specified via --prefix, the hooks libraries will be located in
176{prefix directory}/lib/kea/hooks.
177
178Configuring Hooks Libraries
179===========================
180
181The hooks libraries for a given process are configured using the
182``hooks-libraries`` keyword in the configuration for that process. (Note
183that the word "hooks" is plural.) The value of the keyword is an array
184of map structures, with each structure corresponding to a hooks library. For
185example, to set up two hooks libraries for the DHCPv4 server, the
186configuration would be:
187
188::
189
190   "Dhcp4": {
191       :
192       "hooks-libraries": [
193           {
194               "library": "/opt/charging.so"
195           },
196           {
197               "library": "/opt/local/notification.so",
198               "parameters": {
199                   "mail": "spam@example.com",
200                   "floor": 13,
201                   "debug": false,
202                   "users": [ "alice", "bob", "charlie" ],
203                   "languages": {
204                       "french": "bonjour",
205                       "klingon": "yl'el"
206                   }
207               }
208           }
209       ]
210       :
211   }
212
213..
214
215.. note::
216
217   This syntax is effective as of Kea 1.1.0, to facilitate the
218   specification of library-specific parameters. Libraries should allow a
219   parameter entry for comments, as is the case with many configuration
220   scopes.
221
222..
223
224.. note::
225
226   In all versions of Kea since 1.1.0, libraries
227   are reloaded even if their lists have not changed,
228   because the parameters specified for the library (or the files those
229   parameters point to) may have changed.
230
231Libraries may have additional parameters that are not mandatory, in the
232sense that there may be libraries that do not require them. However, for a
233specific library there is often a specific requirement to specify a certain
234set of parameters. Please consult the documentation for each individual library for
235details. In the example above, the first library has no parameters. The
236second library has five parameters: specifying mail (string parameter),
237floor (integer parameter), debug (boolean parameter), lists
238(list of strings), and maps (containing strings). Nested parameters can
239be used if the library supports it. This topic is explained in detail in
240the `Hooks Developer's Guide section of the Kea Developer's Guide
241<https://reports.kea.isc.org/dev_guide/df/d46/hooksdgDevelopersGuide.html>`__.
242
243Notes:
244
245-  The full path to each library should be given.
246
247-  As noted above, the order in which the hooks are called may be important;
248   consult the documentation for each library for specifics.
249
250-  An empty list has the same effect as omitting the ``hooks-libraries``
251   configuration element altogether.
252
253   .. note::
254
255      There is one case where this is not true: if Kea is running with a
256      configuration that contains a ``hooks-libraries`` item, and that
257      item is removed and the configuration reloaded, the removal will
258      be ignored and the libraries remain loaded. As a workaround,
259      instead of removing the ``hooks-libraries`` item, change it to an
260      empty list. This will be fixed in a future version of Kea.
261
262At the present time, only the kea-dhcp4 and kea-dhcp6 processes support
263hooks libraries.
264
265Available Hooks Libraries
266=========================
267
268As described above, the hooks functionality provides a way to customize
269a Kea server without modifying the core code. ISC has chosen to take
270advantage of this feature to provide functions that may only be useful
271to a subset of Kea users. To this end, ISC has created some hooks
272libraries, discussed in the following sections.
273
274.. note::
275
276   Some of these libraries are available with the base code, while
277   others will be shared with organizations supporting development of
278   Kea. Users who would like to get access to those premium
279   libraries should consider purchasing a support contract from ISC. This
280   includes professional support, advance security notifications, input
281   into ISC's roadmap planning, and many other benefits, while helping
282   make Kea sustainable in the long term.
283
284The following table provides a list of libraries currently available
285from ISC. It is important to pay attention to which libraries may be
286loaded by which Kea processes. It is a common mistake to configure the
287``kea-ctrl-agent`` process to load libraries that should, in fact, be
288loaded by the ``kea-dhcp4`` or ``kea-dhcp6`` processes. If a library
289from ISC does not work as expected, please make sure that it has been
290loaded by the correct process per the table below.
291
292.. warning::
293
294   While the Kea Control Agent includes the "hooks" functionality, (i.e.
295   hooks libraries can be loaded by this process), none of ISC's current
296   hooks libraries should be loaded by the Control Agent.
297
298.. tabularcolumns:: |p{0.1\linewidth}|p{0.1\linewidth}|p{0.8\linewidth}|
299
300.. table:: List of Available Hooks Libraries
301   :class: longtable
302   :widths: 10 10 80
303
304   +-----------------+---------------+------------------------------------------------------------+
305   | Name            | Availability  | Description                                                |
306   +=================+===============+============================================================+
307   | User Check      | Kea sources   |Reads known users list from a file. Unknown users will be   |
308   |                 | (since 0.8)   |assigned a lease from the last subnet defined in the        |
309   |                 |               |configuration file, e.g. to redirect them to a captive      |
310   |                 |               |portal. This demonstrates how an external source of         |
311   |                 |               |information can be used to influence the Kea allocation     |
312   |                 |               |engine. This hook is part of the Kea source code and is     |
313   |                 |               |available in the src/hooks/dhcp/user_chk directory.         |
314   +-----------------+---------------+------------------------------------------------------------+
315   | Forensic        | Support       |This library provides hooks that record a detailed log of   |
316   | Logging         | customers     |lease assignments and renewals into a set of log files. In  |
317   |                 | (since 1.1)   |many legal jurisdictions companies, especially ISPs, must   |
318   |                 |               |record information about the addresses they have leased to  |
319   |                 |               |DHCP clients. This library is designed to help with that    |
320   |                 |               |requirement. If the information that it records is          |
321   |                 |               |sufficient it may be used directly. If your jurisdiction    |
322   |                 |               |requires that you save a different set of information, you  |
323   |                 |               |may use it as a template or example and create your own     |
324   |                 |               |custom logging hooks. In Kea 1.9.8 additional parameters    |
325   |                 |               |have been added to give users more flexibility regarding    |
326   |                 |               |what information should be logged.                          |
327   +-----------------+---------------+------------------------------------------------------------+
328   | Flexible        | Support       |Kea software provides a way to handle host reservations that|
329   | Identifier      | customers     |include addresses, prefixes, options, client classes and    |
330   |                 | (since 1.2)   |other features. The reservation can be based on hardware    |
331   |                 |               |address, DUID, circuit-id or client-id in DHCPv4 and using  |
332   |                 |               |hardware address or DUID in DHCPv6. However, there are      |
333   |                 |               |sometimes scenarios where the reservation is more complex,  |
334   |                 |               |e.g. uses other options that mentioned above, uses part of  |
335   |                 |               |specific options or perhaps even a combination of several   |
336   |                 |               |options and fields to uniquely identify a client. Those     |
337   |                 |               |scenarios are addressed by the Flexible Identifiers hook    |
338   |                 |               |application. It allows defining an expression, similar to   |
339   |                 |               |the one used in client classification,                      |
340   |                 |               |e.g. substring(relay6[0].option[37],0,6). Each incoming     |
341   |                 |               |packet is evaluated against that expression and its value is|
342   |                 |               |then searched in the reservations database.                 |
343   +-----------------+---------------+------------------------------------------------------------+
344   | Flexible        | Kea sources   |This library provides hooks that compute option values      |
345   | Option          | (since 1.7.1) |instead of static configured values. An expression is       |
346   |                 |               |evaluated on the query packet. Defined add, supersede and   |
347   |                 |               |remove actions are applied on the response packet before    |
348   |                 |               |it is sent using the evaluation result.                     |
349   +-----------------+---------------+------------------------------------------------------------+
350   | Host Commands   | Support       |Kea provides a way to store host reservations in a          |
351   |                 | customers     |database. In many larger deployments it is useful to be able|
352   |                 | (since 1.2)   |to manage that information while the server is running. This|
353   |                 |               |library provides management commands for adding, querying   |
354   |                 |               |and deleting host reservations in a safe way without        |
355   |                 |               |restarting the server.  In particular, it validates the     |
356   |                 |               |parameters, so an attempt to insert incorrect data, e.g. add|
357   |                 |               |a host with conflicting identifier in the same subnet will  |
358   |                 |               |be rejected. Those commands are exposed via command channel |
359   |                 |               |(JSON over unix sockets) and Control Agent (JSON over       |
360   |                 |               |RESTful interface). Additional commands and capabilities    |
361   |                 |               |related to host reservations will be added in the future.   |
362   +-----------------+---------------+------------------------------------------------------------+
363   | Subnet Commands | Support       |In deployments in which subnet configuration needs to be    |
364   |                 | customers     |frequently updated, it is a hard requirement that such      |
365   |                 | (since 1.3)   |updates be performed without the need for a full DHCP server|
366   |                 |               |reconfiguration or restart. This hooks library allows for   |
367   |                 |               |incremental changes to the subnet configuration such as:    |
368   |                 |               |adding a subnet, removing a subnet. It also allows for      |
369   |                 |               |listing all available subnets and fetching detailed         |
370   |                 |               |information about a selected subnet. The commands exposed by|
371   |                 |               |this library do not affect other subnets or configuration   |
372   |                 |               |parameters currently used by the server.                    |
373   +-----------------+---------------+------------------------------------------------------------+
374   | Lease Commands  | Kea sources   |The lease commands hook library offers a number of new      |
375   |                 | (since 1.3)   |commands used to manage leases. Kea provides a way to store |
376   |                 |               |lease information in various backends: memfile, MySQL,      |
377   |                 |               |PostgreSQL and Cassandra. This library provides a unified   |
378   |                 |               |interface that can manipulate leases in an unified, safe    |
379   |                 |               |way. In particular, it allows: manipulate leases in memfile |
380   |                 |               |while Kea is running, sanity check changes, check lease     |
381   |                 |               |existence and remove all leases belonging to specific       |
382   |                 |               |subnet. It can also catch more obscure errors, like adding a|
383   |                 |               |lease with subnet-id that does not exist in the             |
384   |                 |               |configuration or configuring a lease to use an address that |
385   |                 |               |is outside of the subnet to which it is supposed to belong. |
386   |                 |               |It provides a way to manage user contexts associated with   |
387   |                 |               |leases.                                                     |
388   +-----------------+---------------+------------------------------------------------------------+
389   | High            | Kea sources   |Minimizing a risk of DHCP service unavailability is achieved|
390   | Availability    | (since 1.4)   |by setting up a pair of the DHCP servers in a network.  Two |
391   |                 |               |modes of operation are supported. The first one is called   |
392   |                 |               |load balancing and is sometimes referred to as              |
393   |                 |               |active-active. Each server can handle selected groups of    |
394   |                 |               |clients in this network or all clients, if it detects that  |
395   |                 |               |its partner has become unavailable. It is also possible to  |
396   |                 |               |designate one server to serve all DHCP clients, and leave   |
397   |                 |               |another server as "standby". This mode is called hot standby|
398   |                 |               |and is sometimes referred to as active-passive. This        |
399   |                 |               |server will activate its DHCP function when it detects that |
400   |                 |               |its partner is not available.  Such cooperation between the |
401   |                 |               |DHCP servers requires that these servers constantly         |
402   |                 |               |communicate with each other to send updates about allocated |
403   |                 |               |leases and to periodically test whether their partners are  |
404   |                 |               |still operational. The hook library also provides an ability|
405   |                 |               |to send lease updates to external backup servers, making it |
406   |                 |               |much easier to have a replacement that is almost up to      |
407   |                 |               |date. The "libdhcp_ha" library provides such functionality  |
408   |                 |               |for Kea DHCP servers.                                       |
409   +-----------------+---------------+------------------------------------------------------------+
410   | Statistics      | Kea sources   |The Statistics Commands library provides additional         |
411   | Commands        | (since 1.4)   |commands for retrieving accurate DHCP lease statistics for  |
412   |                 |               |Kea DHCP servers that share the same lease database. This   |
413   |                 |               |setup is common in deployments where DHCP service redundancy|
414   |                 |               |is required and a shared lease database is used to avoid    |
415   |                 |               |lease data replication between the DHCP servers. A feature  |
416   |                 |               |was introduced in Kea 1.4.0 that allows tracking lease      |
417   |                 |               |allocations within the lease database, thus making the      |
418   |                 |               |statistics accessible to all connected DHCP servers. The    |
419   |                 |               |Statistics Commands hooks library utilizes this feature and |
420   |                 |               |returns lease statistics for all subnets respectively.      |
421   +-----------------+---------------+------------------------------------------------------------+
422   | RADIUS          | Support       |The RADIUS Hook library allows Kea to interact with the     |
423   |                 | customers     |RADIUS servers using access and accounting mechanisms. The  |
424   |                 | (since 1.4)   |access mechanism may be used for access control, assigning  |
425   |                 |               |specific IPv4 or IPv6 addresses reserved by RADIUS,         |
426   |                 |               |dynamically assigning addresses from designated pools chosen|
427   |                 |               |by RADIUS or rejecting the client's messages altogether. The|
428   |                 |               |accounting mechanism allows a RADIUS server to keep track of|
429   |                 |               |device activity over time.                                  |
430   +-----------------+---------------+------------------------------------------------------------+
431   | Host Cache      | Support       |Some of the database backends, such as RADIUS, are          |
432   |                 | customers     |considered slow and may take a long time to respond. Since  |
433   |                 | (since 1.4)   |Kea in general is synchronous, the backend performance      |
434   |                 |               |directly affects the DHCP performance. To minimize the      |
435   |                 |               |impact and improve performance, the Host Cache library      |
436   |                 |               |provides a way to cache responses from other hosts. This    |
437   |                 |               |includes negative caching, i.e. the ability to remember that|
438   |                 |               |there is no client information in the database.             |
439   +-----------------+---------------+------------------------------------------------------------+
440   | Class Commands  | Support       |This Class Cmds hooks library allows for adding, updating,  |
441   |                 | customers     |deleting and fetching configured DHCP client classes without|
442   |                 | (since 1.5)   |the need to restart the DHCP server.                        |
443   +-----------------+---------------+------------------------------------------------------------+
444   | MySQL           | Kea sources   |The MySQL CB hooks library is an implementation of the Kea  |
445   | Configuration   | (since 1.6)   |Configuration Backend for MySQL. It uses a MySQL database as|
446   | Backend         |               |a repository for the Kea configuration information. The Kea |
447   |                 |               |servers use this library to fetch their configurations.     |
448   +-----------------+---------------+------------------------------------------------------------+
449   | Configuration   | Support       |The Configuration Backend Commands (CB Commands) hooks      |
450   | Backend         | customers     |library implements a collection of commands to manage the   |
451   | Commands        | (since 1.6)   |configuration information of the Kea servers in the         |
452   |                 |               |database. This library may only be used in conjunction with |
453   |                 |               |one of the supported configuration backend implementations. |
454   +-----------------+---------------+------------------------------------------------------------+
455   | BOOTP           | Kea sources   |The BOOTP hooks library adds BOOTP support, as defined in   |
456   |                 | (since 1.7.3) |RFC 1497. It recognizes received BOOTP requests:            |
457   |                 |               |they are translated into DHCPREQUEST packets, put into the  |
458   |                 |               |BOOTP client class and get infinite lifetime leases.        |
459   +-----------------+---------------+------------------------------------------------------------+
460   | Leasequery      | Support       |The Leasequery hooks library adds support for DHCPv4        |
461   |                 | customers     |Leasequery as described in RFC 4388; and for DHCPv6         |
462   |                 | (DHCPv4 since |Leasequery as described in RFC 5007.                        |
463   |                 | 1.7.8, DHCPv6 |                                                            |
464   |                 | since 1.7.9)  |                                                            |
465   +-----------------+---------------+------------------------------------------------------------+
466   | Run Script      | Kea sources   |The Run Script hooks library adds support to run external   |
467   |                 | (since 1.9.5) |scripts for specific packet processing hook points. There   |
468   |                 |               |are several exported environment variables available for    |
469   |                 |               |the script.                                                 |
470   +-----------------+---------------+------------------------------------------------------------+
471   | GSS-TSIG        | ISC support   |This hook library adds support to the Kea D2 server         |
472   |                 | customers     |(kea-dhcp-ddns) for using GSS-TSIG to sign DNS updates.     |
473   |                 | (since 2.0.1) |                                                            |
474   +-----------------+---------------+------------------------------------------------------------+
475
476ISC hopes to see more hooks libraries become available as time
477progresses, developed both internally and externally. Since this list
478may evolve dynamically, it is maintained on a wiki page, available
479at this link:
480https://gitlab.isc.org/isc-projects/kea/wikis/Hooks-available.
481Developers or others who are aware of any hooks libraries not listed there
482are asked to please send a note to the kea-users or kea-dev mailing lists for
483updating.
484
485The libraries developed by ISC are described in detail in the following
486sections.
487
488user_chk: Checking User Access
489==============================
490
491The user_chk library is the first hooks library published by ISC. It
492serves several purposes:
493
494-  To assign "new" or "unregistered" users to a restricted subnet, while
495   "known" or "registered" users are assigned to unrestricted subnets.
496
497-  To allow DHCP response options or vendor option values to be
498   customized based on user identity.
499
500-  To provide a real-time record of user registration activity, which
501   can be sampled by an external consumer.
502
503-  To serve as a demonstration of various capabilities possible using
504   the hooks interface.
505
506Once loaded, the library allows the separation of incoming requests into known
507and unknown clients. For known clients, packets are processed
508as usual, although it is possible to override the sending of certain options
509on a per-host basis. Clients that are not on the known
510hosts list will be treated as unknown and will be assigned to the last
511subnet defined in the configuration file.
512
513As an example of a use case, this behavior may be implemented to put unknown users
514into a separate subnet that leads to a "walled garden," where they can
515only access a registration portal. Once they fill in necessary data,
516their details are added to the known clients file and they get a proper
517address after their device is restarted.
518
519.. note::
520
521   This library was developed several years before the host reservation
522   mechanism became available. Host reservation is much
523   more powerful and flexible, but the user_chk capability
524   to consult an external source of information about clients and alter
525   Kea's behavior remains useful and of educational value.
526
527The library reads the /tmp/user_chk_registry.txt file while being loaded
528and each time an incoming packet is processed. Each line of the file is expected to
529contain a self-contained JSON snippet which must have the
530following two entries:
531
532-  ``type`` - whose value is "HW_ADDR" for IPv4 users or "DUID" for IPv6
533   users.
534
535-  ``id`` - whose value is either the hardware address or the DUID from
536   the request formatted as a string of hex digits, with or without ":"
537   delimiters.
538
539and may have zero or more of the following entries:
540
541-  ``bootfile`` - whose value is the pathname of the desired file.
542
543-  ``tftp_server`` - whose value is the hostname or IP address of the
544   desired server.
545
546A sample user registry file is shown below:
547
548::
549
550   { "type" : "HW_ADDR", "id" : "0c:0e:0a:01:ff:04", "bootfile" : "/tmp/v4bootfile" }
551   { "type" : "HW_ADDR", "id" : "0c:0e:0a:01:ff:06", "tftp_server" : "tftp.v4.example.com" }
552   { "type" : "DUID", "id" : "00:01:00:01:19:ef:e6:3b:00:0c:01:02:03:04", "bootfile" : "/tmp/v6bootfile" }
553   { "type" : "DUID", "id" : "00:01:00:01:19:ef:e6:3b:00:0c:01:02:03:06", "tftp_server" : "tftp.v6.example.com" }
554
555As with any other hooks libraries provided by ISC, internals of the
556user_chk code are well-documented. Users may refer to the `user_chk
557library section of the Kea Developer's Guide
558<https://reports.kea.isc.org/dev_guide/d8/db2/libdhcp_user_chk.html>`__
559for information on how the code works internally. That, together with the
560`Hooks Framework section of the Kea Developer's Guide
561<https://reports.kea.isc.org/dev_guide/index.html#hooksFramework>`__ should give users
562some pointers on how to extend this library and perhaps even write one
563from scratch.
564
565legal_log: Forensic Logging Hooks
566=================================
567
568This section describes the forensic log hooks library. This library provides
569hooks that record a detailed log of assignments, renewals, releases and other
570lease events into a set of log files.
571
572Currently this library is only available to ISC customers with a paid support
573contract.
574
575.. note::
576
577   This library may only be loaded by the ``kea-dhcp4`` or ``kea-dhcp6``
578   process.
579
580In many legal jurisdictions, companies, especially ISPs, must record
581information about the addresses they have leased to DHCP clients. This
582library is designed to help with that requirement. If the information
583that it records is sufficient, it may be used directly.
584
585If a jurisdiction requires that a different set of information be saved, users
586may use the custom formatting capability to extract information from the inbound
587request packet, or from the outbound response packet. Use with caution as this
588might affect server performance.  The custom format can not be used for control
589channel commands.
590
591Alternatively, this library may be used as a template or an example for the
592user's own custom logging hook. The logging is done as a set of hooks to allow
593it to be customized to any particular need. Modifying a hooks library is easier
594and safer than updating the core code. In addition by using the hooks features,
595those users who do not need to log this information can leave it out and avoid
596any performance penalties.
597
598Log File Naming
599~~~~~~~~~~~~~~~
600
601The names for the log files have the following form:
602
603Legal file names, if using ``day``, ``month`` or ``year`` as time unit:
604
605::
606
607   path/base-name.CCYYMMDD.txt
608
609where ``CC`` represents century, ``YY`` represents current year,
610``MM`` represents current month and ``DD`` represents current day.
611
612Legal file names, if using ``second`` as time unit:
613
614::
615
616   path/base-name.TXXXXXXXXXXXXXXXXXXXX.txt
617
618where ``XXXXXXXXXXXXXXXXXXXX`` represents time in seconds since epoch.
619
620When using ``second`` as the time unit, the file will be rotated when
621the ``count`` number of seconds pass. In contrast, when using ``day``, ``month``
622or ``year`` as time unit, the file will be rotated whenever the ``count`` th day,
623month or year starts respectively.
624
625The ``"path"`` and ``"base-name"`` are supplied in the configuration as
626described below; see :ref:`forensic-log-configuration`.
627
628.. note::
629
630   When running Kea servers for both DHCPv4 and DHCPv6, the log names
631   must be distinct. See the examples in :ref:`forensic-log-configuration`.
632
633.. _forensic-log-configuration:
634
635Configuring the Forensic Log Hooks
636~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
637
638To use this functionality, the hook library must be included in the
639configuration of the desired DHCP server modules. The legal_log library
640is able to save logs to a text file or to a database (created using
641``kea-admin`` see :ref:`mysql-database-create`, :ref:`pgsql-database-create`).
642The library is installed alongside the Kea libraries in
643``[kea-install-dir]/var/lib/kea`` where ``kea-install-dir`` is determined
644by the "--prefix" option of the configure script. It defaults to
645``/usr/local``. Assuming the default value, configuring kea-dhcp4 to load
646the legal_log library could be done with the following kea-dhcp4 configuration:
647
648.. code-block:: json
649
650    {
651        "Dhcp4": {
652            "hooks-libraries": [
653                {
654                    "library": "/usr/local/lib/kea/hooks/libdhcp_legal_log.so",
655                    "parameters": {
656                        "path": "/var/lib/kea/log",
657                        "base-name": "kea-forensic4"
658                    }
659                }
660            ]
661        }
662    }
663
664For kea-dhcp6, the configuration is:
665
666.. code-block:: json
667
668    {
669        "Dhcp6": {
670            "hooks-libraries": [
671                {
672                    "library": "/usr/local/lib/kea/hooks/libdhcp_legal_log.so",
673                    "parameters": {
674                        "path": "/var/lib/kea/log",
675                        "base-name": "kea-forensic6"
676                    }
677                }
678            ]
679        }
680    }
681
682The hook library parameters for the text file configuration are:
683
684-  ``path`` - the directory in which the forensic file(s) will be written.
685   The default value is ``[prefix]/var/lib/kea``. The directory must exist.
686
687-  ``base-name`` - an arbitrary value which is used in conjunction with the
688   current system date to form the current forensic file name. It
689   defaults to ``kea-legal``.
690
691-  ``time-unit`` - configures the time unit used to rotate the log file. Valid
692   values are ``second``, ``day``, ``month`` or ``year``. It defaults to
693   ``day``.
694
695-  ``count`` - configures the number of time units that need to pass until the
696   log file is rotated. It can be any positive number, or 0 which disables log
697   rotate. It defaults to 1.
698
699If log rotate is disabled, a new file will be created when the library is
700loaded and the new file name is different that any previous file name.
701
702Additional actions can be performed just before closing the old file and after
703opening the new file. These actions must point to an external executable or
704script and are configured by setting:
705
706-  ``prerotate`` - external executable or script called with the name of the
707   file that will be closed. Kea will not wait for the process to finish.
708
709-  ``postrotate`` - external executable or script called with the name of the
710   file that had been opened. Kea will not wait for the process to finish.
711
712Custom formatting can be enabled for logging information that can be extracted
713either from the client's request packet or from the server's response packet.
714Use with caution as this might affect server performance.
715The custom format can not be used for control channel commands.
716Two parameters can be used towards this goal, either together or separately:
717
718-  ``request-parser-format`` - evaluated parsed expression used to extract and
719   log data from the incoming packet
720
721-  ``response-parser-format`` - evaluated parsed expression used to extract and
722   log data from the server response packet
723
724See :ref:`classification-using-expressions` for a list of expressions.
725If any of ``request-parser-format`` or ``response-parser-format`` is
726configured, the default logging format is not used. If both of them are
727configured, the resulting log message is constructed by concatenating the
728data extracted from the request and the data extracted from the response.
729
730Some data might be available in the request or in the response only and some
731data might differ in the request packet from the one in the response packet.
732
733The lease client context can only be printed using the default format, as this
734information is not directly stored in the request packet or in the response
735packet.
736
737Additional parameters for the database connection can be specified, e.g:
738
739.. code-block:: json
740
741    {
742      "Dhcp6": {
743        "hooks-libraries": [
744          {
745            "library": "/usr/local/lib/kea/hooks/libdhcp_legal_log.so",
746            "parameters": {
747              "name": "database-name",
748              "password": "passwd",
749              "type": "mysql",
750              "user": "user-name"
751            }
752          }
753        ]
754      }
755    }
756
757For more specific information about database related parameters please refer to
758:ref:`database-configuration6` and :ref:`database-configuration4`.
759
760If it is desired to restrict forensic logging to certain subnets, the
761"legal-logging" boolean parameter can be specified within a user context
762of these subnets. For example:
763
764.. code-block:: json
765
766    {
767        "Dhcp4": {
768            "subnet4": [
769                {
770                    "subnet": "192.0.2.0/24",
771                    "pools": [
772                        {
773                            "pool": "192.0.2.1 - 192.0.2.200"
774                        }
775                    ],
776                    "user-context": {
777                        "legal-logging": false
778                    }
779                }
780            ]
781        }
782    }
783
784This configuration disables legal logging for the subnet "192.0.2.0/24". If the
785"legal-logging" parameter is not specified, it defaults to 'true', which
786enables legal logging for the subnet.
787
788The following example demonstrates how to selectively disable legal
789logging for an IPv6 subnet:
790
791.. code-block:: json
792
793    {
794        "Dhcp6": {
795            "subnet6": [
796                {
797                    "subnet": "2001:db8:1::/64",
798                    "pools": [
799                        {
800                            "pool": "2001:db8:1::1-2001:db8:1::ffff"
801                        }
802                    ],
803                    "user-context": {
804                        "legal-logging": false
805                    }
806                }
807            ]
808        }
809    }
810
811
812See :ref:`dhcp4-user-contexts` and :ref:`dhcp6-user-contexts` to
813learn more about user contexts in Kea configuration.
814
815DHCPv4 Log Entries
816~~~~~~~~~~~~~~~~~~
817
818For DHCPv4, the library creates entries based on DHCPREQUEST, DHCPDECLINE,
819DHCPRELEASE messages et.al. and their responses. The resulting packets and
820leases are taken into account, intercepted through the following hook points:
821* pkt4_receive
822* leases4_committed
823* pkt4_send
824* lease4_release
825* lease4_decline
826
827An entry is a single string with no embedded end-of-line markers and a
828prepended timestamp, and has the following sections:
829
830::
831
832   timestamp address duration device-id {client-info} {relay-info} {user-context}
833
834Where:
835
836-  timestamp - the current date and time the log entry was written in
837   "%Y-%m-%d %H:%M:%S %Z" strftime format ("%Z" is the time zone name).
838
839-  address - the leased IPv4 address given out and whether it was
840   assigned, renewed or released.
841
842-  duration - the lease lifetime expressed in days (if present), hours,
843   minutes, and seconds. A lease lifetime of 0xFFFFFFFF will be denoted
844   with the text "infinite duration". This information is not given
845   when the lease is released.
846
847-  device-id - the client's hardware address shown as numerical type and
848   hex digit string.
849
850-  client-info - the DHCP client id option (61) if present, shown as a
851   hex string. When its content is printable it is displayed.
852
853-  relay-info - for relayed packets the giaddr and the RAI circuit-id,
854   remote-id, and subscriber-id options (option 82 sub options: 1, 2 and 6)
855   if present. The circuit id and remote id are presented as hex
856   strings. When their content is printable it is displayed.
857
858-  user-context - the optional user context associated with the lease.
859
860For instance (line breaks added for readability; they will not be
861present in the log file):
862
863::
864
865   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:
866   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,
867   identified by circuit-id: 68:6f:77:64:79 (howdy) and remote-id: 87:f6:79:77:ef
868
869or for a release:
870
871::
872
873   2018-01-06 01:02:03 CET Address: 192.2.1.100 has been released from a device with hardware address:
874   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,
875   identified by circuit-id: 68:6f:77:64:79 (howdy) and remote-id: 87:f6:79:77:ef
876
877In addition to logging lease activity driven by DHCPv4 client traffic,
878the hooks library also logs entries for the following lease management control
879channel commands: lease4-add, lease4-update, and lease4-del. These cannot have
880custom formatting. Each entry is a single string with no embedded end-of-line
881markers, and it will typically have the following form:
882
883``lease4-add:``
884
885::
886
887   *timestamp* Administrator added a lease of address: *address* to a device with hardware address: *device-id*
888
889Depending on the arguments of the add command, it may also include the
890client-id and duration.
891
892Example:
893
894::
895
896   2018-01-06 01:02:03 CET Administrator added a lease of address: 192.0.2.202 to a device with hardware address:
897   1a:1b:1c:1d:1e:1f for 1 days 0 hrs 0 mins 0 secs
898
899``lease4-update:``
900
901::
902
903   *timestamp* Administrator updated information on the lease of address: *address* to a device with hardware address: *device-id*
904
905Depending on the arguments of the update command, it may also include
906the client-id and lease duration.
907
908Example:
909
910::
911
912   2018-01-06 01:02:03 CET Administrator updated information on the lease of address: 192.0.2.202 to a device
913   with hardware address: 1a:1b:1c:1d:1e:1f, client-id: 1234567890
914
915``lease4-del:`` deletes have two forms, one by address and one by
916identifier and identifier type:
917
918::
919
920   *timestamp* Administrator deleted the lease for address: *address*
921
922or
923
924::
925
926   *timestamp* Administrator deleted a lease for a device identified by: *identifier-type* of *identifier*
927
928Currently only a type of @b hw-address (hardware address) is supported.
929
930Examples:
931
932::
933
934   2018-01-06 01:02:03 CET Administrator deleted the lease for address: 192.0.2.202
935
936   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
937
938The ``request-parser-format`` and ``response-parser-format`` can be used to
939extract and log data from the incoming packet and server response packet
940respectively. The configured value is an evaluated parsed expression returning a
941string. A list of tokens is described in the server classification process.
942Use with caution as this might affect server performance.
943If any of them is configured, the default logging format is not used.
944If both of them are configured, the resulting log message is constructed by
945concatenating the logged data extracted from the request and the logged data
946extracted from the response.
947
948Some data might be available in the request or in the response only and some
949data might differ in the incoming packet from the one in the response packet.
950
951Examples:
952
953.. code-block:: json
954
955    {
956        "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, ':'), '')), '')",
957        "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, ':'), '')), '')"
958    }
959
960.. raw:: html
961
962    <details><summary>Expand here!</summary>
963    <pre>{
964        "request-parser-format":
965            "ifelse(pkt4.msgtype == 4 or pkt4.msgtype == 7,
966                'Address: ' +
967                ifelse(option[50].exists,
968                    addrtotext(option[50].hex),
969                    addrtotext(pkt4.ciaddr)) +
970                ' has been released from a device with hardware address: hwtype=' + substring(hexstring(pkt4.htype, ''), 7, 1) + ' ' + hexstring(pkt4.mac, ':') +
971                ifelse(option[61].exists,
972                    ', client-id: ' + hexstring(option[61].hex, ':'),
973                    '') +
974                ifelse(pkt4.giaddr == 0.0.0.0,
975                    '',
976                    ' connected via relay at address: ' + addrtotext(pkt4.giaddr) +
977                    ifelse(option[82].option[1].exists,
978                        ', circuit-id: ' + hexstring(option[82].option[1].hex, ':'),
979                        '') +
980                    ifelse(option[82].option[2].exists,
981                        ', remote-id: ' + hexstring(option[82].option[2].hex, ':'),
982                        '') +
983                    ifelse(option[82].option[6].exists,
984                        ', subscriber-id: ' + hexstring(option[82].option[6].hex, ':'),
985                        '')),
986                '')",
987        "response-parser-format":
988            "ifelse(pkt4.msgtype == 5,
989                '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, ':') +
990                ifelse(option[61].exists,
991                    ', client-id: ' + hexstring(option[61].hex, ':'),
992                    '') +
993                ifelse(pkt4.giaddr == 0.0.0.0,
994                    '',
995                    ' connected via relay at address: ' + addrtotext(pkt4.giaddr) +
996                    ifelse(option[82].option[1].exists,
997                        ', circuit-id: ' + hexstring(option[82].option[1].hex, ':'),
998                        '') +
999                    ifelse(option[82].option[2].exists,
1000                        ', remote-id: ' + hexstring(option[82].option[2].hex, ':'),
1001                        '') +
1002                    ifelse(option[82].option[6].exists,
1003                        ', subscriber-id: ' + hexstring(option[82].option[6].hex, ':'),
1004                        '')),
1005                '')"
1006    }</pre>
1007    </details><br>
1008
1009
1010This will log the following data on request and renew:
1011
1012::
1013
1014   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
1015
1016
1017This will log the following data on release and decline:
1018
1019::
1020
1021   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
1022
1023
1024Similar result can be obtained if configuring ``request-parser-format`` only.
1025
1026Examples:
1027
1028
1029.. code-block:: json
1030
1031    {
1032        "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, ':'), '')), ''))"
1033    }
1034
1035.. raw:: html
1036
1037    <details><summary>Expand here!</summary>
1038    <pre>{
1039        "request-parser-format":
1040            "ifelse(pkt4.msgtype == 3,
1041                'Address: ' +
1042                ifelse(option[50].exists,
1043                    addrtotext(option[50].hex),
1044                    addrtotext(pkt4.ciaddr)) +
1045                ' has been assigned' +
1046                ifelse(option[51].exists,
1047                    ' for ' + uint32totext(option[51].hex) + ' seconds',
1048                    '') +
1049                ' to a device with hardware address: hwtype=' + substring(hexstring(pkt4.htype, ''), 7, 1) + ' ' + hexstring(pkt4.mac, ':') +
1050                ifelse(option[61].exists,
1051                    ', client-id: ' + hexstring(option[61].hex, ':'),
1052                    '') +
1053                ifelse(pkt4.giaddr == 0.0.0.0,
1054                    '',
1055                    ' connected via relay at address: ' + addrtotext(pkt4.giaddr) +
1056                    ifelse(option[82].option[1].exists,
1057                        ', circuit-id: ' + hexstring(option[82].option[1].hex, ':'),
1058                        '') +
1059                    ifelse(option[82].option[2].exists,
1060                        ', remote-id: ' + hexstring(option[82].option[2].hex, ':'),
1061                        '') +
1062                    ifelse(option[82].option[6].exists,
1063                        ', subscriber-id: ' + hexstring(option[82].option[6].hex, ':'),
1064                        '')),
1065                ifelse(pkt4.msgtype == 4 or pkt4.msgtype == 7,
1066                    'Address: ' +
1067                    ifelse(option[50].exists,
1068                        addrtotext(option[50].hex),
1069                        addrtotext(pkt4.ciaddr)) +
1070                    ' has been released from a device with hardware address: hwtype=' + substring(hexstring(pkt4.htype, ''), 7, 1) + ' ' + hexstring(pkt4.mac, ':') +
1071                    ifelse(option[61].exists,
1072                        ', client-id: ' + hexstring(option[61].hex, ':'),
1073                        '') +
1074                    ifelse(pkt4.giaddr == 0.0.0.0,
1075                        '',
1076                        ' connected via relay at address: ' + addrtotext(pkt4.giaddr) +
1077                        ifelse(option[82].option[1].exists,
1078                            ', circuit-id: ' + hexstring(option[82].option[1].hex, ':'),
1079                            '') +
1080                        ifelse(option[82].option[2].exists,
1081                            ', remote-id: ' + hexstring(option[82].option[2].hex, ':'),
1082                            '') +
1083                        ifelse(option[82].option[6].exists,
1084                            ', subscriber-id: ' + hexstring(option[82].option[6].hex, ':'),
1085                            '')),
1086                    ''))"
1087    }</pre>
1088    </details><br>
1089
1090
1091DHCPv6 Log Entries
1092~~~~~~~~~~~~~~~~~~
1093
1094For DHCPv6, the library creates entries based on REQUEST, RENEW, RELEASE,
1095DECLINE messages et.al. and their responses. The resulting packets and leases
1096are taken into account, intercepted through the following hook points:
1097* pkt6_receive
1098* leases6_committed
1099* pkt6_send
1100* lease6_release
1101* lease6_decline
1102
1103An entry is a single string with no embedded end-of-line markers and a
1104prepended timestamp, and has the following sections:
1105
1106::
1107
1108   timestamp address duration device-id {relay-info}* {user-context}
1109
1110Where:
1111
1112-  timestamp - the current date and time the log entry was written in
1113   "%Y-%m-%d %H:%M:%S %Z" strftime format ("%Z" is the time zone name).
1114
1115-  address - the leased IPv6 address or prefix given out and whether it
1116   was assigned, renewed or released.
1117
1118-  duration - the lease lifetime expressed in days (if present), hours,
1119   minutes, and seconds. A lease lifetime of 0xFFFFFFFF will be denoted
1120   with the text "infinite duration". This information is not given
1121   when the lease is released.
1122
1123-  device-id - the client's DUID and hardware address (if present).
1124
1125-  relay-info - for relayed packets the content of relay agent messages,
1126   remote-id (code 37), subscriber-id (code 38), and interface-id (code 18)
1127   options, if present. Note that interface-id option, if present,
1128   identifies the whole interface the relay agent received the message
1129   on. This typically translates to a single link in the network, but
1130   it depends on the specific network topology. Nevertheless, this is
1131   useful information to better scope down the location of the device,
1132   so it is recorded, if present.
1133
1134-  user-context - the optional user context associated with the lease.
1135
1136For instance (line breaks added for readability; they will not be
1137present in the log file):
1138
1139::
1140
1141   2018-01-06 01:02:03 PST Address:2001:db8:1:: has been assigned for 0 hrs 11 mins 53 secs
1142   to a device with DUID: 17:34:e2:ff:09:92:54 and hardware address: hwtype=1 08:00:2b:02:3f:4e
1143   (from Raw Socket) connected via relay at address: fe80::abcd for client on link address: 3001::1,
1144   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
1145
1146or for a release:
1147
1148::
1149
1150   2018-01-06 01:02:03 PST Address:2001:db8:1:: has been released
1151   from a device with DUID: 17:34:e2:ff:09:92:54 and hardware address: hwtype=1 08:00:2b:02:3f:4e
1152   (from Raw Socket) connected via relay at address: fe80::abcd for client on link address: 3001::1,
1153   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
1154
1155In addition to logging lease activity driven by DHCPv6 client traffic,
1156the hooks library also logs entries for the following lease management control channel
1157commands: lease6-add, lease6-update, and lease6-del. Each entry is a
1158single string with no embedded end-of-line markers, and it will
1159typically have the following form:
1160
1161``lease6-add:``
1162
1163::
1164
1165   *timestamp* Administrator added a lease of address: *address* to a device with DUID: *DUID*
1166
1167Depending on the arguments of the add command, it may also include the
1168hardware address and duration.
1169
1170Example:
1171
1172::
1173
1174   2018-01-06 01:02:03 PST Administrator added a lease of address: 2001:db8::3 to a device with DUID:
1175   1a:1b:1c:1d:1e:1f:20:21:22:23:24 for 1 days 0 hrs 0 mins 0 secs
1176
1177``lease6-update:``
1178
1179::
1180
1181   *timestamp* Administrator updated information on the lease of address: *address* to a device with DUID: *DUID*
1182
1183Depending on the arguments of the update command, it may also include
1184the hardware address and lease duration.
1185
1186Example:
1187
1188::
1189
1190   2018-01-06 01:02:03 PST Administrator updated information on the lease of address: 2001:db8::3 to a device with
1191   DUID: 1a:1b:1c:1d:1e:1f:20:21:22:23:24, hardware address: 1a:1b:1c:1d:1e:1f
1192
1193``lease6-del:`` deletes have two forms, one by address and one by
1194identifier and identifier type:
1195
1196::
1197
1198   *timestamp* Administrator deleted the lease for address: *address*
1199
1200or
1201
1202::
1203
1204   *timestamp* Administrator deleted a lease for a device identified by: *identifier-type* of *identifier*
1205
1206Currently only a type of DUID is supported.
1207
1208Examples:
1209
1210::
1211
1212   2018-01-06 01:02:03 PST Administrator deleted the lease for address: 2001:db8::3
1213
1214   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
1215
1216The ``request-parser-format`` and ``response-parser-format`` can be used to
1217extract and log data from the incoming packet and server response packet
1218respectively. The configured value is an evaluated parsed expression returning a
1219string. A list of tokens is described in the server classification process.
1220Use with caution as this might affect server performance.
1221If any of them is configured, the default logging format is not used.
1222If both of them are configured, the resulting log message is constructed by
1223concatenating the logged data extracted from the request and the logged data
1224extracted from the response.
1225
1226Some data might be available in the request or in the response only and some
1227data might differ in the incoming packet from the one in the response packet.
1228
1229Examples:
1230
1231
1232.. code-block:: json
1233
1234    {
1235        "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, ':'), '')), ''), '')",
1236        "response-parser-format": "ifelse(pkt6.msgtype == 7, 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, ':'), '')), ''), '')"
1237    }
1238
1239.. raw:: html
1240
1241    <details><summary>Expand here!</summary>
1242    <pre>{
1243        "request-parser-format":
1244            "ifelse(pkt6.msgtype == 8 or pkt6.msgtype == 9,
1245                ifelse(option[3].option[5].exists,
1246                    'Address: ' + addrtotext(substring(option[3].option[5].hex, 0, 16)) + ' has been released from a device with DUID: ' + hexstring(option[1].hex, ':') +
1247                    ifelse(relay6[0].peeraddr == '',
1248                        '',
1249                        ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) +
1250                        ifelse(relay6[0].option[37].exists,
1251                            ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'),
1252                            '') +
1253                        ifelse(relay6[0].option[38].exists,
1254                            ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'),
1255                            '') +
1256                        ifelse(relay6[0].option[18].exists,
1257                            ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'),
1258                            '')),
1259                    '') +
1260                ifelse(option[25].option[26].exists,
1261                    '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, ':') +
1262                    ifelse(relay6[0].peeraddr == '',
1263                        '',
1264                        ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) +
1265                        ifelse(relay6[0].option[37].exists,
1266                            ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'),
1267                            '') +
1268                        ifelse(relay6[0].option[38].exists,
1269                            ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'),
1270                            '') +
1271                        ifelse(relay6[0].option[18].exists,
1272                            ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'),
1273                            '')),
1274                    ''),
1275                '')",
1276        "response-parser-format":
1277            "ifelse(pkt6.msgtype == 7,
1278                ifelse(option[3].option[5].exists,
1279                    '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, ':') +
1280                    ifelse(relay6[0].peeraddr == '',
1281                        '',
1282                        ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) +
1283                        ifelse(relay6[0].option[37].exists,
1284                            ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'),
1285                            '') +
1286                        ifelse(relay6[0].option[38].exists,
1287                            ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'),
1288                            '') +
1289                        ifelse(relay6[0].option[18].exists,
1290                            ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'),
1291                            '')),
1292                    '') +
1293                ifelse(option[25].option[26].exists,
1294                    '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, ':') +
1295                    ifelse(relay6[0].peeraddr == '',
1296                        '',
1297                        ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) +
1298                        ifelse(relay6[0].option[37].exists,
1299                            ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'),
1300                            '') +
1301                        ifelse(relay6[0].option[38].exists,
1302                            ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'),
1303                            '') +
1304                        ifelse(relay6[0].option[18].exists,
1305                            ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'),
1306                            '')),
1307                    ''),
1308                '')"
1309    }</pre>
1310    </details><br>
1311
1312
1313This will log the following data on request, renew and rebind for NA:
1314
1315::
1316
1317   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
1318
1319
1320This will log the following data on request, renew and rebind for PD:
1321
1322::
1323
1324   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
1325
1326
1327This will log the following data on release and decline for NA:
1328
1329::
1330
1331   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
1332
1333
1334This will log the following data on release and decline for PD:
1335
1336::
1337
1338   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
1339
1340
1341Similar result can be obtained if configuring ``request-parser-format`` only.
1342
1343Examples:
1344
1345
1346.. code-block:: json
1347
1348    {
1349        "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, ':'), '')), ''), ''))"
1350    }
1351
1352.. raw:: html
1353
1354    <details><summary>Expand here!</summary>
1355    <pre>{
1356        "request-parser-format":
1357            "ifelse(pkt6.msgtype == 3 or pkt6.msgtype == 5 or pkt6.msgtype == 6,
1358                ifelse(option[3].option[5].exists,
1359                    '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, ':') +
1360                    ifelse(relay6[0].peeraddr == '',
1361                        '',
1362                        ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) +
1363                        ifelse(relay6[0].option[37].exists,
1364                            ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'),
1365                            '') +
1366                        ifelse(relay6[0].option[38].exists,
1367                            ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'),
1368                            '') +
1369                        ifelse(relay6[0].option[18].exists,
1370                            ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'),
1371                            '')),
1372                    '') +
1373                ifelse(option[25].option[26].exists,
1374                    '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, ':') +
1375                    ifelse(relay6[0].peeraddr == '',
1376                        '',
1377                        ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) +
1378                        ifelse(relay6[0].option[37].exists,
1379                            ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'),
1380                            '') +
1381                        ifelse(relay6[0].option[38].exists,
1382                            ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'),
1383                            '') +
1384                        ifelse(relay6[0].option[18].exists,
1385                            ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'),
1386                            '')),
1387                    ''),
1388                ifelse(pkt6.msgtype == 8 or pkt6.msgtype == 9,
1389                    ifelse(option[3].option[5].exists,
1390                        'Address: ' + addrtotext(substring(option[3].option[5].hex, 0, 16)) + ' has been released from a device with DUID: ' + hexstring(option[1].hex, ':') +
1391                        ifelse(relay6[0].peeraddr == '',
1392                            '',
1393                            ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) +
1394                            ifelse(relay6[0].option[37].exists,
1395                                ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'),
1396                                '') +
1397                            ifelse(relay6[0].option[38].exists,
1398                                ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'),
1399                                '') +
1400                            ifelse(relay6[0].option[18].exists,
1401                                ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'),
1402                                '')),
1403                        '') +
1404                    ifelse(option[25].option[26].exists,
1405                        '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, ':') +
1406                        ifelse(relay6[0].peeraddr == '',
1407                            '',
1408                            ' connected via relay at address: ' + addrtotext(relay6[0].peeraddr) + ' for client on link address: ' + addrtotext(relay6[0].linkaddr) +
1409                            ifelse(relay6[0].option[37].exists,
1410                                ', remote-id: ' + hexstring(relay6[0].option[37].hex, ':'),
1411                                '') +
1412                            ifelse(relay6[0].option[38].exists,
1413                                ', subscriber-id: ' + hexstring(relay6[0].option[38].hex, ':'),
1414                                '') +
1415                            ifelse(relay6[0].option[18].exists,
1416                                ', connected at location interface-id: ' + hexstring(relay6[0].option[18].hex, ':'),
1417                                '')),
1418                        ''),
1419                    ''))"
1420    }</pre>
1421    </details><br>
1422
1423.. _forensic-log-database:
1424
1425Database Backend
1426~~~~~~~~~~~~~~~~
1427
1428Log entries can be inserted into a database when Kea is configured with
1429database backend support. A table named "logs" is used that includes a timestamp
1430(timeuuid for Cassandra) generated by the database software, and a
1431text log with the same format as files without the timestamp.
1432
1433Please refer to :ref:`mysql-database` for information on using a MySQL database; to
1434:ref:`pgsql-database` for PostgreSQL database information; or to :ref:`cql-database`
1435for information on using a Cassandra (CQL) database. The logs table is part of the Kea database schemas.
1436
1437Configuration parameters are extended by standard lease database
1438parameters as defined in :ref:`database-configuration4`. The "type"
1439parameter should be "mysql", "postgresql", "cql", or "logfile". When
1440it is absent or set to "logfile", files are used.
1441
1442This database feature is experimental and will be likely improved, for
1443instance to add an address/prefix index (currently the only index is
1444the timestamp). No specific tools are provided to operate the database,
1445but standard tools may be used, for example, to dump the logs table
1446from a CQL database:
1447
1448::
1449
1450   $ echo 'SELECT dateOf(timeuuid), log FROM logs;' | cqlsh -k database-name
1451
1452    system.dateof(timeuuid)         | log
1453   ---------------------------------+---------------------------------------
1454    2018-01-06 01:02:03.227000+0000 | Address: 192.2.1.100 has been renewed ...
1455    ...
1456   (12 rows)
1457
1458Like all the other database-centric features, forensic logging supports database
1459connection recovery which can be enabled by setting the ``on-fail`` parameter.
1460If not specified, the ``on-fail`` parameter defaults to ``serve-retry-continue``
1461as opposed to the case of lease manager, host manager and config backend where
1462it defaults to ``stop-retry-exit``. In this case, the server will continue
1463serving clients and it will not shut down even if the recovery mechanism fails.
1464If the ``on-fail`` is set to ``serve-retry-exit``, the server will shut down if
1465the connection to the database backend is not restored according to the
1466``max-reconnect-tries`` and ``reconnect-wait-time`` parameters, but it will
1467continue serving clients while this mechanism is activated.
1468
1469.. _flex-id:
1470
1471flex_id: Flexible Identifiers for Host Reservations
1472===================================================
1473
1474This section describes a hook application dedicated to generating flexible
1475identifiers for host reservations. The Kea software provides a way to handle
1476host reservations that include addresses, prefixes, options, client
1477classes, and other features. The reservation can be based on hardware
1478address, DUID, circuit-id, or client-id in DHCPv4 and on hardware
1479address or DUID in DHCPv6. However, there are sometimes scenarios where
1480the reservation is more complex; it may use options other than those mentioned
1481above, use parts of specific options, or perhaps even use a combination of
1482several options and fields to uniquely identify a client. Those
1483scenarios are addressed by the Flexible Identifiers hook application.
1484
1485Currently this library is only available to ISC customers with a paid support
1486contract.
1487
1488.. note::
1489
1490   This library may only be loaded by the ``kea-dhcp4`` or ``kea-dhcp6``
1491   process.
1492
1493The library allows the definition of an expression, using notation initially
1494used only for client classification. (See
1495:ref:`classification-using-expressions` for a detailed description of
1496the syntax available.) One notable difference is that for client
1497classification, the expression currently has to evaluate to either true
1498or false, while the flexible identifier expression is expected to
1499evaluate to a string that will be used as an identifier. It is a valid case
1500for the expression to evaluate to an empty string (e.g. in cases where a
1501client does not send specific options). This expression is then
1502evaluated for each incoming packet, and this evaluation generates an
1503identifier that is used to identify the client. In particular, there may
1504be host reservations that are tied to specific values of the flexible
1505identifier.
1506
1507The library can be loaded in a similar way as other hook libraries. It
1508takes a mandatory parameter ``identifier-expression`` and optional boolean
1509parameter ``replace-client-id``:
1510
1511::
1512
1513   "Dhcp6": {
1514       "hooks-libraries": [
1515           {
1516               "library": "/path/libdhcp_flex_id.so",
1517               "parameters": {
1518                   "identifier-expression": "expression",
1519                   "replace-client-id": false
1520               }
1521           },
1522           ...
1523       ]
1524   }
1525
1526The flexible identifier library supports both DHCPv4 and DHCPv6.
1527
1528Let's consider a case of an IPv6 network that has an
1529independent interface for each of its connected customers. Customers are
1530able to plug in whatever device they want, so any type of identifier
1531(e.g. a client-id) is unreliable. Therefore, the operator may decide to
1532use an option inserted by a relay agent to differentiate between
1533clients. In this particular deployment, the operator has verified that the
1534interface-id is unique for each customer-facing interface, so it
1535is suitable for usage as a reservation. However, only the first six bytes of
1536the interface-id are interesting, because remaining bytes are either
1537randomly changed or not unique between devices. Therefore, the customer
1538decided to use the first six bytes of the interface-id option inserted by the
1539relay agent. After adding ``flex-id``, the ``host-reservation-identifiers`` goal
1540can be achieved by using the following configuration:
1541
1542::
1543
1544   "Dhcp6": {
1545       "subnet6": [{ ..., # subnet definition starts here
1546       "reservations": [
1547           "flex-id": "'port1234'", # value of the first 8 bytes of the interface-id
1548           "ip-addresses": [ "2001:db8::1" ]
1549       ],
1550       }], # end of subnet definitions
1551       "host-reservation-identifiers": ["duid", "flex-id"], # add "flex-id" to reservation identifiers
1552       "hooks-libraries": [
1553           {
1554               "library": "/path/libdhcp_flex_id.so",
1555               "parameters": {
1556                   "identifier-expression": "substring(relay6[0].option[18].hex,0,8)"
1557               }
1558           },
1559           ...
1560       ]
1561   }
1562
1563.. note::
1564
1565  Care should be taken when adjusting the expression. If the expression
1566  changes, then all the ``flex-id`` values may change, possibly rendering
1567  all reservations based on ``flex-id`` unusable until they are manually updated.
1568  It is strongly recommended that administrators start with the expression and a
1569  handful of reservations, and then adjust the expression as needed. Once
1570  the expression is confirmed to do what is desired of it, host reservations
1571  can be deployed on a broader scale.
1572
1573``flex-id`` values in host reservations can be specified in two ways. First,
1574they can be expressed as a hex string, e.g. bar string can be represented
1575as 626174. Alternatively, it can be expressed as a quoted value (using
1576double and single quotes), e.g. "'bar'". The former is more convenient
1577for printable characters, while hex string values are more convenient
1578for non-printable characters and do not require the use of the
1579``hexstring`` operator.
1580
1581::
1582
1583   "Dhcp6": {
1584       "subnet6": [{ ..., # subnet definition starts here
1585       "reservations": [
1586           "flex-id": "01:02:03:04:05:06", # value of the first 8 bytes of the interface-id
1587           "ip-addresses": [ "2001:db8::1" ]
1588       ],
1589       }], # end of subnet definitions
1590       "host-reservation-identifiers": ["duid", "flex-id"], # add "flex-id" to reservation identifiers
1591       "hooks-libraries": [
1592           {
1593               "library": "/path/libdhcp_flex_id.so",
1594               "parameters": {
1595                   "identifier-expression": "vendor[4491].option[1026].hex"
1596               }
1597           },
1598           ...
1599       ]
1600   }
1601
1602When ``replace-client-id`` is set to "false" (which is the default setting),
1603the flex-id hook library uses the evaluated flexible identifier solely for
1604identifying host reservations, i.e. searching for reservations within a
1605database. This is the functional equivalent of other identifiers, similar
1606to hardware address or circuit-id. However, this mode of operation
1607implies that if a client device is replaced, it may cause a
1608conflict between an existing lease (allocated to the old device) and the
1609new lease being allocated to the new device. The conflict arises
1610because the same flexible identifier is computed for the replaced device,
1611so the server will try to allocate the same lease. The mismatch between
1612client identifiers sent by the new device and the old device causes the server
1613to refuse this new allocation until the old lease expires. A
1614manifestation of this problem is dependent on the specific expression used
1615as the flexible identifier and is likely to appear if only options
1616and other parameters are used that identify where the device is connected
1617(e.g. circuit-id), rather than the device identification itself (e.g.
1618MAC address).
1619
1620The flex-id library offers a way to overcome the problem with lease
1621conflicts by dynamically replacing the client identifier (or DUID in DHCPv6)
1622with a value derived from the flexible identifier. The server
1623processes the client's query as if the flexible identifier were sent in the
1624client identifier (or DUID) option. This guarantees that a returning
1625client (for which the same flexible identifier is evaluated) will be
1626assigned the same lease despite the client identifier and/or MAC address
1627change.
1628
1629The following is a stub configuration that enables this behavior:
1630
1631::
1632
1633   "Dhcp4": {
1634       "hooks-libraries": [
1635           {
1636               "library": "/path/libdhcp_flex_id.so",
1637               "parameters": {
1638                   "identifier-expression": "expression",
1639                   "replace-client-id": true
1640               }
1641           },
1642           ...
1643       ]
1644   }
1645
1646In the DHCPv4 case, the value derived from the flexible identifier is
1647formed by prepending one byte with a value of zero to the flexible identifier.
1648In the DHCPv6 case, it is formed by prepending two zero bytes before the
1649flexible identifier.
1650
1651Note that for this mechanism to take effect, the DHCPv4 server must be
1652configured to respect the client identifier option value during lease
1653allocation, i.e. ``match-client-id`` must be set to "true". See
1654:ref:`dhcp4-match-client-id` for details. No additional settings are
1655required for DHCPv6.
1656
1657If the ``replace-client-id`` option is set to "true", the value of the
1658``echo-client-id`` parameter (which governs whether to send back a
1659client-id option) is ignored.
1660
1661The :ref:`lease-cmds` section describes commands used to retrieve,
1662update, and delete leases using various identifiers, such as "hw-address" and
1663"client-id". The lease_cmds library does not natively support querying
1664for leases by flexible identifier. However, when ``replace-client-id`` is
1665set to "true", it makes it possible to query for leases using a value
1666derived from the flexible identifier. In the DHCPv4 case, the query will
1667look similar to this:
1668
1669::
1670
1671   {
1672       "command": "lease4-get",
1673       "arguments": {
1674           "identifier-type": "client-id",
1675           "identifier": "00:54:64:45:66",
1676           "subnet-id": 44
1677       }
1678   }
1679
1680where the hexadecimal value of "54:64:45:66" is a flexible identifier
1681computed for the client.
1682
1683In the DHCPv6 case, the corresponding query will look similar to this:
1684
1685::
1686
1687   {
1688       "command": "lease6-get",
1689       "arguments": {
1690           "identifier-type": "duid",
1691           "identifier": "00:00:54:64:45:66",
1692           "subnet-id": 10
1693       }
1694   }
1695
1696.. _flex-option:
1697
1698flex_option Flexible Option for Option value settings
1699=====================================================
1700
1701This library allows you to define an action to take, for a given option,
1702based upon on the result of an expression.  These actions are carried
1703out during the final stages of constructing a query response packet,
1704just before it is sent to the client. The three actions currently
1705supported are ``add``, ``supersede``, and ``remove``.
1706
1707The syntax used for the action expressions is the same syntax used
1708for client classification and the Flex Identifier hook library
1709(See either :ref:`classification-using-expressions` or :ref:`flex-id`
1710for detailed description of the syntax).
1711
1712The ``add`` and ``supersede`` actions use an expression returning a
1713string, doing nothing when it evaluates to the empty string. The
1714``remove`` application uses an expression returning true or false,
1715doing nothing on false. When it is necessary to set an option to the
1716empty value this mechanism does not work but a client class can be
1717used instead.
1718
1719The ``add`` action adds an option only when the option does not already
1720exist and the expression does not evaluate to the empty string.
1721The ``supersede`` action does the same but it overwrites the option value
1722if it already exists. The ``remove`` action removes the option from
1723the response packet if it already exists and the expression evaluates to
1724true.
1725
1726The option to which an action applies may be specified by either its
1727numeric code or its name.. At least the code or the name must be
1728specified. The option space is the DHCPv4 or DHCPv6 spaces depending
1729on the server where the hook library is loaded. Other spaces as vendor
1730spaces could be supported in a further version.
1731
1732The library is available since Kea 1.7.1 and can be loaded in a
1733similar way as other hook libraries by the ``kea-dhcp4`` or `kea-dhcp6``
1734process.. It takes a mandatory ``options`` parameter holding a list of
1735per option parameter maps with code, name, add, supersede and remove
1736actions. Action entries take a string value representing an
1737expression.
1738
1739::
1740
1741    "Dhcp4": {
1742        "hooks-libraries": [
1743            {   "library": "/usr/local/lib/libdhcp_flex_option.so",
1744                "parameters": {
1745                    "options": [
1746                            {
1747                            "code": 67,
1748                            "add":
1749  "ifelse(option[host-name].exists,concat(option[host-name].text,'.boot'),'')"
1750                        }
1751                    ]
1752                }
1753            },
1754            ...
1755        ]
1756    }
1757
1758If (and only if) the query includes a host-name option (code 12),
1759a boot-file-name option (code 67) is added to the response with the host
1760name followed by .boot for content.
1761
1762The flexible option library supports both DHCPv4 and DHCPv6.
1763
1764Since Kea 1.9.0, the add and supersede actions take an optional csv-format
1765boolean parameter. If not specified or configured to false, the option data is
1766set using the raw value of the evaluated expression. When it is configured
1767to true, this value is parsed using the option definition from the option data
1768specified in the configuration file. This eases option setting for options
1769using complex record formats or fully qualified domain names.
1770
1771For instance if the expression evaluation returns "example.com" and
1772the option is defined with the fqdn type the domain name will be
1773encoded into DNS binary format.
1774
1775
1776.. _host-cmds:
1777
1778host_cmds: Host Commands
1779========================
1780
1781This section describes a hook application that offers a number of new
1782commands used to query and manipulate host reservations. Kea provides a
1783way to store host reservations in a database. In many larger deployments
1784it is useful to be able to manage that information while the server is
1785running. This library provides management commands for adding, querying,
1786and deleting host reservations in a safe way without restarting the
1787server. In particular, it validates the parameters, so an attempt to
1788insert incorrect data - such as adding a host with a conflicting identifier in the
1789same subnet - will be rejected. Those commands are exposed via the command
1790channel (JSON over UNIX sockets) and the Control Agent (JSON over a RESTful
1791interface). Additional commands and capabilities related to host
1792reservations will be added in the future.
1793
1794Currently this library is only available to ISC customers with a paid support
1795contract.
1796
1797.. note::
1798
1799   This library may only be loaded by the ``kea-dhcp4`` or ``kea-dhcp6``
1800   process.
1801
1802Currently, six commands are supported: reservation-add (which adds a new
1803host reservation), reservation-get (which returns an existing reservation
1804if specified criteria are matched), reservation-get-all (which returns
1805all reservations in a specified subnet), reservation-get-page (a variant
1806of reservation-get-all which returns all reservations in a specified
1807subnet by pages and since Kea version 1.9.0 all reservations),
1808reservation-get-by-hostname (which returns all reservations
1809with a specified hostname and optionally in a subnet) since Kea version
18101.7.1, reservation-get-by-id (which returns all reservations with a
1811specified identifier) since Kea version 1.9.0,
1812and reservation-del (which attempts to delete a
1813reservation matching specified criteria). To use commands that change
1814the reservation information (currently these are reservation-add and
1815reservation-del, but this rule applies to other commands that may be
1816implemented in the future), the hosts database must be specified and it must not operate
1817in read-only mode (see
1818the hosts-databases descriptions in :ref:`hosts-databases-configuration4`
1819and :ref:`hosts-databases-configuration6`). If the hosts-databases are not specified or are
1820running in read-only mode, the host_cmds library will load, but any
1821attempts to use reservation-add or reservation-del will fail.
1822
1823Additional host reservation commands are planned in future releases of Kea. For a
1824description of envisaged commands, see the `Control API
1825Requirements <https://gitlab.isc.org/isc-projects/kea/wikis/designs/commands>`__
1826document.
1827
1828All commands use JSON syntax. They can be issued either using the
1829control channel (see :ref:`ctrl-channel`) or via the Control Agent (see
1830:ref:`kea-ctrl-agent`).
1831
1832The library can be loaded similarly to other hook libraries. It
1833does not take any parameters, and it supports both DHCPv4 and DHCPv6
1834servers.
1835
1836::
1837
1838   "Dhcp6": {
1839       "hooks-libraries": [
1840           {
1841               "library": "/path/libdhcp_host_cmds.so"
1842           }
1843           ...
1844       ]
1845   }
1846
1847The subnet-id Parameter
1848~~~~~~~~~~~~~~~~~~~~~~~
1849
1850Prior to diving into the individual commands, it is worth discussing the
1851parameter, ``subnet-id``. Currently this parameter is mandatory for all of the
1852commands supplied by this library with the exception of
1853reservation-get-by-hostname where it is optional, and since Kea 1.9.0
1854reservation-get-page where it is optional and reservation-get-by-id
1855where it is forbidden.
1856In previous versions of Kea, reservations had
1857to belong to a specific subnet; as of Kea 1.5.0, reservations may
1858be specified globally. In other words, they are not specific to any
1859subnet. When reservations are supplied via the configuration file, the
1860ID of the containing subnet (or lack thereof) is implicit in the
1861configuration structure. However, when managing reservations using
1862host commands, it is necessary to explicitly identify the scope to which
1863the reservation belongs. This is done via the ``subnet-id`` parameter.
1864For global reservations, use a value of zero (0). For reservations
1865scoped to a specific subnet, use that subnet's ID.
1866
1867On the other hand when the subnet id is not specified in the command
1868parameters it is added to each host in responses. If the subnet id
1869has the unused special value this means the host entry belongs only
1870to the other IP version (i.e. IPv6 in DHCPv4 server or IPv4 in DHCPv6
1871server) and this entry is ignored.
1872
1873.. _command-reservation-add:
1874
1875The reservation-add Command
1876~~~~~~~~~~~~~~~~~~~~~~~~~~~
1877
1878``reservation-add`` allows for the insertion of a new host. It takes a
1879set of arguments that vary depending on the nature of the host
1880reservation. Any parameters allowed in the configuration file that
1881pertain to host reservation are permitted here. For details regarding
1882IPv4 reservations, see :ref:`host-reservation-v4`; for IPv6 reservations, see
1883:ref:`host-reservation-v6`. The ``subnet-id`` is mandatory. Use a
1884value of zero (0) to add a global reservation, or the id of the subnet
1885to which the reservation should be added. An example command can be as
1886simple as:
1887
1888.. code-block:: json
1889
1890   {
1891       "command": "reservation-add",
1892       "arguments": {
1893           "reservation": {
1894               "subnet-id": 1,
1895               "hw-address": "1a:1b:1c:1d:1e:1f",
1896               "ip-address": "192.0.2.202"
1897           }
1898       }
1899   }
1900
1901but it can also take many more parameters, for example:
1902
1903.. code-block:: json
1904
1905   {
1906       "command": "reservation-add",
1907       "arguments": {
1908           "reservation": {
1909               "subnet-id": 1,
1910               "client-id": "01:0a:0b:0c:0d:0e:0f",
1911               "ip-address": "192.0.2.205",
1912               "next-server": "192.0.2.1",
1913               "server-hostname": "hal9000",
1914               "boot-file-name": "/dev/null",
1915               "option-data": [
1916                   {
1917                       "name": "domain-name-servers",
1918                       "data": "10.1.1.202,10.1.1.203"
1919                   }
1920               ],
1921               "client-classes": [ "special_snowflake", "office" ]
1922           }
1923       }
1924   }
1925
1926Here is an example of a complex IPv6 reservation:
1927
1928.. code-block:: json
1929
1930   {
1931       "command": "reservation-add",
1932       "arguments": {
1933           "reservation": {
1934               "subnet-id": 1,
1935               "duid": "01:02:03:04:05:06:07:08:09:0A",
1936               "ip-addresses": [ "2001:db8:1:cafe::1" ],
1937               "prefixes": [ "2001:db8:2:abcd::/64" ],
1938               "hostname": "foo.example.com",
1939               "option-data": [
1940                   {
1941                       "name": "vendor-opts",
1942                       "data": "4491"
1943                   },
1944                   {
1945                       "name": "tftp-servers",
1946                       "space": "vendor-4491",
1947                       "data": "3000:1::234"
1948                   }
1949               ]
1950           }
1951       }
1952   }
1953
1954The command returns a status that indicates either a success (result 0)
1955or a failure (result 1). A failed command always includes a text parameter
1956that explains the cause of the failure. Example results:
1957
1958::
1959
1960   { "result": 0, "text": "Host added." }
1961
1962Example failure:
1963
1964::
1965
1966   { "result": 1, "text": "Mandatory 'subnet-id' parameter missing." }
1967
1968As ``reservation-add`` is expected to store the host, the hosts-databases
1969parameter must be specified in the configuration and databases must not
1970run in read-only mode. In future versions of Kea, it will be possible to
1971modify the reservations read from a configuration file. Interested parties are
1972encouraged to contact ISC for more information on developing this functionality.
1973
1974.. _command-reservation-get:
1975
1976The reservation-get Command
1977~~~~~~~~~~~~~~~~~~~~~~~~~~~
1978
1979``reservation-get`` can be used to query the host database and retrieve
1980existing reservations. There are two types of parameters this command
1981supports: (subnet-id, address) or (subnet-id, identifier-type,
1982identifier). The first type of query is used when the address (either
1983IPv4 or IPv6) is known, but the details of the reservation are not. One
1984common use case of this type of query is to find out whether a given
1985address is reserved. The second query uses identifiers. For
1986maximum flexibility, Kea stores the host identifying information as a
1987pair of values: the type and the actual identifier. Currently supported
1988identifiers are "hw-address", "duid", "circuit-id", "client-id", and
1989"flex-id", but additional types may be added in the future. If any new
1990identifier types are defined in the future, the reservation-get command will
1991support them automatically. The ``subnet-id`` is mandatory. Use a value
1992of zero (0) to fetch a global reservation, or the id of the subnet to
1993which the reservation belongs.
1994
1995An example command for getting a host reservation by a (subnet-id,
1996address) pair looks as follows:
1997
1998::
1999
2000   {
2001       "command": "reservation-get",
2002       "arguments": {
2003           "subnet-id": 1,
2004           "ip-address": "192.0.2.202"
2005       }
2006   }
2007
2008An example query by (subnet-id, identifier-type, identifier) looks as
2009follows:
2010
2011::
2012
2013   {
2014       "command": "reservation-get",
2015       "arguments": {
2016           "subnet-id": 4,
2017           "identifier-type": "hw-address",
2018           "identifier": "01:02:03:04:05:06"
2019       }
2020   }
2021
2022``reservation-get`` typically returns the result 0 when the query was
2023conducted properly. In particular, 0 is returned when the host was not
2024found. If the query was successful, a number of host parameters will be
2025returned. An example of a query that did not find the host looks as
2026follows:
2027
2028::
2029
2030   { "result": 0, "text": "Host not found." }
2031
2032An example result returned when the host was found looks like this:
2033
2034::
2035
2036   {
2037     "arguments": {
2038       "boot-file-name": "bootfile.efi",
2039       "client-classes": [
2040
2041       ],
2042       "hostname": "somehost.example.org",
2043       "hw-address": "01:02:03:04:05:06",
2044       "ip-address": "192.0.2.100",
2045       "next-server": "192.0.0.2",
2046       "option-data": [
2047
2048       ],
2049       "server-hostname": "server-hostname.example.org"
2050     },
2051     "result": 0,
2052     "text": "Host found."
2053   }
2054
2055An example result returned when the query was malformed might look like this:
2056
2057::
2058
2059   { "result": 1, "text": "No 'ip-address' provided and 'identifier-type'
2060                           is either missing or not a string." }
2061
2062.. _command-reservation-get-all:
2063
2064The reservation-get-all Command
2065~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2066
2067``reservation-get-all`` can be used to query the host database and
2068retrieve all reservations in a specified subnet. This command uses
2069parameters providing the mandatory subnet-id. Global host reservations
2070can be retrieved by using a subnet-id value of zero (0).
2071
2072For instance, retrieving host reservations for the subnet 1:
2073
2074::
2075
2076   {
2077       "command": "reservation-get-all",
2078       "arguments": {
2079           "subnet-id": 1
2080        }
2081   }
2082
2083returns some IPv4 hosts:
2084
2085::
2086
2087   {
2088       "arguments": {
2089           "hosts": [
2090               {
2091                   "boot-file-name": "bootfile.efi",
2092                   "client-classes": [ ],
2093                   "hostname": "somehost.example.org",
2094                   "hw-address": "01:02:03:04:05:06",
2095                   "ip-address": "192.0.2.100",
2096                   "next-server": "192.0.0.2",
2097                   "option-data": [ ],
2098                   "server-hostname": "server-hostname.example.org"
2099               },
2100               ...
2101               {
2102                   "boot-file-name": "bootfile.efi",
2103                   "client-classes": [ ],
2104                   "hostname": "otherhost.example.org",
2105                   "hw-address": "01:02:03:04:05:ff",
2106                   "ip-address": "192.0.2.200",
2107                   "next-server": "192.0.0.2",
2108                   "option-data": [ ],
2109                   "server-hostname": "server-hostname.example.org"
2110               }
2111           ]
2112       },
2113       "result": 0,
2114       "text": "72 IPv4 host(s) found."
2115   }
2116
2117The response returned by ``reservation-get-all`` can be very long. The
2118DHCP server does not handle DHCP traffic when preparing a response to
2119reservation-get-all, so if there are many reservations in a subnet, this
2120may be disruptive. Use with caution. For larger deployments, please
2121consider using ``reservation-get-page`` instead (see
2122:ref:`command-reservation-get-page`).
2123
2124For a reference, see :ref:`command-reservation-get-all`.
2125
2126.. _command-reservation-get-page:
2127
2128The reservation-get-page command
2129~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2130
2131``reservation-get-page`` can be used to query the host database and
2132retrieve all reservations in a specified subnet by pages. This command
2133uses parameters providing the mandatory subnet-id. Use a value of zero
2134(0) to fetch global reservations. The second mandatory parameter is the
2135page size limit. Optional source-index and from host id, both defaulting
2136to 0, are used to chain page queries.
2137Since Kea version 1.9.0 the subnet id parameter is optional.
2138
2139The usage of from and source-index parameters requires additional
2140explanation. For the first call, those parameters should not be specified
2141(or specified as zeros). For any follow-up calls, they should be set to
2142the values returned in previous calls in a next map holding from and
2143source-index values. Subsequent calls should be issued until all
2144reservations are returned. The end is reached once the returned list is
2145empty, the count is 0, no next map is present, and result status 3 (empty) is
2146returned.
2147
2148.. note::
2149
2150   The from and source-index parameters are reflecting the internal state of
2151   the search. There is no need to understand what they represent; it is
2152   simply a value that is supposed to be copied from one response to the
2153   next query. However, for those who are curious, the from field represents a
2154   64-bit representation of the host identifier used by a host backend. The
2155   source-index is an internal representation of multiple host
2156   backends: 0 is used to represent hosts defined in a configuration
2157   file, and 1 represents the first database backend. In some uncommon cases
2158   there may be more than one database backend configured, so
2159   potentially there may be a 2. In any case, Kea will iterate over all
2160   backends configured.
2161
2162For instance, retrieving host reservations for the subnet 1 and
2163requesting the first page can be done by:
2164
2165::
2166
2167   {
2168       "command": "reservation-get-page",
2169       "arguments": {
2170           "subnet-id": 1,
2171           "limit": 10
2172        }
2173   }
2174
2175Since this is the first call, source-index and from should not be
2176specified. They will default to their zero default values.
2177
2178Some hosts are returned with information to get the next page:
2179
2180::
2181
2182   {
2183       "arguments": {
2184           "count": 72,
2185           "hosts": [
2186               {
2187                   "boot-file-name": "bootfile.efi",
2188                   "client-classes": [ ],
2189                   "hostname": "somehost.example.org",
2190                   "hw-address": "01:02:03:04:05:06",
2191                   "ip-address": "192.0.2.100",
2192                   "next-server": "192.0.0.2",
2193                   "option-data": [ ],
2194                   "server-hostname": "server-hostname.example.org"
2195               },
2196               ...
2197               {
2198                   "boot-file-name": "bootfile.efi",
2199                   "client-classes": [ ],
2200                   "hostname": "otherhost.example.org",
2201                   "hw-address": "01:02:03:04:05:ff",
2202                   "ip-address": "192.0.2.200",
2203                   "next-server": "192.0.0.2",
2204                   "option-data": [ ],
2205                   "server-hostname": "server-hostname.example.org"
2206               }
2207           ],
2208           "next": {
2209               "from": 1234567,
2210               "source-index": 1
2211           }
2212       },
2213       "result": 0,
2214       "text": "72 IPv4 host(s) found."
2215   }
2216
2217Note that the "from" and "source-index" fields were specified in the response in
2218the next map. Those two must be copied to the next command, so Kea
2219continues from the place where the last command finished. To get the
2220next page the following command can be sent:
2221
2222::
2223
2224   {
2225       "command": "reservation-get-page",
2226       "arguments": {
2227           "subnet-id": 1,
2228           "source-index": 1,
2229           "from": 1234567,
2230           "limit": 10
2231        }
2232   }
2233
2234The response will contain a list of hosts with updated source-index
2235and from fields. Continue calling the command until the last
2236page is received. Its response will look like this:
2237
2238::
2239
2240   {
2241       "arguments": {
2242           "count": 0,
2243           "hosts": [ ],
2244       },
2245       "result": 3,
2246       "0 IPv4 host(s) found."
2247   }
2248
2249This command is more complex than ``reservation-get-all``, but lets
2250users retrieve larger host reservations lists in smaller chunks. For
2251small deployments with few reservations, it is easier to use
2252``reservation-get-all`` (see :ref:`command-reservation-get-all`).
2253
2254.. note::
2255
2256   Currently ``reservation-get-page`` is not supported by the Cassandra
2257   host backend.
2258
2259.. _command-reservation-get-by-hostname:
2260
2261The reservation-get-by-hostname Command
2262~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2263
2264``reservation-get-by-hostname`` can be used to query the host database and
2265retrieve all reservations with a specified hostname and optionally in
2266a specified subnet. This command uses parameters providing the mandatory
2267hostname and the optional subnet-id. Global host reservations
2268can be retrieved by using a subnet-id value of zero (0).
2269Hostname matching is case-insensitive. This command is available since
2270Kea version 1.7.1.
2271
2272For instance, retrieving host reservations for "foobar" in the subnet 1:
2273
2274::
2275
2276   {
2277       "command": "reservation-get-by-hostname",
2278       "arguments": {
2279           "hostname": "foobar.example.org",
2280           "subnet-id": 1
2281        }
2282   }
2283
2284returns some IPv4 hosts:
2285
2286::
2287
2288   {
2289       "arguments": {
2290           "hosts": [
2291               {
2292                   "boot-file-name": "bootfile.efi",
2293                   "client-classes": [ ],
2294                   "hostname": "foobar.example.org",
2295                   "hw-address": "01:02:03:04:05:06",
2296                   "ip-address": "192.0.2.100",
2297                   "next-server": "192.0.0.2",
2298                   "option-data": [ ],
2299                   "server-hostname": "server-hostname.example.org"
2300               },
2301               ...
2302               {
2303                   "boot-file-name": "bootfile.efi",
2304                   "client-classes": [ ],
2305                   "hostname": "foobar.example.org",
2306                   "hw-address": "01:02:03:04:05:ff",
2307                   "ip-address": "192.0.2.200",
2308                   "next-server": "192.0.0.2",
2309                   "option-data": [ ],
2310                   "server-hostname": "server-hostname.example.org"
2311               }
2312           ]
2313       },
2314       "result": 0,
2315       "text": "5 IPv4 host(s) found."
2316   }
2317
2318The response returned by ``reservation-get-by-hostname`` can be long
2319in particular when responses are not limited to a subnet.
2320
2321For a reference, see :ref:`command-reservation-get-by-hostname`.
2322
2323.. note::
2324
2325   When the host backend is MySQL this commands relies on the fact
2326   the hostname column in the hosts table uses a case-insensitive
2327   collation as explained in the :ref:`mysql-database` section of
2328   :ref:`admin`.
2329
2330.. _command-reservation-get-by-id:
2331
2332The reservation-get-by-id Command
2333~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2334
2335``reservation-get-by-id`` can be used to query the host database and
2336retrieve all reservations with a specified identifier (identifier-type
2337and identifier parameters) independently of subnets. The syntax for
2338parameters is the same as for ref:`command-reservation-get`.
2339The subnet-id parameter is forbidden to avoid confusion.
2340This command is available since Kea version 1.9.0.
2341
2342For instance, retrieving host reservations for the 01:02:03:04:05:06 MAC
2343address:
2344
2345::
2346
2347   {
2348       "command": "reservation-get-by-id",
2349       "arguments": {
2350           "identifier-type": "hw-address",
2351           "identifier": "01:02:03:04:05:06"
2352        }
2353    }
2354
2355returns some IPv4 hosts:
2356
2357::
2358
2359   {
2360       "arguments": {
2361           "hosts": [
2362               {
2363                   "boot-file-name": "bootfile.efi",
2364                   "client-classes": [ ],
2365                   "hostname": "foo.example.org",
2366                   "hw-address": "01:02:03:04:05:06",
2367                   "ip-address": "192.0.2.100",
2368                   "next-server": "192.0.0.2",
2369                   "option-data": [ ],
2370                   "server-hostname": "server-hostname.example.org",
2371                   "subnet-id": 123
2372               },
2373               ...
2374               {
2375                   "boot-file-name": "bootfile.efi",
2376                   "client-classes": [ ],
2377                   "hostname": "bar.example.org",
2378                   "hw-address": "01:02:03:04:05:06",
2379                   "ip-address": "192.0.2.200",
2380                   "next-server": "192.0.0.2",
2381                   "option-data": [ ],
2382                   "server-hostname": "server-hostname.example.org",
2383                   "subnet-id": 345
2384               }
2385           ]
2386       },
2387       "result": 0,
2388       "text": "5 IPv4 host(s) found."
2389   }
2390
2391The response returned by ``reservation-get-by-id`` can be long
2392in particular when responses are not limited to a subnet.
2393
2394For a reference, see :ref:`command-reservation-get-by-id`.
2395
2396.. _command-reservation-del:
2397
2398The reservation-del Command
2399~~~~~~~~~~~~~~~~~~~~~~~~~~~
2400
2401``reservation-del`` can be used to delete a reservation from the host
2402database. There are two types of parameters this command supports:
2403(subnet-id, address) or (subnet-id, identifier-type, identifier). The
2404first type of query is used when the address (either IPv4 or IPv6) is
2405known, but the details of the reservation are not. One common use case of
2406this type of query is to remove a reservation (e.g. a specific
2407address should no longer be reserved). The second query uses identifiers.
2408For maximum flexibility, Kea stores the host identifying information as
2409a pair of values: the type and the actual identifier. Currently supported
2410identifiers are "hw-address", "duid", "circuit-id", "client-id", and
2411"flex-id", but additional types may be added in the future. If any new
2412identifier types are defined in the future, the reservation-get command will
2413support them automatically. The ``subnet-id`` is mandatory. Use a value
2414of zero (0) to delete a global reservation, or the id of the subnet from
2415which the reservation should be deleted.
2416
2417An example command for deleting a host reservation by (subnet-id,
2418address) pair looks as follows:
2419
2420::
2421
2422   {
2423       "command": "reservation-del",
2424       "arguments": {
2425           "subnet-id": 1,
2426           "ip-address": "192.0.2.202"
2427       }
2428   }
2429
2430An example deletion by (subnet-id, identifier-type, identifier) looks as
2431follows:
2432
2433::
2434
2435   {
2436       "command": "reservation-del",
2437       "arguments":
2438           "subnet-id": 4,
2439           "identifier-type": "hw-address",
2440           "identifier": "01:02:03:04:05:06"
2441       }
2442   }
2443
2444``reservation-del`` returns a result 0 when the host deletion was
2445successful or 1 if it was not. Descriptive text is provided in the event of
2446an error. Example results look as follows:
2447
2448::
2449
2450   {
2451       "result": 1,
2452       "text": "Host not deleted (not found)."
2453   }
2454
2455::
2456
2457   {
2458       "result": 0,
2459       "text": "Host deleted."
2460   }
2461
2462::
2463
2464   {
2465       "result": 1,
2466       "text": "Unable to delete a host because there is no hosts-database
2467                configured."
2468   }
2469
2470
2471
2472.. include:: hooks-lease-cmds.rst
2473
2474
2475.. _subnet-cmds:
2476
2477subnet_cmds: Subnet Commands
2478============================
2479
2480This section describes a hook application that offers some new
2481commands used to query and manipulate subnet and shared network
2482configurations in Kea. This application is very useful in deployments
2483with a large number of subnets being managed by the DHCP servers,
2484when those subnets are frequently updated. The commands offer a lightweight
2485approach for manipulating subnets without a need to fully reconfigure
2486the server and without affecting existing servers' configurations. An
2487ability to manage shared networks (listing, retrieving details, adding
2488new ones, removing existing ones, and adding subnets to and removing them from
2489shared networks) is also provided.
2490
2491Currently this library is only available to ISC customers with a paid support
2492contract.
2493
2494.. note::
2495
2496   This library may only be loaded by the ``kea-dhcp4`` or ``kea-dhcp6``
2497   process.
2498
2499The following commands are currently supported:
2500
2501-  ``subnet4-list/subnet6-list`` - lists all configured subnets.
2502
2503-  ``subnet4-get/subnet6-get`` - retrieves detailed information about a
2504   specified subnet.
2505
2506-  ``subnet4-add/subnet6-add`` - adds a new subnet into the server's
2507   configuration.
2508
2509-  ``subnet4-update/subnet6-update`` - updates a subnet in the server's
2510   configuration.
2511
2512-  ``subnet4-del/subnet6-del`` - removes a subnet from the server's
2513   configuration.
2514
2515-  ``network4-list/network6-list`` - lists all configured shared networks.
2516
2517-  ``network4-get/network6-get`` - retrieves detailed information about a
2518   specified shared network.
2519
2520-  ``network4-add/network6-add`` - adds a new shared network to the
2521   server's configuration.
2522
2523-  ``network4-del/network6-del`` - removes a shared network from the
2524   server's configuration.
2525
2526-  ``network4-subnet-add/network6-subnet-add`` - adds an existing subnet to
2527   an existing shared network.
2528
2529-  ``network4-subnet-del/network6-subnet-del`` - removes a subnet from
2530   an existing shared network and demotes it to a plain subnet.
2531
2532.. _command-subnet4-list:
2533
2534The subnet4-list Command
2535~~~~~~~~~~~~~~~~~~~~~~~~
2536
2537This command is used to list all currently configured subnets. Each
2538subnet is returned with a subnet identifier and
2539subnet prefix. To retrieve
2540detailed information about the subnet, use the ``subnet4-get`` command.
2541
2542This command has the simple structure:
2543
2544::
2545
2546   {
2547       "command": "subnet4-list"
2548   }
2549
2550The list of subnets is returned in the following format:
2551
2552::
2553
2554   {
2555       "result": 0,
2556       "text": "2 IPv4 subnets found",
2557       "arguments": {
2558       "subnets": [
2559           {
2560               "id": 10,
2561               "subnet": "10.0.0.0/8"
2562           },
2563           {
2564               "id": 100,
2565               "subnet": "192.0.2.0/24"
2566           }
2567       ]
2568   }
2569
2570If no IPv4 subnets are found, an error code is returned along with the
2571error description.
2572
2573.. _command-subnet6-list:
2574
2575The subnet6-list Command
2576~~~~~~~~~~~~~~~~~~~~~~~~
2577
2578This command is used to list all currently configured subnets. Each
2579subnet is returned with a subnet identifier and
2580subnet prefix. To retrieve
2581detailed information about the subnet, use the ``subnet6-get`` command.
2582
2583This command has the simple structure:
2584
2585::
2586
2587   {
2588       "command": "subnet6-list"
2589   }
2590
2591The list of subnets is returned in the following format:
2592
2593::
2594
2595   {
2596       "result": 0,
2597       "text": "2 IPv6 subnets found",
2598       "arguments": {
2599       "subnets": [
2600           {
2601               "id": 11,
2602               "subnet": "2001:db8:1::/64"
2603           },
2604           {
2605               "id": 233,
2606               "subnet": "3000::/16"
2607           }
2608       ]
2609   }
2610
2611If no IPv6 subnets are found, an error code is returned along with the
2612error description.
2613
2614.. _command-subnet4-get:
2615
2616The subnet4-get Command
2617~~~~~~~~~~~~~~~~~~~~~~~
2618
2619This command is used to retrieve detailed information about the
2620specified subnet. This command usually follows ``subnet4-list``,
2621which is used to discover available subnets with their respective subnet
2622identifiers and prefixes. Any of those parameters can be then used in
2623``subnet4-get`` to fetch subnet information:
2624
2625::
2626
2627   {
2628       "command": "subnet4-get",
2629       "arguments": {
2630           "id": 10
2631       }
2632   }
2633
2634or
2635
2636::
2637
2638   {
2639       "command": "subnet4-get",
2640       "arguments": {
2641           "subnet": "10.0.0.0/8"
2642       }
2643   }
2644
2645If the subnet exists the response will be similar to this:
2646
2647::
2648
2649   {
2650       "result": 0,
2651       "text": "Info about IPv4 subnet 10.0.0.0/8 (id 10) returned",
2652       "arguments": {
2653           "subnets": [
2654               {
2655                   "subnet": "10.0.0.0/8",
2656                   "id": 1,
2657                   "option-data": [
2658                       ....
2659                   ]
2660                   ...
2661               }
2662           ]
2663       }
2664   }
2665
2666.. _command-subnet6-get:
2667
2668The subnet6-get Command
2669~~~~~~~~~~~~~~~~~~~~~~~
2670
2671This command is used to retrieve detailed information about the
2672specified subnet. This command usually follows ``subnet6-list``,
2673which is used to discover available subnets with their respective subnet
2674identifiers and prefixes. Any of those parameters can be then used in
2675``subnet6-get`` to fetch subnet information:
2676
2677::
2678
2679   {
2680       "command": "subnet6-get",
2681       "arguments": {
2682           "id": 11
2683       }
2684   }
2685
2686or
2687
2688::
2689
2690   {
2691       "command": "subnet6-get",
2692       "arguments": {
2693           "subnet": "2001:db8:1::/64"
2694       }
2695   }
2696
2697If the subnet exists the response will be similar to this:
2698
2699::
2700
2701   {
2702       "result": 0,
2703       "text": "Info about IPv6 subnet 2001:db8:1::/64 (id 11) returned",
2704       "arguments": {
2705           "subnets": [
2706               {
2707                   "subnet": "2001:db8:1::/64",
2708                   "id": 1,
2709                   "option-data": [
2710                       ...
2711                   ]
2712                   ....
2713               }
2714           ]
2715       }
2716   }
2717
2718.. _command-subnet4-add:
2719
2720The subnet4-add Command
2721~~~~~~~~~~~~~~~~~~~~~~~
2722
2723This command is used to create and add a new subnet to the existing server
2724configuration. This operation has no impact on other subnets. The subnet
2725identifier must be specified and must be unique among all subnets. If
2726the identifier or a subnet prefix is not unique, an error is reported and
2727the subnet is not added.
2728
2729The subnet information within this command has the same structure as the
2730subnet information in the server configuration file, with the exception
2731that static host reservations must not be specified within
2732``subnet4-add``. The commands described in :ref:`host-cmds` should be used to
2733add, remove, and modify static reservations.
2734
2735::
2736
2737   {
2738       "command": "subnet4-add",
2739       "arguments": {
2740           "subnet4": [ {
2741               "id": 123,
2742               "subnet": "10.20.30.0/24",
2743               ...
2744           } ]
2745       }
2746   }
2747
2748The response to this command has the following structure:
2749
2750::
2751
2752   {
2753       "result": 0,
2754       "text": "IPv4 subnet added",
2755       "arguments": {
2756           "subnet4": [
2757               {
2758                   "id": 123,
2759                   "subnet": "10.20.30.0/24"
2760               }
2761           ]
2762       }
2763   }
2764
2765.. _command-subnet6-add:
2766
2767The subnet6-add Command
2768~~~~~~~~~~~~~~~~~~~~~~~
2769
2770This command is used to create and add a new subnet to the existing server
2771configuration. This operation has no impact on other subnets. The subnet
2772identifier must be specified and must be unique among all subnets. If
2773the identifier or a subnet prefix is not unique, an error is reported and
2774the subnet is not added.
2775
2776The subnet information within this command has the same structure as the
2777subnet information in the server configuration file, with the exception
2778that static host reservations must not be specified within
2779``subnet6-add``. The commands described in :ref:`host-cmds` should be used
2780to add, remove, and modify static reservations.
2781
2782::
2783
2784   {
2785       "command": "subnet6-add",
2786       "arguments": {
2787           "subnet6": [ {
2788               "id": 234,
2789               "subnet": "2001:db8:1::/64",
2790               ...
2791           } ]
2792       }
2793   }
2794
2795The response to this command has the following structure:
2796
2797::
2798
2799   {
2800       "result": 0,
2801       "text": "IPv6 subnet added",
2802       "arguments": {
2803           "subnet6": [
2804               {
2805                   "id": 234,
2806                   "subnet": "2001:db8:1::/64"
2807               }
2808           ]
2809       }
2810   }
2811
2812It is recommended, but not mandatory, to specify the subnet ID. If not
2813specified, Kea will try to assign the next subnet-id value. This
2814automatic ID value generator is simple; it returns a previously
2815automatically assigned value, increased by 1. This works well, unless
2816a subnet is manually created with a value bigger than one previously used. For
2817example, if subnet4-add is called five times, each without an ID, Kea will
2818assign IDs 1, 2, 3, 4, and 5 and it will work just fine. However, if
2819subnet4-add is called five times, with the first subnet having the
2820subnet-id of value 3 and the remaining ones having no subnet-id, the operation will
2821fail. The first command (with the explicit value) will use subnet-id 3; the
2822second command will create a subnet with id of 1; the third will use a
2823value of 2; and finally the fourth will have the subnet-id value
2824auto-generated as 3. However, since there is already a subnet with that
2825ID, the process will fail.
2826
2827The general recommendation is either never use explicit values, so
2828the auto-generated values will always work; or always use explicit
2829values, so the auto-generation is never used. The two
2830approaches can be mixed only if the administrator understands how internal
2831automatic subnet-id generation works in Kea.
2832
2833.. note::
2834
2835   Subnet IDs must be greater than zero and less than 4294967295.
2836
2837.. _command-subnet4-update:
2838
2839The subnet4-update Command
2840~~~~~~~~~~~~~~~~~~~~~~~~~~
2841
2842This command is used to update a subnet in the existing server
2843configuration. This operation has no impact on other subnets. The subnet
2844identifier is used to identify the subnet to replace; it must be
2845specified and must be unique among all subnets. The subnet prefix should
2846not be updated.
2847
2848The subnet information within this command has the same structure as the
2849subnet information in the server configuration file, with the exception
2850that static host reservations must not be specified within
2851``subnet4-update``. The commands described in :ref:`host-cmds` should be used
2852to update, remove, and modify static reservations.
2853
2854::
2855
2856   {
2857       "command": "subnet4-update",
2858       "arguments": {
2859           "subnet4": [ {
2860               "id": 123,
2861               "subnet": "10.20.30.0/24",
2862               ...
2863           } ]
2864       }
2865   }
2866
2867The response to this command has the following structure:
2868
2869::
2870
2871   {
2872       "result": 0,
2873       "text": "IPv4 subnet updated",
2874       "arguments": {
2875           "subnet4": [
2876               {
2877                   "id": 123,
2878                   "subnet": "10.20.30.0/24"
2879               }
2880           ]
2881       }
2882   }
2883
2884.. _command-subnet6-update:
2885
2886The subnet6-update Command
2887~~~~~~~~~~~~~~~~~~~~~~~~~~
2888
2889This command is used to update a subnet in the existing server
2890configuration. This operation has no impact on other subnets. The subnet
2891identifier is used to identify the subnet to replace; it must be
2892specified and must be unique among all subnets. The subnet prefix should
2893not be updated.
2894
2895The subnet information within this command has the same structure as the
2896subnet information in the server configuration file, with the exception
2897that static host reservations must not be specified within
2898``subnet6-update``. The commands described in :ref:`host-cmds` should be used
2899to update, remove, and modify static reservations.
2900
2901::
2902
2903   {
2904       "command": "subnet6-update",
2905       "arguments": {
2906           "subnet6": [ {
2907               "id": 234,
2908               "subnet": "2001:db8:1::/64",
2909               ...
2910           } ]
2911       }
2912   }
2913
2914The response to this command has the following structure:
2915
2916::
2917
2918   {
2919       "result": 0,
2920       "text": "IPv6 subnet updated",
2921       "arguments": {
2922           "subnet6": [
2923               {
2924                   "id": 234,
2925                   "subnet": "2001:db8:1::/64"
2926               }
2927           ]
2928       }
2929   }
2930
2931.. _command-subnet4-del:
2932
2933The subnet4-del Command
2934~~~~~~~~~~~~~~~~~~~~~~~
2935
2936This command is used to remove a subnet from the server's configuration.
2937This command has no effect on other configured subnets, but removing a
2938subnet has certain implications which the server's administrator should
2939be aware of.
2940
2941In most cases the server has assigned some leases to the clients
2942belonging to the subnet. The server may also be configured with static
2943host reservations which are associated with this subnet. The current
2944implementation of the ``subnet4-del`` command removes neither the leases nor
2945the host reservations associated with a subnet. This is the safest approach
2946because the server does not lose track of leases assigned to the clients
2947from this subnet. However, removal of the subnet may still cause
2948configuration errors and conflicts. For example: after removal of the
2949subnet, the server administrator may update a new subnet with the ID
2950used previously for the removed subnet. This means that the existing
2951leases and static reservations will be in conflict with this new subnet.
2952Thus, we recommend that this command be used with extreme caution.
2953
2954This command can also be used to completely delete an IPv4 subnet that
2955is part of a shared network. To simply remove the subnet
2956from a shared network and keep the subnet configuration, use the
2957``network4-subnet-del`` command instead.
2958
2959The command has the following structure:
2960
2961::
2962
2963   {
2964       "command": "subnet4-del",
2965       "arguments": {
2966           "id": 123
2967       }
2968   }
2969
2970The example successful response may look like this:
2971
2972::
2973
2974   {
2975       "result": 0,
2976       "text": "IPv4 subnet 192.0.2.0/24 (id 123) deleted",
2977       "arguments": {
2978           "subnets": [
2979               {
2980                   "id": 123,
2981                   "subnet": "192.0.2.0/24"
2982               }
2983           ]
2984       }
2985   }
2986
2987.. _command-subnet6-del:
2988
2989The subnet6-del Command
2990~~~~~~~~~~~~~~~~~~~~~~~
2991
2992This command is used to remove a subnet from the server's configuration.
2993This command has no effect on other configured subnets, but removing a
2994subnet has certain implications which the server's administrator should
2995be aware of.
2996
2997In most cases the server has assigned some leases to the clients
2998belonging to the subnet. The server may also be configured with static
2999host reservations which are associated with this subnet. The current
3000implementation of the ``subnet6-del`` command removes neither the leases nor
3001the host reservations associated with a subnet. This is the safest approach
3002because the server does not lose track of leases assigned to the clients
3003from this subnet. However, removal of the subnet may still cause
3004configuration errors and conflicts. For example: after removal of the
3005subnet, the server administrator may add a new subnet with the ID used
3006previously for the removed subnet. This means that the existing leases
3007and static reservations will be in conflict with this new subnet. Thus,
3008we recommend that this command be used with extreme caution.
3009
3010This command can also be used to completely delete an IPv6 subnet that
3011is part of a shared network. To simply remove the subnet
3012from a shared network and keep the subnet configuration, use the
3013``network6-subnet-del`` command instead.
3014
3015The command has the following structure:
3016
3017::
3018
3019   {
3020       "command": "subnet6-del",
3021       "arguments": {
3022           "id": 234
3023       }
3024   }
3025
3026The example successful response may look like this:
3027
3028::
3029
3030   {
3031       "result": 0,
3032       "text": "IPv6 subnet 2001:db8:1::/64 (id 234) deleted",
3033       "subnets": [
3034           {
3035               "id": 234,
3036               "subnet": "2001:db8:1::/64"
3037           }
3038       ]
3039   }
3040
3041.. _command-network4-list:
3042
3043.. _command-network6-list:
3044
3045The network4-list, network6-list Commands
3046~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3047
3048These commands are used to retrieve the full list of currently configured
3049shared networks. The list contains only very basic information about
3050each shared network. If more details are needed, please use
3051``network4-get`` or ``network6-get`` to retrieve all information
3052available. This command does not require any parameters and its
3053invocation is very simple:
3054
3055::
3056
3057   {
3058       "command": "network4-list"
3059   }
3060
3061An example response for ``network4-list`` looks as follows:
3062
3063::
3064
3065   {
3066       "arguments": {
3067           "shared-networks": [
3068               { "name": "floor1" },
3069               { "name": "office" }
3070           ]
3071       },
3072       "result": 0,
3073       "text": "2 IPv4 network(s) found"
3074   }
3075
3076``network6-list`` follows exactly the same syntax for both the query and
3077the response.
3078
3079.. _command-network4-get:
3080
3081.. _command-network6-get:
3082
3083The network4-get, network6-get Commands
3084~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3085
3086These commands are used to retrieve detailed information about shared
3087networks, including subnets that are currently part of a given network.
3088Both commands take one mandatory parameter, ``name``, which specifies the
3089name of the shared network. An example command to retrieve details about
3090an IPv4 shared network with the name "floor13" looks as follows:
3091
3092::
3093
3094   {
3095       "command": "network4-get",
3096       "arguments": {
3097           "name": "floor13"
3098       }
3099   }
3100
3101An example response could look as follows:
3102
3103::
3104
3105   {
3106       "result": 0,
3107       "text": "Info about IPv4 shared network 'floor13' returned",
3108       "arguments": {
3109           "shared-networks": [
3110           {
3111               "match-client-id": true,
3112               "name": "floor13",
3113               "option-data": [ ],
3114               "rebind-timer": 90,
3115               "relay": {
3116                   "ip-address": "0.0.0.0"
3117               },
3118               "renew-timer": 60,
3119               # "reservation-mode": "all",
3120               # It is replaced by the "reservations-global"
3121               # "reservations-in-subnet" and "reservations-out-of-pool"
3122               # parameters.
3123               # Specify if the server should lookup global reservations.
3124               "reservations-global": false,
3125               # Specify if the server should lookup in-subnet reservations.
3126               "reservations-in-subnet": true,
3127               # Specify if the server can assume that all reserved addresses
3128               # are out-of-pool.
3129               "reservations-out-of-pool": false,
3130               "subnet4": [
3131                   {
3132                       "subnet": "192.0.2.0/24",
3133                       "id": 5,
3134                       # many other subnet-specific details here
3135                   },
3136                   {
3137                       "id": 6,
3138                       "subnet": "192.0.3.0/31",
3139                       # many other subnet-specific details here
3140                   }
3141               ],
3142               "valid-lifetime": 120
3143           }
3144           ]
3145       }
3146   }
3147
3148Note that the actual response contains many additional fields that are
3149omitted here for clarity. The response format is exactly the same as
3150used in ``config-get``, just limited to returning the shared network's
3151information.
3152
3153.. _command-network4-add:
3154
3155.. _command-network6-add:
3156
3157The network4-add, network6-add Commands
3158~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3159
3160These commands are used to add a new shared network, which must
3161have a unique name. This command requires one parameter,
3162``shared-networks``, which is a list and should contain exactly one
3163entry that defines the network. The only mandatory element for a network
3164is its name. Although it does not make operational sense, it is possible
3165to add an empty shared network that does not have any subnets in it.
3166That is allowed for testing purposes, but having empty networks (or with
3167only one subnet) is discouraged in production environments. For details
3168regarding syntax, see :ref:`shared-network4` and
3169:ref:`shared-network6`.
3170
3171.. note::
3172
3173   As opposed to parameter inheritance during the processing of a full new
3174   configuration, this command does not fully handle parameter inheritance.
3175   Any missing parameters will be filled with default values, rather
3176   than inherited from the global scope.
3177
3178An example that showcases how to add a new IPv4 shared network looks as
3179follows:
3180
3181::
3182
3183   {
3184       "command": "network4-add",
3185       "arguments": {
3186           "shared-networks": [ {
3187               "name": "floor13",
3188               "subnet4": [
3189               {
3190                   "id": 100,
3191                   "pools": [ { "pool": "192.0.2.2-192.0.2.99" } ],
3192                   "subnet": "192.0.2.0/24",
3193                   "option-data": [
3194                       {
3195                           "name": "routers",
3196                           "data": "192.0.2.1"
3197                       }
3198                   ]
3199               },
3200               {
3201                   "id": 101,
3202                   "pools": [ { "pool": "192.0.3.2-192.0.3.99" } ],
3203                   "subnet": "192.0.3.0/24",
3204                   "option-data": [
3205                       {
3206                           "name": "routers",
3207                           "data": "192.0.3.1"
3208                       }
3209                   ]
3210               } ]
3211           } ]
3212       }
3213   }
3214
3215Assuming there was no shared network with a name "floor13" and no subnets
3216with IDs 100 and 101 previously configured, the command will be
3217successful and will return the following response:
3218
3219::
3220
3221   {
3222       "arguments": {
3223           "shared-networks": [ { "name": "floor13" } ]
3224       },
3225       "result": 0,
3226       "text": "A new IPv4 shared network 'floor13' added"
3227   }
3228
3229The ``network6-add`` command uses the same syntax for both the query and the
3230response. However, there are some parameters that are IPv4-only (e.g.
3231match-client-id) and some that are IPv6-only (e.g. interface-id). The same
3232applies to subnets within the network.
3233
3234.. _command-network4-del:
3235
3236.. _command-network6-del:
3237
3238The network4-del, network6-del Commands
3239~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3240
3241These commands are used to delete existing shared networks. Both
3242commands take exactly one parameter, ``name``, that specifies the name of
3243the network to be removed. An example invocation of the ``network4-del``
3244command looks as follows:
3245
3246::
3247
3248   {
3249       "command": "network4-del",
3250       "arguments": {
3251           "name": "floor13"
3252       }
3253   }
3254
3255Assuming there was such a network configured, the response will look
3256similar to the following:
3257
3258::
3259
3260   {
3261       "arguments": {
3262           "shared-networks": [
3263               {
3264                   "name": "floor13"
3265               }
3266           ]
3267       },
3268       "result": 0,
3269       "text": "IPv4 shared network 'floor13' deleted"
3270   }
3271
3272The ``network6-del`` command uses exactly the same syntax for both the
3273command and the response.
3274
3275If there are any subnets belonging to the shared network being deleted,
3276they will be demoted to a plain subnet. There is an optional parameter
3277called ``subnets-action`` that, if specified, takes one of two possible
3278values: ``keep`` (which is the default) and ``delete``. It controls
3279whether the subnets are demoted to plain subnets or removed. An example
3280usage in the ``network6-del`` command that deletes the shared network and all
3281subnets in it could look as follows:
3282
3283::
3284
3285   {
3286       "command": "network4-del",
3287       "arguments": {
3288           "name": "floor13",
3289           "subnets-action": "delete"
3290       }
3291   }
3292
3293Alternatively, to completely remove the subnets, it is possible to use the
3294``subnet4-del`` or ``subnet6-del`` commands.
3295
3296.. _command-network4-subnet-add:
3297
3298.. _command-network6-subnet-add:
3299
3300The network4-subnet-add, network6-subnet-add Commands
3301~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3302
3303These commands are used to add existing subnets to existing shared
3304networks. There are several ways to add a new shared network. The system
3305administrator can add the whole shared network at once, either by
3306editing a configuration file or by calling the ``network4-add`` or
3307``network6-add`` command with the desired subnets in it. This approach
3308works better for completely new shared subnets. However, there may be
3309cases when an existing subnet is running out of addresses and needs to
3310be extended with additional address space; in other words, another subnet
3311needs to be added on top of it. For this scenario, a system administrator
3312can use ``network4-add`` or ``network6-add``, and then add an existing
3313subnet to this newly created shared network using
3314``network4-subnet-add`` or ``network6-subnet-add``.
3315
3316The ``network4-subnet-add`` and ``network6-subnet-add`` commands take
3317two parameters: ``id``, which is an integer and specifies the subnet-id of
3318an existing subnet to be added to a shared network; and ``name``, which
3319specifies the name of the shared network to which the subnet will be added. The
3320subnet must not belong to any existing network; to
3321reassign a subnet from one shared network to another, please use the
3322``network4-subnet-del`` or ``network6-subnet-del`` commands first.
3323
3324An example invocation of the ``network4-subnet-add`` command looks as
3325follows:
3326
3327::
3328
3329   {
3330       "command": "network4-subnet-add",
3331       "arguments": {
3332           "name": "floor13",
3333           "id": 5
3334       }
3335   }
3336
3337Assuming there is a network named "floor13", and there is a subnet with
3338subnet-id 5 that is not a part of existing network, the command will
3339return a response similar to the following:
3340
3341::
3342
3343   {
3344       "result": 0,
3345       "text": "IPv4 subnet 10.0.0.0/8 (id 5) is now part of shared network 'floor13'"
3346   }
3347
3348The ``network6-subnet-add`` command uses exactly the same syntax for
3349both the command and the response.
3350
3351.. note::
3352
3353   As opposed to parameter inheritance during the processing of a full new
3354   configuration or when adding a new shared network with new subnets,
3355   this command does not fully handle parameter inheritance.
3356   Any missing parameters will be filled with default values, rather
3357   than inherited from the global scope or from the shared network.
3358
3359.. _command-network4-subnet-del:
3360
3361.. _command-network6-subnet-del:
3362
3363The network4-subnet-del, network6-subnet-del Commands
3364~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3365
3366These commands are used to remove a subnet that is part of an existing
3367shared network and demote it to a plain, stand-alone subnet.
3368To remove a subnet completely, use the ``subnet4-del`` or ``subnet6-del``
3369commands instead. The ``network4-subnet-del`` and
3370``network6-subnet-del`` commands take two parameters: ``id``, which is
3371an integer and specifies the subnet-id of an existing subnet to be removed from
3372a shared network; and ``name``, which specifies the name of the shared
3373network from which the subnet will be removed.
3374
3375An example invocation of the ``network4-subnet-del`` command looks as
3376follows:
3377
3378::
3379
3380    {
3381       "command": "network4-subnet-del",
3382       "arguments": {
3383           "name": "floor13",
3384           "id": 5
3385       }
3386    }
3387
3388Assuming there was a subnet with subnet-id equal to 5, that was part of a
3389shared network named "floor13", the response would look similar to the
3390following:
3391
3392::
3393
3394   {
3395       "result": 0,
3396       "text": "IPv4 subnet 10.0.0.0/8 (id 5) is now removed from shared network 'floor13'"
3397   }
3398
3399The ``network6-subnet-del`` command uses exactly the same syntax for
3400both the command and the response.
3401
3402
3403.. include:: hooks-bootp.rst
3404.. include:: hooks-class-cmds.rst
3405.. include:: hooks-cb-cmds.rst
3406.. include:: hooks-ha.rst
3407.. include:: hooks-stat-cmds.rst
3408.. include:: hooks-radius.rst
3409.. include:: hooks-host-cache.rst
3410.. include:: hooks-lease-query.rst
3411.. include:: hooks-run-script.rst
3412
3413
3414.. _user-context-hooks:
3415
3416User Contexts in Hooks
3417======================
3418
3419Hooks libraries can have their own configuration parameters, which is
3420convenient if the parameter applies to the whole library. However,
3421sometimes it is very useful to extend certain configuration entities
3422with additional configuration data. This is where the concept
3423of user contexts comes in. A system administrator can define an arbitrary set of
3424data and attach it to Kea structures, as long as the data are specified
3425as a JSON map. In particular, it is possible to define fields that are
3426integers, strings, boolean, lists, or maps. It is possible to define
3427nested structures of arbitrary complexity. Kea does not use that data on
3428its own; it simply stores it and makes it available for the hooks libraries.
3429
3430Another use case for user contexts may be storing comments and other
3431information that will be retained by Kea. Regular comments are discarded
3432when the configuration is loaded, but user contexts are retained. This is
3433useful if administrators want their comments to survive config-set or config-get
3434operations, for example.
3435
3436If user context is supported in a given context, the parser translates
3437"comment" entries into user context with a "comment" entry. The pretty
3438print of a configuration did the opposite operation and put "comment"
3439entries at the beginning of maps, but this was withdrawn in 1.7.9.
3440
3441As of Kea 1.3, the structures that allow user contexts are pools of all
3442types (addresses and prefixes) and subnets. Kea 1.4 extended user
3443context support to the global scope, interfaces configuration, shared networks,
3444subnets, client classes, option data and definitions, host
3445reservations, control socket, dhcp ddns, loggers and server ID. These
3446are supported in both DHCPv4 and DHCPv6, with the exception of server ID
3447which is DHCPv6 only.
3448