1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
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
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
// Copyright (C) 2015-2024 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/.

#ifndef CLIENT_CLASS_DEF_H
#define CLIENT_CLASS_DEF_H

#include <cc/cfg_to_element.h>
#include <cc/stamped_element.h>
#include <cc/user_context.h>
#include <dhcpsrv/cfg_option.h>
#include <dhcpsrv/cfg_option_def.h>
#include <eval/token.h>
#include <exceptions/exceptions.h>
#include <util/triplet.h>
#include <util/optional.h>

#include <string><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <unordered_map><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <list><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <vector><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.

/// @file client_class_def.h
///
/// @brief Defines classes for storing client class definitions
///
/// The file defines the class, ClientClassDef, which houses the
/// information for single client class such as the class name, the
/// logical expression used to identify members of the class, and options
/// that may be attributed to class members.
///
/// In addition it defines a container class, ClientClassDictionary, which
/// is houses class definitions keyed by class name.
///
namespace isc {
namespace dhcp {

/// @brief Error that occurs when an attempt is made to add a duplicate class
/// to a class dictionary.
class DuplicateClientClassDef : public isc::Exception {
public:
    DuplicateClientClassDef(const char* file, size_t line, const char* what)
        : isc::Exception(file, line, what) {}
};

/// @brief Embodies a single client class definition
class ClientClassDef : public data::UserContext,
                       public data::CfgToElement,
                       public data::StampedElement {
public:
    /// @brief Constructor
    ///
    /// @param name Name to assign to this class
    /// @param match_expr Expression the class will use to determine membership
    /// @param options Collection of options members should be given
    ClientClassDef(const std::string& name, const ExpressionPtr& match_expr,
                   const CfgOptionPtr& options = CfgOptionPtr());

    /// Copy constructor
    ClientClassDef(const ClientClassDef& rhs);

    /// @brief Destructor
    virtual ~ClientClassDef();

    /// @brief Fetches the class's name
    std::string getName() const;

    /// @brief Sets the class's name
    ///
    /// @param name the name to assign the class
    void setName(const std::string& name);

    /// @brief Fetches the class's match expression
    const ExpressionPtr& getMatchExpr() const;

    /// @brief Sets the class's match expression
    ///
    /// @param match_expr the expression to assign the class
    void setMatchExpr(const ExpressionPtr& match_expr);

    /// @brief Fetches the class's original match expression
    std::string getTest() const;

    /// @brief Sets the class's original match expression
    ///
    /// @param test the original expression to assign the class
    void setTest(const std::string& test);

    /// @brief Fetches the only if required flag
    bool getRequired() const;

    /// @brief Sets the only if required flag
    ///
    /// @param required the value of the only if required flag
    void setRequired(bool required);

    /// @brief Fetches the depend on known flag aka use host flag
    bool getDependOnKnown() const;

    /// @brief Sets the depend on known flag aka use host flag
    ///
    /// @param depend_on_known the value of the depend on known flag
    void setDependOnKnown(bool depend_on_known);

    /// @brief Fetches the class's option definitions
    const CfgOptionDefPtr& getCfgOptionDef() const;

    /// @brief Sets the class's option definition collection
    ///
    /// @param cfg_option_def the option definitions to assign the class
    void setCfgOptionDef(const CfgOptionDefPtr& cfg_option_def);

    /// @brief Fetches the class's option collection
    const CfgOptionPtr& getCfgOption() const;

    /// @brief Sets the class's option collection
    ///
    /// @param cfg_option the option collection to assign the class
    void setCfgOption(const CfgOptionPtr& cfg_option);

    /// @brief Checks direct dependency.
    ///
    /// @param name The client class name.
    ///
    /// @return true if the definition depends on the class name, false if not.
    bool dependOnClass(const std::string& name) const;

    /// @brief Compares two @c ClientClassDef objects for equality.
    ///
    /// @param other Other client class definition to compare to.
    ///
    /// @return true if objects are equal, false otherwise.
    bool equals(const ClientClassDef& other) const;

    /// @brief Equality operator.
    ///
    /// @param other Other client class definition to compare to.
    ///
    /// @return true if the definitions equal, false otherwise.
    bool operator==(const ClientClassDef& other) const {
        return (equals(other));
    }

    /// @brief Inequality operator.
    ///
    /// @param other Other client class definition to compare to.
    ///
    /// @return true if the definitions are not equal, false otherwise.
    bool operator!=(const ClientClassDef& other) const {
        return (!(equals(other)));
    }

    /// @brief Provides a convenient text representation of the class
    friend std::ostream& operator<<(std::ostream& os, const ClientClassDef& x);

    /// @brief returns next-server value
    /// @return next-server value
    const asiolink::IOAddress& getNextServer() const {
        return (next_server_);
    }

    /// @brief sets the next-server value
    ///
    /// @param addr the value to be set
    void setNextServer(const asiolink::IOAddress& addr) {
        next_server_ = addr;
    }

    /// @brief sets the server-name value
    ///
    /// @param sname the value to be set
    void setSname(const std::string& sname) {
        sname_ = sname;
    }

    /// @brief returns server-hostname value
    /// @return the vector that contains server-hostname (may be empty if not defined)
    const std::string& getSname() const {
        return (sname_);
    }

    /// @brief sets the boot-file-name value
    ///
    /// @param filename the value to be set
    void setFilename(const std::string& filename) {
        filename_ = filename;
    }

    /// @brief returns boot-file-name value
    /// @return the vector that contains boot-file-name (may be empty if not defined)
    const std::string& getFilename() const {
        return (filename_);
    }

    /// @brief Return valid-lifetime value
    ///
    /// @return a triplet containing the valid lifetime.
    util::Triplet<uint32_t> getValid() const {
        return (valid_);
    }

    /// @brief Sets new valid lifetime
    ///
    /// @param valid New valid lifetime in seconds.
    void setValid(const util::Triplet<uint32_t>& valid) {
        valid_ = valid;
    }

    /// @brief Return preferred-lifetime value
    ///
    /// @return a triplet containing the preferred lifetime.
    util::Triplet<uint32_t> getPreferred() const {
        return (preferred_);
    }

    /// @brief Sets new preferred lifetime
    ///
    /// @param preferred New valid lifetime in seconds.
    void setPreferred(const util::Triplet<uint32_t>& preferred) {
        preferred_ = preferred;
    }

    /// @brief Sets offer lifetime for the class.
    ///
    /// @param offer_lft the offer lifetime assigned to the class (may be empty if not defined)
    void setOfferLft(const util::Optional<uint32_t>& offer_lft) {
        offer_lft_ = offer_lft;
    }

    /// @brief Returns offer lifetime for the class.
    ///
    /// @return offer lifetime value
    util::Optional<uint32_t> getOfferLft() const {
        return (offer_lft_);
    }

    /// @brief Test method which checks if the packet belongs to the class
    ///
    /// If the packet belongs to the class, the class is added to the packet.
    ///
    /// @param pkt The packet checked if it belongs to the class.
    /// @param expr_ptr Expression the class will use to determine membership
    virtual void test(PktPtr pkt, const ExpressionPtr& expr_ptr);

    /// @brief Unparse a configuration object
    ///
    /// @return a pointer to unparsed configuration
    virtual isc::data::ElementPtr toElement() const;<--- Function in derived class

private:
    /// @brief Unique text identifier by which this class is known.
    std::string name_;

    /// @brief The logical expression which determines membership in
    /// this class.
    ExpressionPtr match_expr_;

    /// @brief The original expression which determines membership in
    /// this class.
    std::string test_;

    /// @brief The only-if-required flag: when false (the default) membership
    /// is determined during classification so is available for instance for
    /// subnet selection. When true, membership is evaluated only when required
    /// and is usable only for option configuration.
    bool required_;

    /// @brief The depend on known aka use host flag: when false (the default),
    /// the required flag is false and the class has a match expression
    /// the expression is evaluated in the first pass. When true and the
    /// two other conditions stand the expression is evaluated later when
    /// the host reservation membership was determined.
    /// This flag is set to true during the match expression parsing if
    /// direct or indirect dependency on the builtin [UN]KNOWN classes is
    /// detected.
    bool depend_on_known_;

    /// @brief The option definition configuration for this class
    CfgOptionDefPtr cfg_option_def_;

    /// @brief The option data configuration for this class
    CfgOptionPtr cfg_option_;

    /// @brief Next server field
    /// If set by the next-server parameter, this value will be set
    /// in the siaddr field of the DHCPv4 packet.
    asiolink::IOAddress next_server_;

    /// @brief server-hostname
    /// If set by the server-hostname parameter, this value will be
    /// set in the sname field of the DHCPv4 packet.
    /// This can be up to 64 octets long.
    std::string sname_;

    /// @brief boot-file-name
    /// If set by the boot-file-name parameter, this value will be
    /// set in the file field of the DHCPv4 packet.
    /// This can be up to 128 octets long.
    std::string filename_;

    /// @brief a Triplet (min/default/max) holding allowed valid lifetime values
    util::Triplet<uint32_t> valid_;

    /// @brief a Triplet (min/default/max) holding allowed preferred lifetime values
    util::Triplet<uint32_t> preferred_;

    /// @brief offer lifetime for this class (V4 only).
    util::Optional<uint32_t> offer_lft_;
};

class TemplateClientClassDef : public ClientClassDef {
public:
    /// @brief Constructor
    ///
    /// @param name Name to assign to this class
    /// @param match_expr Expression the class will use to determine membership
    /// @param options Collection of options members should be given
    TemplateClientClassDef(const std::string& name, const ExpressionPtr& match_expr,
                           const CfgOptionPtr& options = CfgOptionPtr());

