classify.xml 38.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
<!ENTITY mdash  "&#x2014;" >
]>

<chapter id="classify">
  <title>Client Classification</title>

  <section>
    <title>Client Classification Overview</title>
      <para>
      In certain cases it is useful to differentiate between different
14
      types of clients and treat them accordingly. Common reasons include:
15 16
      <itemizedlist>
      <listitem><para>
17 18
      The clients represent different pieces of topology, e.g. a cable
      modem is different to the clients behind that modem.
19 20
      </para></listitem>
      <listitem><para>
21
      The clients have different behavior, e.g. a smart phone behaves
22
      differently to a laptop.
23 24
      </para></listitem>
      <listitem><para>
25 26
      The clients require different values for some options, e.g. a docsis3.0
      cable modem requires different settings to docsis2.0 cable modem.
27 28 29 30 31 32
      </para></listitem>
      </itemizedlist>
      </para>

      <para>
      It is envisaged that client classification will be used for changing the
33 34
      behavior of almost any part of the DHCP message processing, including the assignment of
      leases from different pools, the assignment of different options (or different values of
35 36
      the same options) etc. In the current release of the software however, there are
      only three mechanisms that take
37 38
      advantage of client classification: subnet selection, assignment of different
      options and, for DHCPv4 cable modems, the setting of specific options for use with
39
      the TFTP server address and the boot file field.
40 41 42
      </para>

      <para>
43 44 45 46 47 48 49 50 51 52 53 54
      The process of doing classification is conducted in three steps:
      <orderedlist>
      <listitem><para>
      Assess an incoming packet and assign it to zero or more classes.
      </para></listitem>
      <listitem><para>
      Choose a subnet, possibly based on the class information.
      </para></listitem>
      <listitem><para>
      Assign options, again possibly based on the class information.
      </para></listitem>
      </orderedlist>
55 56 57
      </para>

      <para>
58 59 60
      When determining which options to include in the response the server will examine
      the union of options from all of the assigned classes. In the case two or more
      classes include the same option, the value from the first class examined will
61
      be used.  When choosing a subnet, the server will iterate over all of the
62 63 64 65
      subnets that are feasible given the information found in the packet (client address,
      relay address etc). It will use the first subnet it finds that either doesn't
      have a class associated with it or that has a class which matches one of
      the packet's classes. In the future the processing order of the
66 67
      various classes may be specified but for now it is being left unspecified and
      may change in future releases.
68 69
      </para>

70
      <para>
71 72
      As an example, imagine that an incoming packet matches two classes.
      Class "foo" defines values for an NTP server
