classify.xml 34 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
62
63
64
65
      be used.  When choosing a subnet the server will iterate over all of the
      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
      As an example, imagine two classes.  Class "foo" defines values for an NTP server
72
73
74
75
      (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
76
77
      server will choose only one of the values for the reply: the class from which the
      value is obtained is unspecified.
78
79
      </para>

80
81
82
83
84
      <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
85
      that is evaluated for each packet. If the result is true, the packet is
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
      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>

  <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
103
      option is prepended with &quot;VENDOR_CLASS_&quot; and the result is interpreted
104
      as a class. For example, modern cable modems will send this option with
105
      value &quot;docsis3.0&quot; and so the packet will belong to
106
107
108
109
110
111
112
113
      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.
114
      All values are currently strings and operators take a string or strings and
115
116
117
118
119
120
121
122
123
124
      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
125
126
127
128
129
130
131
132
133
134
135
      errors to be caught and logged during parsing.  Examples of these errors
      include incorrect number or types of arguments to an operator.  The
      evaluation code will also check for this class of error and generally
      throw an exception, though they 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.
136
137
138
      </para>

      <para>
139
      Expressions are a work in progress and the supported operators and
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
      values are limited. The expectation is that additional operators and values
      will be added over time, however it is expected the basic mechanisms will
      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
155
156
              <entry>Example expression</entry>
              <entry>Example value</entry>
157
158
159
              <entry>Description</entry>
            </row>
          </thead>
Francis Dupont's avatar
Francis Dupont committed
160

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

            <row>
              <entry>Vendor option existence (any vendor)</entry>
              <entry>vendor[*].exist</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>0x0000118b</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[*].exist</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>0x0000118b</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>true</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>
376
377
378
379
380
381
382
383
          </tbody>
          </tgroup>
        </table>
      Hex Strings are converted into a string as expected.  The starting &quot;0X&quot; or
      &quot;0x&quot; is removed and if the string is an odd number of characters a
      &quot;0&quot; is prepended to it.
      </para>

Francis Dupont's avatar
Francis Dupont committed
384
      <para>
Francis Dupont's avatar
Francis Dupont committed
385
      IP addresses are converted into strings of length 4 or 16. IPv4, IPv6,
386
      and IPv4 embedded IPv6 (e.g., IPv4 mapped IPv6) addresses are supported.
Francis Dupont's avatar
Francis Dupont committed
387
388
      </para>

389
      <para>
390
391
392
393
394
      Integers in the expression are converted to strings
      when the expression is read into Kea.
      </para>

      <para>
Francis Dupont's avatar
Francis Dupont committed
395
      "option[code].hex" extracts the value of the option with the code "code"
396
      from the incoming packet. If the packet doesn't contain the option, it
397
398
      returns the empty string. The string is presented as a byte string of
      the option payload without the type code or length fields.
399
400
      </para>

Francis Dupont's avatar
Francis Dupont committed
401
      <para>
Francis Dupont's avatar
Francis Dupont committed
402
      "option[code].exist" checks if an option with the code "code" is present
Francis Dupont's avatar
Francis Dupont committed
403
404
405
      in the incoming packet. It can be used with empty options.
      </para>

406
      <para>
407
408
        "relay4[code].hex" attempts to extract the value of the sub-option
        "code" from the option inserted as the DHCPv4 Relay Agent Information
409
410
411
        (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
412
413
414
415
        option payload without the type code or length fields. This
        expression is allowed in DHCPv4 only.
      </para>

416
      <para>
417
       "relay4" shares the same representation types as "option", for
418
       instance "relay4[code].exists" is supported.
419
420
      </para>

421
422
423
424
425
426
427
428
429
430
431
432
433
434
      <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.  If the requested encapsulation
       doesn't exist an empty string "" is returned.  This expression is
       allowed in DHCPv6 only.
      </para>

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

Francis Dupont's avatar
Francis Dupont committed
435
436
437
438
      <para>
        Expressions starting with pkt4 can be used only in DHCPv4.
      </para>

439
440
441
      <para>
       "pkt6" refers to information from the client request.  To access any
       information from an intermediate relay use "relay6".  "pkt6.msgtype"
442
443
444
       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".
445
446
      </para>

Tomek Mrugalski's avatar
Tomek Mrugalski committed
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
      <para>
        Vendor option means Vendor-Identifying Vendor-specific Information
        option (code 125, see Section 4 of RFC3925) in DHCPv4 and
        Vendor-specific Information Option (code 17, defined in Section 22.17 of
        RFC3315) in DHCPv6. Vendor class option means Vendor-Identifying Vendor
        Class Option (code 124, see Section 3 of RFC3925) in DHCPv4 and Vendor
        Class Option (code 16, see Section 22.16 of RFC3315). 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>

      <para>Asterisk (*) or 0 can be used to specify wildcard enterprise-id
      value, i.e. it will match any enterprise-id value.</para>

Tomek Mrugalski's avatar
Tomek Mrugalski committed
463
464
465
      <para>Vendor Class Identifier (option 60 in DHCPv4) can be
      accessed using option[60] expression.</para>

466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
      <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
482
483
484
<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>
485
<row><entry>Substring</entry><entry>substring('foobar',0,3)</entry><entry>Return the requested substring</entry></row>
Tomek Mrugalski's avatar
Tomek Mrugalski committed
486
487
<row><entry>Concat</entry><entry>concat('foo','bar')</entry><entry>Return the
concatenation of the strings</entry></row>
488
489
490
          </tbody>
          </tgroup>
        </table>
491
492
      </para>

Francis Dupont's avatar
Francis Dupont committed
493
494
495
496
497
498
      <section>
        <title>Logical operators</title>
        The Not, And and Or logical operators are the common operators. Not
        has the highest precedence, 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)"
499
        (without parentheses "A and B or C" means "(A and B) or C").
Francis Dupont's avatar
Francis Dupont committed
500
501
      </section>

502
503
504
505
506
507
508
509
510
511
512
      <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:
513

514
          <screen>
515
516
517
518
519
        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'
520
521
        substring('foobar', -1, -3) == 'oba'
        substring('foobar', 4, -2) == 'ob'
522
        substring('foobar', 10, 2) == ''
523
524
          </screen>
      </section>
525
526
527
528
529
530
531
532
      <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>
533
    </section>
534

535
536
537
538
539
540
541
542
543
  <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>

544
545
546
547
548
549
550
  <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>
551

552
553
554
555
556
557
558
559
560
561
562
563
      <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>
564
565
566
567
568
      In the following example the class named &quot;Client_foo&quot; is defined.
      It is comprised of all clients who's client ids (option 61) start with the
      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.

569
570
        <screen>
"Dhcp4": {
571
    "client-classes": [<userinput>
572
573
        {
            "name": "Client_foo",
574
            "test": "substring(option[61].hex,0,3) == 'foo'",
575
576
            "option-data": [
                {
577
                    "name": "domain-name-servers",
578
579
580
581
582
583
                    "code": 6,
                    "space": "dhcp4",
                    "csv-format": true,
                    "data": "192.0.2.1, 192.0.2.2"
                }
            ]
584
585
586
        },
        ...
    ],</userinput>
587
588
589
590
591
    ...
}</screen>
      </para>

      <para>
592
593
594
595
596
597
598
599
600
601
      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",
602
            "test": "substring(option[1].hex,0,6) == 0x0002AABBCCDD'",
603
604
605
606
607
608
609
610
611
612
613
614
615
616
            "option-data": [
                {
                    "name": "dns-servers",
                    "code": 23,
                    "space": "dhcp6",
                    "csv-format": true,
                    "data": "2001:db8:0::1, 2001:db8:2::1"
                }
            ]
        },
        ...
    ],</userinput>
    ...
}</screen>
617
618
619
620
621
622
623
      </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
