option_definition.cc 19 KB

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