Kea 2.5.9
flex_option.h
Go to the documentation of this file.
1// Copyright (C) 2019-2024 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#ifndef FLEX_OPTION_H
8#define FLEX_OPTION_H
9
10#include <cc/data.h>
11#include <cc/simple_parser.h>
12#include <dhcp/classify.h>
13#include <dhcp/libdhcp++.h>
14#include <dhcp/option.h>
16#include <dhcp/option_vendor.h>
18#include <eval/evaluate.h>
19#include <eval/token.h>
20#include <util/str.h>
21
22#include <boost/algorithm/string/split.hpp>
23#include <boost/algorithm/string/classification.hpp>
24
25#include <map>
26#include <string>
27
28namespace isc {
29namespace flex_option {
30
38public:
39
46 enum Action {
50 REMOVE
51 };
52
57 public:
63
65 virtual ~OptionConfig();
66
70 uint16_t getCode() const {
71 return (code_);
72 }
73
78 return (def_);
79 }
80
84 void setAction(Action action) {
85 action_ = action;
86 }
87
91 Action getAction() const {
92 return (action_);
93 }
94
98 void setText(const std::string& text) {
99 text_ = text;
100 };
101
105 const std::string& getText() const {
106 return (text_);
107 }
108
113 expr_ = expr;
114 }
115
120 return (expr_);
121 }
122
126 void setClass(const isc::dhcp::ClientClass& class_name) {
127 class_ = class_name;
128 }
129
134 return (class_);
135 }
136
137 private:
139 uint16_t code_;
140
144
146 Action action_;
147
149 std::string text_;
150
153
156 };
157
159 typedef boost::shared_ptr<OptionConfig> OptionConfigPtr;
160
162 typedef std::list<OptionConfigPtr> OptionConfigList;
163
165 typedef std::map<uint16_t, OptionConfigList> OptionConfigMap;
166
171 public:
178 OptionConfigPtr container);
179
181 virtual ~SubOptionConfig();
182
186 void setVendorId(uint32_t vendor_id) {
187 vendor_id_ = vendor_id;
188 }
189
193 uint32_t getVendorId() const {
194 return (vendor_id_);
195 }
196
200 uint16_t getContainerCode() const {
201 return (container_->getCode());
202 }
203
208 return (container_->getOptionDef());
209 }
210
215 return (container_->getClass());
216 }
217
222 container_action_ = action;
223 }
224
229 return (container_action_);
230 }
231
232 private:
234 OptionConfigPtr container_;
235
237 uint32_t vendor_id_;
238
240 Action container_action_;
241 };
242
244 typedef boost::shared_ptr<SubOptionConfig> SubOptionConfigPtr;
245
248 typedef std::map<uint16_t, SubOptionConfigPtr> SubOptionConfigMap;
249
252 typedef std::map<uint16_t, SubOptionConfigMap> SubOptionConfigMapMap;
253
256
259
264 return (option_config_map_);
265 }
266
271 return (sub_option_config_map_);
272 }
273
279
286 template <typename PktType>
288 PktType query, PktType response) {
289 for (auto const& pair : getOptionConfigMap()) {
290 for (const OptionConfigPtr& opt_cfg : pair.second) {
291 const isc::dhcp::ClientClass& client_class =
292 opt_cfg->getClass();
293 if (!client_class.empty()) {
294 if (!query->inClass(client_class)) {
295 logClass(client_class, opt_cfg->getCode());
296 continue;
297 }
298 }
299 std::string value;
301 uint16_t code = opt_cfg->getCode();
302 isc::dhcp::OptionPtr opt = response->getOption(code);
303 isc::dhcp::OptionDefinitionPtr def = opt_cfg->getOptionDef();
304 switch (opt_cfg->getAction()) {
305 case NONE:
306 break;
307 case ADD:
308 // Don't add if option is already there.
309 if (opt) {
310 break;
311 }
312 // Do nothing is the expression evaluates to empty.
313 value = isc::dhcp::evaluateString(*opt_cfg->getExpr(),
314 *query);
315 if (value.empty()) {
316 break;
317 }
318 // Set the value.
319 if (def) {
320 std::vector<std::string> split_vec =
321 isc::util::str::tokens(value, ",", true);
322 opt = def->optionFactory(universe, code, split_vec);
323 } else {
324 buffer.assign(value.begin(), value.end());
325 opt.reset(new isc::dhcp::Option(universe, code,
326 buffer));
327 }
328 // Add the option.
329 response->addOption(opt);
330 logAction(ADD, code, value);
331 break;
332 case SUPERSEDE:
333 // Do nothing is the expression evaluates to empty.
334 value = isc::dhcp::evaluateString(*opt_cfg->getExpr(),
335 *query);
336 if (value.empty()) {
337 break;
338 }
339 // Set the value.
340 if (def) {
341 std::vector<std::string> split_vec =
342 isc::util::str::tokens(value, ",", true);
343 opt = def->optionFactory(universe, code,
344 split_vec);
345 } else {
346 buffer.assign(value.begin(), value.end());
347 opt.reset(new isc::dhcp::Option(universe,
348 code,
349 buffer));
350 }
351 // Remove the option if already there.
352 while (response->getOption(code)) {
353 response->delOption(code);
354 }
355 // Add the option.
356 response->addOption(opt);
357 logAction(SUPERSEDE, code, value);
358 break;
359 case REMOVE:
360 // Nothing to remove if option is not present.
361 if (!opt) {
362 break;
363 }
364 // Do nothing is the expression evaluates to false.
365 if (!isc::dhcp::evaluateBool(*opt_cfg->getExpr(), *query)) {
366 break;
367 }
368 // Remove the option.
369 while (response->getOption(code)) {
370 response->delOption(code);
371 }
372 logAction(REMOVE, code, "");
373 break;
374 }
375 }
376 }
377 for (auto const& pair : getSubOptionConfigMap()) {
378 for (auto const& sub_pair : pair.second) {
379 const SubOptionConfigPtr& sub_cfg = sub_pair.second;
380 uint16_t sub_code = sub_cfg->getCode();
381 uint16_t opt_code = sub_cfg->getContainerCode();
382 const isc::dhcp::ClientClass& opt_class =
383 sub_cfg->getContainerClass();
384 if (!opt_class.empty()) {
385 if (!query->inClass(opt_class)) {
386 logClass(opt_class, opt_code);
387 continue;
388 }
389 }
390 const isc::dhcp::ClientClass& sub_class =
391 sub_cfg->getClass();
392 if (!sub_class.empty()) {
393 if (!query->inClass(sub_class)) {
394 logSubClass(sub_class, sub_code, opt_code);
395 continue;
396 }
397 }
398 std::string value;
400 isc::dhcp::OptionPtr opt = response->getOption(opt_code);
402 isc::dhcp::OptionDefinitionPtr def = sub_cfg->getOptionDef();
403 uint32_t vendor_id = sub_cfg->getVendorId();
404 switch (sub_cfg->getAction()) {
405 case NONE:
406 break;
407 case ADD:
408 // If no container and no magic add return
409 if (!opt && (sub_cfg->getContainerAction() != ADD)) {
410 break;
411 }
412 // Do nothing is the expression evaluates to empty.
413 value = isc::dhcp::evaluateString(*sub_cfg->getExpr(),
414 *query);
415 if (value.empty()) {
416 break;
417 }
418 // Check vendor id mismatch.
419 if (opt && vendor_id && !checkVendor(opt, vendor_id)) {
420 break;
421 }
422 // Don't add if sub-option is already there.
423 if (opt && opt->getOption(sub_code)) {
424 break;
425 }
426 // Set the value.
427 if (def) {
428 std::vector<std::string> split_vec =
429 isc::util::str::tokens(value, ",", true);
430 sub = def->optionFactory(universe, sub_code,
431 split_vec);
432 } else {
433 buffer.assign(value.begin(), value.end());
434 sub.reset(new isc::dhcp::Option(universe, sub_code,
435 buffer));
436 }
437 // If the container does not exist add it.
438 if (!opt) {
439 if (!vendor_id) {
440 opt.reset(new isc::dhcp::Option(universe,
441 opt_code));
442 } else {
443 opt.reset(new isc::dhcp::OptionVendor(universe,
444 vendor_id));
445 }
446 response->addOption(opt);
447 if (vendor_id) {
448 logAction(ADD, opt_code, vendor_id);
449 } else {
450 logAction(ADD, opt_code, "");
451 }
452 }
453 // Add the sub-option.
454 opt->addOption(sub);
455 logSubAction(ADD, sub_code, opt_code, value);
456 break;
457 case SUPERSEDE:
458 // If no container and no magic add return
459 if (!opt && (sub_cfg->getContainerAction() != ADD)) {
460 break;
461 }
462 // Do nothing is the expression evaluates to empty.
463 value = isc::dhcp::evaluateString(*sub_cfg->getExpr(),
464 *query);
465 if (value.empty()) {
466 break;
467 }
468 // Check vendor id mismatch.
469 if (opt && vendor_id && !checkVendor(opt, vendor_id)) {
470 break;
471 }
472 // Set the value.
473 if (def) {
474 std::vector<std::string> split_vec =
475 isc::util::str::tokens(value, ",", true);
476 sub = def->optionFactory(universe, sub_code,
477 split_vec);
478 } else {
479 buffer.assign(value.begin(), value.end());
480 sub.reset(new isc::dhcp::Option(universe, sub_code,
481 buffer));
482 }
483 // Remove the sub-option if already there.
484 if (opt) {
485 while (opt->getOption(sub_code)) {
486 opt->delOption(sub_code);
487 }
488 }
489 // If the container does not exist add it.
490 if (!opt) {
491 if (!vendor_id) {
492 opt.reset(new isc::dhcp::Option(universe,
493 opt_code));
494 } else {
495 opt.reset(new isc::dhcp::OptionVendor(universe,
496 vendor_id));
497 }
498 response->addOption(opt);
499 if (vendor_id) {
500 logAction(ADD, opt_code, vendor_id);
501 } else {
502 logAction(ADD, opt_code, "");
503 }
504 }
505 // Add the sub-option.
506 opt->addOption(sub);
507 logSubAction(SUPERSEDE, sub_code, opt_code, value);
508 break;
509 case REMOVE:
510 // Nothing to remove if container is not present.
511 if (!opt) {
512 break;
513 }
514 sub = opt->getOption(sub_code);
515 // Nothing to remove if sub-option is not present.
516 if (!sub) {
517 break;
518 }
519 // Do nothing is the expression evaluates to false.
520 if (!isc::dhcp::evaluateBool(*sub_cfg->getExpr(), *query)) {
521 break;
522 }
523 // Check vendor id mismatch.
524 if (opt && vendor_id && !checkVendor(opt, vendor_id)) {
525 break;
526 }
527 // Remove the sub-option.
528 while (opt->getOption(sub_code)) {
529 opt->delOption(sub_code);
530 }
531 logSubAction(REMOVE, sub_code, opt_code, "");
532 // Remove the empty container when wanted.
533 if ((sub_cfg->getContainerAction() == REMOVE) &&
534 opt->getOptions().empty()) {
535 response->delOption(opt_code);
536 logAction(REMOVE, opt_code, "");
537 }
538 break;
539 }
540 }
541 }
542 }
543
544
549 static void logClass(const isc::dhcp::ClientClass &client_class,
550 uint16_t code);
551
557 static void logAction(Action action, uint16_t code,
558 const std::string& value);
559
565 static void logAction(Action action, uint16_t code, uint32_t vendor_id);
566
572 static void logSubClass(const isc::dhcp::ClientClass &client_class,
573 uint16_t code, uint16_t container_code);
574
581 static void logSubAction(Action action, uint16_t code,
582 uint16_t container_code,
583 const std::string& value);
584
589 static bool checkVendor(isc::dhcp::OptionPtr opt, uint32_t vendor_id);
590
591protected:
596 return (option_config_map_);
597 }
598
603 return (sub_option_config_map_);
604 }
605
606private:
608 static const data::SimpleKeywords OPTION_PARAMETERS;
609
611 static const data::SimpleKeywords SUB_OPTION_PARAMETERS;
612
614 OptionConfigMap option_config_map_;
615
617 SubOptionConfigMapMap sub_option_config_map_;
618
623 void parseOptionConfig(isc::data::ConstElementPtr option);
624
630 void parseSubOption(isc::data::ConstElementPtr sub_option,
631 OptionConfigPtr opt_cfg,
633
639 void parseSubOptions(isc::data::ConstElementPtr sub_options,
640 OptionConfigPtr opt_cfg,
642};
643
645typedef boost::shared_ptr<FlexOptionImpl> FlexOptionImplPtr;
646
647} // end of namespace flex_option
648} // end of namespace isc
649#endif
Defines elements for storing the names of client classes.
This class represents vendor-specific information option.
Definition: option_vendor.h:29
Universe
defines option universe DHCPv4 or DHCPv6
Definition: option.h:83
void setExpr(const isc::dhcp::ExpressionPtr &expr)
Set match expression.
Definition: flex_option.h:112
const isc::dhcp::ExpressionPtr & getExpr() const
Get match expression.
Definition: flex_option.h:119
uint16_t getCode() const
Return option code.
Definition: flex_option.h:70
Action getAction() const
Return action.
Definition: flex_option.h:91
const isc::dhcp::ClientClass & getClass() const
Get client class.
Definition: flex_option.h:133
void setClass(const isc::dhcp::ClientClass &class_name)
Set client class.
Definition: flex_option.h:126
isc::dhcp::OptionDefinitionPtr getOptionDef() const
Return option definition.
Definition: flex_option.h:77
void setText(const std::string &text)
Set textual expression.
Definition: flex_option.h:98
void setAction(Action action)
Set action.
Definition: flex_option.h:84
const std::string & getText() const
Get textual expression.
Definition: flex_option.h:105
isc::dhcp::OptionDefinitionPtr getContainerDef() const
Return container definition.
Definition: flex_option.h:207
Action getContainerAction() const
Return action on the container.
Definition: flex_option.h:228
uint32_t getVendorId() const
Return vendor id.
Definition: flex_option.h:193
void setVendorId(uint32_t vendor_id)
Set vendor id.
Definition: flex_option.h:186
const isc::dhcp::ClientClass & getContainerClass() const
Return container client class.
Definition: flex_option.h:214
void setContainerAction(Action action)
Set action on the container.
Definition: flex_option.h:221
uint16_t getContainerCode() const
Return container code.
Definition: flex_option.h:200
Flex Option implementation.
Definition: flex_option.h:37
void configure(isc::data::ConstElementPtr options)
Configure the Flex Option implementation.
Definition: flex_option.cc:134
const OptionConfigMap & getOptionConfigMap() const
Get the option config map.
Definition: flex_option.h:263
boost::shared_ptr< OptionConfig > OptionConfigPtr
The type of shared pointers to option config.
Definition: flex_option.h:159
std::map< uint16_t, OptionConfigList > OptionConfigMap
The type of the option config map.
Definition: flex_option.h:165
std::map< uint16_t, SubOptionConfigMap > SubOptionConfigMapMap
The type of the map of sub-option config maps.
Definition: flex_option.h:252
boost::shared_ptr< SubOptionConfig > SubOptionConfigPtr
The type of shared pointers to sub-option config.
Definition: flex_option.h:244
static void logAction(Action action, uint16_t code, const std::string &value)
Log the action for option.
Definition: flex_option.cc:499
void process(isc::dhcp::Option::Universe universe, PktType query, PktType response)
Process a query / response pair.
Definition: flex_option.h:287
static void logSubClass(const isc::dhcp::ClientClass &client_class, uint16_t code, uint16_t container_code)
Log the client class for sub-option.
Definition: flex_option.cc:549
SubOptionConfigMapMap & getMutableSubOptionConfigMap()
Get a mutable reference to the sub-option config map of maps.
Definition: flex_option.h:602
OptionConfigMap & getMutableOptionConfigMap()
Get a mutable reference to the option config map.
Definition: flex_option.h:595
static void logSubAction(Action action, uint16_t code, uint16_t container_code, const std::string &value)
Log the action for sub-option.
Definition: flex_option.cc:560
std::list< OptionConfigPtr > OptionConfigList
The type of lists of shared pointers to option config.
Definition: flex_option.h:162
static bool checkVendor(isc::dhcp::OptionPtr opt, uint32_t vendor_id)
Check vendor option vendor id mismatch.
Definition: flex_option.cc:598
std::map< uint16_t, SubOptionConfigPtr > SubOptionConfigMap
The type of the sub-option config map.
Definition: flex_option.h:248
static void logClass(const isc::dhcp::ClientClass &client_class, uint16_t code)
Log the client class for option.
Definition: flex_option.cc:490
const SubOptionConfigMapMap & getSubOptionConfigMap() const
Get the sub-option config map of maps.
Definition: flex_option.h:270
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:29
std::map< std::string, isc::data::Element::types > SimpleKeywords
This specifies all accepted keywords with their types.
std::string ClientClass
Defines a single class name.
Definition: classify.h:42
std::string evaluateString(const Expression &expr, Pkt &pkt)
Definition: evaluate.cc:27
boost::shared_ptr< OptionDefinition > OptionDefinitionPtr
Pointer to option definition object.
boost::shared_ptr< Expression > ExpressionPtr
Definition: token.h:30
bool evaluateBool(const Expression &expr, Pkt &pkt)
Evaluate a RPN expression for a v4 or v6 packet and return a true or false decision.
Definition: evaluate.cc:14
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
Definition: option.h:24
boost::shared_ptr< Option > OptionPtr
Definition: option.h:37
boost::shared_ptr< FlexOptionImpl > FlexOptionImplPtr
The type of shared pointers to Flex Option implementations.
Definition: flex_option.h:645
vector< string > tokens(const string &text, const string &delim, bool escape)
Split string into tokens.
Definition: str.cc:52
Defines the logger used by the top-level component of kea-lfc.