mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-29 04:57:52 +00:00
1200 lines
50 KiB
XML
1200 lines
50 KiB
XML
<!--
|
|
- Copyright (C) 2015-2019 Internet Systems Consortium, Inc. ("ISC")
|
|
-
|
|
- This Source Code Form is subject to the terms of the Mozilla Public
|
|
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
- file, you can obtain one at http://mozilla.org/MPL/2.0/.
|
|
-->
|
|
|
|
<!-- Converted by db4-upgrade version 1.1 -->
|
|
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="classify">
|
|
<title>Client Classification</title>
|
|
|
|
<section>
|
|
<title>Client Classification Overview</title>
|
|
<para>
|
|
In certain cases it is useful to differentiate between different
|
|
types of clients and treat them accordingly. Common reasons include:
|
|
<itemizedlist>
|
|
<listitem><para>
|
|
The clients represent different pieces of topology, e.g. a cable
|
|
modem is not the same as the clients behind that modem.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
The clients have different behavior, e.g. a smart phone behaves
|
|
differently from a laptop.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
The clients require different values for some options, e.g. a docsis3.0
|
|
cable modem requires different settings from a docsis2.0 cable modem.
|
|
</para></listitem>
|
|
</itemizedlist>
|
|
</para>
|
|
|
|
<para>
|
|
To make management easier, different clients can be grouped into a client class to receive
|
|
common options.
|
|
</para>
|
|
|
|
<para>
|
|
An incoming packet can be associated with a client class in
|
|
several ways:
|
|
<itemizedlist>
|
|
<listitem><para>
|
|
Implicitly, using a vendor class option or another builtin condition.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
Using an expression which evaluates to true.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
Using static host reservations, a shared network, a subnet, etc.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
Using a hook.
|
|
</para></listitem>
|
|
</itemizedlist>
|
|
</para>
|
|
|
|
<para>
|
|
It is envisaged that client classification will be used for
|
|
changing the behavior of almost any part of the DHCP message
|
|
processing.
|
|
There are currently five mechanisms that take advantage of
|
|
client classification: subnet selection, pool selection,
|
|
definition of DHCPv4 private (codes 224-254) and code 43
|
|
options, assignment of different options, and, for DHCPv4 cable
|
|
modems, the setting of specific options for use with the TFTP
|
|
server address and the boot file field.
|
|
</para>
|
|
|
|
<para>
|
|
The classification process is conducted in several steps:
|
|
<orderedlist>
|
|
<listitem><para>
|
|
The ALL class is associated with the incoming packet.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
Vendor class options are processed.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
Classes with matching expressions and not marked for later ("on
|
|
request" or depending on the KNOWN/UNKNOWN builtin classes)
|
|
evaluation are processed in the order they are defined in the
|
|
configuration; the boolean expression is evaluated and, if it
|
|
returns true ("match"), the incoming packet is associated with the
|
|
class.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
If a private or code 43 DHCPv4 option is received, it is decoded
|
|
following its client class or global (or, for option 43, last
|
|
resort) definition.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
When the incoming packet belongs the special class, "DROP", it is
|
|
dropped and an informational message is logged with the packet
|
|
information.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
A subnet is chosen, possibly based on the class information when
|
|
some subnets are reserved. More precisely: when choosing a subnet,
|
|
the server iterates over all of the subnets that are
|
|
feasible given the information found in the packet (client
|
|
address, relay address, etc). It uses the first subnet it
|
|
finds that either doesn't have a class associated with it, or
|
|
has a class which matches one of the packet's classes.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
The server looks for host reservations. If an identifier from the
|
|
incoming packet matches a host reservation in the subnet or
|
|
shared network, the packet is associated with the KNOWN class
|
|
and all classes of the host reservation. If a reservation is not
|
|
found, the packet is assigned to the UNKNOWN class.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
Classes with matching expressions - directly or indirectly using
|
|
the KNOWN/UNKNOWN builtin classes and not marked for later ("on
|
|
request") evaluation - are processed in the order they are defined
|
|
in the configuration; the boolean expression is evaluated and,
|
|
if it returns true ("match"), the incoming packet is associated
|
|
with the class. After a subnet is selected, the server determines
|
|
whether there is a reservation for a given client. Therefore, it
|
|
is not possible to use KNOWN/UNKNOWN classes to select a shared
|
|
network or a subnet, nor to make the DROP class dependent of
|
|
KNOWN/UNKNOWN classes.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
If needed, addresses and prefixes from pools are assigned,
|
|
possibly based on the class information when some pools are
|
|
reserved for class members.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
Classes marked as "required" are evaluated in the order in which they
|
|
are listed: first the shared network, then the subnet,
|
|
and finally the pools that assigned resources belong to.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
Options are assigned, again possibly based on the class information
|
|
in the order that classes were associated with the incoming packet.
|
|
For DHCPv4 private and code 43 options, this includes class local
|
|
option definitions.
|
|
</para></listitem>
|
|
</orderedlist>
|
|
</para>
|
|
|
|
<note>
|
|
<para>
|
|
Client classes in Kea follow the order
|
|
in which they are specified in the configuration
|
|
(vs. alphabetical order). Required classes
|
|
follow the order in which they are required.
|
|
</para>
|
|
</note>
|
|
|
|
<para>
|
|
When determining which options to include in the response, the
|
|
server examines the union of options from all of the
|
|
assigned classes. If two or more classes include the
|
|
same option, the value from the first class examined is
|
|
used; classes are examined in the order they were associated,
|
|
so ALL is always the first class and matching required classes
|
|
are last.
|
|
</para>
|
|
|
|
<para>
|
|
As an example, imagine that an incoming packet matches two
|
|
classes. Class "foo" defines values for an NTP server (option
|
|
42 in DHCPv4) and an SMTP server (option 69 in DHCPv4), while
|
|
class "bar" defines values for an NTP server and a POP3 server
|
|
(option 70 in DHCPv4). The server examines the three
|
|
options - NTP, SMTP, and POP3 - and returns any that the
|
|
client requested. As the NTP server was defined twice, the
|
|
server chooses only one of the values for the reply; the
|
|
class from which the value is obtained is unspecified.
|
|
</para>
|
|
|
|
<note>
|
|
<para>
|
|
Care should be taken with client classification as it is easy for
|
|
clients that do not meet any class criteria to be denied service altogether.
|
|
</para>
|
|
</note>
|
|
</section>
|
|
|
|
<section xml:id="classification-using-vendor">
|
|
<title>Builtin Client Classes</title>
|
|
<para>
|
|
Some classes are builtin, so they do not need to be defined. The main
|
|
example uses Vendor Class information: The server checks whether
|
|
an incoming DHCPv4 packet includes the vendor class identifier
|
|
option (60) or an incoming DHCPv6 packet includes the vendor
|
|
class option (16). If it does, the content of that option is
|
|
prepended with "VENDOR_CLASS_" and the result is
|
|
interpreted as a class. For example, modern cable modems
|
|
send this option with value "docsis3.0", so the
|
|
packet belongs to class "VENDOR_CLASS_docsis3.0".
|
|
</para>
|
|
|
|
<para>The "HA_" prefix is used by the High Availability
|
|
hooks library to designate certain servers to process DHCP packets
|
|
as a result of load balancing. The class name is constructed by
|
|
prepending the "HA_" prefix to the name of the server
|
|
which should process the DHCP packet. This server will use an appropriate
|
|
pool or subnet to allocate IP addresses (and/or prefixes), based on
|
|
the assigned client classes. The details can be found in
|
|
<xref linkend="high-availability-library"/>.</para>
|
|
|
|
<para>Other examples are: the ALL class, which all incoming packets
|
|
belong to, and the KNOWN class, assigned when host reservations exist
|
|
for a particular client. By convention, builtin classes' names
|
|
begin with all capital letters.
|
|
</para>
|
|
|
|
<para>Currently recognized builtin class names are ALL, KNOWN
|
|
and UNKNOWN, and prefixes VENDOR_CLASS_, HA_, AFTER_, and
|
|
EXTERNAL_. Although the AFTER_ prefix is a provision for an as-yet-unwritten
|
|
hook, the EXTERNAL_ prefix can be freely used; builtin
|
|
classes are implicitly defined so they never raise warnings if they
|
|
do not appear in the configuration.
|
|
</para>
|
|
|
|
</section>
|
|
|
|
<section xml:id="classification-using-expressions">
|
|
<title>Using Expressions in Classification</title>
|
|
<para>
|
|
The expression portion of a classification definition contains operators and
|
|
values. All values are currently strings; operators take a
|
|
string or strings and return another string. When all the
|
|
operations have completed, the result should be a value of
|
|
"true" or "false". The packet belongs to
|
|
the class (and the class name is added to the list of classes)
|
|
if the result is "true". Expressions are written in
|
|
standard format and can be nested.
|
|
</para>
|
|
|
|
<para>
|
|
Expressions are pre-processed during the parsing of the
|
|
configuration file and converted to an internal
|
|
representation. This allows certain types of errors to be caught
|
|
and logged during parsing. Examples of these errors include an
|
|
incorrect number or type of argument to an operator. The
|
|
evaluation code also checks for this class of error and
|
|
generally throws an exception, though this should not occur in a
|
|
normally functioning system.
|
|
</para>
|
|
|
|
<para>
|
|
Other issues, for example the starting position of a substring being
|
|
outside of the substring or an option not existing in the packet, result
|
|
in the operator returning an empty string.
|
|
</para>
|
|
|
|
<para>
|
|
Dependencies between classes are also checked. For instance,
|
|
forward dependencies are rejected when the configuration is
|
|
parsed; an expression can only depend on already-defined classes
|
|
(including builtin classes) which are evaluated in a
|
|
previous or the same evaluation phase. This does not apply to
|
|
the KNOWN or UNKNOWN classes.
|
|
</para>
|
|
|
|
<para>
|
|
<table frame="all" xml:id="classification-values-list">
|
|
<title>List of Classification Values</title>
|
|
<tgroup cols="3">
|
|
<colspec colname="name"/>
|
|
<colspec colname="example"/>
|
|
<colspec colname="description"/>
|
|
<thead>
|
|
<row>
|
|
<entry>Name</entry>
|
|
<entry>Example expression</entry>
|
|
<entry>Example value</entry>
|
|
<entry>Description</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry>String literal</entry>
|
|
<entry>'example'</entry>
|
|
<entry>'example'</entry>
|
|
<entry>A string</entry>
|
|
</row>
|
|
<row>
|
|
<entry>Hexadecimal string literal</entry>
|
|
<entry>0x5a7d</entry>
|
|
<entry>'Z}'</entry>
|
|
<entry>A hexadecimal string</entry>
|
|
</row>
|
|
<row>
|
|
<entry>IP address literal</entry>
|
|
<entry>10.0.0.1</entry>
|
|
<entry>0x0a000001</entry>
|
|
<entry>An IP address</entry>
|
|
</row>
|
|
<row>
|
|
<entry>Integer literal</entry>
|
|
<entry>123</entry>
|
|
<entry>'123'</entry>
|
|
<entry>A 32-bit unsigned integer value</entry>
|
|
</row>
|
|
<row/>
|
|
<row>
|
|
<entry>Binary content of the option</entry>
|
|
<entry>option[123].hex</entry>
|
|
<entry>'(content of the option)'</entry>
|
|
<entry>The value of the option with given code from the
|
|
packet as hex</entry>
|
|
</row>
|
|
<!-- Text option not fully defined yet, leave it out
|
|
<row>
|
|
<entry>Option Text</entry>
|
|
<entry>option[123].text</entry>
|
|
<entry>'foobar'</entry>
|
|
<entry>The value of the option with given code from the
|
|
packet as text</entry>
|
|
</row>
|
|
-->
|
|
<row>
|
|
<entry>Option existence</entry>
|
|
<entry>option[123].exists</entry>
|
|
<entry>'true'</entry>
|
|
<entry>If the option with given code is present in the
|
|
packet "true" else "false"</entry>
|
|
</row>
|
|
<row>
|
|
<entry>Client class membership</entry>
|
|
<entry>member('foobar')</entry>
|
|
<entry>'true'</entry>
|
|
<entry>If the packet belongs to the given client class
|
|
"true" else "false"</entry>
|
|
</row>
|
|
<row>
|
|
<entry>Known client</entry>
|
|
<entry>known</entry>
|
|
<entry>member('KNOWN')</entry>
|
|
<entry>If there is a host reservation for the client
|
|
"true" else "false"</entry>
|
|
</row>
|
|
<row>
|
|
<entry>Unknown client</entry>
|
|
<entry>unknown</entry>
|
|
<entry>not member('KNOWN')</entry>
|
|
<entry>If there is a host reservation for the client
|
|
"false" else "true"</entry>
|
|
</row>
|
|
<row>
|
|
<entry>DHCPv4 relay agent sub-option</entry>
|
|
<entry>relay4[123].hex</entry>
|
|
<entry>'(content of the RAI sub-option)'</entry>
|
|
<entry>The value of sub-option with given code from the
|
|
DHCPv4 Relay Agent Information option (option 82)</entry>
|
|
</row>
|
|
<row>
|
|
<entry>DHCPv6 Relay Options</entry>
|
|
<entry>relay6[nest].option[code].hex</entry>
|
|
<entry>(value of the option)</entry>
|
|
<entry>The value of the option with code "code" from the
|
|
relay encapsulation "nest"</entry>
|
|
</row>
|
|
<row>
|
|
<entry>DHCPv6 Relay Peer Address</entry>
|
|
<entry>relay6[nest].peeraddr</entry>
|
|
<entry>2001:DB8::1</entry>
|
|
<entry>The value of the peer address field from the
|
|
relay encapsulation "nest"</entry>
|
|
</row>
|
|
<row>
|
|
<entry>DHCPv6 Relay Link Address</entry>
|
|
<entry>relay6[nest].linkaddr</entry>
|
|
<entry>2001:DB8::1</entry>
|
|
<entry>The value of the link address field from the
|
|
relay encapsulation "nest"</entry>
|
|
</row>
|
|
<row>
|
|
<entry>Interface name of packet</entry>
|
|
<entry>pkt.iface</entry>
|
|
<entry>eth0</entry>
|
|
<entry>The name of the incoming interface of a DHCP packet.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>Source address of packet</entry>
|
|
<entry>pkt.src</entry>
|
|
<entry>10.1.2.3</entry>
|
|
<entry>The IP source address of a DHCP packet.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>Destination address of packet</entry>
|
|
<entry>pkt.dst</entry>
|
|
<entry>10.1.2.3</entry>
|
|
<entry>The IP destination address of a DHCP packet.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>Length of packet</entry>
|
|
<entry>pkt.len</entry>
|
|
<entry>513</entry>
|
|
<entry>The length of a DHCP packet (UDP header field), expressed
|
|
as a 32-bit unsigned integer.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>Hardware address in DHCPv4 packet</entry>
|
|
<entry>pkt4.mac</entry>
|
|
<entry>0x010203040506</entry>
|
|
<entry>The value of the chaddr field of the DHCPv4 packet, hlen (0 to 16) bytes</entry>
|
|
</row>
|
|
<row>
|
|
<entry>Hardware length in DHCPv4 packet</entry>
|
|
<entry>pkt4.hlen</entry>
|
|
<entry>6</entry>
|
|
<entry>The value of the hlen field of the DHCPv4 packet padded to 4 bytes</entry>
|
|
</row>
|
|
<row>
|
|
<entry>Hardware type in DHCPv4 packet</entry>
|
|
<entry>pkt4.htype</entry>
|
|
<entry>6</entry>
|
|
<entry>The value of the htype field of the DHCPv4 packet padded to 4 bytes</entry>
|
|
</row>
|
|
<row>
|
|
<entry>ciaddr field in DHCPv4 packet</entry>
|
|
<entry>pkt4.ciaddr</entry>
|
|
<entry>192.0.2.1</entry>
|
|
<entry>The value of the ciaddr field of the DHCPv4 packet (IPv4 address, 4 bytes)</entry>
|
|
</row>
|
|
<row>
|
|
<entry>giaddr field in DHCPv4 packet</entry>
|
|
<entry>pkt4.giaddr</entry>
|
|
<entry>192.0.2.1</entry>
|
|
<entry>The value of the giaddr field of the DHCPv4 packet (IPv4 address, 4 bytes)</entry>
|
|
</row>
|
|
<row>
|
|
<entry>yiaddr field in DHCPv4 packet</entry>
|
|
<entry>pkt4.yiaddr</entry>
|
|
<entry>192.0.2.1</entry>
|
|
<entry>The value of the yiaddr field of the DHCPv4 packet (IPv4 address, 4 bytes)</entry>
|
|
</row>
|
|
<row>
|
|
<entry>siaddr field in DHCPv4 packet</entry>
|
|
<entry>pkt4.siaddr</entry>
|
|
<entry>192.0.2.1</entry>
|
|
<entry>The value of the siaddr field of the DHCPv4 packet (IPv4 address, 4 bytes)</entry>
|
|
</row>
|
|
<row>
|
|
<entry>Message type in DHCPv4 packet</entry>
|
|
<entry>pkt4.msgtype</entry>
|
|
<entry>1</entry>
|
|
<entry>The value of the message type field in the DHCPv4
|
|
packet (expressed as a 32-bit unsigned integer).</entry>
|
|
</row>
|
|
<row>
|
|
<entry>Transaction ID (xid) in DHCPv4 packet</entry>
|
|
<entry>pkt4.transid</entry>
|
|
<entry>12345</entry>
|
|
<entry>The value of the transaction id in the DHCPv4
|
|
packet (expressed as a 32-bit unsigned integer).</entry>
|
|
</row>
|
|
<row>
|
|
<entry>Message type in DHCPv6 packet</entry>
|
|
<entry>pkt6.msgtype</entry>
|
|
<entry>1</entry>
|
|
<entry>The value of the message type field in the DHCPv6
|
|
packet (expressed as a 32-bit unsigned integer).</entry>
|
|
</row>
|
|
<row>
|
|
<entry>Transaction ID in DHCPv6 packet</entry>
|
|
<entry>pkt6.transid</entry>
|
|
<entry>12345</entry>
|
|
<entry>The value of the transaction id in the DHCPv6
|
|
packet (expressed as a 32-bit unsigned integer).</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry>Vendor option existence (any vendor)</entry>
|
|
<entry>vendor[*].exists</entry>
|
|
<entry>true</entry>
|
|
<entry>Returns whether a vendor option from any vendor
|
|
is present ('true') or absent ('false').</entry>
|
|
</row>
|
|
<row>
|
|
<entry>Vendor option existence (specific vendor)</entry>
|
|
<entry>vendor[4491].exists</entry>
|
|
<entry>true</entry>
|
|
<entry>Returns whether a vendor option from specified
|
|
vendor (determined by its enterprise-id)
|
|
is present ('true') or absent ('false').</entry>
|
|
</row>
|
|
<row>
|
|
<entry>Enterprise-id from vendor option</entry>
|
|
<entry>vendor.enterprise</entry>
|
|
<entry>4491</entry>
|
|
<entry>If the vendor option is present, it returns the
|
|
value of the enterprise-id field padded to 4
|
|
bytes. Returns "" otherwise.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>Vendor sub-option existence</entry>
|
|
<entry>vendor[4491].option[1].exists</entry>
|
|
<entry>true</entry>
|
|
<entry>Returns 'true' if there is vendor option with
|
|
specified enterprise-id and given sub-option is present.
|
|
Returns 'false' otherwise.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>Vendor sub-option content</entry>
|
|
<entry>vendor[4491].option[1].hex</entry>
|
|
<entry>docsis3.0</entry>
|
|
<entry>Returns content of the specified sub-option of
|
|
a vendor option with specified enterprise id. Returns
|
|
'' if no such option or sub-option is present.
|
|
</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry>Vendor class option existence (any vendor)</entry>
|
|
<entry>vendor-class[*].exists</entry>
|
|
<entry>true</entry>
|
|
<entry>Returns whether a vendor class option from any vendor
|
|
is present ('true') or absent ('false').</entry>
|
|
</row>
|
|
<row>
|
|
<entry>Vendor class option existence (specific vendor)</entry>
|
|
<entry>vendor-class[4491].exists</entry>
|
|
<entry>true</entry>
|
|
<entry>Returns whether a vendor class option from specified
|
|
vendor (determined by its enterprise-id)
|
|
is present ('true') or absent ('false').</entry>
|
|
</row>
|
|
<row>
|
|
<entry>Enterprise-id from vendor class option</entry>
|
|
<entry>vendor-class.enterprise</entry>
|
|
<entry>4491</entry>
|
|
<entry>If the vendor option is present, it returns the
|
|
value of the enterprise-id field padded to 4
|
|
bytes. Returns "" otherwise.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>First data chunk from vendor class option</entry>
|
|
<entry>vendor-class[4491].data</entry>
|
|
<entry>docsis3.0</entry>
|
|
<entry>Returns content of the first data chunk from
|
|
the vendor class option with specified enterprise-id.
|
|
Returns "" if missing.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>Specific data chunk from vendor class option</entry>
|
|
<entry>vendor-class[4491].data[3]</entry>
|
|
<entry>docsis3.0</entry>
|
|
<entry>Returns content of the specified data chunk of
|
|
a vendor class option with specified enterprise id. Returns
|
|
'' if no such option or data chunk is present.
|
|
</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
Notes:
|
|
</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem><para>
|
|
Hexadecimal strings are converted into a string as expected. The starting "0X" or
|
|
"0x" is removed, and if the string is an odd number of characters a
|
|
"0" is prepended to it.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
IP addresses are converted into strings of length 4 or 16. IPv4, IPv6,
|
|
and IPv4-embedded IPv6 (e.g., IPv4-mapped IPv6) addresses are supported.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
Integers in an expression are converted to 32-bit unsigned integers and
|
|
are represented as four-byte strings; for example, 123 is represented as
|
|
0x0000007b. All expressions that return numeric values use 32-bit
|
|
unsigned integers, even if the field in the packet is smaller. In general,
|
|
it is easier to use decimal notation to represent integers, but it is also
|
|
possible to use hexadecimal notation. When writing an integer in hexadecimal,
|
|
care should be taken to make sure the value is represented as 32
|
|
bits, e.g. use 0x00000001 instead of 0x1 or 0x01. Also, make
|
|
sure the value is specified in network order, e.g. 1 is
|
|
represented as 0x00000001.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
"option[code].hex" extracts the value of the option with the code "code"
|
|
from the incoming packet. If the packet doesn't contain the option, it
|
|
returns an empty string. The string is presented as a byte string of
|
|
the option payload, without the type code or length fields.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
"option[code].exists" checks whether an option with the code "code" is present
|
|
in the incoming packet. It can be used with empty options.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
"member('foobar')" checks whether the packet belongs to the client
|
|
class "foobar". To avoid dependency loops, the configuration file
|
|
parser verifies whether client classes were already defined or are
|
|
builtin, i.e., beginning by "VENDOR_CLASS_",
|
|
"AFTER__" (for the to come "after" hook) and
|
|
"EXTERNAL_" or equal to "ALL", "KNOWN",
|
|
"UNKNOWN"etc.
|
|
</para>
|
|
<para>"known" and "unknown" are short hands for "member('KNOWN')" and
|
|
"not member('KNOWN')". Note the evaluation of any expression using
|
|
directly or indirectly the "KNOWN" class is deferred
|
|
after the host reservation lookup (i.e. when the "KNOWN"
|
|
or "UNKNOWN" partition is determined).
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
"relay4[code].hex" attempts to extract the value of the sub-option
|
|
"code" from the option inserted as the DHCPv4 Relay Agent Information
|
|
(82) option. If the packet doesn't contain a RAI option, or the RAI
|
|
option doesn't contain the requested sub-option, the expression returns
|
|
an empty string. The string is presented as a byte string of the
|
|
option payload without the type code or length fields. This
|
|
expression is allowed in DHCPv4 only.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
"relay4" shares the same representation types as "option", for
|
|
instance "relay4[code].exists" is supported.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
"relay6[nest]" allows access to the encapsulations used by any DHCPv6
|
|
relays that forwarded the packet. The "nest" level specifies the relay
|
|
from which to extract the information, with a value of 0 indicating
|
|
the relay closest to the DHCPv6 server. Negative values allow to
|
|
specify relays counted from the DHCPv6 client, -1 indicating the
|
|
relay closest to the client. In general negative "nest" level is
|
|
the same as the number of relays + "nest" level.
|
|
If the requested encapsulation doesn't exist an empty string ""
|
|
is returned. This expression is allowed in DHCPv6 only.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
"relay6[nest].option[code]" shares the same representation types as
|
|
"option", for instance "relay6[nest].option[code].exists" is supported.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
Expressions starting with "pkt4" can be used only in DHCPv4.
|
|
They allows access to DHCPv4 message fields.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
"pkt6" refers to information from the client request. To access any
|
|
information from an intermediate relay use "relay6". "pkt6.msgtype"
|
|
and "pkt6.transid" output a 4 byte binary string for the message type
|
|
or transaction id. For example the message type SOLICIT will be
|
|
"0x00000001" or simply 1 as in "pkt6.msgtype == 1".
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
Vendor option means Vendor-Identifying Vendor-specific Information
|
|
option in DHCPv4 (code 125, see
|
|
<link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://tools.ietf.org/html/rfc3925#section-4">Section 4 of RFC 3925</link>) and
|
|
Vendor-specific Information Option in DHCPv6 (code 17, defined in
|
|
<link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="https://tools.ietf.org/html/rfc8415#section-21.17">Section 21.17 of
|
|
RFC 8415</link>). Vendor class option means Vendor-Identifying Vendor
|
|
Class Option in DHCPv4 (code 124, see
|
|
<link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://tools.ietf.org/html/rfc3925#section-3">Section 3 of RFC 3925</link>) in DHCPv4 and
|
|
Class Option in DHCPv6 (code 16, see
|
|
<link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="https://tools.ietf.org/html/rfc8415#section-21.16">Section 21.16 of RFC 8415</link>).
|
|
Vendor options may
|
|
have sub-options that are referenced by their codes. Vendor class
|
|
options do not have sub-options, but rather data chunks, which are
|
|
referenced by index value. Index 0 means the first data chunk, Index 1
|
|
is for the second data chunk (if present), etc.
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
In the vendor and vendor-class constructs Asterisk (*) or 0 can be
|
|
used to specify a wildcard enterprise-id value, i.e. it will match any
|
|
enterprise-id value.
|
|
</para></listitem>
|
|
|
|
<listitem><para>Vendor Class Identifier (option 60 in DHCPv4) can be
|
|
accessed using option[60] expression.</para></listitem>
|
|
|
|
<listitem><para>
|
|
<link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://tools.ietf.org/html/rfc3925">RFC 3925</link> and
|
|
<link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://tools.ietf.org/html/rfc8415">RFC 8415</link>
|
|
allow for multiple instances of vendor options
|
|
to appear in a single message. The client classification code currently
|
|
examines the first instance if more than one appear. For vendor.enterprise
|
|
and vendor-class.enterprise expressions, the value from the first instance
|
|
is returned. Please submit a feature request on Kea website if you need
|
|
support for multiple instances.
|
|
</para></listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
<table frame="all" xml:id="classification-expressions-list">
|
|
<title>List of Classification Expressions</title>
|
|
<tgroup cols="3">
|
|
<colspec colname="name"/>
|
|
<colspec colname="example"/>
|
|
<colspec colname="description"/>
|
|
<thead>
|
|
<row>
|
|
<entry>Name</entry>
|
|
<entry>Example</entry>
|
|
<entry>Description</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row><entry>Equal</entry> <entry>'foo' == 'bar'</entry><entry>Compare the two values and return "true" or "false"</entry></row>
|
|
<row><entry>Not</entry> <entry>not ('foo' == 'bar')</entry><entry>Logical negation</entry></row>
|
|
<row><entry>And</entry> <entry>('foo' == 'bar') and ('bar' == 'foo')</entry><entry>Logical and</entry></row>
|
|
<row><entry>Or</entry> <entry>('foo' == 'bar') or ('bar' == 'foo')</entry><entry>Logical or</entry></row>
|
|
<row><entry>Substring</entry><entry>substring('foobar',0,3)</entry><entry>Return the requested substring</entry></row>
|
|
<row><entry>Concat</entry><entry>concat('foo','bar')</entry><entry>Return the
|
|
concatenation of the strings</entry></row>
|
|
<row><entry>Ifelse</entry><entry>ifelse('foo' == 'bar','us','them')</entry><entry>Return the branch value according to the condition</entry></row>
|
|
<row><entry>Hexstring</entry><entry>hexstring('foo', '-')</entry><entry>Converts the value to a hexadecimal string, e.g. 0a:1b:2c:3e</entry></row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
</para>
|
|
|
|
<section>
|
|
<title>Logical operators</title>
|
|
The Not, And and Or logical operators are the common operators. Not
|
|
has the highest precedence and Or the lowest. And and Or are (left)
|
|
associative, parentheses around a logical expression can be used
|
|
to enforce a specific grouping, for instance in "A and (B or C)"
|
|
(without parentheses "A and B or C" means "(A and B) or C").
|
|
</section>
|
|
|
|
<section>
|
|
<title>Substring</title>
|
|
The substring operator "substring(value, start, length)" accepts both positive and
|
|
negative values for the starting position and the length. For "start", a value of
|
|
0 is the first byte in the string while -1 is the last byte. If the starting
|
|
point is outside of the original string an empty string is returned. "length"
|
|
is the number of bytes to extract. A negative number means to count towards
|
|
the beginning of the string but doesn't include the byte pointed to by "start".
|
|
The special value "all" means to return all bytes from start to the end of the
|
|
string. If length is longer than the remaining portion of the string then
|
|
the entire remaining portion is returned. Some examples may be helpful:
|
|
|
|
<screen>
|
|
substring('foobar', 0, 6) == 'foobar'
|
|
substring('foobar', 3, 3) == 'bar'
|
|
substring('foobar', 3, all) == 'bar'
|
|
substring('foobar', 1, 4) == 'ooba'
|
|
substring('foobar', -5, 4) == 'ooba'
|
|
substring('foobar', -1, -3) == 'oba'
|
|
substring('foobar', 4, -2) == 'ob'
|
|
substring('foobar', 10, 2) == ''
|
|
</screen>
|
|
</section>
|
|
<section>
|
|
<title>Concat</title>
|
|
The concat function "concat(string1, string2)" returns the
|
|
concatenation of its two arguments. For instance:
|
|
<screen>
|
|
concat('foo', 'bar') == 'foobar'
|
|
</screen>
|
|
</section>
|
|
<section>
|
|
<title>Ifelse</title>
|
|
The ifelse function "ifelse(cond, iftrue, ifelse)" returns the
|
|
"iftrue" or "ifelse" branch value following the boolean
|
|
condition "cond". For instance:
|
|
<screen>
|
|
ifelse(option[230].exists, option[230].hex, 'none')
|
|
</screen>
|
|
</section>
|
|
<section>
|
|
<title>Hexstring</title>
|
|
The hexstring function "hexstring(binary, separator)" returns
|
|
the binary value as its hexadecimal string representation:
|
|
pairs of hexadecimal digits separated by the separator, e.g
|
|
':', '-', '' (empty separator).
|
|
<screen>
|
|
hexstring(pkt4.mac, ':')
|
|
</screen>
|
|
</section>
|
|
</section>
|
|
|
|
<note>
|
|
<para>
|
|
The expression for each class is executed on each packet received.
|
|
If the expressions are overly complex, the time taken to execute
|
|
them may impact the performance of the server. If you need
|
|
complex or time consuming expressions you should write a <link linkend="hooks-libraries">hook</link> to perform the necessary work.
|
|
</para> </note>
|
|
|
|
<section xml:id="classification-configuring">
|
|
<title>Configuring Classes</title>
|
|
<para>
|
|
A class contains five items: a name, a test expression, option data,
|
|
option definition and only-if-required flag.
|
|
The name must exist and must be unique amongst all classes. The test
|
|
expression, option data and definition, and only-if-required flag are
|
|
optional.
|
|
</para>
|
|
|
|
<para>
|
|
The test expression is a string containing the logical expression used to
|
|
determine membership in the class. The entire expression is in double
|
|
quotes.
|
|
</para>
|
|
|
|
<para>
|
|
The option data is a list which defines any options that should be assigned
|
|
to members of this class.
|
|
</para>
|
|
|
|
<para>
|
|
The option definition is for DHCPv4 option 43 (<xref
|
|
linkend="dhcp4-vendor-opts"/> and DHCPv4 private options
|
|
(<xref linkend="dhcp4-private-opts"/>).
|
|
</para>
|
|
|
|
<para>
|
|
Usually the test expression is evaluated before subnet selection
|
|
but in some cases it is useful to evaluate it later when the
|
|
subnet, shared-network or pools are known but output option
|
|
processing not yet done. The only-if-required flag, false by default,
|
|
allows to perform the evaluation of the test expression only
|
|
when it was required, i.e. in a require-client-classes list of the
|
|
selected subnet, shared-network or pool.
|
|
</para>
|
|
|
|
<para>
|
|
The require-client-classes list which is valid for shared-network,
|
|
subnet and pool scope specifies the classes which are evaluated
|
|
in the second pass before output option processing.
|
|
The list is built in the reversed precedence order of option
|
|
data, i.e. an option data in a subnet takes precedence on one
|
|
in a shared-network but required class in a subnet is added
|
|
after one in a shared-network.
|
|
The mechanism is related to the only-if-required flag but it is
|
|
not mandatory that the flag was set to true.
|
|
</para>
|
|
|
|
<para>
|
|
In the following example the class named "Client_foo" is defined.
|
|
It is comprised of all clients whose client ids (option 61) start with the
|
|
string "foo". Members of this class will be given 192.0.2.1 and
|
|
192.0.2.2 as their domain name servers.
|
|
|
|
<screen>
|
|
"Dhcp4": {
|
|
"client-classes": [<userinput>
|
|
{
|
|
"name": "Client_foo",
|
|
"test": "substring(option[61].hex,0,3) == 'foo'",
|
|
"option-data": [
|
|
{
|
|
"name": "domain-name-servers",
|
|
"code": 6,
|
|
"space": "dhcp4",
|
|
"csv-format": true,
|
|
"data": "192.0.2.1, 192.0.2.2"
|
|
}
|
|
]
|
|
},
|
|
...
|
|
],</userinput>
|
|
...
|
|
}</screen>
|
|
</para>
|
|
|
|
<para>
|
|
This example shows a client class being defined for use by the DHCPv6 server.
|
|
In it the class named "Client_enterprise" is defined. It is comprised
|
|
of all clients who's client identifiers start with the given hex string (which
|
|
would indicate a DUID based on an enterprise id of 0xAABBCCDD). Members of this
|
|
class will be given an 2001:db8:0::1 and 2001:db8:2::1 as their domain name servers.
|
|
<screen>
|
|
"Dhcp6": {
|
|
"client-classes": [<userinput>
|
|
{
|
|
"name": "Client_enterprise",
|
|
"test": "substring(option[1].hex,0,6) == 0x0002AABBCCDD",
|
|
"option-data": [
|
|
{
|
|
"name": "dns-servers",
|
|
"code": 23,
|
|
"space": "dhcp6",
|
|
"csv-format": true,
|
|
"data": "2001:db8:0::1, 2001:db8:2::1"
|
|
}
|
|
]
|
|
},
|
|
...
|
|
],</userinput>
|
|
...
|
|
}</screen>
|
|
</para>
|
|
</section>
|
|
|
|
<section id="classification-using-host-reservations">
|
|
<title>Using Static Host Reservations In Classification</title>
|
|
<para>Classes can be statically assigned to the clients using techniques described
|
|
in <xref linkend="reservation4-client-classes"/> and
|
|
<xref linkend="reservation6-client-classes"/>.
|
|
</para>
|
|
</section>
|
|
|
|
<section xml:id="classification-subnets">
|
|
<title>Configuring Subnets With Class Information</title>
|
|
<para>
|
|
In certain cases it beneficial to restrict access to certain subnets
|
|
only to clients that belong to a given class, using the "client-class"
|
|
keyword when defining the subnet.
|
|
</para>
|
|
|
|
<para>
|
|
Let's assume that the server is connected to a network segment that uses
|
|
the 192.0.2.0/24 prefix. The Administrator of that network has decided
|
|
that addresses from range 192.0.2.10 to 192.0.2.20 are going to be
|
|
managed by the DHCP4 server. Only clients belonging to client class
|
|
Client_foo are allowed to use this subnet. Such a
|
|
configuration can be achieved in the following way:
|
|
<screen>
|
|
"Dhcp4": {
|
|
"client-classes": [
|
|
{
|
|
"name": "Client_foo",
|
|
"test": "substring(option[61].hex,0,3) == 'foo'",
|
|
"option-data": [
|
|
{
|
|
"name": "domain-name-servers",
|
|
"code": 6,
|
|
"space": "dhcp4",
|
|
"csv-format": true,
|
|
"data": "192.0.2.1, 192.0.2.2"
|
|
}
|
|
]
|
|
},
|
|
...
|
|
],<userinput>
|
|
"subnet4": [
|
|
{
|
|
"subnet": "192.0.2.0/24",
|
|
"pools": [ { "pool": "192.0.2.10 - 192.0.2.20" } ],
|
|
"client-class": "Client_foo"
|
|
},
|
|
...
|
|
],</userinput>,
|
|
...
|
|
}</screen>
|
|
</para>
|
|
|
|
<para>
|
|
The following example shows restricting access to a DHCPv6 subnet. This
|
|
configuration will restrict use of the addresses 2001:db8:1::1 to
|
|
2001:db8:1::FFFF to members of the "Client_enterprise" class.
|
|
|
|
<screen>
|
|
"Dhcp6": {
|
|
"client-classes": [
|
|
{
|
|
"name": "Client_enterprise",
|
|
"test": "substring(option[1].hex,0,6) == 0x0002AABBCCDD",
|
|
"option-data": [
|
|
{
|
|
"name": "dns-servers",
|
|
"code": 23,
|
|
"space": "dhcp6",
|
|
"csv-format": true,
|
|
"data": "2001:db8:0::1, 2001:db8:2::1"
|
|
}
|
|
]
|
|
},
|
|
...
|
|
], <userinput>
|
|
"subnet6": [
|
|
{
|
|
"subnet": "2001:db8:1::/64",
|
|
"pools": [ { "pool": "2001:db8:1::-2001:db8:1::ffff" } ],
|
|
"client-class": "Client_enterprise"
|
|
}
|
|
],</userinput>
|
|
...
|
|
}</screen>
|
|
</para>
|
|
</section>
|
|
|
|
<section id="classification-pools">
|
|
<title>Configuring Pools With Class Information</title>
|
|
<para>
|
|
Similar to subnets in certain cases access to certain address or
|
|
prefix pools must be restricted to only clients that belong to a
|
|
given class, using the "client-class" when defining the pool.
|
|
</para>
|
|
|
|
<para>
|
|
Let's assume that the server is connected to a network segment that uses
|
|
the 192.0.2.0/24 prefix. The Administrator of that network has decided
|
|
that addresses from range 192.0.2.10 to 192.0.2.20 are going to be
|
|
managed by the DHCP4 server. Only clients belonging to client class
|
|
Client_foo are allowed to use this pool. Such a
|
|
configuration can be achieved in the following way:
|
|
<screen>
|
|
"Dhcp4": {
|
|
"client-classes": [
|
|
{
|
|
"name": "Client_foo",
|
|
"test": "substring(option[61].hex,0,3) == 'foo'",
|
|
"option-data": [
|
|
{
|
|
"name": "domain-name-servers",
|
|
"code": 6,
|
|
"space": "dhcp4",
|
|
"csv-format": true,
|
|
"data": "192.0.2.1, 192.0.2.2"
|
|
}
|
|
]
|
|
},
|
|
...
|
|
],<userinput>
|
|
"subnet4": [
|
|
{
|
|
"subnet": "192.0.2.0/24",
|
|
"pools": [
|
|
{
|
|
"pool": "192.0.2.10 - 192.0.2.20",
|
|
"client-class": "Client_foo"
|
|
}
|
|
]
|
|
},
|
|
...
|
|
],</userinput>,
|
|
|
|
}</screen>
|
|
</para>
|
|
|
|
<para>
|
|
The following example shows restricting access to an address pool.
|
|
This configuration will restrict use of the addresses 2001:db8:1::1
|
|
to 2001:db8:1::FFFF to members of the "Client_enterprise" class.
|
|
<screen>
|
|
"Dhcp6": {
|
|
"client-classes": [
|
|
{
|
|
"name": "Client_enterprise_",
|
|
"test": "substring(option[1].hex,0,6) == 0x0002AABBCCDD",
|
|
"option-data": [
|
|
{
|
|
"name": "dns-servers",
|
|
"code": 23,
|
|
"space": "dhcp6",
|
|
"csv-format": true,
|
|
"data": "2001:db8:0::1, 2001:db8:2::1"
|
|
}
|
|
]
|
|
},
|
|
...
|
|
],
|
|
"subnet6": [
|
|
{
|
|
"subnet": "2001:db8:1::/64",
|
|
<userinput>
|
|
"pools": [
|
|
{
|
|
"pool": "2001:db8:1::-2001:db8:1::ffff",
|
|
"client-class": "Client_foo"
|
|
}
|
|
]</userinput>
|
|
},
|
|
...
|
|
],
|
|
...
|
|
}</screen>
|
|
</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Using Classes</title>
|
|
<para>
|
|
Currently classes can be used for two functions. They can supply options
|
|
to the members of the class and they can be used to choose a subnet from which an
|
|
address will be assigned to the class member.
|
|
</para>
|
|
|
|
<para>
|
|
When supplying options, options defined as part of the class definition
|
|
are considered "class globals". They will override any global options that
|
|
may be defined and in turn will be overridden by any options defined for an
|
|
individual subnet.
|
|
</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Classes and Hooks</title>
|
|
<para>
|
|
You may use a hook to classify your packets. This may be useful if the
|
|
expression would either be complex or time consuming and be easier or
|
|
better to write as code. Once the hook has added the proper class name
|
|
to the packet the rest of the classification system will work as normal
|
|
in choosing a subnet and selecting options. For a description of
|
|
hooks see <xref linkend="hooks-libraries"/>, for a description on
|
|
configuring classes see <xref linkend="classification-configuring"/>
|
|
and <xref linkend="classification-subnets"/>.
|
|
</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Debugging Expressions</title>
|
|
<para>
|
|
While you are constructing your classification expressions you may
|
|
find it useful to enable logging see <xref linkend="logging"/> for
|
|
a more complete description of the logging facility.
|
|
</para>
|
|
|
|
<para>
|
|
To enable the debug statements in the classification system you will
|
|
need to set the severity to "DEBUG" and the debug level to at least 55.
|
|
The specific loggers are "kea-dhcp4.eval" and "kea-dhcp6.eval".
|
|
</para>
|
|
|
|
<para>
|
|
In order to understand the logging statements, one must understand a
|
|
bit about how expressions are evaluated; for a more complete description
|
|
refer to the design document at <uri xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="https://gitlab.isc.org/isc-projects/kea/wikis/design%20documents">https://gitlab.isc.org/isc-projects/kea/wikis/design%20documents</uri>.
|
|
In brief there are two structures used during the evaluation of an expression:
|
|
a list of tokens which represent the expressions and a value stack which
|
|
represents the values being manipulated.
|
|
</para>
|
|
|
|
<para>
|
|
The list of tokens is created when the configuration file is processed with
|
|
most expressions and values being converted to a token. The list is organized
|
|
in reverse Polish notation. During execution, the list will be traversed
|
|
in order. As each token is executed it will be able to pop values
|
|
from the top of the stack and eventually push its result on the top of the
|
|
stack. Imagine the following expression:
|
|
<screen>
|
|
"test": "substring(option[61].hex,0,3) == 'foo'",
|
|
</screen>
|
|
This will result in the following tokens:
|
|
<screen>
|
|
option, number (0), number (3), substring, text ('foo'), equals
|
|
</screen>
|
|
In this example the first three tokens will simply push values onto the
|
|
stack. The substring token will then remove those three values and
|
|
compute a result that it places on the stack. The text option also
|
|
places a value on the stack and finally the equals token removes the
|
|
two tokens on the stack and places its result on the stack.
|
|
</para>
|
|
|
|
<para>
|
|
When debug logging is enabled, each time a token is evaluated it will
|
|
emit a log message indicating the values of any objects that were popped
|
|
off of the value stack and any objects that were pushed onto the value
|
|
stack.
|
|
</para>
|
|
|
|
<para>
|
|
The values will be displayed as either text if the command is known
|
|
to use text values or hexadecimal if the command either uses binary values or
|
|
can manipulate either text or binary values. For expressions that
|
|
pop multiple values off the stack, the values will be displayed in
|
|
the order they were popped. For most expressions this won't matter
|
|
but for the concat expression the values are displayed in reverse
|
|
order from how they are written in the expression.
|
|
</para>
|
|
|
|
<para>
|
|
Let us assume that the following test has been entered into the configuration.
|
|
This example skips most of the configuration to concentrate on the test.
|
|
<screen>
|
|
"test": "substring(option[61].hex,0,3) == 'foo'",
|
|
</screen>
|
|
The logging might then resemble this:
|
|
<screen>
|
|
2016-05-19 13:35:04.163 DEBUG [kea.eval/44478] EVAL_DEBUG_OPTION Pushing option 61 with value 0x666F6F626172
|
|
2016-05-19 13:35:04.164 DEBUG [kea.eval/44478] EVAL_DEBUG_STRING Pushing text string '0'
|
|
2016-05-19 13:35:04.165 DEBUG [kea.eval/44478] EVAL_DEBUG_STRING Pushing text string '3'
|
|
2016-05-19 13:35:04.166 DEBUG [kea.eval/44478] EVAL_DEBUG_SUBSTRING Popping length 3, start 0, string 0x666F6F626172 pushing result 0x666F6F
|
|
2016-05-19 13:35:04.167 DEBUG [kea.eval/44478] EVAL_DEBUG_STRING Pushing text string 'foo'
|
|
2016-05-19 13:35:04.168 DEBUG [kea.eval/44478] EVAL_DEBUG_EQUAL Popping 0x666F6F and 0x666F6F pushing result 'true'
|
|
</screen>
|
|
</para>
|
|
|
|
<note><para>
|
|
The debug logging may be quite verbose if you have a number of expressions
|
|
to evaluate. It is intended as an aid in helping you create and debug
|
|
your expressions. You should plan to disable debug logging when you have your
|
|
expressions working correctly. You also may wish to include only one set of
|
|
expressions at a time in the configuration file while debugging them in order
|
|
to limit the log statements. For example when adding a new set of expressions
|
|
you might find it more convenient to create a configuration file that only
|
|
includes the new expressions until you have them working correctly and then
|
|
add the new set to the main configuration file.
|
|
</para></note>
|
|
</section>
|
|
|
|
</chapter>
|