Kea  1.5.0
client_class_def.cc
Go to the documentation of this file.
1 // Copyright (C) 2015-2018 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 #include <config.h>
8 
9 #include <eval/dependency.h>
11 #include <dhcpsrv/cfgmgr.h>
12 #include <boost/foreach.hpp>
13 
14 using namespace isc::data;
15 
16 namespace isc {
17 namespace dhcp {
18 
19 //********** ClientClassDef ******************//
20 
21 ClientClassDef::ClientClassDef(const std::string& name,
22  const ExpressionPtr& match_expr,
23  const CfgOptionPtr& cfg_option)
24  : name_(name), match_expr_(match_expr), required_(false),
25  depend_on_known_(false), cfg_option_(cfg_option),
26  next_server_(asiolink::IOAddress::IPV4_ZERO_ADDRESS()) {
27 
28  // Name can't be blank
29  if (name_.empty()) {
30  isc_throw(BadValue, "Client Class name cannot be blank");
31  }
32 
33  // We permit an empty expression for now. This will likely be useful
34  // for automatic classes such as vendor class.
35 
36  // For classes without options, make sure we have an empty collection
37  if (!cfg_option_) {
38  cfg_option_.reset(new CfgOption());
39  }
40 }
41 
43  : name_(rhs.name_), match_expr_(ExpressionPtr()), required_(false),
44  depend_on_known_(false), cfg_option_(new CfgOption()),
45  next_server_(asiolink::IOAddress::IPV4_ZERO_ADDRESS()) {
46 
47  if (rhs.match_expr_) {
48  match_expr_.reset(new Expression());
49  *match_expr_ = *(rhs.match_expr_);
50  }
51 
52  if (rhs.cfg_option_def_) {
53  rhs.cfg_option_def_->copyTo(*cfg_option_def_);
54  }
55 
56  if (rhs.cfg_option_) {
57  rhs.cfg_option_->copyTo(*cfg_option_);
58  }
59 
60  required_ = rhs.required_;
61  depend_on_known_ = rhs.depend_on_known_;
62  next_server_ = rhs.next_server_;
63  sname_ = rhs.sname_;
64  filename_ = rhs.filename_;
65 }
66 
68 }
69 
70 std::string
72  return (name_);
73 }
74 
75 void
76 ClientClassDef::setName(const std::string& name) {
77  name_ = name;
78 }
79 
80 const ExpressionPtr&
82  return (match_expr_);
83 }
84 
85 void
87  match_expr_ = match_expr;
88 }
89 
90 std::string
92  return (test_);
93 }
94 
95 void
96 ClientClassDef::setTest(const std::string& test) {
97  test_ = test;
98 }
99 
100 bool
102  return (required_);
103 }
104 
105 void
107  required_ = required;
108 }
109 
110 bool
112  return (depend_on_known_);
113 }
114 
115 void
116 ClientClassDef::setDependOnKnown(bool depend_on_known) {
117  depend_on_known_ = depend_on_known;
118 }
119 
120 const CfgOptionDefPtr&
122  return (cfg_option_def_);
123 }
124 
125 void
127  cfg_option_def_ = cfg_option_def;
128 }
129 
130 const CfgOptionPtr&
132  return (cfg_option_);
133 }
134 
135 void
137  cfg_option_ = cfg_option;
138 }
139 
140 bool
141 ClientClassDef::dependOnClass(const std::string& name) const {
142  return (isc::dhcp::dependOnClass(match_expr_, name));
143 }
144 
145 bool
147  return ((name_ == other.name_) &&
148  ((!match_expr_ && !other.match_expr_) ||
149  (match_expr_ && other.match_expr_ &&
150  (*match_expr_ == *(other.match_expr_)))) &&
151  ((!cfg_option_ && !other.cfg_option_) ||
152  (cfg_option_ && other.cfg_option_ &&
153  (*cfg_option_ == *other.cfg_option_))) &&
154  ((!cfg_option_def_ && !other.cfg_option_def_) ||
155  (cfg_option_def_ && other.cfg_option_def_ &&
156  (*cfg_option_def_ == *other.cfg_option_def_))) &&
157  (required_ == other.required_) &&
158  (depend_on_known_ == other.depend_on_known_) &&
159  (next_server_ == other.next_server_) &&
160  (sname_ == other.sname_) &&
161  (filename_ == other.filename_));
162 }
163 
166  uint16_t family = CfgMgr::instance().getFamily();
167  ElementPtr result = Element::createMap();
168  // Set user-context
169  contextToElement(result);
170  // Set name
171  result->set("name", Element::create(name_));
172  // Set original match expression (empty string won't parse)
173  if (!test_.empty()) {
174  result->set("test", Element::create(test_));
175  }
176  // Set only-if-required
177  if (required_) {
178  result->set("only-if-required", Element::create(required_));
179  }
180  // Set option-def (used only by DHCPv4)
181  if (cfg_option_def_ && (family == AF_INET)) {
182  result->set("option-def", cfg_option_def_->toElement());
183  }
184  // Set option-data
185  result->set("option-data", cfg_option_->toElement());
186  if (family != AF_INET) {
187  // Other parameters are DHCPv4 specific
188  return (result);
189  }
190  // Set next-server
191  result->set("next-server", Element::create(next_server_.toText()));
192  // Set server-hostname
193  result->set("server-hostname", Element::create(sname_));
194  // Set boot-file-name
195  result->set("boot-file-name", Element::create(filename_));
196  return (result);
197 }
198 
199 std::ostream& operator<<(std::ostream& os, const ClientClassDef& x) {
200  os << "ClientClassDef:" << x.getName();
201  return (os);
202 }
203 
204 //********** ClientClassDictionary ******************//
205 
207  : map_(new ClientClassDefMap()), list_(new ClientClassDefList()) {
208 }
209 
211  : map_(new ClientClassDefMap()), list_(new ClientClassDefList()) {
212  BOOST_FOREACH(ClientClassDefPtr cclass, *(rhs.list_)) {
213  ClientClassDefPtr copy(new ClientClassDef(*cclass));
214  addClass(copy);
215  }
216 }
217 
219 }
220 
221 void
222 ClientClassDictionary::addClass(const std::string& name,
223  const ExpressionPtr& match_expr,
224  const std::string& test,
225  bool required,
226  bool depend_on_known,
227  const CfgOptionPtr& cfg_option,
228  CfgOptionDefPtr cfg_option_def,
229  ConstElementPtr user_context,
230  asiolink::IOAddress next_server,
231  const std::string& sname,
232  const std::string& filename) {
233  ClientClassDefPtr cclass(new ClientClassDef(name, match_expr, cfg_option));
234  cclass->setTest(test);
235  cclass->setRequired(required);
236  cclass->setDependOnKnown(depend_on_known);
237  cclass->setCfgOptionDef(cfg_option_def);
238  cclass->setContext(user_context),
239  cclass->setNextServer(next_server);
240  cclass->setSname(sname);
241  cclass->setFilename(filename);
242  addClass(cclass);
243 }
244 
245 void
247  if (!class_def) {
248  isc_throw(BadValue, "ClientClassDictionary::addClass "
249  " - class definition cannot be null");
250  }
251 
252  if (findClass(class_def->getName())) {
253  isc_throw(DuplicateClientClassDef, "Client Class: "
254  << class_def->getName() << " has already been defined");
255  }
256 
257  list_->push_back(class_def);
258  (*map_)[class_def->getName()] = class_def;
259 }
260 
262 ClientClassDictionary::findClass(const std::string& name) const {
263  ClientClassDefMap::iterator it = map_->find(name);
264  if (it != map_->end()) {
265  return (*it).second;
266  }
267 
268  return(ClientClassDefPtr());
269 }
270 
271 void
272 ClientClassDictionary::removeClass(const std::string& name) {
273  for (ClientClassDefList::iterator this_class = list_->begin();
274  this_class != list_->end(); ++this_class) {
275  if ((*this_class)->getName() == name) {
276  list_->erase(this_class);
277  break;
278  }
279  }
280  map_->erase(name);
281 }
282 
285  return (list_);
286 }
287 
288 bool
289 ClientClassDictionary::dependOnClass(const std::string& name,
290  std::string& dependent_class) const {
291  // Skip previous classes as they should not depend on name.
292  bool found = false;
293  for (ClientClassDefList::iterator this_class = list_->begin();
294  this_class != list_->end(); ++this_class) {
295  if (found) {
296  if ((*this_class)->dependOnClass(name)) {
297  dependent_class = (*this_class)->getName();
298  return (true);
299  }
300  } else {
301  if ((*this_class)->getName() == name) {
302  found = true;
303  }
304  }
305  }
306  return (false);
307 }
308 
309 bool
311  if (list_->size() != other.list_->size()) {
312  return (false);
313  }
314 
315  ClientClassDefList::const_iterator this_class = list_->cbegin();
316  ClientClassDefList::const_iterator other_class = other.list_->cbegin();
317  while (this_class != list_->cend() &&
318  other_class != other.list_->cend()) {
319  if (!*this_class || !*other_class ||
320  **this_class != **other_class) {
321  return false;
322  }
323 
324  ++this_class;
325  ++other_class;
326  }
327 
328  return (true);
329 }
330 
333  ElementPtr result = Element::createList();
334  // Iterate on the map
335  for (ClientClassDefList::const_iterator this_class = list_->begin();
336  this_class != list_->cend(); ++this_class) {
337  result->add((*this_class)->toElement());
338  }
339  return (result);
340 }
341 
342 std::list<std::string>
344  "ALL", "KNOWN", "UNKNOWN"
345 };
346 
347 std::list<std::string>
349  "VENDOR_CLASS_", "HA_", "AFTER_", "EXTERNAL_"
350 };
351 
352 bool
353 isClientClassBuiltIn(const ClientClass& client_class) {
354  for (std::list<std::string>::const_iterator bn = builtinNames.cbegin();
355  bn != builtinNames.cend(); ++bn) {
356  if (client_class == *bn) {
357  return true;
358  }
359  }
360 
361  for (std::list<std::string>::const_iterator bt = builtinPrefixes.cbegin();
362  bt != builtinPrefixes.cend(); ++bt) {
363  if (client_class.size() <= bt->size()) {
364  continue;
365  }
366  auto mis = std::mismatch(bt->cbegin(), bt->cend(), client_class.cbegin());
367  if (mis.first == bt->cend()) {
368  return true;
369  }
370  }
371 
372  return false;
373 }
374 
375 bool
377  bool& depend_on_known,
378  const ClientClass& client_class) {
379  // First check built-in classes
380  if (isClientClassBuiltIn(client_class)) {
381  // Check direct dependency on [UN]KNOWN
382  if ((client_class == "KNOWN") || (client_class == "UNKNOWN")) {
383  depend_on_known = true;
384  }
385  return (true);
386  }
387 
388  // Second check already defined, i.e. in the dictionary
389  ClientClassDefPtr def = class_dictionary->findClass(client_class);
390  if (def) {
391  // Check indirect dependency on [UN]KNOWN
392  if (def->getDependOnKnown()) {
393  depend_on_known = true;
394  }
395  return (true);
396  }
397 
398  // Not defined...
399  return (false);
400 }
401 
402 } // namespace isc::dhcp
403 } // namespace isc
void setMatchExpr(const ExpressionPtr &match_expr)
Sets the class's match expression.
bool dependOnClass(const std::string &name, std::string &dependent_class) const
Checks direct dependency.
virtual isc::data::ElementPtr toElement() const
Unparse a configuration object.
boost::shared_ptr< CfgOption > CfgOptionPtr
Non-const pointer.
Definition: cfg_option.h:497
const CfgOptionDefPtr & getCfgOptionDef() const
Fetches the class's option definitions.
void setDependOnKnown(bool depend_on_known)
Sets the depend on known flag aka use host flag.
bool dependOnClass(const std::string &name) const
Checks direct dependency.
ClientClassDefPtr findClass(const std::string &name) const
Fetches the class definition for a given class name.
void setRequired(bool required)
Sets the only if required flag.
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition: cfgmgr.cc:25
const ClientClassDefListPtr & getClasses() const
Fetches the dictionary's list of classes.
std::unordered_map< std::string, ClientClassDefPtr > ClientClassDefMap
Defines a map of ClientClassDef's, keyed by the class name.
boost::shared_ptr< Element > ElementPtr
Definition: data.h:20
std::string getName() const
Fetches the class's name.
boost::shared_ptr< CfgOptionDef > CfgOptionDefPtr
Non-const pointer.
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())
Adds a new class to the list.
void setTest(const std::string &test)
Sets the class's original match expression.
bool equals(const ClientClassDef &other) const
Compares two ClientClassDef objects for equality.
Maintains a list of ClientClassDef's.
bool isClientClassDefined(ClientClassDictionaryPtr &class_dictionary, bool &depend_on_known, const ClientClass &client_class)
Check if a client class name is already defined, i.e.
const CfgOptionPtr & getCfgOption() const
Fetches the class's option collection.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
Represents option data configuration for the DHCP server.
Definition: cfg_option.h:248
ElementPtr copy(ConstElementPtr from, int level)
Copy the data up to a nesting level.
Definition: data.cc:1114
Error that occurs when an attempt is made to add a duplicate class to a class dictionary.
uint16_t getFamily() const
Returns address family.
Definition: cfgmgr.h:242
boost::shared_ptr< ClientClassDictionary > ClientClassDictionaryPtr
Defines a pointer to a ClientClassDictionary.
Embodies a single client class definition.
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:23
std::string getTest() const
Fetches the class's original match expression.
bool dependOnClass(const TokenPtr &token, const std::string &name)
Checks dependency on a token.
Definition: dependency.cc:15
void contextToElement(data::ElementPtr map) const
Merge unparse a user_context object.
Definition: user_context.cc:15
std::list< std::string > builtinNames
List of built-in client class names.
std::list< std::string > builtinPrefixes
List of built-in client class prefixes i.e.
boost::shared_ptr< ClientClassDef > ClientClassDefPtr
a pointer to an ClientClassDef
virtual isc::data::ElementPtr toElement() const
Unparse a configuration object.
std::vector< ClientClassDefPtr > ClientClassDefList
Defines a list of ClientClassDefPtr's, using insert order.
Defines the logger used by the top-level component of kea-dhcp-ddns.
std::vector< TokenPtr > Expression
This is a structure that holds an expression converted to RPN.
Definition: token.h:28
virtual ~ClientClassDef()
Destructor.
boost::shared_ptr< ClientClassDefList > ClientClassDefListPtr
Defines a pointer to a ClientClassDefList.
const Name & name_
Definition: dns/message.cc:693
void removeClass(const std::string &name)
Removes a given class definition from the dictionary.
std::ostream & operator<<(std::ostream &os, const OpaqueDataTuple &tuple)
Inserts the OpaqueDataTuple as a string into stream.
const ExpressionPtr & getMatchExpr() const
Fetches the class's match expression.
bool getRequired() const
Fetches the only if required flag.
void setName(const std::string &name)
Sets the class's name.
void setCfgOption(const CfgOptionPtr &cfg_option)
Sets the class's option collection.
ClientClassDef(const std::string &name, const ExpressionPtr &match_expr, const CfgOptionPtr &options=CfgOptionPtr())
Constructor.
bool isClientClassBuiltIn(const ClientClass &client_class)
Check if a client class name is builtin.
std::string ClientClass
Defines a single class name.
Definition: classify.h:37
Defines classes for storing client class definitions.
bool getDependOnKnown() const
Fetches the depend on known flag aka use host flag.
boost::shared_ptr< Expression > ExpressionPtr
Definition: token.h:30
bool equals(const ClientClassDictionary &other) const
Compares two ClientClassDictionary objects for equality.
void setCfgOptionDef(const CfgOptionDefPtr &cfg_option_def)
Sets the class's option definition collection.