    /// @brief Test method which checks if the packet belongs to the class
    ///
    /// If the packet belongs to the class, the class is added to the packet.
    ///
    /// @param pkt The packet checked if it belongs to the class.
    /// @param expr_ptr Expression the class will use to determine membership
    virtual void test(PktPtr pkt, const ExpressionPtr& expr_ptr) override;

    /// @brief Unparse a configuration object
    ///
    /// @return a pointer to unparsed configuration
    virtual isc::data::ElementPtr toElement() const override;

    /// @brief This is a prefix added to the spawned class name
    ///
    /// If incoming packet is associated with the template class, the name of
    /// generated spawned class is prepended with this prefix.
    /// For example, a packet that associates with the template class "FOO" by
    /// evaluating the template class expression to BAR will cause the packet to
    /// be assigned to class SPAWN_FOO_BAR.
    static const std::string SPAWN_CLASS_PREFIX;
};

/// @brief a pointer to an ClientClassDef
typedef boost::shared_ptr<ClientClassDef> ClientClassDefPtr;

/// @brief Defines a map of ClientClassDef's, keyed by the class name.
typedef std::unordered_map<std::string, ClientClassDefPtr> ClientClassDefMap;

/// @brief Defines a pointer to a ClientClassDefMap
typedef boost::shared_ptr<ClientClassDefMap> ClientClassDefMapPtr;

/// @brief Defines a list of ClientClassDefPtr's, using insert order.
typedef std::vector<ClientClassDefPtr> ClientClassDefList;

/// @brief Defines a pointer to a ClientClassDefList
typedef boost::shared_ptr<ClientClassDefList> ClientClassDefListPtr;

/// @brief Maintains a list of ClientClassDef's
class ClientClassDictionary : public isc::data::CfgToElement {

public:
    /// @brief Constructor
    ClientClassDictionary();

