option_definition.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  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_definition.h>
  22. #include <util/encode/hex.h>
  23. using namespace std;
  24. using namespace isc::util;
  25. namespace isc {
  26. namespace dhcp {
  27. OptionDefinition::DataTypeUtil::DataTypeUtil() {
  28. data_types_["empty"] = OPT_EMPTY_TYPE;
  29. data_types_["binary"] = OPT_BINARY_TYPE;
  30. data_types_["boolean"] = OPT_BOOLEAN_TYPE;
  31. data_types_["int8"] = OPT_INT8_TYPE;
  32. data_types_["int16"] = OPT_INT16_TYPE;
  33. data_types_["int32"] = OPT_INT32_TYPE;
  34. data_types_["uint8"] = OPT_UINT8_TYPE;
  35. data_types_["uint16"] = OPT_UINT16_TYPE;
  36. data_types_["uint32"] = OPT_UINT32_TYPE;
  37. data_types_["ipv4-address"] = OPT_IPV4_ADDRESS_TYPE;
  38. data_types_["ipv6-address"] = OPT_IPV6_ADDRESS_TYPE;
  39. data_types_["string"] = OPT_STRING_TYPE;
  40. data_types_["fqdn"] = OPT_FQDN_TYPE;
  41. data_types_["record"] = OPT_RECORD_TYPE;
  42. }
  43. OptionDataType
  44. OptionDefinition::DataTypeUtil::getOptionDataType(const std::string& data_type) {
  45. std::map<std::string, OptionDataType>::const_iterator data_type_it =
  46. data_types_.find(data_type);
  47. if (data_type_it != data_types_.end()) {
  48. return (data_type_it->second);
  49. }
  50. return (OPT_UNKNOWN_TYPE);
  51. }
  52. template<typename T>
  53. T OptionDefinition::DataTypeUtil::lexicalCastWithRangeCheck(const std::string& value_str) const {
  54. if (!OptionDataTypeTraits<T>::integer_type &&
  55. OptionDataTypeTraits<T>::type != OPT_BOOLEAN_TYPE) {
  56. isc_throw(BadDataTypeCast, "unable to do lexical cast to non-integer and"
  57. << " non-boolean data type");
  58. }
  59. int64_t result = 0;
  60. try {
  61. result = boost::lexical_cast<int64_t>(value_str);
  62. } catch (const boost::bad_lexical_cast& ex) {
  63. std::string data_type_str = "boolean";
  64. if (OptionDataTypeTraits<T>::integer_type) {
  65. data_type_str = "integer";
  66. }
  67. isc_throw(BadDataTypeCast, "unable to do lexical cast to " << data_type_str
  68. << " data type for value " << value_str << ": " << ex.what());
  69. }
  70. if (OptionDataTypeTraits<T>::integer_type) {
  71. if (result > numeric_limits<T>::max() ||
  72. result < numeric_limits<T>::min()) {
  73. isc_throw(BadDataTypeCast, "unable to do lexical cast for value "
  74. << value_str << ". This value is expected to be in the range of "
  75. << numeric_limits<T>::min() << ".." << numeric_limits<T>::max());
  76. }
  77. }
  78. return (static_cast<T>(result));
  79. }
  80. void
  81. OptionDefinition::DataTypeUtil::writeToBuffer(const std::string& value, uint16_t type,
  82. OptionBuffer& buf) {
  83. switch (type) {
  84. case OPT_BINARY_TYPE:
  85. {
  86. OptionBuffer binary;
  87. try {
  88. util::encode::decodeHex(value, binary);
  89. } catch (const Exception& ex) {
  90. isc_throw(BadDataTypeCast, "unable to cast " << value
  91. << " to binary data type: " << ex.what());
  92. }
  93. buf.insert(buf.end(), binary.begin(), binary.end());
  94. return;
  95. }
  96. case OPT_BOOLEAN_TYPE:
  97. {
  98. bool bool_value = lexicalCastWithRangeCheck<bool>(value);
  99. if (bool_value) {
  100. buf.push_back(static_cast<uint8_t>(1));
  101. } else {
  102. buf.push_back(static_cast<uint8_t>(0));
  103. }
  104. return;
  105. }
  106. case OPT_INT8_TYPE:
  107. {
  108. buf.push_back(static_cast<uint8_t>(lexicalCastWithRangeCheck<int8_t>(value)));
  109. return;
  110. }
  111. case OPT_INT16_TYPE:
  112. {
  113. int16_t int_value = lexicalCastWithRangeCheck<int16_t>(value);
  114. buf.resize(buf.size() + 2);
  115. writeUint16(static_cast<uint16_t>(int_value), &buf[buf.size() - 2]);
  116. return;
  117. }
  118. case OPT_INT32_TYPE:
  119. {
  120. int32_t int_value = lexicalCastWithRangeCheck<int32_t>(value);
  121. buf.resize(buf.size() + 4);
  122. writeUint32(static_cast<uint32_t>(int_value), &buf[buf.size() - 4]);
  123. return;
  124. }
  125. case OPT_UINT8_TYPE:
  126. {
  127. buf.push_back(lexicalCastWithRangeCheck<int8_t>(value));
  128. return;
  129. }
  130. case OPT_UINT16_TYPE:
  131. {
  132. uint16_t uint_value = lexicalCastWithRangeCheck<uint16_t>(value);
  133. buf.resize(buf.size() + 2);
  134. writeUint16(uint_value, &buf[buf.size() - 2]);
  135. return;
  136. }
  137. case OPT_UINT32_TYPE:
  138. {
  139. uint32_t uint_value = lexicalCastWithRangeCheck<uint32_t>(value);
  140. buf.resize(buf.size() + 4);
  141. writeUint32(uint_value, &buf[buf.size() - 4]);
  142. return;
  143. }
  144. case OPT_IPV4_ADDRESS_TYPE:
  145. {
  146. asiolink::IOAddress address(value);
  147. if (!address.getAddress().is_v4()) {
  148. isc_throw(BadDataTypeCast, "provided address " << address.toText()
  149. << " is not a valid IPV4 address");
  150. }
  151. asio::ip::address_v4::bytes_type addr_bytes =
  152. address.getAddress().to_v4().to_bytes();
  153. buf.resize(buf.size() + addr_bytes.size());
  154. std::copy_backward(addr_bytes.begin(), addr_bytes.end(),
  155. buf.end());
  156. return;
  157. }
  158. case OPT_IPV6_ADDRESS_TYPE:
  159. {
  160. asiolink::IOAddress address(value);
  161. if (!address.getAddress().is_v6()) {
  162. isc_throw(BadDataTypeCast, "provided address " << address.toText()
  163. << " is not a valid IPV6 address");
  164. }
  165. asio::ip::address_v6::bytes_type addr_bytes =
  166. address.getAddress().to_v6().to_bytes();
  167. buf.resize(buf.size() + addr_bytes.size());
  168. std::copy_backward(addr_bytes.begin(), addr_bytes.end(),
  169. buf.end());
  170. return;
  171. }
  172. default:
  173. ;
  174. }
  175. isc_throw(isc::NotImplemented, "write of string, FQDN record into option buffer"
  176. " is not supported yet");
  177. }
  178. OptionDefinition::OptionDefinition(const std::string& name,
  179. const uint16_t code,
  180. const std::string& type,
  181. const bool array_type /* = false */)
  182. : name_(name),
  183. code_(code),
  184. type_(OPT_UNKNOWN_TYPE),
  185. array_type_(array_type) {
  186. // Data type is held as enum value by this class.
  187. // Use the provided option type string to get the
  188. // corresponding enum value.
  189. type_ = DataTypeUtil::instance().getOptionDataType(type);
  190. }
  191. OptionDefinition::OptionDefinition(const std::string& name,
  192. const uint16_t code,
  193. const OptionDataType type,
  194. const bool array_type /* = false */)
  195. : name_(name),
  196. code_(code),
  197. type_(type),
  198. array_type_(array_type) {
  199. }
  200. void
  201. OptionDefinition::addRecordField(const std::string& data_type_name) {
  202. OptionDataType data_type = DataTypeUtil::instance().getOptionDataType(data_type_name);
  203. addRecordField(data_type);
  204. }
  205. void
  206. OptionDefinition::addRecordField(const OptionDataType data_type) {
  207. if (type_ != OPT_RECORD_TYPE) {
  208. isc_throw(isc::InvalidOperation, "'record' option type must be used"
  209. " to add data fields to the record");
  210. }
  211. if (data_type >= OPT_UNKNOWN_TYPE) {
  212. isc_throw(isc::BadValue, "attempted to add invalid data type to the record");
  213. }
  214. record_fields_.push_back(data_type);
  215. }
  216. OptionPtr
  217. OptionDefinition::optionFactory(Option::Universe u, uint16_t type,
  218. OptionBufferConstIter begin,
  219. OptionBufferConstIter end) const {
  220. validate();
  221. if (type_ == OPT_BINARY_TYPE) {
  222. return (factoryGeneric(u, type, begin, end));
  223. } else if (type_ == OPT_IPV6_ADDRESS_TYPE && array_type_) {
  224. return (factoryAddrList6(u, type, begin, end));
  225. } else if (type_ == OPT_IPV4_ADDRESS_TYPE && array_type_) {
  226. return (factoryAddrList4(u, type, begin, end));
  227. } else if (type_ == OPT_EMPTY_TYPE) {
  228. return (factoryEmpty(u, type, begin, end));
  229. } else if (code_ == D6O_IA_NA && haveIA6Format()) {
  230. return (factoryIA6(u, type, begin, end));
  231. } else if (code_ == D6O_IAADDR && haveIAAddr6Format()) {
  232. return (factoryIAAddr6(u, type, begin, end));
  233. } else if (type_ == OPT_UINT8_TYPE) {
  234. if (array_type_) {
  235. return (factoryGeneric(u, type, begin, end));
  236. } else {
  237. return (factoryInteger<uint8_t>(u, type, begin, end));
  238. }
  239. } else if (type_ == OPT_UINT16_TYPE) {
  240. if (array_type_) {
  241. return (factoryIntegerArray<uint16_t>(u, type, begin, end));
  242. } else {
  243. return (factoryInteger<uint16_t>(u, type, begin, end));
  244. }
  245. } else if (type_ == OPT_UINT32_TYPE) {
  246. if (array_type_) {
  247. return (factoryIntegerArray<uint32_t>(u, type, begin, end));
  248. } else {
  249. return (factoryInteger<uint32_t>(u, type, begin, end));
  250. }
  251. }
  252. return (factoryGeneric(u, type, begin, end));
  253. }
  254. OptionPtr
  255. OptionDefinition::optionFactory(Option::Universe u, uint16_t type,
  256. const OptionBuffer& buf) const {
  257. return (optionFactory(u, type, buf.begin(), buf.end()));
  258. }
  259. OptionPtr
  260. OptionDefinition::optionFactory(Option::Universe u, uint16_t type,
  261. const std::vector<std::string>& values) const {
  262. validate();
  263. OptionBuffer buf;
  264. if (!array_type_ && type_ != OPT_RECORD_TYPE) {
  265. if (values.size() == 0) {
  266. isc_throw(InvalidOptionValue, "no option value specified");
  267. }
  268. DataTypeUtil::instance().writeToBuffer(values[0], type_, buf);
  269. } else if (array_type_ && type_ != OPT_RECORD_TYPE) {
  270. for (size_t i = 0; i < values.size(); ++i) {
  271. DataTypeUtil::instance().writeToBuffer(values[i], type_, buf);
  272. }
  273. } else if (type_ == OPT_RECORD_TYPE) {
  274. const RecordFieldsCollection& records = getRecordFields();
  275. if (records.size() > values.size()) {
  276. isc_throw(InvalidOptionValue, "number of data fields for the option"
  277. << " type " << type_ << " is greater than number of values"
  278. << " provided.");
  279. }
  280. for (size_t i = 0; i < records.size(); ++i) {
  281. DataTypeUtil::instance().writeToBuffer(values[i], records[i], buf);
  282. }
  283. }
  284. return (optionFactory(u, type, buf.begin(), buf.end()));
  285. }
  286. void
  287. OptionDefinition::sanityCheckUniverse(const Option::Universe expected_universe,
  288. const Option::Universe actual_universe) {
  289. if (expected_universe != actual_universe) {
  290. isc_throw(isc::BadValue, "invalid universe specified for the option");
  291. }
  292. }
  293. void
  294. OptionDefinition::validate() const {
  295. // Option name must not be empty.
  296. if (name_.empty()) {
  297. isc_throw(isc::BadValue, "option name must not be empty");
  298. }
  299. // Option name must not contain spaces.
  300. if (name_.find(" ") != string::npos) {
  301. isc_throw(isc::BadValue, "option name must not contain spaces");
  302. }
  303. // Unsupported option types are not allowed.
  304. if (type_ >= OPT_UNKNOWN_TYPE) {
  305. isc_throw(isc::OutOfRange, "option type value " << type_
  306. << " is out of range");
  307. }
  308. }
  309. bool
  310. OptionDefinition::haveIAx6Format(OptionDataType first_type) const {
  311. return (haveType(OPT_RECORD_TYPE) &&
  312. record_fields_.size() == 3 &&
  313. record_fields_[0] == first_type &&
  314. record_fields_[1] == OPT_UINT32_TYPE &&
  315. record_fields_[2] == OPT_UINT32_TYPE);
  316. }
  317. bool
  318. OptionDefinition::haveIA6Format() const {
  319. // Expect that IA_NA option format is defined as record.
  320. // Although it consists of 3 elements of the same (uint32)
  321. // type it can't be defined as array of uint32 elements because
  322. // arrays do not impose limitations on number of elements in
  323. // the array while this limitation is needed for IA_NA - need
  324. // exactly 3 elements.
  325. return (haveIAx6Format(OPT_UINT32_TYPE));
  326. }
  327. bool
  328. OptionDefinition::haveIAAddr6Format() const {
  329. return (haveIAx6Format(OPT_IPV6_ADDRESS_TYPE));
  330. }
  331. OptionPtr
  332. OptionDefinition::factoryAddrList4(Option::Universe u, uint16_t type,
  333. OptionBufferConstIter begin,
  334. OptionBufferConstIter end) {
  335. sanityCheckUniverse(u, Option::V4);
  336. boost::shared_ptr<Option4AddrLst> option(new Option4AddrLst(type, begin, end));
  337. return (option);
  338. }
  339. OptionPtr
  340. OptionDefinition::factoryAddrList6(Option::Universe u, uint16_t type,
  341. OptionBufferConstIter begin,
  342. OptionBufferConstIter end) {
  343. sanityCheckUniverse(u, Option::V6);
  344. boost::shared_ptr<Option6AddrLst> option(new Option6AddrLst(type, begin, end));
  345. return (option);
  346. }
  347. OptionPtr
  348. OptionDefinition::factoryEmpty(Option::Universe u, uint16_t type,
  349. OptionBufferConstIter,
  350. OptionBufferConstIter) {
  351. OptionPtr option(new Option(u, type));
  352. return (option);
  353. }
  354. OptionPtr
  355. OptionDefinition::factoryGeneric(Option::Universe u, uint16_t type,
  356. OptionBufferConstIter begin,
  357. OptionBufferConstIter end) {
  358. OptionPtr option(new Option(u, type, begin, end));
  359. return (option);
  360. }
  361. OptionPtr
  362. OptionDefinition::factoryIA6(Option::Universe u, uint16_t type,
  363. OptionBufferConstIter begin,
  364. OptionBufferConstIter end) {
  365. sanityCheckUniverse(u, Option::V6);
  366. if (std::distance(begin, end) < Option6IA::OPTION6_IA_LEN) {
  367. isc_throw(isc::OutOfRange, "input option buffer has invalid size, expected "
  368. "at least " << Option6IA::OPTION6_IA_LEN << " bytes");
  369. }
  370. boost::shared_ptr<Option6IA> option(new Option6IA(type, begin, end));
  371. return (option);
  372. }
  373. OptionPtr
  374. OptionDefinition::factoryIAAddr6(Option::Universe u, uint16_t type,
  375. OptionBufferConstIter begin,
  376. OptionBufferConstIter end) {
  377. sanityCheckUniverse(u, Option::V6);
  378. if (std::distance(begin, end) < Option6IAAddr::OPTION6_IAADDR_LEN) {
  379. isc_throw(isc::OutOfRange, "input option buffer has invalid size, expected "
  380. " at least " << Option6IAAddr::OPTION6_IAADDR_LEN << " bytes");
  381. }
  382. boost::shared_ptr<Option6IAAddr> option(new Option6IAAddr(type, begin, end));
  383. return (option);
  384. }
  385. } // end of isc::dhcp namespace
  386. } // end of isc namespace