73 74 75 76
      (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 will examine the three options NTP, SMTP and POP3 and return any
      of them that the client requested.  As the NTP server was defined twice the
77 78
      server will choose only one of the values for the reply: the class from which the
      value is obtained is unspecified.
79 80
      </para>

81 82 83 84 85
      <para>
      There are two methods of doing classification. The first is automatic and relies
      on examining the values in the vendor class options. Information from these
      options is extracted and a class name is constructed from it and added to
      the class list for the packet. The second allows you to specify an expression
86
      that is evaluated for each packet. If the result is true, the packet is
87 88 89 90 91 92 93 94 95 96 97
      a member of the class.
      </para>

      <note>
      <para>
        Care should be taken with client classification as it is easy for
        clients that do not meet class criteria to be denied any service altogether.
      </para>
      </note>
  </section>

98 99 100 101 102 103 104 105
  <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>

106 107 108 109 110 111
  <section id="classification-using-vendor">
    <title>Using Vendor Class Information In Classification</title>
      <para>
      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
112
      option is prepended with &quot;VENDOR_CLASS_&quot; and the result is interpreted
113
      as a class. For example, modern cable modems will send this option with
114
      value &quot;docsis3.0&quot; and so the packet will belong to
115 116 117 118 119 120 121 122
      class &quot;VENDOR_CLASS_docsis3.0&quot;.
      </para>
  </section>

  <section id="classification-using-expressions">
    <title>Using Expressions In Classification</title>
      <para>
      The expression portion of classification contains operators and values.
123
      All values are currently strings and operators take a string or strings and
124 125 126 127 128 129 130 131 132 133
      return another string. When all the operations have completed
      the result should be a value of &quot;true&quot; or &quot;false&quot;.
      The packet belongs to
      the class (and the class name is added to the list of classes) if the result
      is &quot;true&quot;. 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
134
      errors to be caught and logged during parsing.  Examples of these errors
135
      include an incorrect number or types of arguments to an operator.  The
136
      evaluation code will also check for this class of error and generally
137
      throw an exception, though this should not occur in a normally functioning
138 139 140 141 142 143 144
      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.
145 146 147
      </para>

      <para>
148
      Expressions are a work in progress and the supported operators and
149
      values are limited. The expectation is that additional operators and values
150
      will be added over time, however the basic mechanisms will
151 152 153 154 155 156 157 158 159 160 161 162 163
      remain the same.
      </para>

      <para>
        <table frame="all" 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>
Francis Dupont's avatar
Francis Dupont committed
164 165
              <entry>Example expression</entry>
              <entry>Example value</entry>
166 167 168
              <entry>Description</entry>
            </row>
          </thead>
Francis Dupont's avatar
Francis Dupont committed
169

170
          <tbody>
Francis Dupont's avatar
Francis Dupont committed
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
            <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>
193
              <entry>A 32 bit unsigned integer value</entry>
Francis Dupont's avatar
Francis Dupont committed
194
            </row>
Francis Dupont's avatar
Francis Dupont committed
195
            <row></row>
Francis Dupont's avatar
Francis Dupont committed
196 197 198 199 200 201 202
            <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>
203
<!-- Text option not fully defined yet, leave it out
Francis Dupont's avatar
Francis Dupont committed
204 205 206 207 208 209 210
            <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>
211
-->
Francis Dupont's avatar
Francis Dupont committed
212 213
            <row>
              <entry>Option existence</entry>
214
              <entry>option[123].exists</entry>
Francis Dupont's avatar
Francis Dupont committed
215 216 217 218 219 220 221 222 223 224 225
              <entry>'true'</entry>
              <entry>If the option with given code is present in the
              packet "true" else "false"</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>
226 227 228
            <row>
              <entry>DHCPv6 Relay Options</entry>
              <entry>relay6[nest].option[code].hex</entry>
229
              <entry>(value of the option)</entry>
230 231 232 233 234 235
              <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>
236
              <entry>2001:DB8::1</entry>
237 238 239 240 241 242
              <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>
243
              <entry>2001:DB8::1</entry>
244 245 246
              <entry>The value of the link address field from the
              relay encapsulation "nest"</entry>
            </row>
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
            <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>
268
              <entry>513</entry>
Tomek Mrugalski's avatar
Tomek Mrugalski committed
269
              <entry>The length of a DHCP packet (UDP header field), expressed
270
              as a 32 bit unsigned integer.</entry>
271
            </row>
Francis Dupont's avatar
Francis Dupont committed
272 273 274 275
            <row>
              <entry>Hardware address in DHCPv4 packet</entry>
              <entry>pkt4.mac</entry>
              <entry>0x010203040506</entry>
276
              <entry>The value of the chaddr field of the DHCPv4 packet, hlen (0 to 16) bytes</entry>
Francis Dupont's avatar
Francis Dupont committed
277 278 279 280
            </row>
            <row>
              <entry>Hardware length in DHCPv4 packet</entry>
              <entry>pkt4.hlen</entry>
281
              <entry>6</entry>
Francis Dupont's avatar
Francis Dupont committed
282
              <entry>The value of the hlen field of the DHCPv4 packet padded to 4 bytes</entry>
Francis Dupont's avatar
Francis Dupont committed
283 284 285 286
            </row>
            <row>
              <entry>Hardware type in DHCPv4 packet</entry>
              <entry>pkt4.htype</entry>
287
              <entry>6</entry>
Francis Dupont's avatar
Francis Dupont committed
288
              <entry>The value of the htype field of the DHCPv4 packet padded to 4 bytes</entry>
Francis Dupont's avatar
Francis Dupont committed
289 290 291 292 293
            </row>
            <row>
              <entry>ciaddr field in DHCPv4 packet</entry>
              <entry>pkt4.ciaddr</entry>
              <entry>192.0.2.1</entry>
294
              <entry>The value of the ciaddr field of the DHCPv4 packet (IPv4 address, 4 bytes)</entry>
Francis Dupont's avatar
Francis Dupont committed
295 296 297 298 299
            </row>
            <row>
              <entry>giaddr field in DHCPv4 packet</entry>
              <entry>pkt4.giaddr</entry>
              <entry>192.0.2.1</entry>
300
              <entry>The value of the giaddr field of the DHCPv4 packet (IPv4 address, 4 bytes)</entry>
Francis Dupont's avatar
Francis Dupont committed
301 302 303 304 305
            </row>
            <row>
              <entry>yiaddr field in DHCPv4 packet</entry>
              <entry>pkt4.yiaddr</entry>
              <entry>192.0.2.1</entry>
306
              <entry>The value of the yiaddr field of the DHCPv4 packet (IPv4 address, 4 bytes)</entry>
Francis Dupont's avatar
Francis Dupont committed
307 308 309 310 311
            </row>
            <row>
              <entry>siaddr field in DHCPv4 packet</entry>
              <entry>pkt4.siaddr</entry>
              <entry>192.0.2.1</entry>
312
              <entry>The value of the siaddr field of the DHCPv4 packet (IPv4 address, 4 bytes)</entry>
Francis Dupont's avatar
Francis Dupont committed
313
            </row>
Tomek Mrugalski's avatar
Tomek Mrugalski committed
314 315 316 317 318
            <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
319
              packet (expressed as a 32 bit unsigned integer).</entry>
Tomek Mrugalski's avatar
Tomek Mrugalski committed
320 321 322 323 324 325
            </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
326
              packet (expressed as a 32 bit unsigned integer).</entry>
Tomek Mrugalski's avatar
Tomek Mrugalski committed
327
            </row>
328 329 330
            <row>
              <entry>Message Type in DHCPv6 packet</entry>
              <entry>pkt6.msgtype</entry>
331
              <entry>1</entry>
332
              <entry>The value of the message type field in the DHCPv6
333
              packet (expressed as a 32 bit unsigned integer).</entry>
334 335 336 337
            </row>
            <row>
              <entry>Transaction ID in DHCPv6 packet</entry>
              <entry>pkt6.transid</entry>
338
              <entry>12345</entry>
339
              <entry>The value of the transaction id in the DHCPv6
340
              packet (expressed as a 32 bit unsigned integer).</entry>
341
            </row>
Tomek Mrugalski's avatar
Tomek Mrugalski committed
342 343 344

            <row>
              <entry>Vendor option existence (any vendor)</entry>
345
              <entry>vendor[*].exists</entry>
Tomek Mrugalski's avatar
Tomek Mrugalski committed
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
              <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>
361
              <entry>4491</entry>
Tomek Mrugalski's avatar
Tomek Mrugalski committed
362 363
              <entry>If the vendor option is present, it returns the
              value of the enterprise-id field padded to 4
364
              bytes. Returns "" otherwise.</entry>
Tomek Mrugalski's avatar
Tomek Mrugalski committed
365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
            </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>
386
              <entry>vendor-class[*].exists</entry>
Tomek Mrugalski's avatar
Tomek Mrugalski committed
387 388 389 390 391 392 393 394 395 396 397 398 399 400 401
              <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>
402
              <entry>4491</entry>
Tomek Mrugalski's avatar
Tomek Mrugalski committed
403 404
              <entry>If the vendor option is present, it returns the
              value of the enterprise-id field padded to 4
405
              bytes. Returns "" otherwise.</entry>
Tomek Mrugalski's avatar
Tomek Mrugalski committed
406 407 408 409
            </row>
            <row>
              <entry>First data chunk from vendor class option</entry>
              <entry>vendor-class[4491].data</entry>
410
              <entry>docsis3.0</entry>
Tomek Mrugalski's avatar
Tomek Mrugalski committed
411 412
              <entry>Returns content of the first data chunk from
              the vendor class option with specified enterprise-id.
413
              Returns "" if missing.</entry>
Tomek Mrugalski's avatar
Tomek Mrugalski committed
414 415 416 417 418 419 420 421 422 423
            </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>
424 425 426
          </tbody>
          </tgroup>
        </table>
427 428 429 430 431 432 433
        Notes:
      </para>

      <itemizedlist>

      <listitem><para>
      Hexadecimal strings are converted into a string as expected.  The starting &quot;0X&quot; or
434 435
      &quot;0x&quot; is removed and if the string is an odd number of characters a
      &quot;0&quot; is prepended to it.
436
      </para></listitem>
437

438
      <listitem><para>
Francis Dupont's avatar
Francis Dupont committed
439
      IP addresses are converted into strings of length 4 or 16. IPv4, IPv6,
440
      and IPv4 embedded IPv6 (e.g., IPv4 mapped IPv6) addresses are supported.
441
      </para></listitem>
Francis Dupont's avatar
Francis Dupont committed
442

443
      <listitem><para>
444
      Integers in an expression are converted to 32 bit unsigned integers and
445 446
      are represented as four-byte strings. For example 123 is represented as
      0x0000007b. All expressions that return numeric values use 32-bit
Tomek Mrugalski's avatar
Tomek Mrugalski committed
447 448 449 450
      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 hex notation. When using hex notation to represent an
      integer care should be taken to make sure the value is represented as 32
451 452 453
      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.
454
      </para></listitem>
455

456
      <listitem><para>
Francis Dupont's avatar
Francis Dupont committed
457
      "option[code].hex" extracts the value of the option with the code "code"
458
      from the incoming packet. If the packet doesn't contain the option, it
459 460
      returns the empty string. The string is presented as a byte string of
      the option payload without the type code or length fields.
461
      </para></listitem>
462

463
      <listitem><para>
464
      "option[code].exists" checks if an option with the code "code" is present
Francis Dupont's avatar
Francis Dupont committed
465
      in the incoming packet. It can be used with empty options.
466
      </para></listitem>
Francis Dupont's avatar
Francis Dupont committed
467

468 469 470 471 472 473 474 475 476
      <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>
477

478 479 480 481
      <listitem><para>
      "relay4" shares the same representation types as "option", for
      instance "relay4[code].exists" is supported.
      </para></listitem>
482

483 484 485 486
      <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
Francis Dupont's avatar
Francis Dupont committed
487 488
      the relay closest to the DHCPv6 server. Negative values allow to
      specify relays counted from the DHCPv6 client, -1 indicating the
489 490
      relay closest to the client. In general negative "nest" level is
      the same as the number of relays + "nest" level.
Francis Dupont's avatar
Francis Dupont committed
491 492
      If the requested encapsulation doesn't exist an empty string ""
      is returned.  This expression is allowed in DHCPv6 only.
493
      </para></listitem>
494

495 496 497 498
      <listitem><para>
      "relay6[nest].option[code]" shares the same representation types as
      "option", for instance "relay6[nest].option[code].exists" is supported.
      </para></listitem>
499

500 501 502 503
      <listitem><para>
       Expressions starting with "pkt4" can be used only in DHCPv4.
       They allows access to DHCPv4 message fields.
      </para></listitem>
Francis Dupont's avatar
Francis Dupont committed
504

505 506 507 508 509 510 511
      <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>
512

513 514
      <listitem><para>
      Vendor option means Vendor-Identifying Vendor-specific Information
515 516 517
      option in DHCPv4 (code 125, see
      <ulink url="http://tools.ietf.org/html/rfc3925#section-4">Section 4 of RFC 3925</ulink>) and
      Vendor-specific Information Option in DHCPv6 (code 17, defined in
518
      <ulink url="https://tools.ietf.org/html/rfc3315#section-22.17">Section 22.17 of
519 520
      RFC 3315</ulink>). Vendor class option means Vendor-Identifying Vendor
      Class Option in DHCPv4 (code 124, see
521
      <ulink url="http://tools.ietf.org/html/rfc3925#section-3">Section 3 of RFC 3925</ulink>) in DHCPv4 and
522
      Class Option in DHCPv6 (code 16, see
523 524 525 526 527 528 529
      <ulink url="https://tools.ietf.org/html/rfc3315#section-22.16">Section 22.16 of RFC 3315</ulink>).
      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>
Tomek Mrugalski's avatar
Tomek Mrugalski committed
530

531 532
      <listitem><para>
      In the vendor and vendor-class constructs Asterisk (*) or 0 can be
Tomek Mrugalski's avatar
Tomek Mrugalski committed
533
      used to specify a wildcard enterprise-id value, i.e. it will match any
534 535
      enterprise-id value.
      </para></listitem>
Tomek Mrugalski's avatar
Tomek Mrugalski committed
536

537 538
      <listitem><para>Vendor Class Identifier (option 60 in DHCPv4) can be
      accessed using option[60] expression.</para></listitem>
Tomek Mrugalski's avatar
Tomek Mrugalski committed
539

540 541 542 543
      <listitem><para>
      <ulink url="http://tools.ietf.org/html/rfc3925">RFC3925</ulink> and
      <ulink url="http://tools.ietf.org/html/rfc3315">RFC3315</ulink>
      allow for multiple instances of vendor options
Tomek Mrugalski's avatar
Tomek Mrugalski committed
544 545 546 547
      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
548 549 550 551
      support for multiple instances.
      </para></listitem>

      </itemizedlist>
Tomek Mrugalski's avatar
Tomek Mrugalski committed
552

553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568
      <para>
        <table frame="all" 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>
Francis Dupont's avatar
Francis Dupont committed
569 570 571
<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>
572
<row><entry>Substring</entry><entry>substring('foobar',0,3)</entry><entry>Return the requested substring</entry></row>
Tomek Mrugalski's avatar
Tomek Mrugalski committed
573 574
<row><entry>Concat</entry><entry>concat('foo','bar')</entry><entry>Return the
concatenation of the strings</entry></row>
575 576 577
          </tbody>
          </tgroup>
        </table>
578 579
      </para>

Francis Dupont's avatar
Francis Dupont committed
580 581 582
      <section>
        <title>Logical operators</title>
        The Not, And and Or logical operators are the common operators. Not
583
        has the highest precedence and Or the lowest. And and Or are (left)
Francis Dupont's avatar
Francis Dupont committed
584 585
        associative, parentheses around a logical expression can be used
        to enforce a specific grouping, for instance in "A and (B or C)"
586
        (without parentheses "A and B or C" means "(A and B) or C").
Francis Dupont's avatar
Francis Dupont committed
587 588
      </section>

589 590 591 592 593 594 595 596 597 598 599
      <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:
600

601
          <screen>
602 603 604 605 606
        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'
607 608
        substring('foobar', -1, -3) == 'oba'
        substring('foobar', 4, -2) == 'ob'
609
        substring('foobar', 10, 2) == ''
610 611
          </screen>
      </section>
612 613 614 615 616 617 618 619
      <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>
620
    </section>
621

622 623 624 625 626 627 628 629 630
  <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>

631 632 633 634 635 636 637
  <section id="classification-configuring">
    <title>Configuring Classes</title>
      <para>
      A class contains three items: a name, a test expression and option data.
      The name must exist and must be unique amongst all classes. The test
      expression and option data are optional.
      </para>
638

639 640 641 642 643 644 645 646 647 648 649 650
      <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>
651
      In the following example the class named &quot;Client_foo&quot; is defined.
652
      It is comprised of all clients whose client ids (option 61) start with the
653 654 655
      string &quot;foo&quot;. Members of this class will be given 192.0.2.1 and
      192.0.2.2 as their domain name servers.

656 657
        <screen>
"Dhcp4": {
658
    "client-classes": [<userinput>
659 660
        {
            "name": "Client_foo",
661
            "test": "substring(option[61].hex,0,3) == 'foo'",
662 663
            "option-data": [
                {
664
                    "name": "domain-name-servers",
665 666 667 668 669 670
                    "code": 6,
                    "space": "dhcp4",
                    "csv-format": true,
                    "data": "192.0.2.1, 192.0.2.2"
                }
            ]
671 672 673
        },
        ...
    ],</userinput>
674 675 676 677 678
    ...
}</screen>
      </para>

      <para>
679 680 681 682 683 684 685 686 687 688
      This example shows a client class being defined for use by the DHCPv6 server.
      In it the class named &quot;Client_enterprise&quot; 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",
689
            "test": "substring(option[1].hex,0,6) == 0x0002AABBCCDD'",
690 691 692 693 694 695 696 697 698 699 700 701 702 703
            "option-data": [
                {
                    "name": "dns-servers",
                    "code": 23,
                    "space": "dhcp6",
                    "csv-format": true,
                    "data": "2001:db8:0::1, 2001:db8:2::1"
                }
            ]
        },
        ...
    ],</userinput>
    ...
}</screen>
704 705 706 707 708 709 710
      </para>
  </section>

  <section id="classification-subnets">
    <title>Configuring Subnets With Class Information</title>
      <para>
        In certain cases it beneficial to restrict access to certain subnets
