option_definition.cc 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  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. // Lexical cast in case of our data types make sense only
  55. // for uintX_t, intX_t and bool type.
  56. if (!OptionDataTypeTraits<T>::integer_type &&
  57. OptionDataTypeTraits<T>::type != OPT_BOOLEAN_TYPE) {
  58. isc_throw(BadDataTypeCast, "unable to do lexical cast to non-integer and"
  59. << " non-boolean data type");
  60. }
  61. // We use the 64-bit value here because it has wider range than
  62. // any other type we use here and it allows to detect out of
  63. // bounds conditions e.g. negative value specified for uintX_t
  64. // data type. Obviously if the value exceeds the limits of int64
  65. // this function will not handle that properly.
  66. int64_t result = 0;
  67. try {
  68. result = boost::lexical_cast<int64_t>(value_str);
  69. } catch (const boost::bad_lexical_cast& ex) {
  70. // Prepare error message here.
  71. std::string data_type_str = "boolean";
  72. if (OptionDataTypeTraits<T>::integer_type) {
  73. data_type_str = "integer";
  74. }
  75. isc_throw(BadDataTypeCast, "unable to do lexical cast to " << data_type_str
  76. << " data type for value " << value_str << ": " << ex.what());
  77. }
  78. // Perform range checks for integer values only (exclude bool values).
  79. if (OptionDataTypeTraits<T>::integer_type) {
  80. if (result > numeric_limits<T>::max() ||
  81. result < numeric_limits<T>::min()) {
  82. isc_throw(BadDataTypeCast, "unable to do lexical cast for value "
  83. << value_str << ". This value is expected to be in the range of "
  84. << numeric_limits<T>::min() << ".." << numeric_limits<T>::max());
  85. }
  86. }
  87. return (static_cast<T>(result));
  88. }
  89. void
  90. OptionDefinition::DataTypeUtil::writeToBuffer(const std::string& value,
  91. const OptionDataType type,
  92. OptionBuffer& buf) {
  93. // We are going to write value given by value argument to the buffer.
  94. // The actual type of the value is given by second argument. Check
  95. // this argument to determine how to write this value to the buffer.
  96. switch (type) {
  97. case OPT_BINARY_TYPE:
  98. {
  99. // Binary value means that the value is encoded as a string
  100. // of hexadecimal deigits. We need to decode this string
  101. // to the binary format here.
  102. OptionBuffer binary;
  103. try {
  104. util::encode::decodeHex(value, binary);
  105. } catch (const Exception& ex) {
  106. isc_throw(BadDataTypeCast, "unable to cast " << value
  107. << " to binary data type: " << ex.what());
  108. }
  109. // Decode was successful so append decoded binary value
  110. // to the buffer.
  111. buf.insert(buf.end(), binary.begin(), binary.end());
  112. return;
  113. }
  114. case OPT_BOOLEAN_TYPE:
  115. {
  116. // We encode the true value as 1 and false as 0 on 8 bits.
  117. // That way we actually waist 7 bits but it seems to be the
  118. // simpler way to encode boolean.
  119. // @todo Consider if any other encode methods can be used.
  120. bool bool_value = lexicalCastWithRangeCheck<bool>(value);
  121. if (bool_value) {
  122. buf.push_back(static_cast<uint8_t>(1));
  123. } else {
  124. buf.push_back(static_cast<uint8_t>(0));
  125. }
  126. return;
  127. }
  128. case OPT_INT8_TYPE:
  129. {
  130. // Buffer holds the uin8_t values so we need to cast the signed
  131. // value to unsigned but the bits values remain untouched.
  132. buf.push_back(static_cast<uint8_t>(lexicalCastWithRangeCheck<int8_t>(value)));
  133. return;
  134. }
  135. case OPT_INT16_TYPE:
  136. {
  137. // Write the int16 value as uint16 value is ok because the bit values
  138. // remain untouched.
  139. int16_t int_value = lexicalCastWithRangeCheck<int16_t>(value);
  140. buf.resize(buf.size() + 2);
  141. writeUint16(static_cast<uint16_t>(int_value), &buf[buf.size() - 2]);
  142. return;
  143. }
  144. case OPT_INT32_TYPE:
  145. {
  146. int32_t int_value = lexicalCastWithRangeCheck<int32_t>(value);
  147. buf.resize(buf.size() + 4);
  148. writeUint32(static_cast<uint32_t>(int_value), &buf[buf.size() - 4]);
  149. return;
  150. }
  151. case OPT_UINT8_TYPE:
  152. {
  153. buf.push_back(lexicalCastWithRangeCheck<int8_t>(value));
  154. return;
  155. }
  156. case OPT_UINT16_TYPE:
  157. {
  158. uint16_t uint_value = lexicalCastWithRangeCheck<uint16_t>(value);
  159. buf.resize(buf.size() + 2);
  160. writeUint16(uint_value, &buf[buf.size() - 2]);
  161. return;
  162. }
  163. case OPT_UINT32_TYPE:
  164. {
  165. uint32_t uint_value = lexicalCastWithRangeCheck<uint32_t>(value);
  166. buf.resize(buf.size() + 4);
  167. writeUint32(uint_value, &buf[buf.size() - 4]);
  168. return;
  169. }
  170. case OPT_IPV4_ADDRESS_TYPE:
  171. {
  172. // The easiest way to get the binary form of IPv4 address is
  173. // to create IOAddress object from string and use its accessors
  174. // to retrieve the binary form.
  175. asiolink::IOAddress address(value);
  176. if (!address.getAddress().is_v4()) {
  177. isc_throw(BadDataTypeCast, "provided address " << address.toText()
  178. << " is not a valid IPV4 address");
  179. }
  180. asio::ip::address_v4::bytes_type addr_bytes =
  181. address.getAddress().to_v4().to_bytes();
  182. // Increase the buffer size by the size of IPv4 address.
  183. buf.resize(buf.size() + addr_bytes.size());
  184. std::copy_backward(addr_bytes.begin(), addr_bytes.end(),
  185. buf.end());
  186. return;
  187. }
  188. case OPT_IPV6_ADDRESS_TYPE:
  189. {
  190. asiolink::IOAddress address(value);
  191. if (!address.getAddress().is_v6()) {
  192. isc_throw(BadDataTypeCast, "provided address " << address.toText()
  193. << " is not a valid IPV6 address");
  194. }
  195. asio::ip::address_v6::bytes_type addr_bytes =
  196. address.getAddress().to_v6().to_bytes();
  197. // Incresase the buffer size by the size of IPv6 address.
  198. buf.resize(buf.size() + addr_bytes.size());
  199. std::copy_backward(addr_bytes.begin(), addr_bytes.end(),
  200. buf.end());
  201. return;
  202. }
  203. case OPT_STRING_TYPE:
  204. if (value.size() > 0) {
  205. // Increase the size of the storage by the size of the string.
  206. buf.resize(buf.size() + value.size());
  207. // Assuming that the string is already UTF8 encoded.
  208. std::copy_backward(value.c_str(), value.c_str() + value.length(),
  209. buf.end());
  210. return;
  211. }
  212. case OPT_FQDN_TYPE:
  213. {
  214. // FQDN implementation is not terribly complicated but will require
  215. // creation of some additional logic (maybe object) that will parse
  216. // the fqdn into labels.
  217. isc_throw(isc::NotImplemented, "write of FQDN record into option buffer"
  218. " is not supported yet");
  219. return;
  220. }
  221. default:
  222. // We hit this point because invalid option data type has been specified
  223. // This may be the case because 'empty' or 'record' data type has been
  224. // specified. We don't throw exception here because it will be thrown
  225. // at the exit point from this function.
  226. ;
  227. }
  228. isc_throw(isc::BadValue, "attempt to write invalid option data field type"
  229. " into the option buffer: " << type);
  230. }
  231. OptionDefinition::OptionDefinition(const std::string& name,
  232. const uint16_t code,
  233. const std::string& type,
  234. const bool array_type /* = false */)
  235. : name_(name),
  236. code_(code),
  237. type_(OPT_UNKNOWN_TYPE),
  238. array_type_(array_type) {
  239. // Data type is held as enum value by this class.
  240. // Use the provided option type string to get the
  241. // corresponding enum value.
  242. type_ = DataTypeUtil::instance().getOptionDataType(type);
  243. }
  244. OptionDefinition::OptionDefinition(const std::string& name,
  245. const uint16_t code,
  246. const OptionDataType type,
  247. const bool array_type /* = false */)
  248. : name_(name),
  249. code_(code),
  250. type_(type),
  251. array_type_(array_type) {
  252. }
  253. void
  254. OptionDefinition::addRecordField(const std::string& data_type_name) {
  255. OptionDataType data_type = DataTypeUtil::instance().getOptionDataType(data_type_name);
  256. addRecordField(data_type);
  257. }
  258. void
  259. OptionDefinition::addRecordField(const OptionDataType data_type) {
  260. if (type_ != OPT_RECORD_TYPE) {
  261. isc_throw(isc::InvalidOperation, "'record' option type must be used"
  262. " to add data fields to the record");
  263. }
  264. if (data_type >= OPT_UNKNOWN_TYPE) {
  265. isc_throw(isc::BadValue, "attempted to add invalid data type to the record");
  266. }
  267. record_fields_.push_back(data_type);
  268. }
  269. OptionPtr
  270. OptionDefinition::optionFactory(Option::Universe u, uint16_t type,
  271. OptionBufferConstIter begin,
  272. OptionBufferConstIter end) const {
  273. validate();
  274. try {
  275. if (type_ == OPT_BINARY_TYPE) {
  276. return (factoryGeneric(u, type, begin, end));
  277. } else if (type_ == OPT_IPV6_ADDRESS_TYPE && array_type_) {
  278. return (factoryAddrList6(type, begin, end));
  279. } else if (type_ == OPT_IPV4_ADDRESS_TYPE && array_type_) {
  280. return (factoryAddrList4(type, begin, end));
  281. } else if (type_ == OPT_EMPTY_TYPE) {
  282. return (factoryEmpty(u, type));
  283. } else if (u == Option::V6 &&
  284. code_ == D6O_IA_NA &&
  285. haveIA6Format()) {
  286. return (factoryIA6(type, begin, end));
  287. } else if (u == Option::V6 &&
  288. code_ == D6O_IAADDR &&
  289. haveIAAddr6Format()) {
  290. return (factoryIAAddr6(type, begin, end));
  291. } else if (type_ == OPT_UINT8_TYPE) {
  292. if (array_type_) {
  293. return (factoryGeneric(u, type, begin, end));
  294. } else {
  295. return (factoryInteger<uint8_t>(u, type, begin, end));
  296. }
  297. } else if (type_ == OPT_UINT16_TYPE) {
  298. if (array_type_) {
  299. return (factoryIntegerArray<uint16_t>(type, begin, end));
  300. } else {
  301. return (factoryInteger<uint16_t>(u, type, begin, end));
  302. }
  303. } else if (type_ == OPT_UINT32_TYPE) {
  304. if (array_type_) {
  305. return (factoryIntegerArray<uint32_t>(type, begin, end));
  306. } else {
  307. return (factoryInteger<uint32_t>(u, type, begin, end));
  308. }
  309. }
  310. return (factoryGeneric(u, type, begin, end));
  311. } catch (const Exception& ex) {
  312. isc_throw(InvalidOptionValue, ex.what());
  313. }
  314. }
  315. OptionPtr
  316. OptionDefinition::optionFactory(Option::Universe u, uint16_t type,
  317. const OptionBuffer& buf) const {
  318. return (optionFactory(u, type, buf.begin(), buf.end()));
  319. }
  320. OptionPtr
  321. OptionDefinition::optionFactory(Option::Universe u, uint16_t type,
  322. const std::vector<std::string>& values) const {
  323. validate();
  324. OptionBuffer buf;
  325. if (!array_type_ && type_ != OPT_RECORD_TYPE) {
  326. if (values.size() == 0) {
  327. isc_throw(InvalidOptionValue, "no option value specified");
  328. }
  329. DataTypeUtil::instance().writeToBuffer(values[0], type_, buf);
  330. } else if (array_type_ && type_ != OPT_RECORD_TYPE) {
  331. for (size_t i = 0; i < values.size(); ++i) {
  332. DataTypeUtil::instance().writeToBuffer(values[i], type_, buf);
  333. }
  334. } else if (type_ == OPT_RECORD_TYPE) {
  335. const RecordFieldsCollection& records = getRecordFields();
  336. if (records.size() > values.size()) {
  337. isc_throw(InvalidOptionValue, "number of data fields for the option"
  338. << " type " << type_ << " is greater than number of values"
  339. << " provided.");
  340. }
  341. for (size_t i = 0; i < records.size(); ++i) {
  342. DataTypeUtil::instance().writeToBuffer(values[i], records[i], buf);
  343. }
  344. }
  345. return (optionFactory(u, type, buf.begin(), buf.end()));
  346. }
  347. void
  348. OptionDefinition::sanityCheckUniverse(const Option::Universe expected_universe,
  349. const Option::Universe actual_universe) {
  350. if (expected_universe != actual_universe) {
  351. isc_throw(isc::BadValue, "invalid universe specified for the option");
  352. }
  353. }
  354. void
  355. OptionDefinition::validate() const {
  356. std::ostringstream err_str;
  357. if (name_.empty()) {
  358. // Option name must not be empty.
  359. err_str << "option name must not be empty";
  360. } else if (name_.find(" ") != string::npos) {
  361. // Option name must not contain spaces.
  362. err_str << "option name must not contain spaces";
  363. } else if (type_ >= OPT_UNKNOWN_TYPE) {
  364. // Option definition must be of a known type.
  365. err_str << "option type value " << type_ << " is out of range";
  366. } else if (type_ == OPT_STRING_TYPE && array_type_) {
  367. // Array of strings is not allowed because there is no way
  368. // to determine the size of a particular string and thus there
  369. // it no way to tell when other data fields begin.
  370. err_str << "array of strings is not a valid option definition";
  371. } else if (type_ == OPT_RECORD_TYPE) {
  372. // At least two data fields should be added to the record. Otherwise
  373. // non-record option definition could be used.
  374. if (getRecordFields().size() < 2) {
  375. err_str << "invalid number of data fields: " << getRecordFields().size()
  376. << " specified for the option of type 'record'. Expected at"
  377. << " least 2 fields.";
  378. } else {
  379. // If the number of fields is valid we have to check if their order
  380. // is valid too. We check that string data fields are not laid before
  381. // other fields. But we allow that they are laid at the end of
  382. // an option.
  383. const RecordFieldsCollection& fields = getRecordFields();
  384. for (RecordFieldsConstIter it = fields.begin();
  385. it != fields.end(); ++it) {
  386. if (*it == OPT_STRING_TYPE &&
  387. it < fields.end() - 1) {
  388. err_str << "string data field can't be laid before data fields"
  389. << " of other types.";
  390. break;
  391. }
  392. }
  393. }
  394. }
  395. // Non-empty error string means that we have hit the error. We throw
  396. // exception and include error string.
  397. if (!err_str.str().empty()) {
  398. isc_throw(MalformedOptionDefinition, err_str.str());
  399. }
  400. }
  401. bool
  402. OptionDefinition::haveIAx6Format(OptionDataType first_type) const {
  403. return (haveType(OPT_RECORD_TYPE) &&
  404. record_fields_.size() == 3 &&
  405. record_fields_[0] == first_type &&
  406. record_fields_[1] == OPT_UINT32_TYPE &&
  407. record_fields_[2] == OPT_UINT32_TYPE);
  408. }
  409. bool
  410. OptionDefinition::haveIA6Format() const {
  411. // Expect that IA_NA option format is defined as record.
  412. // Although it consists of 3 elements of the same (uint32)
  413. // type it can't be defined as array of uint32 elements because
  414. // arrays do not impose limitations on number of elements in
  415. // the array while this limitation is needed for IA_NA - need
  416. // exactly 3 elements.
  417. return (haveIAx6Format(OPT_UINT32_TYPE));
  418. }
  419. bool
  420. OptionDefinition::haveIAAddr6Format() const {
  421. return (haveIAx6Format(OPT_IPV6_ADDRESS_TYPE));
  422. }
  423. OptionPtr
  424. OptionDefinition::factoryAddrList4(uint16_t type,
  425. OptionBufferConstIter begin,
  426. OptionBufferConstIter end) {
  427. boost::shared_ptr<Option4AddrLst> option(new Option4AddrLst(type, begin, end));
  428. return (option);
  429. }
  430. OptionPtr
  431. OptionDefinition::factoryAddrList6(uint16_t type,
  432. OptionBufferConstIter begin,
  433. OptionBufferConstIter end) {
  434. boost::shared_ptr<Option6AddrLst> option(new Option6AddrLst(type, begin, end));
  435. return (option);
  436. }
  437. OptionPtr
  438. OptionDefinition::factoryEmpty(Option::Universe u, uint16_t type) {
  439. OptionPtr option(new Option(u, type));
  440. return (option);
  441. }
  442. OptionPtr
  443. OptionDefinition::factoryGeneric(Option::Universe u, uint16_t type,
  444. OptionBufferConstIter begin,
  445. OptionBufferConstIter end) {
  446. OptionPtr option(new Option(u, type, begin, end));
  447. return (option);
  448. }
  449. OptionPtr
  450. OptionDefinition::factoryIA6(uint16_t type,
  451. OptionBufferConstIter begin,
  452. OptionBufferConstIter end) {
  453. if (std::distance(begin, end) < Option6IA::OPTION6_IA_LEN) {
  454. isc_throw(isc::OutOfRange, "input option buffer has invalid size, expected "
  455. "at least " << Option6IA::OPTION6_IA_LEN << " bytes");
  456. }
  457. boost::shared_ptr<Option6IA> option(new Option6IA(type, begin, end));
  458. return (option);
  459. }
  460. OptionPtr
  461. OptionDefinition::factoryIAAddr6(uint16_t type,
  462. OptionBufferConstIter begin,
  463. OptionBufferConstIter end) {
  464. if (std::distance(begin, end) < Option6IAAddr::OPTION6_IAADDR_LEN) {
  465. isc_throw(isc::OutOfRange, "input option buffer has invalid size, expected "
  466. " at least " << Option6IAAddr::OPTION6_IAADDR_LEN << " bytes");
  467. }
  468. boost::shared_ptr<Option6IAAddr> option(new Option6IAAddr(type, begin, end));
  469. return (option);
  470. }
  471. } // end of isc::dhcp namespace
  472. } // end of isc namespace