Kea  2.3.7
option_definition.cc
Go to the documentation of this file.
1 // Copyright (C) 2012-2023 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 <dhcp/dhcp4.h>
10 #include <dhcp/dhcp6.h>
11 #include <dhcp/option4_addrlst.h>
13 #include <dhcp/option6_addrlst.h>
15 #include <dhcp/option6_ia.h>
16 #include <dhcp/option6_iaaddr.h>
17 #include <dhcp/option6_iaprefix.h>
18 #include <dhcp/option6_pdexclude.h>
20 #include <dhcp/option_custom.h>
21 #include <dhcp/option_definition.h>
22 #include <dhcp/option_int.h>
23 #include <dhcp/option_int_array.h>
25 #include <dhcp/option_string.h>
26 #include <dhcp/option_vendor.h>
28 #include <util/encode/hex.h>
29 #include <dns/labelsequence.h>
30 #include <dns/name.h>
31 #include <util/strutil.h>
32 #include <boost/algorithm/string/classification.hpp>
33 #include <boost/algorithm/string/predicate.hpp>
34 #include <boost/dynamic_bitset.hpp>
35 #include <boost/make_shared.hpp>
36 #include <sstream>
37 
38 using namespace std;
39 using namespace isc::util;
40 
41 namespace isc {
42 namespace dhcp {
43 
44 OptionDefinition::OptionDefinition(const std::string& name,
45  const uint16_t code,
46  const std::string& space,
47  const std::string& type,
48  const bool array_type /* = false */)
49  : name_(name),
50  code_(code),
51  type_(OPT_UNKNOWN_TYPE),
52  array_type_(array_type),
53  encapsulated_space_(""),
54  record_fields_(),
55  user_context_(),
56  option_space_name_(space) {
57  // Data type is held as enum value by this class.
58  // Use the provided option type string to get the
59  // corresponding enum value.
60  type_ = OptionDataTypeUtil::getDataType(type);
61 }
62 
63 OptionDefinition::OptionDefinition(const std::string& name,
64  const uint16_t code,
65  const std::string& space,
66  const OptionDataType type,
67  const bool array_type /* = false */)
68  : name_(name),
69  code_(code),
70  type_(type),
71  array_type_(array_type),
72  encapsulated_space_(""),
73  option_space_name_(space){
74 }
75 
76 OptionDefinition::OptionDefinition(const std::string& name,
77  const uint16_t code,
78  const std::string& space,
79  const std::string& type,
80  const char* encapsulated_space)
81  : name_(name),
82  code_(code),
83  // Data type is held as enum value by this class.
84  // Use the provided option type string to get the
85  // corresponding enum value.
86  type_(OptionDataTypeUtil::getDataType(type)),
87  array_type_(false),
88  encapsulated_space_(encapsulated_space),
89  record_fields_(),
90  user_context_(),
91  option_space_name_(space) {
92 }
93 
94 OptionDefinition::OptionDefinition(const std::string& name,
95  const uint16_t code,
96  const std::string& space,
97  const OptionDataType type,
98  const char* encapsulated_space)
99  : name_(name),
100  code_(code),
101  type_(type),
102  array_type_(false),
103  encapsulated_space_(encapsulated_space),
104  record_fields_(),
105  user_context_(),
106  option_space_name_(space) {
107 }
108 
110 OptionDefinition::create(const std::string& name,
111  const uint16_t code,
112  const std::string& space,
113  const std::string& type,
114  const bool array_type) {
115  return (boost::make_shared<OptionDefinition>(name, code, space, type, array_type));
116 }
117 
119 OptionDefinition::create(const std::string& name,
120  const uint16_t code,
121  const std::string& space,
122  const OptionDataType type,
123  const bool array_type) {
124  return (boost::make_shared<OptionDefinition>(name, code, space, type, array_type));
125 }
126 
128 OptionDefinition::create(const std::string& name,
129  const uint16_t code,
130  const std::string& space,
131  const std::string& type,
132  const char* encapsulated_space) {
133  return (boost::make_shared<OptionDefinition>(name, code, space, type, encapsulated_space));
134 }
135 
137 OptionDefinition::create(const std::string& name,
138  const uint16_t code,
139  const std::string& space,
140  const OptionDataType type,
141  const char* encapsulated_space) {
142  return (boost::make_shared<OptionDefinition>(name, code, space, type, encapsulated_space));
143 }
144 
145 bool
147  return (name_ == other.name_ &&
148  code_ == other.code_ &&
149  type_ == other.type_ &&
150  array_type_ == other.array_type_ &&
151  encapsulated_space_ == other.encapsulated_space_ &&
152  record_fields_ == other.record_fields_ &&
153  option_space_name_ == other.option_space_name_);
154 }
155 
156 void
157 OptionDefinition::addRecordField(const std::string& data_type_name) {
158  OptionDataType data_type = OptionDataTypeUtil::getDataType(data_type_name);
159  addRecordField(data_type);
160 }
161 
162 void
164  if (type_ != OPT_RECORD_TYPE) {
166  "'record' option type must be used instead of '"
168  << "' to add data fields to the record");
169  }
170  if (data_type >= OPT_RECORD_TYPE ||
171  data_type == OPT_ANY_ADDRESS_TYPE ||
172  data_type == OPT_EMPTY_TYPE) {
174  "attempted to add invalid data type '"
176  << "' to the record.");
177  }
178  record_fields_.push_back(data_type);
179 }
180 
181 OptionPtr
183  OptionBufferConstIter begin,
184  OptionBufferConstIter end) const {
185 
186  try {
187  // Some of the options are represented by the specialized classes derived
188  // from Option class (e.g. IA_NA, IAADDR). Although, they can be also
189  // represented by the generic classes, we want the object of the specialized
190  // type to be returned. Therefore, we first check that if we are dealing
191  // with such an option. If the instance is returned we just exit at this
192  // point. If not, we will search for a generic option type to return.
193  OptionPtr option = factorySpecialFormatOption(u, begin, end);
194  if (option) {
195  return (option);
196  }
197 
198  switch (type_) {
199  case OPT_EMPTY_TYPE:
200  if (getEncapsulatedSpace().empty()) {
201  return (factoryEmpty(u, type));
202  } else {
203  return (OptionPtr(new OptionCustom(*this, u, begin, end)));
204  }
205 
206  case OPT_BINARY_TYPE:
207  return (factoryGeneric(u, type, begin, end));
208 
209  case OPT_UINT8_TYPE:
210  return (array_type_ ?
211  factoryIntegerArray<uint8_t>(u, type, begin, end) :
212  factoryInteger<uint8_t>(u, type, getEncapsulatedSpace(),
213  begin, end));
214 
215  case OPT_INT8_TYPE:
216  return (array_type_ ?
217  factoryIntegerArray<int8_t>(u, type, begin, end) :
218  factoryInteger<int8_t>(u, type, getEncapsulatedSpace(),
219  begin, end));
220 
221  case OPT_UINT16_TYPE:
222  return (array_type_ ?
223  factoryIntegerArray<uint16_t>(u, type, begin, end) :
224  factoryInteger<uint16_t>(u, type, getEncapsulatedSpace(),
225  begin, end));
226 
227  case OPT_INT16_TYPE:
228  return (array_type_ ?
229  factoryIntegerArray<uint16_t>(u, type, begin, end) :
230  factoryInteger<int16_t>(u, type, getEncapsulatedSpace(),
231  begin, end));
232 
233  case OPT_UINT32_TYPE:
234  return (array_type_ ?
235  factoryIntegerArray<uint32_t>(u, type, begin, end) :
236  factoryInteger<uint32_t>(u, type, getEncapsulatedSpace(),
237  begin, end));
238 
239  case OPT_INT32_TYPE:
240  return (array_type_ ?
241  factoryIntegerArray<uint32_t>(u, type, begin, end) :
242  factoryInteger<int32_t>(u, type, getEncapsulatedSpace(),
243  begin, end));
244 
246  // If definition specifies that an option is an array
247  // of IPv4 addresses we return an instance of specialized
248  // class (OptionAddrLst4). For non-array types there is no
249  // specialized class yet implemented so we drop through
250  // to return an instance of OptionCustom.
251  if (array_type_) {
252  return (factoryAddrList4(type, begin, end));
253  }
254  break;
255 
257  // Handle array type only here (see comments for
258  // OPT_IPV4_ADDRESS_TYPE case).
259  if (array_type_) {
260  return (factoryAddrList6(type, begin, end));
261  }
262  break;
263 
264  case OPT_STRING_TYPE:
265  return (OptionPtr(new OptionString(u, type, begin, end)));
266 
267  case OPT_TUPLE_TYPE:
268  // Handle array type only here (see comments for
269  // OPT_IPV4_ADDRESS_TYPE case).
270  if (array_type_) {
271  return (factoryOpaqueDataTuples(u, type, begin, end));
272  }
273  break;
274 
275  default:
276  // Do nothing. We will return generic option a few lines down.
277  ;
278  }
279  return (OptionPtr(new OptionCustom(*this, u, begin, end)));
280  } catch (const SkipThisOptionError&) {
281  // We need to throw this one as is.
282  throw;
283  } catch (const SkipRemainingOptionsError&) {
284  // We need to throw this one as is.
285  throw;
286  } catch (const Exception& ex) {
288  }
289 }
290 
291 OptionPtr
293  const OptionBuffer& buf) const {
294  return (optionFactory(u, type, buf.begin(), buf.end()));
295 }
296 
297 OptionPtr
299  const std::vector<std::string>& values) const {
300  OptionBuffer buf;
301  if (!array_type_ && type_ != OPT_RECORD_TYPE) {
302  if (values.empty()) {
303  if (type_ != OPT_EMPTY_TYPE) {
304  isc_throw(InvalidOptionValue, "no option value specified");
305  }
306  } else {
307  writeToBuffer(u, util::str::trim(values[0]), type_, buf);
308  }
309  } else if (array_type_ && type_ != OPT_RECORD_TYPE) {
310  for (size_t i = 0; i < values.size(); ++i) {
311  writeToBuffer(u, util::str::trim(values[i]), type_, buf);
312  }
313  } else if (type_ == OPT_RECORD_TYPE) {
314  const RecordFieldsCollection& records = getRecordFields();
315  if (records.size() > values.size()) {
316  isc_throw(InvalidOptionValue, "number of data fields for the option"
317  << " type '" << getCode() << "' is greater than number"
318  << " of values provided.");
319  }
320  for (size_t i = 0; i < records.size(); ++i) {
321  writeToBuffer(u, util::str::trim(values[i]), records[i], buf);
322  }
323  if (array_type_ && (values.size() > records.size())) {
324  for (size_t i = records.size(); i < values.size(); ++i) {
325  writeToBuffer(u, util::str::trim(values[i]),
326  records.back(), buf);
327  }
328  }
329  }
330  return (optionFactory(u, type, buf.begin(), buf.end()));
331 }
332 
333 void
335 
336  using namespace boost::algorithm;
337 
338  std::ostringstream err_str;
339 
340  // Allowed characters in the option name are: lower or
341  // upper case letters, digits, underscores and hyphens.
342  // Empty option spaces are not allowed.
343  if (!all(name_, boost::is_from_range('a', 'z') ||
344  boost::is_from_range('A', 'Z') ||
345  boost::is_digit() ||
346  boost::is_any_of(std::string("-_"))) ||
347  name_.empty() ||
348  // Hyphens and underscores are not allowed at the beginning
349  // and at the end of the option name.
350  all(find_head(name_, 1), boost::is_any_of(std::string("-_"))) ||
351  all(find_tail(name_, 1), boost::is_any_of(std::string("-_")))) {
352  err_str << "invalid option name '" << name_ << "'";
353 
354  } else if (!OptionSpace::validateName(option_space_name_)) {
355  err_str << "invalid option space name: '"
356  << option_space_name_ << "'";
357 
358  } else if (!encapsulated_space_.empty() &&
359  !OptionSpace::validateName(encapsulated_space_)) {
360  err_str << "invalid encapsulated option space name: '"
361  << encapsulated_space_ << "'";
362 
363  } else if (type_ >= OPT_UNKNOWN_TYPE) {
364  // Option definition must be of a known type.
365  err_str << "option type " << type_ << " not supported.";
366 
367  } else if (type_ == OPT_RECORD_TYPE) {
368  // At least two data fields should be added to the record. Otherwise
369  // non-record option definition could be used.
370  if (getRecordFields().size() < 2) {
371  err_str << "invalid number of data fields: "
372  << getRecordFields().size()
373  << " specified for the option of type 'record'. Expected at"
374  << " least 2 fields.";
375 
376  } else {
377  // If the number of fields is valid we have to check if their order
378  // is valid too. We check that string or binary data fields are not
379  // laid before other fields. But we allow that they are laid at the
380  // end of an option.
381  const RecordFieldsCollection& fields = getRecordFields();
382  for (RecordFieldsConstIter it = fields.begin();
383  it != fields.end(); ++it) {
384  if (*it == OPT_STRING_TYPE &&
385  it < fields.end() - 1) {
386  err_str << "string data field can't be laid before data"
387  << " fields of other types.";
388  break;
389  }
390  if (*it == OPT_BINARY_TYPE &&
391  it < fields.end() - 1) {
392  err_str << "binary data field can't be laid before data"
393  << " fields of other types.";
394  break;
395  }
396  // Empty type is not allowed within a record.
397  if (*it == OPT_EMPTY_TYPE) {
398  err_str << "empty data type can't be stored as a field in"
399  << " an option record.";
400  break;
401  }
402  }
403  // If the array flag is set the last field is an array.
404  if (err_str.str().empty() && array_type_) {
405  const OptionDataType& last_type = fields.back();
406  if (last_type == OPT_STRING_TYPE) {
407  err_str
408  << "array of strings is not a valid option definition.";
409  } else if (last_type == OPT_BINARY_TYPE) {
410  err_str << "array of binary values is not a valid option "
411  "definition.";
412  }
413  // Empty type was already checked.
414  }
415  }
416 
417  } else if (array_type_) {
418  if (type_ == OPT_STRING_TYPE) {
419  // Array of strings is not allowed because there is no way
420  // to determine the size of a particular string and thus there
421  // it no way to tell when other data fields begin.
422  err_str << "array of strings is not a valid option definition.";
423  } else if (type_ == OPT_BINARY_TYPE) {
424  err_str << "array of binary values is not"
425  << " a valid option definition.";
426 
427  } else if (type_ == OPT_EMPTY_TYPE) {
428  err_str << "array of empty value is not"
429  << " a valid option definition.";
430 
431  }
432  }
433 
434  // Non-empty error string means that we have hit the error. We throw
435  // exception and include error string.
436  if (!err_str.str().empty()) {
437  isc_throw(MalformedOptionDefinition, err_str.str());
438  }
439 }
440 
441 bool
442 OptionDefinition::haveCompressedFqdnListFormat() const {
443  return (haveType(OPT_FQDN_TYPE) && getArrayType());
444 }
445 
446 bool
447 OptionDefinition::convertToBool(const std::string& value_str) const {
448  // Case-insensitive check that the input is one of: "true" or "false".
449  if (boost::iequals(value_str, "true")) {
450  return (true);
451 
452  } else if (boost::iequals(value_str, "false")) {
453  return (false);
454 
455  }
456 
457  // The input string is neither "true" nor "false", so let's check
458  // if it is not an integer wrapped in a string.
459  int result;
460  try {
461  result = boost::lexical_cast<int>(value_str);
462 
463  } catch (const boost::bad_lexical_cast&) {
464  isc_throw(BadDataTypeCast, "unable to covert the value '"
465  << value_str << "' to boolean data type");
466  }
467  // The boolean value is encoded in DHCP option as 0 or 1. Therefore,
468  // we only allow a user to specify those values for options which
469  // have boolean fields.
470  if (result != 1 && result != 0) {
471  isc_throw(BadDataTypeCast, "unable to convert '" << value_str
472  << "' to boolean data type");
473  }
474  return (static_cast<bool>(result));
475 }
476 
477 template<typename T>
478 T
479 OptionDefinition::lexicalCastWithRangeCheck(const std::string& value_str)
480  const {
481  // The lexical cast should be attempted when converting to an integer
482  // value only.
484  isc_throw(BadDataTypeCast,
485  "must not convert '" << value_str
486  << "' to non-integer data type");
487  }
488 
489  // We use the 64-bit value here because it has wider range than
490  // any other type we use here and it allows to detect out of
491  // bounds conditions e.g. negative value specified for uintX_t
492  // data type. Obviously if the value exceeds the limits of int64
493  // this function will not handle that properly.
494  int64_t result = 0;
495  try {
496  result = boost::lexical_cast<int64_t>(value_str);
497 
498  } catch (const boost::bad_lexical_cast&) {
499  // boost::lexical_cast does not handle hexadecimal
500  // but stringstream does so do it the hard way.
501  std::stringstream ss;
502  ss << std::hex << value_str;
503  ss >> result;
504  if (ss.fail() || !ss.eof()) {
505  isc_throw(BadDataTypeCast, "unable to convert the value '"
506  << value_str << "' to integer data type");
507  }
508  }
509  // Perform range checks.
511  if (result > numeric_limits<T>::max() ||
512  result < numeric_limits<T>::min()) {
513  isc_throw(BadDataTypeCast, "unable to convert '"
514  << value_str << "' to numeric type. This value is "
515  "expected to be in the range of "
516  << +numeric_limits<T>::min() << ".."
517  << +numeric_limits<T>::max());
518  }
519  }
520  return (static_cast<T>(result));
521 }
522 
523 void
524 OptionDefinition::writeToBuffer(Option::Universe u,
525  const std::string& value,
526  const OptionDataType type,
527  OptionBuffer& buf) const {
528  // We are going to write value given by value argument to the buffer.
529  // The actual type of the value is given by second argument. Check
530  // this argument to determine how to write this value to the buffer.
531  switch (type) {
532  case OPT_BINARY_TYPE:
534  return;
535  case OPT_BOOLEAN_TYPE:
536  // We encode the true value as 1 and false as 0 on 8 bits.
537  // That way we actually waste 7 bits but it seems to be the
538  // simpler way to encode boolean.
539  // @todo Consider if any other encode methods can be used.
540  OptionDataTypeUtil::writeBool(convertToBool(value), buf);
541  return;
542  case OPT_INT8_TYPE:
543  OptionDataTypeUtil::writeInt<uint8_t>
544  (lexicalCastWithRangeCheck<int8_t>(value),
545  buf);
546  return;
547  case OPT_INT16_TYPE:
548  OptionDataTypeUtil::writeInt<uint16_t>
549  (lexicalCastWithRangeCheck<int16_t>(value),
550  buf);
551  return;
552  case OPT_INT32_TYPE:
553  OptionDataTypeUtil::writeInt<uint32_t>
554  (lexicalCastWithRangeCheck<int32_t>(value),
555  buf);
556  return;
557  case OPT_UINT8_TYPE:
558  OptionDataTypeUtil::writeInt<uint8_t>
559  (lexicalCastWithRangeCheck<uint8_t>(value),
560  buf);
561  return;
562  case OPT_UINT16_TYPE:
563  OptionDataTypeUtil::writeInt<uint16_t>
564  (lexicalCastWithRangeCheck<uint16_t>(value),
565  buf);
566  return;
567  case OPT_UINT32_TYPE:
568  OptionDataTypeUtil::writeInt<uint32_t>
569  (lexicalCastWithRangeCheck<uint32_t>(value),
570  buf);
571  return;
574  {
575  asiolink::IOAddress address(value);
576  if (!address.isV4() && !address.isV6()) {
577  isc_throw(BadDataTypeCast, "provided address "
578  << address
579  << " is not a valid IPv4 or IPv6 address.");
580  }
581  OptionDataTypeUtil::writeAddress(address, buf);
582  return;
583  }
585  {
586  std::string txt = value;
587 
588  // first let's remove any whitespaces
589  boost::erase_all(txt, " "); // space
590  boost::erase_all(txt, "\t"); // tabulation
591 
592  // Is this prefix/len notation?
593  size_t pos = txt.find("/");
594 
595  if (pos == string::npos) {
596  isc_throw(BadDataTypeCast, "provided address/prefix "
597  << value
598  << " is not valid.");
599  }
600 
601  std::string txt_address = txt.substr(0, pos);
602  isc::asiolink::IOAddress address = isc::asiolink::IOAddress(txt_address);
603  if (!address.isV6()) {
604  isc_throw(BadDataTypeCast, "provided address "
605  << txt_address
606  << " is not a valid IPv4 or IPv6 address.");
607  }
608 
609  std::string txt_prefix = txt.substr(pos + 1);
610  uint8_t len = 0;
611  try {
612  // start with the first character after /
613  len = lexicalCastWithRangeCheck<uint8_t>(txt_prefix);
614  } catch (...) {
615  isc_throw(BadDataTypeCast, "provided prefix "
616  << txt_prefix
617  << " is not valid.");
618  }
619 
620  // Write a prefix.
621  OptionDataTypeUtil::writePrefix(PrefixLen(len), address, buf);
622 
623  return;
624  }
625  case OPT_PSID_TYPE:
626  {
627  std::string txt = value;
628 
629  // first let's remove any whitespaces
630  boost::erase_all(txt, " "); // space
631  boost::erase_all(txt, "\t"); // tabulation
632 
633  // Is this prefix/len notation?
634  size_t pos = txt.find("/");
635 
636  if (pos == string::npos) {
637  isc_throw(BadDataTypeCast, "provided PSID value "
638  << value << " is not valid");
639  }
640 
641  const std::string txt_psid = txt.substr(0, pos);
642  const std::string txt_psid_len = txt.substr(pos + 1);
643 
644  uint16_t psid = 0;
645  uint8_t psid_len = 0;
646 
647  try {
648  psid = lexicalCastWithRangeCheck<uint16_t>(txt_psid);
649  } catch (...) {
650  isc_throw(BadDataTypeCast, "provided PSID "
651  << txt_psid << " is not valid");
652  }
653 
654  try {
655  psid_len = lexicalCastWithRangeCheck<uint8_t>(txt_psid_len);
656  } catch (...) {
657  isc_throw(BadDataTypeCast, "provided PSID length "
658  << txt_psid_len << " is not valid");
659  }
660 
661  OptionDataTypeUtil::writePsid(PSIDLen(psid_len), PSID(psid), buf);
662  return;
663  }
664  case OPT_STRING_TYPE:
666  return;
667  case OPT_FQDN_TYPE:
668  OptionDataTypeUtil::writeFqdn(value, buf);
669  return;
670  case OPT_TUPLE_TYPE:
671  {
672  // In case of V4_SZTP_REDIRECT option #143, bootstrap-server-list is formatted
673  // as a list of tuples "uri-length;URI" where uri-length is coded on 2 octets,
674  // which is not typical for V4 Universe.
678  OptionDataTypeUtil::writeTuple(value, lft, buf);
679  return;
680  }
681  default:
682  // We hit this point because invalid option data type has been specified
683  // This may be the case because 'empty' or 'record' data type has been
684  // specified. We don't throw exception here because it will be thrown
685  // at the exit point from this function.
686  ;
687  }
688  isc_throw(isc::BadValue, "attempt to write invalid option data field type"
689  " into the option buffer: " << type);
690 
691 }
692 
693 OptionPtr
695  OptionBufferConstIter begin,
696  OptionBufferConstIter end) {
697  boost::shared_ptr<Option4AddrLst> option(new Option4AddrLst(type, begin,
698  end));
699  return (option);
700 }
701 
702 OptionPtr
704  OptionBufferConstIter begin,
705  OptionBufferConstIter end) {
706  boost::shared_ptr<Option6AddrLst> option(new Option6AddrLst(type, begin,
707  end));
708  return (option);
709 }
710 
711 
712 OptionPtr
714  OptionPtr option(new Option(u, type));
715  return (option);
716 }
717 
718 OptionPtr
720  OptionBufferConstIter begin,
721  OptionBufferConstIter end) {
722  OptionPtr option(new Option(u, type, begin, end));
723  return (option);
724 }
725 
726 OptionPtr
728  OptionBufferConstIter begin,
729  OptionBufferConstIter end) {
730  if (std::distance(begin, end) < Option6IA::OPTION6_IA_LEN) {
731  isc_throw(isc::OutOfRange, "input option buffer has invalid size,"
732  << " expected at least " << Option6IA::OPTION6_IA_LEN
733  << " bytes");
734  }
735  boost::shared_ptr<Option6IA> option(new Option6IA(type, begin, end));
736  return (option);
737 }
738 
739 OptionPtr
741  OptionBufferConstIter begin,
742  OptionBufferConstIter end) {
743  if (std::distance(begin, end) < Option6IAAddr::OPTION6_IAADDR_LEN) {
745  "input option buffer has invalid size, expected at least "
746  << Option6IAAddr::OPTION6_IAADDR_LEN << " bytes");
747  }
748  boost::shared_ptr<Option6IAAddr> option(new Option6IAAddr(type, begin,
749  end));
750  return (option);
751 }
752 
753 OptionPtr
755  OptionBufferConstIter begin,
756  OptionBufferConstIter end) {
757  if (std::distance(begin, end) < Option6IAPrefix::OPTION6_IAPREFIX_LEN) {
759  "input option buffer has invalid size, expected at least "
761  }
762  boost::shared_ptr<Option6IAPrefix> option(new Option6IAPrefix(type, begin,
763  end));
764  return (option);
765 }
766 
767 OptionPtr
769  uint16_t type,
770  OptionBufferConstIter begin,
771  OptionBufferConstIter end) {
772  boost::shared_ptr<OptionOpaqueDataTuples>
773  option(new OptionOpaqueDataTuples(u, type, begin, end));
774 
775  return (option);
776 }
777 
778 OptionPtr
780  uint16_t type,
781  OptionBufferConstIter begin,
783  OpaqueDataTuple::LengthFieldType length_field_type) {
784  boost::shared_ptr<OptionOpaqueDataTuples>
785  option(new OptionOpaqueDataTuples(u, type, begin, end, length_field_type));
786 
787  return (option);
788 }
789 
790 OptionPtr
791 OptionDefinition::factoryFqdnList(Option::Universe u,
792  OptionBufferConstIter begin,
793  OptionBufferConstIter end) const {
794 
795  const std::vector<uint8_t> data(begin, end);
796  if (data.empty()) {
797  isc_throw(InvalidOptionValue, "FQDN list option has invalid length of 0");
798  }
799  InputBuffer in_buf(static_cast<const void*>(&data[0]), data.size());
800  std::vector<uint8_t> out_buf;
801  out_buf.reserve(data.size());
802  while (in_buf.getPosition() < in_buf.getLength()) {
803  // Reuse readFqdn and writeFqdn code but on the whole buffer
804  // so the DNS name code handles compression for us.
805  try {
806  isc::dns::Name name(in_buf);
807  isc::dns::LabelSequence labels(name);
808  if (labels.getDataLength() > 0) {
809  size_t read_len = 0;
810  const uint8_t* label = labels.getData(&read_len);
811  out_buf.insert(out_buf.end(), label, label + read_len);
812  }
813  } catch (const isc::Exception& ex) {
814  isc_throw(InvalidOptionValue, ex.what());
815  }
816  }
817  return OptionPtr(new OptionCustom(*this, u,
818  out_buf.begin(), out_buf.end()));
819 }
820 
821 OptionPtr
822 OptionDefinition::factorySpecialFormatOption(Option::Universe u,
823  OptionBufferConstIter begin,
824  OptionBufferConstIter end) const {
825  if ((u == Option::V6) && haveSpace(DHCP6_OPTION_SPACE)) {
826  switch (getCode()) {
827  case D6O_IA_NA:
828  case D6O_IA_PD:
829  // Record of 3 uint32, no array.
830  return (factoryIA6(getCode(), begin, end));
831 
832  case D6O_IAADDR:
833  // Record of an IPv6 address followed by 2 uint32, no array.
834  return (factoryIAAddr6(getCode(), begin, end));
835 
836  case D6O_IAPREFIX:
837  // Record of 2 uint32, one uint8 and an IPv6 address, no array.
838  return (factoryIAPrefix6(getCode(), begin, end));
839 
840  case D6O_CLIENT_FQDN:
841  // Record of one uint8 and one FQDN, no array.
842  return (OptionPtr(new Option6ClientFqdn(begin, end)));
843 
844  case D6O_VENDOR_OPTS:
845  // Type uint32.
846  // Vendor-Specific Information (option code 17).
847  return (OptionPtr(new OptionVendor(Option::V6, begin, end)));
848 
849  case D6O_VENDOR_CLASS:
850  // Record of one uint32 and one string.
851  // Vendor Class (option code 16).
852  return (OptionPtr(new OptionVendorClass(Option::V6, begin, end)));
853 
854  case D6O_STATUS_CODE:
855  // Record of one uint16 and one string.
856  // Status Code (option code 13).
857  return (OptionPtr(new Option6StatusCode(begin, end)));
858 
859  case D6O_BOOTFILE_PARAM:
860  // Array of tuples.
861  // Bootfile params (option code 60).
862  return (factoryOpaqueDataTuples(Option::V6, getCode(), begin, end));
863 
864  case D6O_PD_EXCLUDE:
865  // Type IPv6 prefix.
866  // Prefix Exclude (option code 67),
867  return (OptionPtr(new Option6PDExclude(begin, end)));
868 
869  default:
870  break;
871  }
872  } else if ((u == Option::V4) && haveSpace(DHCP4_OPTION_SPACE)) {
873  switch (getCode()) {
874  case DHO_SERVICE_SCOPE:
875  // Record of a boolean and a string.
876  return (OptionPtr(new Option4SlpServiceScope(begin, end)));
877 
878  case DHO_FQDN:
879  // Record of 3 uint8 and a FQDN, no array.
880  return (OptionPtr(new Option4ClientFqdn(begin, end)));
881 
883  // Record of uint32 followed by binary.
884  // V-I Vendor Class (option code 124).
885  return (OptionPtr(new OptionVendorClass(Option::V4, begin, end)));
886 
888  // Type uint32.
889  // Vendor-Specific Information (option code 125).
890  return (OptionPtr(new OptionVendor(Option::V4, begin, end)));
891 
893  // Array of tuples.
894  // DHCPv4 SZTP Redirect Option (option code 143).
896 
897  default:
898  break;
899  }
900  }
901  if ((u == Option::V4) && haveCompressedFqdnListFormat()) {
902  return (factoryFqdnList(Option::V4, begin, end));
903  }
904  return (OptionPtr());
905 }
906 
907 } // end of isc::dhcp namespace
908 } // end of isc namespace
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
This is a base class for exceptions thrown from the DNS library module.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown if a function is called in a prohibited way.
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
Exception to be thrown when invalid option value has been specified for a particular option definitio...
Exception to be thrown when option definition is invalid.
LengthFieldType
Size of the length field in the tuple.
DHCPv4 Option class for handling list of IPv4 addresses.
DHCPv6 Option class for handling list of IPv6 addresses.
static const size_t OPTION6_IAADDR_LEN
length of the fixed part of the IAADDR option
Class that represents IAPREFIX option in DHCPv6.
static const size_t OPTION6_IAPREFIX_LEN
length of the fixed part of the IAPREFIX option
static const size_t OPTION6_IA_LEN
Length of IA_NA and IA_PD content.
Definition: option6_ia.h:26
Option with defined data fields represented as buffers that can be accessed using data field index.
Definition: option_custom.h:32
Utility class for option data types.
static void writeFqdn(const std::string &fqdn, std::vector< uint8_t > &buf, const bool downcase=false)
Append FQDN into a buffer.
static void writePrefix(const PrefixLen &prefix_len, const asiolink::IOAddress &prefix, std::vector< uint8_t > &buf)
Append prefix into a buffer.
static const std::string & getDataTypeName(const OptionDataType data_type)
Return option data type name from the data type enumerator.
static OptionDataType getDataType(const std::string &data_type)
Return option data type from its name.
static void writeBinary(const std::string &hex_str, std::vector< uint8_t > &buf)
Append hex-encoded binary values to a buffer.
static void writeAddress(const asiolink::IOAddress &address, std::vector< uint8_t > &buf)
Append IPv4 or IPv6 address to a buffer.
static void writePsid(const PSIDLen &psid_len, const PSID &psid, std::vector< uint8_t > &buf)
Append PSID length/value into a buffer.
static void writeString(const std::string &value, std::vector< uint8_t > &buf)
Write UTF8-encoded string into a buffer.
static void writeTuple(const std::string &value, OpaqueDataTuple::LengthFieldType lengthfieldtype, std::vector< uint8_t > &buf)
Append length and string tuple to a buffer.
static OpaqueDataTuple::LengthFieldType getTupleLenFieldType(Option::Universe u)
Returns Length Field Type for a tuple.
static void writeBool(const bool value, std::vector< uint8_t > &buf)
Append boolean value into a buffer.
Base class representing a DHCP option definition.
uint16_t getCode() const
Return option code.
OptionPtr optionFactory(Option::Universe u, uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end) const
Option factory.
static OptionPtr factoryEmpty(Option::Universe u, uint16_t type)
Empty option factory.
static OptionPtr factoryIAPrefix6(uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end)
Factory for IAPREFIX-type of option.
OptionDefinition(const std::string &name, const uint16_t code, const std::string &space, const std::string &type, const bool array_type=false)
Constructor.
static OptionPtr factoryAddrList6(uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end)
Factory to create option with address list.
static OptionPtr factoryAddrList4(uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end)
Factory to create option with address list.
const RecordFieldsCollection & getRecordFields() const
Return list of record fields.
std::vector< OptionDataType >::const_iterator RecordFieldsConstIter
Const iterator for record data fields.
static OptionPtr factoryIAAddr6(uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end)
Factory for IAADDR-type of option.
void addRecordField(const std::string &data_type_name)
Adds data field to the record.
bool equals(const OptionDefinition &other) const
Check if option definition is equal to other.
void validate() const
Check if the option definition is valid.
std::vector< OptionDataType > RecordFieldsCollection
List of fields within the record.
static OptionPtr factoryIA6(uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end)
Factory for IA-type of option.
std::string getEncapsulatedSpace() const
Return name of the encapsulated option space.
static OptionDefinitionPtr create(const std::string &name, const uint16_t code, const std::string &space, const std::string &type, const bool array_type=false)
Factory function creating an instance of the OptionDefinition.
static OptionPtr factoryOpaqueDataTuples(Option::Universe u, uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end)
Factory to create option with tuple list.
bool getArrayType() const
Return array type indicator.
static OptionPtr factoryGeneric(Option::Universe u, uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end)
Factory to create generic option.
This class encapsulates a collection of data tuples and could be used by multiple options.
static bool validateName(const std::string &name)
Checks that the provided option space name is valid.
Definition: option_space.cc:26
Class which represents an option carrying a single string value.
Definition: option_string.h:28
Universe
defines option universe DHCPv4 or DHCPv6
Definition: option.h:83
Exception thrown during option unpacking This exception is thrown when an error has occurred,...
Definition: option.h:52
Exception thrown during option unpacking This exception is thrown when an error has occurred unpackin...
Definition: option.h:67
Light-weight Accessor to Name data.
Definition: labelsequence.h:35
The Name class encapsulates DNS names.
Definition: name.h:223
The InputBuffer class is a buffer abstraction for manipulating read-only data.
Definition: buffer.h:81
@ D6O_CLIENT_FQDN
Definition: dhcp6.h:59
@ D6O_VENDOR_OPTS
Definition: dhcp6.h:37
@ D6O_BOOTFILE_PARAM
Definition: dhcp6.h:80
@ D6O_IA_NA
Definition: dhcp6.h:23
@ D6O_PD_EXCLUDE
Definition: dhcp6.h:87
@ D6O_IA_PD
Definition: dhcp6.h:45
@ D6O_IAADDR
Definition: dhcp6.h:25
@ D6O_VENDOR_CLASS
Definition: dhcp6.h:36
@ D6O_STATUS_CODE
Definition: dhcp6.h:33
@ D6O_IAPREFIX
Definition: dhcp6.h:46
const Name & name_
Definition: dns/message.cc:693
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
OptionDataType
Data types of DHCP option fields.
@ DHO_V4_SZTP_REDIRECT
Definition: dhcp4.h:200
@ DHO_SERVICE_SCOPE
Definition: dhcp4.h:148
@ DHO_VIVCO_SUBOPTIONS
Definition: dhcp4.h:189
@ DHO_FQDN
Definition: dhcp4.h:150
@ DHO_VIVSO_SUBOPTIONS
Definition: dhcp4.h:190
OptionBuffer::const_iterator OptionBufferConstIter
const_iterator for walking over OptionBuffer
Definition: option.h:30
boost::shared_ptr< OptionDefinition > OptionDefinitionPtr
Pointer to option definition object.
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
Definition: option.h:24
boost::shared_ptr< Option > OptionPtr
Definition: option.h:36
string trim(const string &instring)
Trim Leading and Trailing Spaces.
Definition: strutil.cc:53
Definition: edns.h:19
Defines the logger used by the top-level component of kea-lfc.
uint16_t code_
#define DHCP4_OPTION_SPACE
global std option spaces
#define DHCP6_OPTION_SPACE