711
        only to clients that belong to a given class, using the "client-class"
712 713 714 715
        keyword when defining the subnet.
      </para>

      <para>
716 717 718 719
        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
720
        Client_foo  are allowed to use this subnet. Such a
721 722 723
        configuration can be achieved in the following way:
        <screen>
"Dhcp4": {
724
    "client-classes": [
725 726
        {
            "name": "Client_foo",
727
            "test": "substring(option[61].hex,0,3) == 'foo'",
728 729
            "option-data": [
                {
730
                    "name": "domain-name-servers",
731 732 733 734 735 736
                    "code": 6,
                    "space": "dhcp4",
                    "csv-format": true,
                    "data": "192.0.2.1, 192.0.2.2"
                }
            ]
737 738 739 740 741 742 743 744
        },
        ...
    ],<userinput>
    "subnet4": [
        {
            "subnet": "192.0.2.0/24",
            "pools": [ { "pool": "192.0.2.10 - 192.0.2.20" } ],
            "client-class": "Client_foo"
745 746 747 748 749 750 751 752
        },
        ...
    ],</userinput>,
    ...
}</screen>
      </para>

      <para>
Francis Dupont's avatar
Francis Dupont committed
753
        The following example shows restricting access to a DHCPv6 subnet.  This
754 755 756 757 758 759 760 761
        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",