    ClientClassDictionary(const ClientClassDictionary& rhs);

    /// @brief Destructor
    ~ClientClassDictionary();

    /// @brief Adds a new class to the list
    ///
    /// @param name Name to assign to this class
    /// @param match_expr Expression the class will use to determine membership
    /// @param test Original version of match_expr
    /// @param required Original value of the only if required flag
    /// @param depend_on_known Using host so will be evaluated later
    /// @param options Collection of options members should be given
    /// @param defs Option definitions (optional)
    /// @param user_context User context (optional)
    /// @param next_server next-server value for this class (optional)
    /// @param sname server-name value for this class (optional)
    /// @param filename boot-file-name value for this class (optional)
    /// @param valid valid-lifetime triplet (optional)
    /// @param preferred preferred-lifetime triplet (optional)
    /// @param is_template true if class is a template class. Defaults to false.
    /// @param offer_lft the offer lifetime assigned to the class (may be empty if not defined)
    ///
    /// @throw DuplicateClientClassDef if class already exists within the
    /// dictionary.  See @ref dhcp::ClientClassDef::ClientClassDef() for
    /// others.
    void addClass(const std::string& name, const ExpressionPtr& match_expr,
                  const std::string& test, bool required, bool depend_on_known,
                  const CfgOptionPtr& options,
                  CfgOptionDefPtr defs = CfgOptionDefPtr(),
                  isc::data::ConstElementPtr user_context = isc::data::ConstElementPtr(),
                  asiolink::IOAddress next_server = asiolink::IOAddress("0.0.0.0"),
                  const std::string& sname = std::string(),
                  const std::string& filename = std::string(),
                  const util::Triplet<uint32_t>& valid = util::Triplet<uint32_t>(),
                  const util::Triplet<uint32_t>& preferred = util::Triplet<uint32_t>(),
                  bool is_template = false,
                  const util::Optional<uint32_t>& offer_lft = util::Optional<uint32_t>());

    /// @brief Adds a new class to the list
    ///
    /// @param class_def pointer to class definition to add
    ///
    /// @throw DuplicateClientClassDef if class already exists within the
    /// dictionary, BadValue if the pointer is empty.
    void addClass(const ClientClassDefPtr& class_def);