624
625
626
627
628
        only to clients that belong to a given class using the "client-class"
        keyword when defining the subnet.
      </para>

      <para>
629
630
631
632
        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
633
        Client_foo  are allowed to use this subnet. Such a
634
635
636
        configuration can be achieved in the following way:
        <screen>
"Dhcp4": {
637
    "client-classes": [
638
639
        {
            "name": "Client_foo",
640
            "test": "substring(option[61].hex,0,3) == 'foo'",
641
642
            "option-data": [
                {
643
                    "name": "domain-name-servers",
644
645
646
647
648
649
                    "code": 6,
                    "space": "dhcp4",
                    "csv-format": true,
                    "data": "192.0.2.1, 192.0.2.2"
                }
            ]
650
651
652
653
654
655
656
657
        },
        ...
    ],<userinput>
    "subnet4": [
        {
            "subnet": "192.0.2.0/24",
            "pools": [ { "pool": "192.0.2.10 - 192.0.2.20" } ],
            "client-class": "Client_foo"
658
659
660
661
662
663
664
665
        },
        ...
    ],</userinput>,
    ...
}</screen>
      </para>

      <para>
Francis Dupont's avatar
Francis Dupont committed
666
        The following example shows restricting access to a DHCPv6 subnet.  This
667
668
669
670
671
672
673
674
        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",
675
            "test": "substring(option[1].hex,0,6) == 0x0002AABBCCDD'",
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
            "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"
693
        }
694
    ],</userinput>
695
696
697
698
699
700
701
702
703
    ...
}</screen>
      </para>
  </section>

  <section>
    <title>Using Classes</title>
      <para>
      Currently classes can be used for two functions.  They can supply options
704
705
      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.
706
707
708
      </para>

      <para>
709
710
      When supplying options, options defined as part of the class definition
      are considered &quot;class globals&quot;.  They will override any global options that
711
712
713
714
715
716
717
718
719
720
721
722
      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
723
724
725
726
      in choosing a subnet and selecting options.  For a description of the
      hooks see <xref linkend="hooks-libraries"/>, for a description on
      configuring he classes see <xref linkend="classification-configuring"/>
      and <xref linkend="classification-subnets"/>.
727
728
729
      </para>
  </section>

730
731
732
733
734
735
736
737
738
739
740
741
742
743
  <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 classifciaton 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>

744
745
746
747
     <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
748
     In brief there are two structures used during the evaluation of an expression:
749
750
751
752
753
754
755
     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
Thomas Markwalder's avatar
Thomas Markwalder committed
756
     in reverse Polish notation.  During execution the list will be traversed
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
     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>

774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
     <para>
     When debug logging is enabled each time a token is evaluated it will
     emit a log line 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 hex 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
800
801
       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'
802
803
       2016-05-19 13:35:04.166 DEBUG [kea.eval/44478] EVAL_DEBUG_SUBSTRING Popping length 3, start 0,
       string 0x666F6F626172 pushing result 0x666F6F
804
805
       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'
806
807
808
809
810
811
812
       </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 aide in helping you create and debug
     your expressions.  You should plan to disable debug logging when you have your
813
814
815
816
817
818
     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.
819
820
821
     </para></note>
  </section>

822
</chapter>