option_definition.cc 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. // Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <dhcp/dhcp4.h>
  15. #include <dhcp/dhcp6.h>
  16. #include <dhcp/option4_addrlst.h>
  17. #include <dhcp/option4_client_fqdn.h>
  18. #include <dhcp/option6_addrlst.h>
  19. #include <dhcp/option6_ia.h>
  20. #include <dhcp/option6_iaaddr.h>
  21. #include <dhcp/option_custom.h>
  22. #include <dhcp/option_definition.h>
  23. #include <dhcp/option_int.h>
  24. #include <dhcp/option_int_array.h>
  25. #include <dhcp/option_space.h>
  26. #include <dhcp/option_string.h>
  27. #include <util/encode/hex.h>
  28. #include <util/strutil.h>
  29. #include <boost/algorithm/string/classification.hpp>
  30. #include <boost/algorithm/string/predicate.hpp>
  31. using namespace std;
  32. using namespace isc::util;
  33. namespace isc {
  34. namespace dhcp {
  35. OptionDefinition::OptionDefinition(const std::string& name,
  36. const uint16_t code,
  37. const std::string& type,
  38. const bool array_type /* = false */)
  39. : name_(name),
  40. code_(code),
  41. type_(OPT_UNKNOWN_TYPE),
  42. array_type_(array_type),
  43. encapsulated_space_("") {
  44. // Data type is held as enum value by this class.
  45. // Use the provided option type string to get the
  46. // corresponding enum value.
  47. type_ = OptionDataTypeUtil::getDataType(type);
  48. }
  49. OptionDefinition::OptionDefinition(const std::string& name,
  50. const uint16_t code,
  51. const OptionDataType type,
  52. const bool array_type /* = false */)
  53. : name_(name),
  54. code_(code),
  55. type_(type),
  56. array_type_(array_type),
  57. encapsulated_space_("") {
  58. }
  59. OptionDefinition::OptionDefinition(const std::string& name,
  60. const uint16_t code,
  61. const std::string& type,
  62. const char* encapsulated_space)
  63. : name_(name),
  64. code_(code),
  65. // Data type is held as enum value by this class.
  66. // Use the provided option type string to get the
  67. // corresponding enum value.
  68. type_(OptionDataTypeUtil::getDataType(type)),
  69. array_type_(false),
  70. encapsulated_space_(encapsulated_space) {
  71. }
  72. OptionDefinition::OptionDefinition(const std::string& name,
  73. const uint16_t code,
  74. const OptionDataType type,
  75. const char* encapsulated_space)
  76. : name_(name),
  77. code_(code),
  78. type_(type),
  79. array_type_(false),
  80. encapsulated_space_(encapsulated_space) {
  81. }
  82. void
  83. OptionDefinition::addRecordField(const std::string& data_type_name) {
  84. OptionDataType data_type = OptionDataTypeUtil::getDataType(data_type_name);
  85. addRecordField(data_type);
  86. }
  87. void
  88. OptionDefinition::addRecordField(const OptionDataType data_type) {
  89. if (type_ != OPT_RECORD_TYPE) {
  90. isc_throw(isc::InvalidOperation, "'record' option type must be used"
  91. " to add data fields to the record");
  92. }
  93. if (data_type >= OPT_RECORD_TYPE ||
  94. data_type == OPT_ANY_ADDRESS_TYPE ||
  95. data_type == OPT_EMPTY_TYPE) {
  96. isc_throw(isc::BadValue, "attempted to add invalid data type to the record.");
  97. }
  98. record_fields_.push_back(data_type);
  99. }
  100. OptionPtr
  101. OptionDefinition::optionFactory(Option::Universe u, uint16_t type,
  102. OptionBufferConstIter begin,
  103. OptionBufferConstIter end) const {
  104. try {
  105. switch(type_) {
  106. case OPT_EMPTY_TYPE:
  107. return (factoryEmpty(u, type));
  108. case OPT_BINARY_TYPE:
  109. return (factoryGeneric(u, type, begin, end));
  110. case OPT_UINT8_TYPE:
  111. return (array_type_ ? factoryGeneric(u, type, begin, end) :
  112. factoryInteger<uint8_t>(u, type, begin, end));
  113. case OPT_INT8_TYPE:
  114. return (array_type_ ? factoryGeneric(u, type, begin, end) :
  115. factoryInteger<int8_t>(u, type, begin, end));
  116. case OPT_UINT16_TYPE:
  117. return (array_type_ ? factoryIntegerArray<uint16_t>(u, type, begin, end) :
  118. factoryInteger<uint16_t>(u, type, begin, end));
  119. case OPT_INT16_TYPE:
  120. return (array_type_ ? factoryIntegerArray<uint16_t>(u, type, begin, end) :
  121. factoryInteger<int16_t>(u, type, begin, end));
  122. case OPT_UINT32_TYPE:
  123. return (array_type_ ? factoryIntegerArray<uint32_t>(u, type, begin, end) :
  124. factoryInteger<uint32_t>(u, type, begin, end));
  125. case OPT_INT32_TYPE:
  126. return (array_type_ ? factoryIntegerArray<uint32_t>(u, type, begin, end) :
  127. factoryInteger<int32_t>(u, type, begin, end));
  128. case OPT_IPV4_ADDRESS_TYPE:
  129. // If definition specifies that an option is an array
  130. // of IPv4 addresses we return an instance of specialized
  131. // class (OptionAddrLst4). For non-array types there is no
  132. // specialized class yet implemented so we drop through
  133. // to return an instance of OptionCustom.
  134. if (array_type_) {
  135. return (factoryAddrList4(type, begin, end));
  136. }
  137. break;
  138. case OPT_IPV6_ADDRESS_TYPE:
  139. // Handle array type only here (see comments for
  140. // OPT_IPV4_ADDRESS_TYPE case).
  141. if (array_type_) {
  142. return (factoryAddrList6(type, begin, end));
  143. }
  144. break;
  145. case OPT_STRING_TYPE:
  146. return (OptionPtr(new OptionString(u, type, begin, end)));
  147. default:
  148. if (u == Option::V6) {
  149. if ((code_ == D6O_IA_NA || code_ == D6O_IA_PD) &&
  150. haveIA6Format()) {
  151. // Return Option6IA instance for IA_PD and IA_NA option
  152. // types only. We don't want to return Option6IA for other
  153. // options that comprise 3 UINT32 data fields because
  154. // Option6IA accessors' and modifiers' names are derived
  155. // from the IA_NA and IA_PD options' field names: IAID,
  156. // T1, T2. Using functions such as getIAID, getT1 etc. for
  157. // options other than IA_NA and IA_PD would be bad practice
  158. // and cause confusion.
  159. return (factoryIA6(type, begin, end));
  160. } else if (code_ == D6O_IAADDR && haveIAAddr6Format()) {
  161. // Rerurn Option6IAAddr option instance for the IAADDR
  162. // option only for the same reasons as described in
  163. // for IA_NA and IA_PD above.
  164. return (factoryIAAddr6(type, begin, end));
  165. }
  166. } else {
  167. if ((code_ == DHO_FQDN) && haveFqdn4Format()) {
  168. return (OptionPtr(new Option4ClientFqdn(begin, end)));
  169. }
  170. }
  171. }
  172. return (OptionPtr(new OptionCustom(*this, u, begin, end)));
  173. } catch (const Exception& ex) {
  174. isc_throw(InvalidOptionValue, ex.what());
  175. }
  176. }
  177. OptionPtr
  178. OptionDefinition::optionFactory(Option::Universe u, uint16_t type,
  179. const OptionBuffer& buf) const {
  180. return (optionFactory(u, type, buf.begin(), buf.end()));
  181. }
  182. OptionPtr
  183. OptionDefinition::optionFactory(Option::Universe u, uint16_t type,
  184. const std::vector<std::string>& values) const {
  185. OptionBuffer buf;
  186. if (!array_type_ && type_ != OPT_RECORD_TYPE) {
  187. if (values.empty()) {
  188. isc_throw(InvalidOptionValue, "no option value specified");
  189. }
  190. writeToBuffer(util::str::trim(values[0]), type_, buf);
  191. } else if (array_type_ && type_ != OPT_RECORD_TYPE) {
  192. for (size_t i = 0; i < values.size(); ++i) {
  193. writeToBuffer(util::str::trim(values[i]), type_, buf);
  194. }
  195. } else if (type_ == OPT_RECORD_TYPE) {
  196. const RecordFieldsCollection& records = getRecordFields();
  197. if (records.size() > values.size()) {
  198. isc_throw(InvalidOptionValue, "number of data fields for the option"
  199. << " type '" << getCode() << "' is greater than number"
  200. << " of values provided.");
  201. }
  202. for (size_t i = 0; i < records.size(); ++i) {
  203. writeToBuffer(util::str::trim(values[i]),
  204. records[i], buf);
  205. }
  206. }
  207. return (optionFactory(u, type, buf.begin(), buf.end()));
  208. }
  209. void
  210. OptionDefinition::validate() const {
  211. using namespace boost::algorithm;
  212. std::ostringstream err_str;
  213. // Allowed characters in the option name are: lower or
  214. // upper case letters, digits, underscores and hyphens.
  215. // Empty option spaces are not allowed.
  216. if (!all(name_, boost::is_from_range('a', 'z') ||
  217. boost::is_from_range('A', 'Z') ||
  218. boost::is_digit() ||
  219. boost::is_any_of(std::string("-_"))) ||
  220. name_.empty() ||
  221. // Hyphens and underscores are not allowed at the beginning
  222. // and at the end of the option name.
  223. all(find_head(name_, 1), boost::is_any_of(std::string("-_"))) ||
  224. all(find_tail(name_, 1), boost::is_any_of(std::string("-_")))) {
  225. err_str << "invalid option name '" << name_ << "'";
  226. } else if (!encapsulated_space_.empty() &&
  227. !OptionSpace::validateName(encapsulated_space_)) {
  228. err_str << "invalid encapsulated option space name: '"
  229. << encapsulated_space_ << "'";
  230. } else if (type_ >= OPT_UNKNOWN_TYPE) {
  231. // Option definition must be of a known type.
  232. err_str << "option type value " << type_ << " is out of range.";
  233. } else if (array_type_) {
  234. if (type_ == OPT_STRING_TYPE) {
  235. // Array of strings is not allowed because there is no way
  236. // to determine the size of a particular string and thus there
  237. // it no way to tell when other data fields begin.
  238. err_str << "array of strings is not a valid option definition.";
  239. } else if (type_ == OPT_BINARY_TYPE) {
  240. err_str << "array of binary values is not a valid option definition.";
  241. } else if (type_ == OPT_EMPTY_TYPE) {
  242. err_str << "array of empty value is not a valid option definition.";
  243. }
  244. } else if (type_ == OPT_RECORD_TYPE) {
  245. // At least two data fields should be added to the record. Otherwise
  246. // non-record option definition could be used.
  247. if (getRecordFields().size() < 2) {
  248. err_str << "invalid number of data fields: " << getRecordFields().size()
  249. << " specified for the option of type 'record'. Expected at"
  250. << " least 2 fields.";
  251. } else {
  252. // If the number of fields is valid we have to check if their order
  253. // is valid too. We check that string or binary data fields are not
  254. // laid before other fields. But we allow that they are laid at the end of
  255. // an option.
  256. const RecordFieldsCollection& fields = getRecordFields();
  257. for (RecordFieldsConstIter it = fields.begin();
  258. it != fields.end(); ++it) {
  259. if (*it == OPT_STRING_TYPE &&
  260. it < fields.end() - 1) {
  261. err_str << "string data field can't be laid before data fields"
  262. << " of other types.";
  263. break;
  264. }
  265. if (*it == OPT_BINARY_TYPE &&
  266. it < fields.end() - 1) {
  267. err_str << "binary data field can't be laid before data fields"
  268. << " of other types.";
  269. }
  270. /// Empty type is not allowed within a record.
  271. if (*it == OPT_EMPTY_TYPE) {
  272. err_str << "empty data type can't be stored as a field in an"
  273. << " option record.";
  274. break;
  275. }
  276. }
  277. }
  278. }
  279. // Non-empty error string means that we have hit the error. We throw
  280. // exception and include error string.
  281. if (!err_str.str().empty()) {
  282. isc_throw(MalformedOptionDefinition, err_str.str());
  283. }
  284. }
  285. bool
  286. OptionDefinition::haveIAx6Format(OptionDataType first_type) const {
  287. return (haveType(OPT_RECORD_TYPE) &&
  288. record_fields_.size() == 3 &&
  289. record_fields_[0] == first_type &&
  290. record_fields_[1] == OPT_UINT32_TYPE &&
  291. record_fields_[2] == OPT_UINT32_TYPE);
  292. }
  293. bool
  294. OptionDefinition::haveIA6Format() const {
  295. // Expect that IA_NA option format is defined as record.
  296. // Although it consists of 3 elements of the same (uint32)
  297. // type it can't be defined as array of uint32 elements because
  298. // arrays do not impose limitations on number of elements in
  299. // the array while this limitation is needed for IA_NA - need
  300. // exactly 3 elements.
  301. return (haveIAx6Format(OPT_UINT32_TYPE));
  302. }
  303. bool
  304. OptionDefinition::haveIAAddr6Format() const {
  305. return (haveIAx6Format(OPT_IPV6_ADDRESS_TYPE));
  306. }
  307. bool
  308. OptionDefinition::haveFqdn4Format() const {
  309. return (haveType(OPT_RECORD_TYPE) &&
  310. record_fields_.size() == 4 &&
  311. record_fields_[0] == OPT_UINT8_TYPE &&
  312. record_fields_[1] == OPT_UINT8_TYPE &&
  313. record_fields_[2] == OPT_UINT8_TYPE &&
  314. record_fields_[3] == OPT_FQDN_TYPE);
  315. }
  316. template<typename T>
  317. T OptionDefinition::lexicalCastWithRangeCheck(const std::string& value_str) const {
  318. // Lexical cast in case of our data types make sense only
  319. // for uintX_t, intX_t and bool type.
  320. if (!OptionDataTypeTraits<T>::integer_type &&
  321. OptionDataTypeTraits<T>::type != OPT_BOOLEAN_TYPE) {
  322. isc_throw(BadDataTypeCast, "unable to do lexical cast to non-integer and"
  323. << " non-boolean data type");
  324. }
  325. // We use the 64-bit value here because it has wider range than
  326. // any other type we use here and it allows to detect out of
  327. // bounds conditions e.g. negative value specified for uintX_t
  328. // data type. Obviously if the value exceeds the limits of int64
  329. // this function will not handle that properly.
  330. int64_t result = 0;
  331. try {
  332. result = boost::lexical_cast<int64_t>(value_str);
  333. } catch (const boost::bad_lexical_cast& ex) {
  334. // Prepare error message here.
  335. std::string data_type_str = "boolean";
  336. if (OptionDataTypeTraits<T>::integer_type) {
  337. data_type_str = "integer";
  338. }
  339. isc_throw(BadDataTypeCast, "unable to do lexical cast to " << data_type_str
  340. << " data type for value " << value_str << ": " << ex.what());
  341. }
  342. // Perform range checks for integer values only (exclude bool values).
  343. if (OptionDataTypeTraits<T>::integer_type) {
  344. if (result > numeric_limits<T>::max() ||
  345. result < numeric_limits<T>::min()) {
  346. isc_throw(BadDataTypeCast, "unable to do lexical cast for value "
  347. << value_str << ". This value is expected to be in the range of "
  348. << numeric_limits<T>::min() << ".." << numeric_limits<T>::max());
  349. }
  350. }
  351. return (static_cast<T>(result));
  352. }
  353. void
  354. OptionDefinition::writeToBuffer(const std::string& value,
  355. const OptionDataType type,
  356. OptionBuffer& buf) const {
  357. // We are going to write value given by value argument to the buffer.
  358. // The actual type of the value is given by second argument. Check
  359. // this argument to determine how to write this value to the buffer.
  360. switch (type) {
  361. case OPT_BINARY_TYPE:
  362. OptionDataTypeUtil::writeBinary(value, buf);
  363. return;
  364. case OPT_BOOLEAN_TYPE:
  365. // We encode the true value as 1 and false as 0 on 8 bits.
  366. // That way we actually waste 7 bits but it seems to be the
  367. // simpler way to encode boolean.
  368. // @todo Consider if any other encode methods can be used.
  369. OptionDataTypeUtil::writeBool(lexicalCastWithRangeCheck<bool>(value), buf);
  370. return;
  371. case OPT_INT8_TYPE:
  372. OptionDataTypeUtil::writeInt<uint8_t>(lexicalCastWithRangeCheck<int8_t>(value),
  373. buf);
  374. return;
  375. case OPT_INT16_TYPE:
  376. OptionDataTypeUtil::writeInt<uint16_t>(lexicalCastWithRangeCheck<int16_t>(value),
  377. buf);
  378. return;
  379. case OPT_INT32_TYPE:
  380. OptionDataTypeUtil::writeInt<uint32_t>(lexicalCastWithRangeCheck<int32_t>(value),
  381. buf);
  382. return;
  383. case OPT_UINT8_TYPE:
  384. OptionDataTypeUtil::writeInt<uint8_t>(lexicalCastWithRangeCheck<uint8_t>(value),
  385. buf);
  386. return;
  387. case OPT_UINT16_TYPE:
  388. OptionDataTypeUtil::writeInt<uint16_t>(lexicalCastWithRangeCheck<uint16_t>(value),
  389. buf);
  390. return;
  391. case OPT_UINT32_TYPE:
  392. OptionDataTypeUtil::writeInt<uint32_t>(lexicalCastWithRangeCheck<uint32_t>(value),
  393. buf);
  394. return;
  395. case OPT_IPV4_ADDRESS_TYPE:
  396. case OPT_IPV6_ADDRESS_TYPE:
  397. {
  398. asiolink::IOAddress address(value);
  399. if (!address.isV4() && !address.isV6()) {
  400. isc_throw(BadDataTypeCast, "provided address " << address.toText()
  401. << " is not a valid IPv4 or IPv6 address.");
  402. }
  403. OptionDataTypeUtil::writeAddress(address, buf);
  404. return;
  405. }
  406. case OPT_STRING_TYPE:
  407. OptionDataTypeUtil::writeString(value, buf);
  408. return;
  409. case OPT_FQDN_TYPE:
  410. OptionDataTypeUtil::writeFqdn(value, buf);
  411. return;
  412. default:
  413. // We hit this point because invalid option data type has been specified
  414. // This may be the case because 'empty' or 'record' data type has been
  415. // specified. We don't throw exception here because it will be thrown
  416. // at the exit point from this function.
  417. ;
  418. }
  419. isc_throw(isc::BadValue, "attempt to write invalid option data field type"
  420. " into the option buffer: " << type);
  421. }
  422. OptionPtr
  423. OptionDefinition::factoryAddrList4(uint16_t type,
  424. OptionBufferConstIter begin,
  425. OptionBufferConstIter end) {
  426. boost::shared_ptr<Option4AddrLst> option(new Option4AddrLst(type, begin, end));
  427. return (option);
  428. }
  429. OptionPtr
  430. OptionDefinition::factoryAddrList6(uint16_t type,
  431. OptionBufferConstIter begin,
  432. OptionBufferConstIter end) {
  433. boost::shared_ptr<Option6AddrLst> option(new Option6AddrLst(type, begin, end));
  434. return (option);
  435. }
  436. OptionPtr
  437. OptionDefinition::factoryEmpty(Option::Universe u, uint16_t type) {
  438. OptionPtr option(new Option(u, type));
  439. return (option);
  440. }
  441. OptionPtr
  442. OptionDefinition::factoryGeneric(Option::Universe u, uint16_t type,
  443. OptionBufferConstIter begin,
  444. OptionBufferConstIter end) {
  445. OptionPtr option(new Option(u, type, begin, end));
  446. return (option);
  447. }
  448. OptionPtr
  449. OptionDefinition::factoryIA6(uint16_t type,
  450. OptionBufferConstIter begin,
  451. OptionBufferConstIter end) {
  452. if (std::distance(begin, end) < Option6IA::OPTION6_IA_LEN) {
  453. isc_throw(isc::OutOfRange, "input option buffer has invalid size, expected "
  454. "at least " << Option6IA::OPTION6_IA_LEN << " bytes");
  455. }
  456. boost::shared_ptr<Option6IA> option(new Option6IA(type, begin, end));
  457. return (option);
  458. }
  459. OptionPtr
  460. OptionDefinition::factoryIAAddr6(uint16_t type,
  461. OptionBufferConstIter begin,
  462. OptionBufferConstIter end) {
  463. if (std::distance(begin, end) < Option6IAAddr::OPTION6_IAADDR_LEN) {
  464. isc_throw(isc::OutOfRange, "input option buffer has invalid size, expected "
  465. " at least " << Option6IAAddr::OPTION6_IAADDR_LEN << " bytes");
  466. }
  467. boost::shared_ptr<Option6IAAddr> option(new Option6IAAddr(type, begin, end));
  468. return (option);
  469. }
  470. } // end of isc::dhcp namespace
  471. } // end of isc namespace