option_definition.cc 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875
  1. // Copyright (C) 2012-2017 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. #include <config.h>
  7. #include <dhcp/dhcp4.h>
  8. #include <dhcp/dhcp6.h>
  9. #include <dhcp/option4_addrlst.h>
  10. #include <dhcp/option4_client_fqdn.h>
  11. #include <dhcp/option6_addrlst.h>
  12. #include <dhcp/option6_client_fqdn.h>
  13. #include <dhcp/option6_ia.h>
  14. #include <dhcp/option6_iaaddr.h>
  15. #include <dhcp/option6_iaprefix.h>
  16. #include <dhcp/option6_pdexclude.h>
  17. #include <dhcp/option6_status_code.h>
  18. #include <dhcp/option_custom.h>
  19. #include <dhcp/option_definition.h>
  20. #include <dhcp/option_int.h>
  21. #include <dhcp/option_int_array.h>
  22. #include <dhcp/option_opaque_data_tuples.h>
  23. #include <dhcp/option_string.h>
  24. #include <dhcp/option_vendor.h>
  25. #include <dhcp/option_vendor_class.h>
  26. #include <util/encode/hex.h>
  27. #include <dns/labelsequence.h>
  28. #include <dns/name.h>
  29. #include <util/strutil.h>
  30. #include <boost/algorithm/string/classification.hpp>
  31. #include <boost/algorithm/string/predicate.hpp>
  32. #include <boost/dynamic_bitset.hpp>
  33. #include <sstream>
  34. using namespace std;
  35. using namespace isc::util;
  36. namespace isc {
  37. namespace dhcp {
  38. OptionDefinition::OptionDefinition(const std::string& name,
  39. const uint16_t code,
  40. const std::string& type,
  41. const bool array_type /* = false */)
  42. : name_(name),
  43. code_(code),
  44. type_(OPT_UNKNOWN_TYPE),
  45. array_type_(array_type),
  46. encapsulated_space_("") {
  47. // Data type is held as enum value by this class.
  48. // Use the provided option type string to get the
  49. // corresponding enum value.
  50. type_ = OptionDataTypeUtil::getDataType(type);
  51. }
  52. OptionDefinition::OptionDefinition(const std::string& name,
  53. const uint16_t code,
  54. const OptionDataType type,
  55. const bool array_type /* = false */)
  56. : name_(name),
  57. code_(code),
  58. type_(type),
  59. array_type_(array_type),
  60. encapsulated_space_("") {
  61. }
  62. OptionDefinition::OptionDefinition(const std::string& name,
  63. const uint16_t code,
  64. const std::string& type,
  65. const char* encapsulated_space)
  66. : name_(name),
  67. code_(code),
  68. // Data type is held as enum value by this class.
  69. // Use the provided option type string to get the
  70. // corresponding enum value.
  71. type_(OptionDataTypeUtil::getDataType(type)),
  72. array_type_(false),
  73. encapsulated_space_(encapsulated_space) {
  74. }
  75. OptionDefinition::OptionDefinition(const std::string& name,
  76. const uint16_t code,
  77. const OptionDataType type,
  78. const char* encapsulated_space)
  79. : name_(name),
  80. code_(code),
  81. type_(type),
  82. array_type_(false),
  83. encapsulated_space_(encapsulated_space) {
  84. }
  85. bool
  86. OptionDefinition::equals(const OptionDefinition& other) const {
  87. return (name_ == other.name_ &&
  88. code_ == other.code_ &&
  89. type_ == other.type_ &&
  90. array_type_ == other.array_type_ &&
  91. encapsulated_space_ == other.encapsulated_space_ &&
  92. record_fields_ == other.record_fields_);
  93. }
  94. void
  95. OptionDefinition::addRecordField(const std::string& data_type_name) {
  96. OptionDataType data_type = OptionDataTypeUtil::getDataType(data_type_name);
  97. addRecordField(data_type);
  98. }
  99. void
  100. OptionDefinition::addRecordField(const OptionDataType data_type) {
  101. if (type_ != OPT_RECORD_TYPE) {
  102. isc_throw(isc::InvalidOperation, "'record' option type must be used"
  103. " to add data fields to the record");
  104. }
  105. if (data_type >= OPT_RECORD_TYPE ||
  106. data_type == OPT_ANY_ADDRESS_TYPE ||
  107. data_type == OPT_EMPTY_TYPE) {
  108. isc_throw(isc::BadValue,
  109. "attempted to add invalid data type to the record.");
  110. }
  111. record_fields_.push_back(data_type);
  112. }
  113. OptionPtr
  114. OptionDefinition::optionFactory(Option::Universe u, uint16_t type,
  115. OptionBufferConstIter begin,
  116. OptionBufferConstIter end) const {
  117. try {
  118. // Some of the options are represented by the specialized classes derived
  119. // from Option class (e.g. IA_NA, IAADDR). Although, they can be also
  120. // represented by the generic classes, we want the object of the specialized
  121. // type to be returned. Therefore, we first check that if we are dealing
  122. // with such an option. If the instance is returned we just exit at this
  123. // point. If not, we will search for a generic option type to return.
  124. OptionPtr option = factorySpecialFormatOption(u, begin, end);
  125. if (option) {
  126. return (option);
  127. }
  128. switch(type_) {
  129. case OPT_EMPTY_TYPE:
  130. if (getEncapsulatedSpace().empty()) {
  131. return (factoryEmpty(u, type));
  132. } else {
  133. return (OptionPtr(new OptionCustom(*this, u, begin, end)));
  134. }
  135. case OPT_BINARY_TYPE:
  136. return (factoryGeneric(u, type, begin, end));
  137. case OPT_UINT8_TYPE:
  138. return (array_type_ ?
  139. factoryIntegerArray<uint8_t>(u, type, begin, end) :
  140. factoryInteger<uint8_t>(u, type, getEncapsulatedSpace(),
  141. begin, end));
  142. case OPT_INT8_TYPE:
  143. return (array_type_ ?
  144. factoryIntegerArray<int8_t>(u, type, begin, end) :
  145. factoryInteger<int8_t>(u, type, getEncapsulatedSpace(),
  146. begin, end));
  147. case OPT_UINT16_TYPE:
  148. return (array_type_ ?
  149. factoryIntegerArray<uint16_t>(u, type, begin, end) :
  150. factoryInteger<uint16_t>(u, type, getEncapsulatedSpace(),
  151. begin, end));
  152. case OPT_INT16_TYPE:
  153. return (array_type_ ?
  154. factoryIntegerArray<uint16_t>(u, type, begin, end) :
  155. factoryInteger<int16_t>(u, type, getEncapsulatedSpace(),
  156. begin, end));
  157. case OPT_UINT32_TYPE:
  158. return (array_type_ ?
  159. factoryIntegerArray<uint32_t>(u, type, begin, end) :
  160. factoryInteger<uint32_t>(u, type, getEncapsulatedSpace(),
  161. begin, end));
  162. case OPT_INT32_TYPE:
  163. return (array_type_ ?
  164. factoryIntegerArray<uint32_t>(u, type, begin, end) :
  165. factoryInteger<int32_t>(u, type, getEncapsulatedSpace(),
  166. begin, end));
  167. case OPT_IPV4_ADDRESS_TYPE:
  168. // If definition specifies that an option is an array
  169. // of IPv4 addresses we return an instance of specialized
  170. // class (OptionAddrLst4). For non-array types there is no
  171. // specialized class yet implemented so we drop through
  172. // to return an instance of OptionCustom.
  173. if (array_type_) {
  174. return (factoryAddrList4(type, begin, end));
  175. }
  176. break;
  177. case OPT_IPV6_ADDRESS_TYPE:
  178. // Handle array type only here (see comments for
  179. // OPT_IPV4_ADDRESS_TYPE case).
  180. if (array_type_) {
  181. return (factoryAddrList6(type, begin, end));
  182. }
  183. break;
  184. case OPT_STRING_TYPE:
  185. return (OptionPtr(new OptionString(u, type, begin, end)));
  186. case OPT_TUPLE_TYPE:
  187. // Handle array type only here (see comments for
  188. // OPT_IPV4_ADDRESS_TYPE case).
  189. if (array_type_) {
  190. return (factoryOpaqueDataTuples(u, type, begin, end));
  191. }
  192. break;
  193. default:
  194. // Do nothing. We will return generic option a few lines down.
  195. ;
  196. }
  197. return (OptionPtr(new OptionCustom(*this, u, begin, end)));
  198. } catch (const Exception& ex) {
  199. isc_throw(InvalidOptionValue, ex.what());
  200. }
  201. }
  202. OptionPtr
  203. OptionDefinition::optionFactory(Option::Universe u, uint16_t type,
  204. const OptionBuffer& buf) const {
  205. return (optionFactory(u, type, buf.begin(), buf.end()));
  206. }
  207. OptionPtr
  208. OptionDefinition::optionFactory(Option::Universe u, uint16_t type,
  209. const std::vector<std::string>& values) const {
  210. OptionBuffer buf;
  211. if (!array_type_ && type_ != OPT_RECORD_TYPE) {
  212. if (values.empty()) {
  213. if (type_ != OPT_EMPTY_TYPE) {
  214. isc_throw(InvalidOptionValue, "no option value specified");
  215. }
  216. } else {
  217. writeToBuffer(u, util::str::trim(values[0]), type_, buf);
  218. }
  219. } else if (array_type_ && type_ != OPT_RECORD_TYPE) {
  220. for (size_t i = 0; i < values.size(); ++i) {
  221. writeToBuffer(u, util::str::trim(values[i]), type_, buf);
  222. }
  223. } else if (type_ == OPT_RECORD_TYPE) {
  224. const RecordFieldsCollection& records = getRecordFields();
  225. if (records.size() > values.size()) {
  226. isc_throw(InvalidOptionValue, "number of data fields for the option"
  227. << " type '" << getCode() << "' is greater than number"
  228. << " of values provided.");
  229. }
  230. for (size_t i = 0; i < records.size(); ++i) {
  231. writeToBuffer(u, util::str::trim(values[i]), records[i], buf);
  232. }
  233. }
  234. return (optionFactory(u, type, buf.begin(), buf.end()));
  235. }
  236. void
  237. OptionDefinition::validate() const {
  238. using namespace boost::algorithm;
  239. std::ostringstream err_str;
  240. // Allowed characters in the option name are: lower or
  241. // upper case letters, digits, underscores and hyphens.
  242. // Empty option spaces are not allowed.
  243. if (!all(name_, boost::is_from_range('a', 'z') ||
  244. boost::is_from_range('A', 'Z') ||
  245. boost::is_digit() ||
  246. boost::is_any_of(std::string("-_"))) ||
  247. name_.empty() ||
  248. // Hyphens and underscores are not allowed at the beginning
  249. // and at the end of the option name.
  250. all(find_head(name_, 1), boost::is_any_of(std::string("-_"))) ||
  251. all(find_tail(name_, 1), boost::is_any_of(std::string("-_")))) {
  252. err_str << "invalid option name '" << name_ << "'";
  253. } else if (!encapsulated_space_.empty() &&
  254. !OptionSpace::validateName(encapsulated_space_)) {
  255. err_str << "invalid encapsulated option space name: '"
  256. << encapsulated_space_ << "'";
  257. } else if (type_ >= OPT_UNKNOWN_TYPE) {
  258. // Option definition must be of a known type.
  259. err_str << "option type " << type_ << " not supported.";
  260. } else if (array_type_) {
  261. if (type_ == OPT_STRING_TYPE) {
  262. // Array of strings is not allowed because there is no way
  263. // to determine the size of a particular string and thus there
  264. // it no way to tell when other data fields begin.
  265. err_str << "array of strings is not a valid option definition.";
  266. } else if (type_ == OPT_BINARY_TYPE) {
  267. err_str << "array of binary values is not"
  268. << " a valid option definition.";
  269. } else if (type_ == OPT_EMPTY_TYPE) {
  270. err_str << "array of empty value is not"
  271. << " a valid option definition.";
  272. }
  273. } else if (type_ == OPT_RECORD_TYPE) {
  274. // At least two data fields should be added to the record. Otherwise
  275. // non-record option definition could be used.
  276. if (getRecordFields().size() < 2) {
  277. err_str << "invalid number of data fields: "
  278. << getRecordFields().size()
  279. << " specified for the option of type 'record'. Expected at"
  280. << " least 2 fields.";
  281. } else {
  282. // If the number of fields is valid we have to check if their order
  283. // is valid too. We check that string or binary data fields are not
  284. // laid before other fields. But we allow that they are laid at the
  285. // end of an option.
  286. const RecordFieldsCollection& fields = getRecordFields();
  287. for (RecordFieldsConstIter it = fields.begin();
  288. it != fields.end(); ++it) {
  289. if (*it == OPT_STRING_TYPE &&
  290. it < fields.end() - 1) {
  291. err_str << "string data field can't be laid before data"
  292. << " fields of other types.";
  293. break;
  294. }
  295. if (*it == OPT_BINARY_TYPE &&
  296. it < fields.end() - 1) {
  297. err_str << "binary data field can't be laid before data"
  298. << " fields of other types.";
  299. }
  300. /// Empty type is not allowed within a record.
  301. if (*it == OPT_EMPTY_TYPE) {
  302. err_str << "empty data type can't be stored as a field in"
  303. << " an option record.";
  304. break;
  305. }
  306. }
  307. }
  308. }
  309. // Non-empty error string means that we have hit the error. We throw
  310. // exception and include error string.
  311. if (!err_str.str().empty()) {
  312. isc_throw(MalformedOptionDefinition, err_str.str());
  313. }
  314. }
  315. bool
  316. OptionDefinition::haveIAx6Format(OptionDataType first_type) const {
  317. return (haveType(OPT_RECORD_TYPE) &&
  318. record_fields_.size() == 3 &&
  319. record_fields_[0] == first_type &&
  320. record_fields_[1] == OPT_UINT32_TYPE &&
  321. record_fields_[2] == OPT_UINT32_TYPE);
  322. }
  323. bool
  324. OptionDefinition::haveIA6Format() const {
  325. // Expect that IA_NA option format is defined as record.
  326. // Although it consists of 3 elements of the same (uint32)
  327. // type it can't be defined as array of uint32 elements because
  328. // arrays do not impose limitations on number of elements in
  329. // the array while this limitation is needed for IA_NA - need
  330. // exactly 3 elements.
  331. return (haveIAx6Format(OPT_UINT32_TYPE));
  332. }
  333. bool
  334. OptionDefinition::haveIAAddr6Format() const {
  335. return (haveIAx6Format(OPT_IPV6_ADDRESS_TYPE));
  336. }
  337. bool
  338. OptionDefinition::haveIAPrefix6Format() const {
  339. return (haveType(OPT_RECORD_TYPE) &&
  340. record_fields_.size() == 4 &&
  341. record_fields_[0] == OPT_UINT32_TYPE &&
  342. record_fields_[1] == OPT_UINT32_TYPE &&
  343. record_fields_[2] == OPT_UINT8_TYPE &&
  344. record_fields_[3] == OPT_IPV6_ADDRESS_TYPE);
  345. }
  346. bool
  347. OptionDefinition::haveFqdn4Format() const {
  348. return (haveType(OPT_RECORD_TYPE) &&
  349. record_fields_.size() == 4 &&
  350. record_fields_[0] == OPT_UINT8_TYPE &&
  351. record_fields_[1] == OPT_UINT8_TYPE &&
  352. record_fields_[2] == OPT_UINT8_TYPE &&
  353. record_fields_[3] == OPT_FQDN_TYPE);
  354. }
  355. bool
  356. OptionDefinition::haveClientFqdnFormat() const {
  357. return (haveType(OPT_RECORD_TYPE) &&
  358. (record_fields_.size() == 2) &&
  359. (record_fields_[0] == OPT_UINT8_TYPE) &&
  360. (record_fields_[1] == OPT_FQDN_TYPE));
  361. }
  362. bool
  363. OptionDefinition::haveVendor4Format() const {
  364. return (true);
  365. }
  366. bool
  367. OptionDefinition::haveVendor6Format() const {
  368. return (getType() == OPT_UINT32_TYPE && !getEncapsulatedSpace().empty());
  369. }
  370. bool
  371. OptionDefinition::haveVendorClass4Format() const {
  372. return (haveType(OPT_RECORD_TYPE) &&
  373. (record_fields_.size() == 2) &&
  374. (record_fields_[0] == OPT_UINT32_TYPE) &&
  375. (record_fields_[1] == OPT_BINARY_TYPE));
  376. }
  377. bool
  378. OptionDefinition::haveVendorClass6Format() const {
  379. return (haveType(OPT_RECORD_TYPE) &&
  380. (record_fields_.size() == 2) &&
  381. (record_fields_[0] == OPT_UINT32_TYPE) &&
  382. (record_fields_[1] == OPT_BINARY_TYPE));
  383. }
  384. bool
  385. OptionDefinition::haveStatusCodeFormat() const {
  386. return (haveType(OPT_RECORD_TYPE) &&
  387. (record_fields_.size() == 2) &&
  388. (record_fields_[0] == OPT_UINT16_TYPE) &&
  389. (record_fields_[1] == OPT_STRING_TYPE));
  390. }
  391. bool
  392. OptionDefinition::haveOpaqueDataTuplesFormat() const {
  393. return (haveType(OPT_TUPLE_TYPE) && getArrayType());
  394. }
  395. bool
  396. OptionDefinition::haveCompressedFqdnListFormat() const {
  397. return (haveType(OPT_FQDN_TYPE) && getArrayType());
  398. }
  399. bool
  400. OptionDefinition::convertToBool(const std::string& value_str) const {
  401. // Case-insensitive check that the input is one of: "true" or "false".
  402. if (boost::iequals(value_str, "true")) {
  403. return (true);
  404. } else if (boost::iequals(value_str, "false")) {
  405. return (false);
  406. }
  407. // The input string is neither "true" nor "false", so let's check
  408. // if it is not an integer wrapped in a string.
  409. int result;
  410. try {
  411. result = boost::lexical_cast<int>(value_str);
  412. } catch (const boost::bad_lexical_cast&) {
  413. isc_throw(BadDataTypeCast, "unable to covert the value '"
  414. << value_str << "' to boolean data type");
  415. }
  416. // The boolean value is encoded in DHCP option as 0 or 1. Therefore,
  417. // we only allow a user to specify those values for options which
  418. // have boolean fields.
  419. if (result != 1 && result != 0) {
  420. isc_throw(BadDataTypeCast, "unable to convert '" << value_str
  421. << "' to boolean data type");
  422. }
  423. return (static_cast<bool>(result));
  424. }
  425. template<typename T>
  426. T
  427. OptionDefinition::lexicalCastWithRangeCheck(const std::string& value_str)
  428. const {
  429. // The lexical cast should be attempted when converting to an integer
  430. // value only.
  431. if (!OptionDataTypeTraits<T>::integer_type) {
  432. isc_throw(BadDataTypeCast,
  433. "must not convert '" << value_str
  434. << "' to non-integer data type");
  435. }
  436. // We use the 64-bit value here because it has wider range than
  437. // any other type we use here and it allows to detect out of
  438. // bounds conditions e.g. negative value specified for uintX_t
  439. // data type. Obviously if the value exceeds the limits of int64
  440. // this function will not handle that properly.
  441. int64_t result = 0;
  442. try {
  443. result = boost::lexical_cast<int64_t>(value_str);
  444. } catch (const boost::bad_lexical_cast&) {
  445. // boost::lexical_cast does not handle hexadecimal
  446. // but stringstream does so do it the hard way.
  447. std::stringstream ss;
  448. ss << std::hex << value_str;
  449. ss >> result;
  450. if (ss.fail() || !ss.eof()) {
  451. isc_throw(BadDataTypeCast, "unable to convert the value '"
  452. << value_str << "' to integer data type");
  453. }
  454. }
  455. // Perform range checks.
  456. if (OptionDataTypeTraits<T>::integer_type) {
  457. if (result > numeric_limits<T>::max() ||
  458. result < numeric_limits<T>::min()) {
  459. isc_throw(BadDataTypeCast, "unable to convert '"
  460. << value_str << "' to numeric type. This value is "
  461. " expected to be in the range of "
  462. << numeric_limits<T>::min()
  463. << ".." << numeric_limits<T>::max());
  464. }
  465. }
  466. return (static_cast<T>(result));
  467. }
  468. void
  469. OptionDefinition::writeToBuffer(Option::Universe u,
  470. const std::string& value,
  471. const OptionDataType type,
  472. OptionBuffer& buf) const {
  473. // We are going to write value given by value argument to the buffer.
  474. // The actual type of the value is given by second argument. Check
  475. // this argument to determine how to write this value to the buffer.
  476. switch (type) {
  477. case OPT_BINARY_TYPE:
  478. OptionDataTypeUtil::writeBinary(value, buf);
  479. return;
  480. case OPT_BOOLEAN_TYPE:
  481. // We encode the true value as 1 and false as 0 on 8 bits.
  482. // That way we actually waste 7 bits but it seems to be the
  483. // simpler way to encode boolean.
  484. // @todo Consider if any other encode methods can be used.
  485. OptionDataTypeUtil::writeBool(convertToBool(value), buf);
  486. return;
  487. case OPT_INT8_TYPE:
  488. OptionDataTypeUtil::writeInt<uint8_t>
  489. (lexicalCastWithRangeCheck<int8_t>(value),
  490. buf);
  491. return;
  492. case OPT_INT16_TYPE:
  493. OptionDataTypeUtil::writeInt<uint16_t>
  494. (lexicalCastWithRangeCheck<int16_t>(value),
  495. buf);
  496. return;
  497. case OPT_INT32_TYPE:
  498. OptionDataTypeUtil::writeInt<uint32_t>
  499. (lexicalCastWithRangeCheck<int32_t>(value),
  500. buf);
  501. return;
  502. case OPT_UINT8_TYPE:
  503. OptionDataTypeUtil::writeInt<uint8_t>
  504. (lexicalCastWithRangeCheck<uint8_t>(value),
  505. buf);
  506. return;
  507. case OPT_UINT16_TYPE:
  508. OptionDataTypeUtil::writeInt<uint16_t>
  509. (lexicalCastWithRangeCheck<uint16_t>(value),
  510. buf);
  511. return;
  512. case OPT_UINT32_TYPE:
  513. OptionDataTypeUtil::writeInt<uint32_t>
  514. (lexicalCastWithRangeCheck<uint32_t>(value),
  515. buf);
  516. return;
  517. case OPT_IPV4_ADDRESS_TYPE:
  518. case OPT_IPV6_ADDRESS_TYPE:
  519. {
  520. asiolink::IOAddress address(value);
  521. if (!address.isV4() && !address.isV6()) {
  522. isc_throw(BadDataTypeCast, "provided address "
  523. << address
  524. << " is not a valid IPv4 or IPv6 address.");
  525. }
  526. OptionDataTypeUtil::writeAddress(address, buf);
  527. return;
  528. }
  529. case OPT_IPV6_PREFIX_TYPE:
  530. {
  531. std::string txt = value;
  532. // first let's remove any whitespaces
  533. boost::erase_all(txt, " "); // space
  534. boost::erase_all(txt, "\t"); // tabulation
  535. // Is this prefix/len notation?
  536. size_t pos = txt.find("/");
  537. if (pos == string::npos) {
  538. isc_throw(BadDataTypeCast, "provided address/prefix "
  539. << value
  540. << " is not valid.");
  541. }
  542. std::string txt_address = txt.substr(0, pos);
  543. isc::asiolink::IOAddress address = isc::asiolink::IOAddress(txt_address);
  544. if (!address.isV6()) {
  545. isc_throw(BadDataTypeCast, "provided address "
  546. << txt_address
  547. << " is not a valid IPv4 or IPv6 address.");
  548. }
  549. std::string txt_prefix = txt.substr(pos + 1);
  550. uint8_t len = 0;
  551. try {
  552. // start with the first character after /
  553. len = lexicalCastWithRangeCheck<uint8_t>(txt_prefix);
  554. } catch (...) {
  555. isc_throw(BadDataTypeCast, "provided prefix "
  556. << txt_prefix
  557. << " is not valid.");
  558. }
  559. // Write a prefix.
  560. OptionDataTypeUtil::writePrefix(PrefixLen(len), address, buf);
  561. return;
  562. }
  563. case OPT_PSID_TYPE:
  564. {
  565. std::string txt = value;
  566. // first let's remove any whitespaces
  567. boost::erase_all(txt, " "); // space
  568. boost::erase_all(txt, "\t"); // tabulation
  569. // Is this prefix/len notation?
  570. size_t pos = txt.find("/");
  571. if (pos == string::npos) {
  572. isc_throw(BadDataTypeCast, "provided PSID value "
  573. << value << " is not valid");
  574. }
  575. const std::string txt_psid = txt.substr(0, pos);
  576. const std::string txt_psid_len = txt.substr(pos + 1);
  577. uint16_t psid = 0;
  578. uint8_t psid_len = 0;
  579. try {
  580. psid = lexicalCastWithRangeCheck<uint16_t>(txt_psid);
  581. } catch (...) {
  582. isc_throw(BadDataTypeCast, "provided PSID "
  583. << txt_psid << " is not valid");
  584. }
  585. try {
  586. psid_len = lexicalCastWithRangeCheck<uint8_t>(txt_psid_len);
  587. } catch (...) {
  588. isc_throw(BadDataTypeCast, "provided PSID length "
  589. << txt_psid_len << " is not valid");
  590. }
  591. OptionDataTypeUtil::writePsid(PSIDLen(psid_len), PSID(psid), buf);
  592. return;
  593. }
  594. case OPT_STRING_TYPE:
  595. OptionDataTypeUtil::writeString(value, buf);
  596. return;
  597. case OPT_FQDN_TYPE:
  598. OptionDataTypeUtil::writeFqdn(value, buf);
  599. return;
  600. case OPT_TUPLE_TYPE:
  601. {
  602. OpaqueDataTuple::LengthFieldType lft = u == Option::V4 ?
  603. OpaqueDataTuple::LENGTH_1_BYTE : OpaqueDataTuple::LENGTH_2_BYTES;
  604. OptionDataTypeUtil::writeTuple(value, lft, buf);
  605. return;
  606. }
  607. default:
  608. // We hit this point because invalid option data type has been specified
  609. // This may be the case because 'empty' or 'record' data type has been
  610. // specified. We don't throw exception here because it will be thrown
  611. // at the exit point from this function.
  612. ;
  613. }
  614. isc_throw(isc::BadValue, "attempt to write invalid option data field type"
  615. " into the option buffer: " << type);
  616. }
  617. OptionPtr
  618. OptionDefinition::factoryAddrList4(uint16_t type,
  619. OptionBufferConstIter begin,
  620. OptionBufferConstIter end) {
  621. boost::shared_ptr<Option4AddrLst> option(new Option4AddrLst(type, begin,
  622. end));
  623. return (option);
  624. }
  625. OptionPtr
  626. OptionDefinition::factoryAddrList6(uint16_t type,
  627. OptionBufferConstIter begin,
  628. OptionBufferConstIter end) {
  629. boost::shared_ptr<Option6AddrLst> option(new Option6AddrLst(type, begin,
  630. end));
  631. return (option);
  632. }
  633. OptionPtr
  634. OptionDefinition::factoryEmpty(Option::Universe u, uint16_t type) {
  635. OptionPtr option(new Option(u, type));
  636. return (option);
  637. }
  638. OptionPtr
  639. OptionDefinition::factoryGeneric(Option::Universe u, uint16_t type,
  640. OptionBufferConstIter begin,
  641. OptionBufferConstIter end) {
  642. OptionPtr option(new Option(u, type, begin, end));
  643. return (option);
  644. }
  645. OptionPtr
  646. OptionDefinition::factoryIA6(uint16_t type,
  647. OptionBufferConstIter begin,
  648. OptionBufferConstIter end) {
  649. if (std::distance(begin, end) < Option6IA::OPTION6_IA_LEN) {
  650. isc_throw(isc::OutOfRange, "input option buffer has invalid size,"
  651. << " expected at least " << Option6IA::OPTION6_IA_LEN
  652. << " bytes");
  653. }
  654. boost::shared_ptr<Option6IA> option(new Option6IA(type, begin, end));
  655. return (option);
  656. }
  657. OptionPtr
  658. OptionDefinition::factoryIAAddr6(uint16_t type,
  659. OptionBufferConstIter begin,
  660. OptionBufferConstIter end) {
  661. if (std::distance(begin, end) < Option6IAAddr::OPTION6_IAADDR_LEN) {
  662. isc_throw(isc::OutOfRange,
  663. "input option buffer has invalid size, expected at least "
  664. << Option6IAAddr::OPTION6_IAADDR_LEN << " bytes");
  665. }
  666. boost::shared_ptr<Option6IAAddr> option(new Option6IAAddr(type, begin,
  667. end));
  668. return (option);
  669. }
  670. OptionPtr
  671. OptionDefinition::factoryIAPrefix6(uint16_t type,
  672. OptionBufferConstIter begin,
  673. OptionBufferConstIter end) {
  674. if (std::distance(begin, end) < Option6IAPrefix::OPTION6_IAPREFIX_LEN) {
  675. isc_throw(isc::OutOfRange,
  676. "input option buffer has invalid size, expected at least "
  677. << Option6IAPrefix::OPTION6_IAPREFIX_LEN << " bytes");
  678. }
  679. boost::shared_ptr<Option6IAPrefix> option(new Option6IAPrefix(type, begin,
  680. end));
  681. return (option);
  682. }
  683. OptionPtr
  684. OptionDefinition::factoryOpaqueDataTuples(Option::Universe u,
  685. uint16_t type,
  686. OptionBufferConstIter begin,
  687. OptionBufferConstIter end) {
  688. boost::shared_ptr<OptionOpaqueDataTuples>
  689. option(new OptionOpaqueDataTuples(u, type, begin, end));
  690. return (option);
  691. }
  692. OptionPtr
  693. OptionDefinition::factoryFqdnList(Option::Universe u,
  694. OptionBufferConstIter begin,
  695. OptionBufferConstIter end) const {
  696. const std::vector<uint8_t> data(begin, end);
  697. InputBuffer in_buf(static_cast<const void*>(&data[0]), data.size());
  698. std::vector<uint8_t> out_buf;
  699. out_buf.reserve(data.size());
  700. while (in_buf.getPosition() < in_buf.getLength()) {
  701. // Reuse readFqdn and writeFqdn code but on the whole buffer
  702. // so the DNS name code handles compression for us.
  703. try {
  704. isc::dns::Name name(in_buf);
  705. isc::dns::LabelSequence labels(name);
  706. if (labels.getDataLength() > 0) {
  707. size_t read_len = 0;
  708. const uint8_t* label = labels.getData(&read_len);
  709. out_buf.insert(out_buf.end(), label, label + read_len);
  710. }
  711. } catch (const isc::Exception& ex) {
  712. isc_throw(InvalidOptionValue, ex.what());
  713. }
  714. }
  715. return OptionPtr(new OptionCustom(*this, u,
  716. out_buf.begin(), out_buf.end()));
  717. }
  718. OptionPtr
  719. OptionDefinition::factorySpecialFormatOption(Option::Universe u,
  720. OptionBufferConstIter begin,
  721. OptionBufferConstIter end) const {
  722. if (u == Option::V6) {
  723. if ((getCode() == D6O_IA_NA || getCode() == D6O_IA_PD) &&
  724. haveIA6Format()) {
  725. // Return Option6IA instance for IA_PD and IA_NA option
  726. // types only. We don't want to return Option6IA for other
  727. // options that comprise 3 UINT32 data fields because
  728. // Option6IA accessors' and modifiers' names are derived
  729. // from the IA_NA and IA_PD options' field names: IAID,
  730. // T1, T2. Using functions such as getIAID, getT1 etc. for
  731. // options other than IA_NA and IA_PD would be bad practice
  732. // and cause confusion.
  733. return (factoryIA6(getCode(), begin, end));
  734. } else if (getCode() == D6O_IAADDR && haveIAAddr6Format()) {
  735. // Rerurn Option6IAAddr option instance for the IAADDR
  736. // option only for the same reasons as described in
  737. // for IA_NA and IA_PD above.
  738. return (factoryIAAddr6(getCode(), begin, end));
  739. } else if (getCode() == D6O_IAPREFIX && haveIAPrefix6Format()) {
  740. return (factoryIAPrefix6(getCode(), begin, end));
  741. } else if (getCode() == D6O_CLIENT_FQDN && haveClientFqdnFormat()) {
  742. // FQDN option requires special processing. Thus, there is
  743. // a specialized class to handle it.
  744. return (OptionPtr(new Option6ClientFqdn(begin, end)));
  745. } else if (getCode() == D6O_VENDOR_OPTS && haveVendor6Format()) {
  746. // Vendor-Specific Information (option code 17)
  747. return (OptionPtr(new OptionVendor(Option::V6, begin, end)));
  748. } else if (getCode() == D6O_VENDOR_CLASS && haveVendorClass6Format()) {
  749. // Vendor Class (option code 16).
  750. return (OptionPtr(new OptionVendorClass(Option::V6, begin, end)));
  751. } else if (getCode() == D6O_STATUS_CODE && haveStatusCodeFormat()) {
  752. // Status Code (option code 13)
  753. return (OptionPtr(new Option6StatusCode(begin, end)));
  754. } else if (getCode() == D6O_BOOTFILE_PARAM && haveOpaqueDataTuplesFormat()) {
  755. // Bootfile params (option code 60)
  756. return (factoryOpaqueDataTuples(Option::V6, getCode(), begin, end));
  757. } else if ((getCode() == D6O_PD_EXCLUDE) && haveType(OPT_IPV6_PREFIX_TYPE)) {
  758. // Prefix Exclude (option code 67)
  759. return (OptionPtr(new Option6PDExclude(begin, end)));
  760. }
  761. } else {
  762. if ((getCode() == DHO_FQDN) && haveFqdn4Format()) {
  763. return (OptionPtr(new Option4ClientFqdn(begin, end)));
  764. } else if ((getCode() == DHO_DOMAIN_SEARCH) &&
  765. haveCompressedFqdnListFormat()) {
  766. return (factoryFqdnList(Option::V4, begin, end));
  767. } else if ((getCode() == DHO_VIVCO_SUBOPTIONS) &&
  768. haveVendorClass4Format()) {
  769. // V-I Vendor Class (option code 124).
  770. return (OptionPtr(new OptionVendorClass(Option::V4, begin, end)));
  771. } else if (getCode() == DHO_VIVSO_SUBOPTIONS && haveVendor4Format()) {
  772. // Vendor-Specific Information (option code 125).
  773. return (OptionPtr(new OptionVendor(Option::V4, begin, end)));
  774. }
  775. }
  776. return (OptionPtr());
  777. }
  778. } // end of isc::dhcp namespace
  779. } // end of isc namespace