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