762
            "test": "substring(option[1].hex,0,6) == 0x0002AABBCCDD'",
763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779
            "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"
780
        }
781
    ],</userinput>
782 783 784 785 786 787 788 789 790
    ...
}</screen>
      </para>
  </section>

  <section>
    <title>Using Classes</title>
      <para>
      Currently classes can be used for two functions.  They can supply options
791 792
      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.
793 794 795
      </para>

      <para>
796 797
      When supplying options, options defined as part of the class definition
      are considered &quot;class globals&quot;.  They will override any global options that
798 799 800 801 802 803 804 805 806 807 808 809
      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
810
      in choosing a subnet and selecting options.  For a description of
811
      hooks see <xref linkend="hooks-libraries"/>, for a description on
812
      configuring classes see <xref linkend="classification-configuring"/>
813
      and <xref linkend="classification-subnets"/>.
814 815 816
      </para>
  </section>

817 818 819 820 821 822 823 824 825
  <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>
Francis Dupont's avatar
Francis Dupont committed
826
     To enable the debug statements in the classification system you will
827 828 829 830
     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>

831 832 833 834
     <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 <ulink url="http://kea.isc.org/wiki/KeaDesigns"/>.
Thomas Markwalder's avatar
Thomas Markwalder committed
835
     In brief there are two structures used during the evaluation of an expression:
836 837 838 839 840 841 842
     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
843
     in reverse Polish notation.  During execution, the list will be traversed
844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860
     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>

861
     <para>
862 863
     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
864 865 866 867 868 869
     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
870
     to use text values or hexadecimal if the command either uses binary values or
871
     can manipulate either text or binary values.  For expressions that
872
     pop multiple values off the stack, the values will be displayed in
873 874 875 876 877 878 879 880 881 882 883 884 885 886
     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
887 888
       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'
889
       2016-05-19 13:35:04.166 DEBUG [kea.eval/44478] EVAL_DEBUG_SUBSTRING Popping length 3, start 0, string 0x666F6F626172 pushing result 0x666F6F
890 891
       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'
892 893 894 895 896
       </screen>
     </para>

     <note><para>
     The debug logging may be quite verbose if you have a number of expressions
897
     to evaluate.  It is intended as an aid in helping you create and debug
898
     your expressions.  You should plan to disable debug logging when you have your
899 900 901 902 903 904
     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.
905 906 907
     </para></note>
  </section>

908
</chapter>