    /// @brief Fetches the class definition for a given class name
    ///
    /// @param name the name of the desired class
    ///
    /// @return ClientClassDefPtr to the desired class if found, or
    /// an empty pointer if not.
    ClientClassDefPtr findClass(const std::string& name) const;

    /// @brief Removes a given class definition from the dictionary
    ///
    /// Removes the class definition from the map if it exists, otherwise
    /// no harm, no foul.
    ///
    /// @param name the name of the class to remove
    void removeClass(const std::string& name);

    /// @brief Removes a client class by id.
    ///
    /// @param id class id.
    void removeClass(const uint64_t id);

    /// @brief Fetches the dictionary's list of classes
    ///
    /// @return ClientClassDefListPtr to the list of classes
    const ClientClassDefListPtr& getClasses() const;

    /// @brief Checks if the class dictionary is empty.
    ///
    /// @return true if there are no classes, false otherwise.
    bool empty() const;

    /// @brief Checks direct dependency.
    ///
    /// @param name The client class name.
    /// @param [out] dependent_class Reference to a variable where the
    /// name of the first class depending on the checked class is set.
    ///
    /// @return true if a definition depends on the class name, false if none.
    bool dependOnClass(const std::string& name, std::string& dependent_class) const;

    /// @brief Compares two @c ClientClassDictionary objects for equality.
    ///
    /// @param other Other client class definition to compare to.
    ///
    /// @return true if descriptors equal, false otherwise.
    bool equals(const ClientClassDictionary& other) const;

    /// @brief Iterates over the classes in the dictionary and ensures that
    /// that match expressions are initialized.
    ///
    /// @param family Class universe, e.g. AF_INET or AF_INET6.
    void initMatchExpr(uint16_t family);

    /// @brief Iterates over the classes in the dictionary and recreates
    /// the options.
    ///
    /// @param cfg_option_def set of option definitions to use.
    void createOptions(const CfgOptionDefPtr& cfg_option_def);

    /// @brief Equality operator.
    ///
    /// @param other Other client class dictionary to compare to.
    ///
    /// @return true if the dictionaries are equal, false otherwise.
    bool operator==(const ClientClassDictionary& other) const {
        return (equals(other));
    }

    /// @brief Inequality operator.
    ///
    /// @param other Other client class dictionary to compare to.
    ///
    /// @return true if the dictionaries are not equal, false otherwise.
    bool operator!=(const ClientClassDictionary& other) const {
        return (!equals(other));
    }

    /// @brief Copy assignment operator.
    ///
    /// @param rhs Client class dictionary to be copied from.
    /// @return Instance copy.
    ClientClassDictionary& operator=(const ClientClassDictionary& rhs);

    /// @brief Unparse a configuration object
    ///
    /// @return a pointer to unparsed configuration
    virtual isc::data::ElementPtr toElement() const;<--- Function in derived class

private:

    /// @brief Map of the class definitions
    ClientClassDefMapPtr map_;

    /// @brief List of the class definitions
    ClientClassDefListPtr list_;
};

/// @brief Defines a pointer to a ClientClassDictionary
typedef boost::shared_ptr<ClientClassDictionary> ClientClassDictionaryPtr;

/// @brief List of built-in client class names.
/// i.e. ALL, KNOWN, UNKNOWN and BOOTP but not DROP.
extern std::list<std::string> builtinNames;

/// @brief List of built-in client class prefixes
/// i.e. VENDOR_CLASS_, HA_, AFTER_ and EXTERNAL_.
extern std::list<std::string> builtinPrefixes;

/// @brief Check if a client class name is builtin.
///
/// @param client_class A client class name to look for.
/// @return true if built-in, false if not.
bool isClientClassBuiltIn(const ClientClass& client_class);

/// @brief Check if a client class name is already defined,
/// i.e. is built-in or in the dictionary,
///
/// The reference to depend on known flag is set to true if the class
/// is KNOWN or UNKNOWN (direct dependency) or has this flag set
/// (indirect dependency).
///
/// @param class_dictionary A class dictionary where to look for.
/// @param depend_on_known A reference to depend on known flag.
/// @param client_class A client class name to look for.
/// @return true if defined or built-in, false if not.
bool isClientClassDefined(ClientClassDictionaryPtr& class_dictionary,
                          bool& depend_on_known,
                          const ClientClass& client_class);

} // namespace isc::dhcp
} // namespace isc

#endif // CLIENT_CLASS_DEF_H