libdhcp++_unittest.cc 75 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748
  1. // Copyright (C) 2011-2016 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 <asiolink/io_address.h>
  8. #include <dhcp/dhcp4.h>
  9. #include <dhcp/dhcp6.h>
  10. #include <dhcp/docsis3_option_defs.h>
  11. #include <dhcp/libdhcp++.h>
  12. #include <dhcp/option4_addrlst.h>
  13. #include <dhcp/option4_client_fqdn.h>
  14. #include <dhcp/option6_addrlst.h>
  15. #include <dhcp/option6_client_fqdn.h>
  16. #include <dhcp/option6_ia.h>
  17. #include <dhcp/option6_iaaddr.h>
  18. #include <dhcp/option6_iaprefix.h>
  19. #include <dhcp/option6_status_code.h>
  20. #include <dhcp/option_custom.h>
  21. #include <dhcp/option_int.h>
  22. #include <dhcp/option_int_array.h>
  23. #include <dhcp/option_opaque_data_tuples.h>
  24. #include <dhcp/option_space.h>
  25. #include <dhcp/option_string.h>
  26. #include <dhcp/option_vendor.h>
  27. #include <dhcp/option_vendor_class.h>
  28. #include <util/buffer.h>
  29. #include <util/encode/hex.h>
  30. #include <boost/pointer_cast.hpp>
  31. #include <gtest/gtest.h>
  32. #include <iostream>
  33. #include <sstream>
  34. #include <typeinfo>
  35. #include <arpa/inet.h>
  36. using namespace std;
  37. using namespace isc;
  38. using namespace isc::asiolink;
  39. using namespace isc::dhcp;
  40. using namespace isc::util;
  41. namespace {
  42. // DHCPv6 suboptions of Vendor Options Option.
  43. /// @todo move to src/lib/dhcp/docsis3_option_defs.h once #3194 is merged.
  44. const uint16_t OPTION_CMTS_CAPS = 1025;
  45. const uint16_t OPTION_CM_MAC = 1026;
  46. class LibDhcpTest : public ::testing::Test {
  47. public:
  48. /// @brief Constructor.
  49. ///
  50. /// Removes runtime option definitions.
  51. LibDhcpTest() {
  52. LibDHCP::clearRuntimeOptionDefs();
  53. }
  54. /// @brief Destructor.
  55. ///
  56. /// Removes runtime option definitions.
  57. virtual ~LibDhcpTest() {
  58. LibDHCP::clearRuntimeOptionDefs();
  59. }
  60. /// @brief Generic factory function to create any option.
  61. ///
  62. /// Generic factory function to create any option.
  63. ///
  64. /// @param u universe (V4 or V6)
  65. /// @param type option-type
  66. /// @param buf option-buffer
  67. static OptionPtr genericOptionFactory(Option::Universe u, uint16_t type,
  68. const OptionBuffer& buf) {
  69. return (OptionPtr(new Option(u, type, buf)));
  70. }
  71. /// @brief Test DHCPv4 option definition.
  72. ///
  73. /// This function tests if option definition for standard
  74. /// option has been initialized correctly.
  75. ///
  76. /// @param code option code.
  77. /// @param begin iterator pointing at beginning of a buffer to
  78. /// be used to create option instance.
  79. /// @param end iterator pointing at end of a buffer to be
  80. /// used to create option instance.
  81. /// @param expected_type type of the option created by the
  82. /// factory function returned by the option definition.
  83. /// @param encapsulates name of the option space being encapsulated
  84. /// by the option.
  85. static void testStdOptionDefs4(const uint16_t code,
  86. const OptionBufferConstIter begin,
  87. const OptionBufferConstIter end,
  88. const std::type_info& expected_type,
  89. const std::string& encapsulates = "") {
  90. // Use V4 universe.
  91. testStdOptionDefs(Option::V4, code, begin, end, expected_type,
  92. encapsulates);
  93. }
  94. /// @brief Test DHCPv6 option definition.
  95. ///
  96. /// This function tests if option definition for standard
  97. /// option has been initialized correctly.
  98. ///
  99. /// @param code option code.
  100. /// @param begin iterator pointing at beginning of a buffer to
  101. /// be used to create option instance.
  102. /// @param end iterator pointing at end of a buffer to be
  103. /// used to create option instance.
  104. /// @param expected_type type of the option created by the
  105. /// factory function returned by the option definition.
  106. /// @param encapsulates name of the option space being encapsulated
  107. /// by the option.
  108. static void testStdOptionDefs6(const uint16_t code,
  109. const OptionBufferConstIter begin,
  110. const OptionBufferConstIter end,
  111. const std::type_info& expected_type,
  112. const std::string& encapsulates = "") {
  113. // Use V6 universe.
  114. testStdOptionDefs(Option::V6, code, begin, end, expected_type,
  115. encapsulates);
  116. }
  117. /// @brief Create a sample DHCPv4 option 43 with suboptions.
  118. static OptionBuffer createVendorOption() {
  119. const uint8_t opt_data[] = {
  120. 0x2B, 0x0D, // Vendor-Specific Information (CableLabs)
  121. // Suboptions start here...
  122. 0x02, 0x05, // Device Type Option (length = 5)
  123. 'D', 'u', 'm', 'm', 'y',
  124. 0x04, 0x04, // Serial Number Option (length = 4)
  125. 0x42, 0x52, 0x32, 0x32 // Serial number
  126. };
  127. return (OptionBuffer(opt_data, opt_data + sizeof(opt_data)));
  128. }
  129. /// @brief Create a sample DHCPv4 option 82 with suboptions.
  130. static OptionBuffer createAgentInformationOption() {
  131. const uint8_t opt_data[] = {
  132. 0x52, 0x0E, // Agent Information Option (length = 14)
  133. // Suboptions start here...
  134. 0x01, 0x04, // Agent Circuit ID (length = 4)
  135. 0x20, 0x00, 0x00, 0x02, // ID
  136. 0x02, 0x06, // Agent Remote ID
  137. 0x20, 0xE5, 0x2A, 0xB8, 0x15, 0x14 // ID
  138. };
  139. return (OptionBuffer(opt_data, opt_data + sizeof(opt_data)));
  140. }
  141. /// @brief Create option definitions and store in the container.
  142. ///
  143. /// @param spaces_num Number of option spaces to be created.
  144. /// @param defs_num Number of option definitions to be created for
  145. /// each option space.
  146. /// @param [out] defs Container to which option definitions should be
  147. /// added.
  148. static void createRuntimeOptionDefs(const uint16_t spaces_num,
  149. const uint16_t defs_num,
  150. OptionDefSpaceContainer& defs) {
  151. for (uint16_t space = 0; space < spaces_num; ++space) {
  152. std::ostringstream space_name;
  153. space_name << "option-space-" << space;
  154. for (uint16_t code = 0; code < defs_num; ++code) {
  155. std::ostringstream name;
  156. name << "name-for-option-" << code;
  157. OptionDefinitionPtr opt_def(new OptionDefinition(name.str(),
  158. code, "string"));
  159. defs.addItem(opt_def, space_name.str());
  160. }
  161. }
  162. }
  163. /// @brief Test if runtime option definitions have been added.
  164. ///
  165. /// This method uses the same naming conventions for space names and
  166. /// options names as @c createRuntimeOptionDefs method.
  167. ///
  168. /// @param spaces_num Number of option spaces to be tested.
  169. /// @param defs_num Number of option definitions that should exist
  170. /// in each option space.
  171. /// @param should_exist Boolean value which indicates if option
  172. /// definitions should exist. If this is false, this function will
  173. /// check that they don't exist.
  174. static void testRuntimeOptionDefs(const uint16_t spaces_num,
  175. const uint16_t defs_num,
  176. const bool should_exist) {
  177. for (uint16_t space = 0; space < spaces_num; ++space) {
  178. std::ostringstream space_name;
  179. space_name << "option-space-" << space;
  180. for (uint16_t code = 0; code < defs_num; ++code) {
  181. std::ostringstream name;
  182. name << "name-for-option-" << code;
  183. OptionDefinitionPtr opt_def =
  184. LibDHCP::getRuntimeOptionDef(space_name.str(), name.str());
  185. if (should_exist) {
  186. ASSERT_TRUE(opt_def);
  187. } else {
  188. ASSERT_FALSE(opt_def);
  189. }
  190. }
  191. }
  192. }
  193. private:
  194. /// @brief Test DHCPv4 or DHCPv6 option definition.
  195. ///
  196. /// This function tests if option definition for standard
  197. /// option has been initialized correctly.
  198. ///
  199. /// @param code option code.
  200. /// @param begin iterator pointing at beginning of a buffer to
  201. /// be used to create option instance.
  202. /// @param end iterator pointing at end of a buffer to be
  203. /// used to create option instance.
  204. /// @param expected_type type of the option created by the
  205. /// factory function returned by the option definition.
  206. /// @param encapsulates name of the option space being encapsulated
  207. /// by the option.
  208. static void testStdOptionDefs(const Option::Universe u,
  209. const uint16_t code,
  210. const OptionBufferConstIter begin,
  211. const OptionBufferConstIter end,
  212. const std::type_info& expected_type,
  213. const std::string& encapsulates) {
  214. // Get all option definitions, we will use them to extract
  215. // the definition for a particular option code.
  216. // We don't have to initialize option definitions here because they
  217. // are initialized in the class's constructor.
  218. OptionDefContainerPtr options = LibDHCP::getOptionDefs(u);
  219. // Get the container index #1. This one allows for searching
  220. // option definitions using option code.
  221. const OptionDefContainerTypeIndex& idx = options->get<1>();
  222. // Get 'all' option definitions for a particular option code.
  223. // For standard options we expect that the range returned
  224. // will contain single option as their codes are unique.
  225. OptionDefContainerTypeRange range = idx.equal_range(code);
  226. ASSERT_EQ(1, std::distance(range.first, range.second))
  227. << "Standard option definition for the code " << code
  228. << " has not been found.";
  229. // If we have single option definition returned, the
  230. // first iterator holds it.
  231. OptionDefinitionPtr def = *(range.first);
  232. // It should not happen that option definition is NULL but
  233. // let's make sure (test should take things like that into
  234. // account).
  235. ASSERT_TRUE(def) << "Option definition for the code "
  236. << code << " is NULL.";
  237. // Check that option definition is valid.
  238. ASSERT_NO_THROW(def->validate())
  239. << "Option definition for the option code " << code
  240. << " is invalid";
  241. // Check that the valid encapsulated option space name
  242. // has been specified.
  243. EXPECT_EQ(encapsulates, def->getEncapsulatedSpace());
  244. OptionPtr option;
  245. // Create the option.
  246. ASSERT_NO_THROW(option = def->optionFactory(u, code, begin, end))
  247. << "Option creation failed for option code " << code;
  248. // Make sure it is not NULL.
  249. ASSERT_TRUE(option);
  250. // And the actual object type is the one that we expect.
  251. // Note that for many options there are dedicated classes
  252. // derived from Option class to represent them.
  253. const Option* optptr = option.get();
  254. EXPECT_TRUE(typeid(*optptr) == expected_type)
  255. << "Invalid class returned for option code " << code;
  256. }
  257. };
  258. // The DHCPv6 options in the wire format, used by multiple tests.
  259. const uint8_t v6packed[] = {
  260. 0, 1, 0, 5, 100, 101, 102, 103, 104, // CLIENT_ID (9 bytes)
  261. 0, 2, 0, 3, 105, 106, 107, // SERVER_ID (7 bytes)
  262. 0, 14, 0, 0, // RAPID_COMMIT (0 bytes)
  263. 0, 6, 0, 4, 108, 109, 110, 111, // ORO (8 bytes)
  264. 0, 8, 0, 2, 112, 113, // ELAPSED_TIME (6 bytes)
  265. // Vendor Specific Information Option starts here
  266. 0x00, 0x11, // VSI Option Code
  267. 0x00, 0x16, // VSI Option Length
  268. 0x00, 0x00, 0x11, 0x8B, // Enterprise ID
  269. 0x04, 0x01, // CMTS Capabilities Option
  270. 0x00, 0x04, // Length
  271. 0x01, 0x02,
  272. 0x03, 0x00, // DOCSIS Version Number
  273. 0x04, 0x02, // CM MAC Address Suboption
  274. 0x00, 0x06, // Length
  275. 0x74, 0x56, 0x12, 0x29, 0x97, 0xD0, // Actual MAC Address
  276. };
  277. TEST_F(LibDhcpTest, optionFactory) {
  278. OptionBuffer buf;
  279. // Factory functions for specific options must be registered before
  280. // they can be used to create options instances. Otherwise exception
  281. // is rised.
  282. EXPECT_THROW(LibDHCP::optionFactory(Option::V4, DHO_SUBNET_MASK, buf),
  283. isc::BadValue);
  284. // Let's register some factory functions (two v4 and one v6 function).
  285. // Registration may trigger exception if function for the specified
  286. // option has been registered already.
  287. ASSERT_NO_THROW(
  288. LibDHCP::OptionFactoryRegister(Option::V4, DHO_SUBNET_MASK,
  289. &LibDhcpTest::genericOptionFactory);
  290. );
  291. ASSERT_NO_THROW(
  292. LibDHCP::OptionFactoryRegister(Option::V4, DHO_TIME_OFFSET,
  293. &LibDhcpTest::genericOptionFactory);
  294. );
  295. ASSERT_NO_THROW(
  296. LibDHCP::OptionFactoryRegister(Option::V6, D6O_CLIENTID,
  297. &LibDhcpTest::genericOptionFactory);
  298. );
  299. // Invoke factory functions for all options (check if registration
  300. // was successful).
  301. OptionPtr opt_subnet_mask;
  302. opt_subnet_mask = LibDHCP::optionFactory(Option::V4,
  303. DHO_SUBNET_MASK,
  304. buf);
  305. // Check if non-NULL DHO_SUBNET_MASK option pointer has been returned.
  306. ASSERT_TRUE(opt_subnet_mask);
  307. // Validate if type and universe is correct.
  308. EXPECT_EQ(Option::V4, opt_subnet_mask->getUniverse());
  309. EXPECT_EQ(DHO_SUBNET_MASK, opt_subnet_mask->getType());
  310. // Expect that option does not have content..
  311. EXPECT_EQ(0, opt_subnet_mask->len() - opt_subnet_mask->getHeaderLen());
  312. // Fill the time offset buffer with 4 bytes of data. Each byte set to 1.
  313. OptionBuffer time_offset_buf(4, 1);
  314. OptionPtr opt_time_offset;
  315. opt_time_offset = LibDHCP::optionFactory(Option::V4,
  316. DHO_TIME_OFFSET,
  317. time_offset_buf);
  318. // Check if non-NULL DHO_TIME_OFFSET option pointer has been returned.
  319. ASSERT_TRUE(opt_time_offset);
  320. // Validate if option length, type and universe is correct.
  321. EXPECT_EQ(Option::V4, opt_time_offset->getUniverse());
  322. EXPECT_EQ(DHO_TIME_OFFSET, opt_time_offset->getType());
  323. EXPECT_EQ(time_offset_buf.size(),
  324. opt_time_offset->len() - opt_time_offset->getHeaderLen());
  325. // Validate data in the option.
  326. EXPECT_TRUE(std::equal(time_offset_buf.begin(), time_offset_buf.end(),
  327. opt_time_offset->getData().begin()));
  328. // Fill the client id buffer with 20 bytes of data. Each byte set to 2.
  329. OptionBuffer clientid_buf(20, 2);
  330. OptionPtr opt_clientid;
  331. opt_clientid = LibDHCP::optionFactory(Option::V6,
  332. D6O_CLIENTID,
  333. clientid_buf);
  334. // Check if non-NULL D6O_CLIENTID option pointer has been returned.
  335. ASSERT_TRUE(opt_clientid);
  336. // Validate if option length, type and universe is correct.
  337. EXPECT_EQ(Option::V6, opt_clientid->getUniverse());
  338. EXPECT_EQ(D6O_CLIENTID, opt_clientid->getType());
  339. EXPECT_EQ(clientid_buf.size(), opt_clientid->len() - opt_clientid->getHeaderLen());
  340. // Validate data in the option.
  341. EXPECT_TRUE(std::equal(clientid_buf.begin(), clientid_buf.end(),
  342. opt_clientid->getData().begin()));
  343. }
  344. TEST_F(LibDhcpTest, packOptions6) {
  345. OptionBuffer buf(512);
  346. isc::dhcp::OptionCollection opts; // list of options
  347. // generate content for options
  348. for (unsigned i = 0; i < 64; i++) {
  349. buf[i]=i+100;
  350. }
  351. OptionPtr opt1(new Option(Option::V6, 1, buf.begin() + 0, buf.begin() + 5));
  352. OptionPtr opt2(new Option(Option::V6, 2, buf.begin() + 5, buf.begin() + 8));
  353. OptionPtr opt3(new Option(Option::V6, 14, buf.begin() + 8, buf.begin() + 8));
  354. OptionPtr opt4(new Option(Option::V6, 6, buf.begin() + 8, buf.begin() + 12));
  355. OptionPtr opt5(new Option(Option::V6, 8, buf.begin() + 12, buf.begin() + 14));
  356. OptionPtr cm_mac(new Option(Option::V6, OPTION_CM_MAC,
  357. OptionBuffer(v6packed + 54, v6packed + 60)));
  358. OptionPtr cmts_caps(new Option(Option::V6, OPTION_CMTS_CAPS,
  359. OptionBuffer(v6packed + 46, v6packed + 50)));
  360. boost::shared_ptr<OptionInt<uint32_t> >
  361. vsi(new OptionInt<uint32_t>(Option::V6, D6O_VENDOR_OPTS, 4491));
  362. vsi->addOption(cm_mac);
  363. vsi->addOption(cmts_caps);
  364. opts.insert(make_pair(opt1->getType(), opt1));
  365. opts.insert(make_pair(opt1->getType(), opt2));
  366. opts.insert(make_pair(opt1->getType(), opt3));
  367. opts.insert(make_pair(opt1->getType(), opt4));
  368. opts.insert(make_pair(opt1->getType(), opt5));
  369. opts.insert(make_pair(opt1->getType(), vsi));
  370. OutputBuffer assembled(512);
  371. EXPECT_NO_THROW(LibDHCP::packOptions6(assembled, opts));
  372. EXPECT_EQ(sizeof(v6packed), assembled.getLength());
  373. EXPECT_EQ(0, memcmp(assembled.getData(), v6packed, sizeof(v6packed)));
  374. }
  375. TEST_F(LibDhcpTest, unpackOptions6) {
  376. // just couple of random options
  377. // Option is used as a simple option implementation
  378. // More advanced uses are validated in tests dedicated for
  379. // specific derived classes.
  380. isc::dhcp::OptionCollection options; // list of options
  381. OptionBuffer buf(512);
  382. memcpy(&buf[0], v6packed, sizeof(v6packed));
  383. EXPECT_NO_THROW ({
  384. LibDHCP::unpackOptions6(OptionBuffer(buf.begin(), buf.begin() + sizeof(v6packed)),
  385. "dhcp6", options);
  386. });
  387. EXPECT_EQ(options.size(), 6); // there should be 5 options
  388. isc::dhcp::OptionCollection::const_iterator x = options.find(1);
  389. ASSERT_FALSE(x == options.end()); // option 1 should exist
  390. EXPECT_EQ(1, x->second->getType()); // this should be option 1
  391. ASSERT_EQ(9, x->second->len()); // it should be of length 9
  392. ASSERT_EQ(5, x->second->getData().size());
  393. EXPECT_EQ(0, memcmp(&x->second->getData()[0], v6packed + 4, 5)); // data len=5
  394. x = options.find(2);
  395. ASSERT_FALSE(x == options.end()); // option 2 should exist
  396. EXPECT_EQ(2, x->second->getType()); // this should be option 2
  397. ASSERT_EQ(7, x->second->len()); // it should be of length 7
  398. ASSERT_EQ(3, x->second->getData().size());
  399. EXPECT_EQ(0, memcmp(&x->second->getData()[0], v6packed + 13, 3)); // data len=3
  400. x = options.find(14);
  401. ASSERT_FALSE(x == options.end()); // option 14 should exist
  402. EXPECT_EQ(14, x->second->getType()); // this should be option 14
  403. ASSERT_EQ(4, x->second->len()); // it should be of length 4
  404. EXPECT_EQ(0, x->second->getData().size()); // data len = 0
  405. x = options.find(6);
  406. ASSERT_FALSE(x == options.end()); // option 6 should exist
  407. EXPECT_EQ(6, x->second->getType()); // this should be option 6
  408. ASSERT_EQ(8, x->second->len()); // it should be of length 8
  409. // Option with code 6 is the OPTION_ORO. This option is
  410. // represented by the OptionIntArray<uint16_t> class which
  411. // comprises the set of uint16_t values. We need to cast the
  412. // returned pointer to this type to get values stored in it.
  413. boost::shared_ptr<OptionIntArray<uint16_t> > opt_oro =
  414. boost::dynamic_pointer_cast<OptionIntArray<uint16_t> >(x->second);
  415. // This value will be NULL if cast was unsuccessful. This is the case
  416. // when returned option has different type than expected.
  417. ASSERT_TRUE(opt_oro);
  418. // Get set of uint16_t values.
  419. std::vector<uint16_t> opts = opt_oro->getValues();
  420. // Prepare the refrence data.
  421. std::vector<uint16_t> expected_opts;
  422. expected_opts.push_back(0x6C6D); // equivalent to: 108, 109
  423. expected_opts.push_back(0x6E6F); // equivalent to 110, 111
  424. ASSERT_EQ(expected_opts.size(), opts.size());
  425. // Validated if option has been unpacked correctly.
  426. EXPECT_TRUE(std::equal(expected_opts.begin(), expected_opts.end(),
  427. opts.begin()));
  428. x = options.find(8);
  429. ASSERT_FALSE(x == options.end()); // option 8 should exist
  430. EXPECT_EQ(8, x->second->getType()); // this should be option 8
  431. ASSERT_EQ(6, x->second->len()); // it should be of length 9
  432. // Option with code 8 is OPTION_ELAPSED_TIME. This option is
  433. // represented by Option6Int<uint16_t> value that holds single
  434. // uint16_t value.
  435. boost::shared_ptr<OptionInt<uint16_t> > opt_elapsed_time =
  436. boost::dynamic_pointer_cast<OptionInt<uint16_t> >(x->second);
  437. // This value will be NULL if cast was unsuccessful. This is the case
  438. // when returned option has different type than expected.
  439. ASSERT_TRUE(opt_elapsed_time);
  440. // Returned value should be equivalent to two byte values: 112, 113
  441. EXPECT_EQ(0x7071, opt_elapsed_time->getValue());
  442. // Check if Vendor Specific Information Option along with suboptions
  443. // have been parsed correctly.
  444. x = options.find(D6O_VENDOR_OPTS);
  445. EXPECT_FALSE(x == options.end());
  446. EXPECT_EQ(D6O_VENDOR_OPTS, x->second->getType());
  447. EXPECT_EQ(26, x->second->len());
  448. // CM MAC Address Option
  449. OptionPtr cm_mac = x->second->getOption(OPTION_CM_MAC);
  450. ASSERT_TRUE(cm_mac);
  451. EXPECT_EQ(OPTION_CM_MAC, cm_mac->getType());
  452. ASSERT_EQ(10, cm_mac->len());
  453. EXPECT_EQ(0, memcmp(&cm_mac->getData()[0], v6packed + 54, 6));
  454. // CMTS Capabilities
  455. OptionPtr cmts_caps = x->second->getOption(OPTION_CMTS_CAPS);
  456. ASSERT_TRUE(cmts_caps);
  457. EXPECT_EQ(OPTION_CMTS_CAPS, cmts_caps->getType());
  458. ASSERT_EQ(8, cmts_caps->len());
  459. EXPECT_EQ(0, memcmp(&cmts_caps->getData()[0], v6packed + 46, 4));
  460. x = options.find(0);
  461. EXPECT_TRUE(x == options.end()); // option 0 not found
  462. x = options.find(256); // 256 is htons(1) on little endians. Worth checking
  463. EXPECT_TRUE(x == options.end()); // option 1 not found
  464. x = options.find(7);
  465. EXPECT_TRUE(x == options.end()); // option 2 not found
  466. x = options.find(32000);
  467. EXPECT_TRUE(x == options.end()); // option 32000 not found */
  468. }
  469. // Check parsing of an empty DHCPv6 option.
  470. TEST_F(LibDhcpTest, unpackEmptyOption6) {
  471. // Create option definition for the option code 1024 without fields.
  472. OptionDefinitionPtr opt_def(new OptionDefinition("option-empty", 1024,
  473. "empty", false));
  474. // Use it as runtime option definition within standard options space.
  475. // The tested code should find this option definition within runtime
  476. // option definitions set when it detects that this definition is
  477. // not a standard definition.
  478. OptionDefSpaceContainer defs;
  479. defs.addItem(opt_def, DHCP6_OPTION_SPACE);
  480. LibDHCP::setRuntimeOptionDefs(defs);
  481. LibDHCP::commitRuntimeOptionDefs();
  482. // Create the buffer holding the structure of the empty option.
  483. const uint8_t raw_data[] = {
  484. 0x04, 0x00, // option code = 1024
  485. 0x00, 0x00 // option length = 0
  486. };
  487. size_t raw_data_len = sizeof(raw_data) / sizeof(uint8_t);
  488. OptionBuffer buf(raw_data, raw_data + raw_data_len);
  489. // Parse options.
  490. OptionCollection options;
  491. ASSERT_NO_THROW(LibDHCP::unpackOptions6(buf, DHCP6_OPTION_SPACE,
  492. options));
  493. // There should be one option.
  494. ASSERT_EQ(1, options.size());
  495. OptionPtr option_empty = options.begin()->second;
  496. ASSERT_TRUE(option_empty);
  497. EXPECT_EQ(1024, option_empty->getType());
  498. EXPECT_EQ(4, option_empty->len());
  499. }
  500. // This test verifies that the following option structure can be parsed:
  501. // - option (option space 'foobar')
  502. // - sub option (option space 'foo')
  503. // - sub option (option space 'bar')
  504. TEST_F(LibDhcpTest, unpackSubOptions6) {
  505. // Create option definition for each level of encapsulation. Each option
  506. // definition is for the option code 1. Options may have the same
  507. // option code because they belong to different option spaces.
  508. // Top level option encapsulates options which belong to 'space-foo'.
  509. OptionDefinitionPtr opt_def(new OptionDefinition("option-foobar", 1, "uint32",
  510. "space-foo"));\
  511. // Middle option encapsulates options which belong to 'space-bar'
  512. OptionDefinitionPtr opt_def2(new OptionDefinition("option-foo", 1, "uint16",
  513. "space-bar"));
  514. // Low level option doesn't encapsulate any option space.
  515. OptionDefinitionPtr opt_def3(new OptionDefinition("option-bar", 1,
  516. "uint8"));
  517. // Register created option definitions as runtime option definitions.
  518. OptionDefSpaceContainer defs;
  519. ASSERT_NO_THROW(defs.addItem(opt_def, "space-foobar"));
  520. ASSERT_NO_THROW(defs.addItem(opt_def2, "space-foo"));
  521. ASSERT_NO_THROW(defs.addItem(opt_def3, "space-bar"));
  522. LibDHCP::setRuntimeOptionDefs(defs);
  523. LibDHCP::commitRuntimeOptionDefs();
  524. // Create the buffer holding the structure of options.
  525. const char raw_data[] = {
  526. // First option starts here.
  527. 0x00, 0x01, // option code = 1
  528. 0x00, 0x0F, // option length = 15
  529. 0x00, 0x01, 0x02, 0x03, // This option carries uint32 value
  530. // Sub option starts here.
  531. 0x00, 0x01, // option code = 1
  532. 0x00, 0x07, // option length = 7
  533. 0x01, 0x02, // this option carries uint16 value
  534. // Last option starts here.
  535. 0x00, 0x01, // option code = 1
  536. 0x00, 0x01, // option length = 1
  537. 0x00 // This option carries a single uint8 value and has no sub options.
  538. };
  539. OptionBuffer buf(raw_data, raw_data + sizeof(raw_data));
  540. // Parse options.
  541. OptionCollection options;
  542. ASSERT_NO_THROW(LibDHCP::unpackOptions6(buf, "space-foobar", options, 0, 0));
  543. // There should be one top level option.
  544. ASSERT_EQ(1, options.size());
  545. boost::shared_ptr<OptionInt<uint32_t> > option_foobar =
  546. boost::dynamic_pointer_cast<OptionInt<uint32_t> >(options.begin()->
  547. second);
  548. ASSERT_TRUE(option_foobar);
  549. EXPECT_EQ(1, option_foobar->getType());
  550. EXPECT_EQ(0x00010203, option_foobar->getValue());
  551. // There should be a middle level option held in option_foobar.
  552. boost::shared_ptr<OptionInt<uint16_t> > option_foo =
  553. boost::dynamic_pointer_cast<OptionInt<uint16_t> >(option_foobar->
  554. getOption(1));
  555. ASSERT_TRUE(option_foo);
  556. EXPECT_EQ(1, option_foo->getType());
  557. EXPECT_EQ(0x0102, option_foo->getValue());
  558. // Finally, there should be a low level option under option_foo.
  559. boost::shared_ptr<OptionInt<uint8_t> > option_bar =
  560. boost::dynamic_pointer_cast<OptionInt<uint8_t> >(option_foo->getOption(1));
  561. ASSERT_TRUE(option_bar);
  562. EXPECT_EQ(1, option_bar->getType());
  563. EXPECT_EQ(0x0, option_bar->getValue());
  564. }
  565. /// V4 Options being used to test pack/unpack operations.
  566. /// These are variable length options only so as there
  567. /// is no restriction on the data length being carried by them.
  568. /// For simplicity, we assign data of the length 3 for each
  569. /// of them.
  570. static uint8_t v4_opts[] = {
  571. 12, 3, 0, 1, 2, // Hostname
  572. 60, 3, 10, 11, 12, // Class Id
  573. 14, 3, 20, 21, 22, // Merit Dump File
  574. 254, 3, 30, 31, 32, // Reserved
  575. 128, 3, 40, 41, 42, // Vendor specific
  576. 125, 11, 0, 0, 0x11, 0x8B, // V-I Vendor-Specific Information (Cable Labs)
  577. 6, 2, 4, 10, 0, 0, 10, // TFTP servers suboption (2)
  578. 43, 2, // Vendor Specific Information
  579. 0xDC, 0, // VSI suboption
  580. 0x52, 0x19, // RAI
  581. 0x01, 0x04, 0x20, 0x00, 0x00, 0x02, // Agent Circuit ID
  582. 0x02, 0x06, 0x20, 0xE5, 0x2A, 0xB8, 0x15, 0x14, // Agent Remote ID
  583. 0x09, 0x09, 0x00, 0x00, 0x11, 0x8B, 0x04, // Vendor Specific Information
  584. 0x01, 0x02, 0x03, 0x00 // Vendor Specific Information continued
  585. };
  586. // This test verifies that pack options for v4 is working correctly.
  587. TEST_F(LibDhcpTest, packOptions4) {
  588. vector<uint8_t> payload[5];
  589. for (unsigned i = 0; i < 5; i++) {
  590. payload[i].resize(3);
  591. payload[i][0] = i*10;
  592. payload[i][1] = i*10+1;
  593. payload[i][2] = i*10+2;
  594. }
  595. OptionPtr opt1(new Option(Option::V4, 12, payload[0]));
  596. OptionPtr opt2(new Option(Option::V4, 60, payload[1]));
  597. OptionPtr opt3(new Option(Option::V4, 14, payload[2]));
  598. OptionPtr opt4(new Option(Option::V4,254, payload[3]));
  599. OptionPtr opt5(new Option(Option::V4,128, payload[4]));
  600. // Create vendor option instance with DOCSIS3.0 enterprise id.
  601. OptionVendorPtr vivsi(new OptionVendor(Option::V4, 4491));
  602. vivsi->addOption(OptionPtr(new Option4AddrLst(DOCSIS3_V4_TFTP_SERVERS,
  603. IOAddress("10.0.0.10"))));
  604. OptionPtr vsi(new Option(Option::V4, DHO_VENDOR_ENCAPSULATED_OPTIONS,
  605. OptionBuffer()));
  606. vsi->addOption(OptionPtr(new Option(Option::V4, 0xDC, OptionBuffer())));
  607. // Add RAI option, which comprises 3 sub-options.
  608. // Get the option definition for RAI option. This option is represented
  609. // by OptionCustom which requires a definition to be passed to
  610. // the constructor.
  611. OptionDefinitionPtr rai_def = LibDHCP::getOptionDef(Option::V4,
  612. DHO_DHCP_AGENT_OPTIONS);
  613. ASSERT_TRUE(rai_def);
  614. // Create RAI option.
  615. OptionCustomPtr rai(new OptionCustom(*rai_def, Option::V4));
  616. // The sub-options are created using the bits of v4_opts buffer because
  617. // we want to use this buffer as a reference to verify that produced
  618. // option in on-wire format is correct.
  619. // Create Ciruit ID sub-option and add to RAI.
  620. OptionPtr circuit_id(new Option(Option::V4, RAI_OPTION_AGENT_CIRCUIT_ID,
  621. OptionBuffer(v4_opts + 46,
  622. v4_opts + 50)));
  623. rai->addOption(circuit_id);
  624. // Create Remote ID option and add to RAI.
  625. OptionPtr remote_id(new Option(Option::V4, RAI_OPTION_REMOTE_ID,
  626. OptionBuffer(v4_opts + 52, v4_opts + 58)));
  627. rai->addOption(remote_id);
  628. // Create Vendor Specific Information and add to RAI.
  629. OptionPtr rai_vsi(new Option(Option::V4, RAI_OPTION_VSI,
  630. OptionBuffer(v4_opts + 60, v4_opts + 69)));
  631. rai->addOption(rai_vsi);
  632. isc::dhcp::OptionCollection opts; // list of options
  633. // Note that we insert each option under the same option code into
  634. // the map. This gurantees that options are packed in the same order
  635. // they were added. Otherwise, options would get sorted by code and
  636. // the resulting buffer wouldn't match with the reference buffer.
  637. opts.insert(make_pair(opt1->getType(), opt1));
  638. opts.insert(make_pair(opt1->getType(), opt2));
  639. opts.insert(make_pair(opt1->getType(), opt3));
  640. opts.insert(make_pair(opt1->getType(), opt4));
  641. opts.insert(make_pair(opt1->getType(), opt5));
  642. opts.insert(make_pair(opt1->getType(), vivsi));
  643. opts.insert(make_pair(opt1->getType(), vsi));
  644. opts.insert(make_pair(opt1->getType(), rai));
  645. OutputBuffer buf(100);
  646. EXPECT_NO_THROW(LibDHCP::packOptions4(buf, opts));
  647. ASSERT_EQ(buf.getLength(), sizeof(v4_opts));
  648. EXPECT_EQ(0, memcmp(v4_opts, buf.getData(), sizeof(v4_opts)));
  649. }
  650. // This test verifies that pack options for v4 is working correctly
  651. // and RAI option is packed last.
  652. TEST_F(LibDhcpTest, packOptions4Order) {
  653. uint8_t expected[] = {
  654. 12, 3, 0, 1, 2, // Just a random option
  655. 99, 3, 10, 11, 12, // Another random option
  656. 82, 3, 20, 21, 22 // Relay Agent Info option
  657. };
  658. vector<uint8_t> payload[3];
  659. for (unsigned i = 0; i < 3; i++) {
  660. payload[i].resize(3);
  661. payload[i][0] = i*10;
  662. payload[i][1] = i*10+1;
  663. payload[i][2] = i*10+2;
  664. }
  665. OptionPtr opt12(new Option(Option::V4, 12, payload[0]));
  666. OptionPtr opt99(new Option(Option::V4, 99, payload[1]));
  667. OptionPtr opt82(new Option(Option::V4, 82, payload[2]));
  668. // Let's create options. They are added in 82,12,99, but the should be
  669. // packed in 12,99,82 order (82, which is RAI, should go last)
  670. isc::dhcp::OptionCollection opts;
  671. opts.insert(make_pair(opt82->getType(), opt82));
  672. opts.insert(make_pair(opt12->getType(), opt12));
  673. opts.insert(make_pair(opt99->getType(), opt99));
  674. OutputBuffer buf(100);
  675. EXPECT_NO_THROW(LibDHCP::packOptions4(buf, opts));
  676. ASSERT_EQ(buf.getLength(), sizeof(expected));
  677. EXPECT_EQ(0, memcmp(expected, buf.getData(), sizeof(expected)));
  678. }
  679. TEST_F(LibDhcpTest, unpackOptions4) {
  680. vector<uint8_t> v4packed(v4_opts, v4_opts + sizeof(v4_opts));
  681. isc::dhcp::OptionCollection options; // list of options
  682. ASSERT_NO_THROW(
  683. LibDHCP::unpackOptions4(v4packed, "dhcp4", options);
  684. );
  685. isc::dhcp::OptionCollection::const_iterator x = options.find(12);
  686. ASSERT_FALSE(x == options.end()); // option 1 should exist
  687. // Option 12 holds a string so let's cast it to an appropriate type.
  688. OptionStringPtr option12 = boost::static_pointer_cast<OptionString>(x->second);
  689. ASSERT_TRUE(option12);
  690. EXPECT_EQ(12, option12->getType()); // this should be option 12
  691. ASSERT_EQ(3, option12->getValue().length()); // it should be of length 3
  692. EXPECT_EQ(5, option12->len()); // total option length 5
  693. EXPECT_EQ(0, memcmp(&option12->getValue()[0], v4_opts + 2, 3)); // data len=3
  694. x = options.find(60);
  695. ASSERT_FALSE(x == options.end()); // option 2 should exist
  696. EXPECT_EQ(60, x->second->getType()); // this should be option 60
  697. ASSERT_EQ(3, x->second->getData().size()); // it should be of length 3
  698. EXPECT_EQ(5, x->second->len()); // total option length 5
  699. EXPECT_EQ(0, memcmp(&x->second->getData()[0], v4_opts + 7, 3)); // data len=3
  700. x = options.find(14);
  701. ASSERT_FALSE(x == options.end()); // option 3 should exist
  702. OptionStringPtr option14 = boost::static_pointer_cast<OptionString>(x->second);
  703. ASSERT_TRUE(option14);
  704. EXPECT_EQ(14, option14->getType()); // this should be option 14
  705. ASSERT_EQ(3, option14->getValue().length()); // it should be of length 3
  706. EXPECT_EQ(5, option14->len()); // total option length 5
  707. EXPECT_EQ(0, memcmp(&option14->getValue()[0], v4_opts + 12, 3)); // data len=3
  708. x = options.find(254);
  709. ASSERT_FALSE(x == options.end()); // option 4 should exist
  710. EXPECT_EQ(254, x->second->getType()); // this should be option 254
  711. ASSERT_EQ(3, x->second->getData().size()); // it should be of length 3
  712. EXPECT_EQ(5, x->second->len()); // total option length 5
  713. EXPECT_EQ(0, memcmp(&x->second->getData()[0], v4_opts + 17, 3)); // data len=3
  714. x = options.find(128);
  715. ASSERT_FALSE(x == options.end()); // option 5 should exist
  716. EXPECT_EQ(128, x->second->getType()); // this should be option 128
  717. ASSERT_EQ(3, x->second->getData().size()); // it should be of length 3
  718. EXPECT_EQ(5, x->second->len()); // total option length 5
  719. EXPECT_EQ(0, memcmp(&x->second->getData()[0], v4_opts + 22, 3)); // data len=3
  720. // Verify that V-I Vendor Specific Information option is parsed correctly.
  721. x = options.find(125);
  722. ASSERT_FALSE(x == options.end());
  723. OptionVendorPtr vivsi = boost::dynamic_pointer_cast<OptionVendor>(x->second);
  724. ASSERT_TRUE(vivsi);
  725. EXPECT_EQ(DHO_VIVSO_SUBOPTIONS, vivsi->getType());
  726. EXPECT_EQ(4491, vivsi->getVendorId());
  727. OptionCollection suboptions = vivsi->getOptions();
  728. // There should be one suboption of V-I VSI.
  729. ASSERT_EQ(1, suboptions.size());
  730. // This vendor option has a standard definition and thus should be
  731. // converted to appropriate class, i.e. Option4AddrLst. If this cast
  732. // fails, it means that its definition was not used while it was
  733. // parsed.
  734. Option4AddrLstPtr tftp =
  735. boost::dynamic_pointer_cast<Option4AddrLst>(suboptions.begin()->second);
  736. ASSERT_TRUE(tftp);
  737. EXPECT_EQ(DOCSIS3_V4_TFTP_SERVERS, tftp->getType());
  738. EXPECT_EQ(6, tftp->len());
  739. Option4AddrLst::AddressContainer addresses = tftp->getAddresses();
  740. ASSERT_EQ(1, addresses.size());
  741. EXPECT_EQ("10.0.0.10", addresses[0].toText());
  742. // Vendor Specific Information option
  743. x = options.find(43);
  744. ASSERT_FALSE(x == options.end());
  745. OptionPtr vsi = x->second;
  746. ASSERT_TRUE(vsi);
  747. EXPECT_EQ(DHO_VENDOR_ENCAPSULATED_OPTIONS, vsi->getType());
  748. suboptions = vsi->getOptions();
  749. // There should be one suboption of VSI.
  750. ASSERT_EQ(1, suboptions.size());
  751. OptionPtr eso = suboptions.begin()->second;
  752. ASSERT_TRUE(eso);
  753. EXPECT_EQ(0xdc, eso->getType());
  754. EXPECT_EQ(2, eso->len());
  755. // Checking DHCP Relay Agent Information Option.
  756. x = options.find(DHO_DHCP_AGENT_OPTIONS);
  757. ASSERT_FALSE(x == options.end());
  758. EXPECT_EQ(DHO_DHCP_AGENT_OPTIONS, x->second->getType());
  759. // RAI is represented by OptionCustom.
  760. OptionCustomPtr rai = boost::dynamic_pointer_cast<OptionCustom>(x->second);
  761. ASSERT_TRUE(rai);
  762. // RAI should have 3 sub-options: Circuit ID, Agent Remote ID, Vendor
  763. // Specific Information option. Note that by parsing these suboptions we
  764. // are checking that unpackOptions4 differentiates between standard option
  765. // space called "dhcp4" and other option spaces. These sub-options do not
  766. // belong to standard option space and should be parsed using different
  767. // option definitions.
  768. // @todo Currently, definitions for option space "dhcp-agent-options-space"
  769. // are not defined. Therefore all suboptions will be represented here by
  770. // the generic Option class.
  771. // Check that Circuit ID option is among parsed options.
  772. OptionPtr rai_option = rai->getOption(RAI_OPTION_AGENT_CIRCUIT_ID);
  773. ASSERT_TRUE(rai_option);
  774. EXPECT_EQ(RAI_OPTION_AGENT_CIRCUIT_ID, rai_option->getType());
  775. ASSERT_EQ(6, rai_option->len());
  776. EXPECT_EQ(0, memcmp(&rai_option->getData()[0], v4_opts + 46, 4));
  777. // Check that Remote ID option is among parsed options.
  778. rai_option = rai->getOption(RAI_OPTION_REMOTE_ID);
  779. ASSERT_TRUE(rai_option);
  780. EXPECT_EQ(RAI_OPTION_REMOTE_ID, rai_option->getType());
  781. ASSERT_EQ(8, rai_option->len());
  782. EXPECT_EQ(0, memcmp(&rai_option->getData()[0], v4_opts + 52, 6));
  783. // Check that Vendor Specific Information option is among parsed options.
  784. rai_option = rai->getOption(RAI_OPTION_VSI);
  785. ASSERT_TRUE(rai_option);
  786. EXPECT_EQ(RAI_OPTION_VSI, rai_option->getType());
  787. ASSERT_EQ(11, rai_option->len());
  788. EXPECT_EQ(0, memcmp(&rai_option->getData()[0], v4_opts + 60, 9));
  789. // Make sure, that option other than those above is not present.
  790. EXPECT_FALSE(rai->getOption(10));
  791. // Check the same for the global option space.
  792. x = options.find(0);
  793. EXPECT_TRUE(x == options.end()); // option 0 not found
  794. x = options.find(1);
  795. EXPECT_TRUE(x == options.end()); // option 1 not found
  796. x = options.find(2);
  797. EXPECT_TRUE(x == options.end()); // option 2 not found
  798. }
  799. // Check parsing of an empty option.
  800. TEST_F(LibDhcpTest, unpackEmptyOption4) {
  801. // Create option definition for the option code 254 without fields.
  802. OptionDefinitionPtr opt_def(new OptionDefinition("option-empty", 254,
  803. "empty", false));
  804. // Use it as runtime option definition within standard options space.
  805. // The tested code should find this option definition within runtime
  806. // option definitions set when it detects that this definition is
  807. // not a standard definition.
  808. OptionDefSpaceContainer defs;
  809. defs.addItem(opt_def, DHCP4_OPTION_SPACE);
  810. LibDHCP::setRuntimeOptionDefs(defs);
  811. LibDHCP::commitRuntimeOptionDefs();
  812. // Create the buffer holding the structure of the empty option.
  813. const uint8_t raw_data[] = {
  814. 0xFE, // option code = 254
  815. 0x00 // option length = 0
  816. };
  817. size_t raw_data_len = sizeof(raw_data) / sizeof(uint8_t);
  818. OptionBuffer buf(raw_data, raw_data + raw_data_len);
  819. // Parse options.
  820. OptionCollection options;
  821. ASSERT_NO_THROW(LibDHCP::unpackOptions4(buf, DHCP4_OPTION_SPACE,
  822. options));
  823. // There should be one option.
  824. ASSERT_EQ(1, options.size());
  825. OptionPtr option_empty = options.begin()->second;
  826. ASSERT_TRUE(option_empty);
  827. EXPECT_EQ(254, option_empty->getType());
  828. EXPECT_EQ(2, option_empty->len());
  829. }
  830. // This test verifies that the following option structure can be parsed:
  831. // - option (option space 'foobar')
  832. // - sub option (option space 'foo')
  833. // - sub option (option space 'bar')
  834. // @todo Add more thorough unit tests for unpackOptions.
  835. TEST_F(LibDhcpTest, unpackSubOptions4) {
  836. // Create option definition for each level of encapsulation. Each option
  837. // definition is for the option code 1. Options may have the same
  838. // option code because they belong to different option spaces.
  839. // Top level option encapsulates options which belong to 'space-foo'.
  840. OptionDefinitionPtr opt_def(new OptionDefinition("option-foobar", 1, "uint32",
  841. "space-foo"));\
  842. // Middle option encapsulates options which belong to 'space-bar'
  843. OptionDefinitionPtr opt_def2(new OptionDefinition("option-foo", 1, "uint16",
  844. "space-bar"));
  845. // Low level option doesn't encapsulate any option space.
  846. OptionDefinitionPtr opt_def3(new OptionDefinition("option-bar", 1,
  847. "uint8"));
  848. // Register created option definitions as runtime option definitions.
  849. OptionDefSpaceContainer defs;
  850. ASSERT_NO_THROW(defs.addItem(opt_def, "space-foobar"));
  851. ASSERT_NO_THROW(defs.addItem(opt_def2, "space-foo"));
  852. ASSERT_NO_THROW(defs.addItem(opt_def3, "space-bar"));
  853. LibDHCP::setRuntimeOptionDefs(defs);
  854. LibDHCP::commitRuntimeOptionDefs();
  855. // Create the buffer holding the structure of options.
  856. const uint8_t raw_data[] = {
  857. // First option starts here.
  858. 0x01, // option code = 1
  859. 0x0B, // option length = 11
  860. 0x00, 0x01, 0x02, 0x03, // This option carries uint32 value
  861. // Sub option starts here.
  862. 0x01, // option code = 1
  863. 0x05, // option length = 5
  864. 0x01, 0x02, // this option carries uint16 value
  865. // Last option starts here.
  866. 0x01, // option code = 1
  867. 0x01, // option length = 1
  868. 0x00 // This option carries a single uint8
  869. // value and has no sub options.
  870. };
  871. size_t raw_data_len = sizeof(raw_data) / sizeof(uint8_t);
  872. OptionBuffer buf(raw_data, raw_data + raw_data_len);
  873. // Parse options.
  874. OptionCollection options;
  875. ASSERT_NO_THROW(LibDHCP::unpackOptions4(buf, "space-foobar", options));
  876. // There should be one top level option.
  877. ASSERT_EQ(1, options.size());
  878. boost::shared_ptr<OptionInt<uint32_t> > option_foobar =
  879. boost::dynamic_pointer_cast<OptionInt<uint32_t> >(options.begin()->
  880. second);
  881. ASSERT_TRUE(option_foobar);
  882. EXPECT_EQ(1, option_foobar->getType());
  883. EXPECT_EQ(0x00010203, option_foobar->getValue());
  884. // There should be a middle level option held in option_foobar.
  885. boost::shared_ptr<OptionInt<uint16_t> > option_foo =
  886. boost::dynamic_pointer_cast<OptionInt<uint16_t> >(option_foobar->
  887. getOption(1));
  888. ASSERT_TRUE(option_foo);
  889. EXPECT_EQ(1, option_foo->getType());
  890. EXPECT_EQ(0x0102, option_foo->getValue());
  891. // Finally, there should be a low level option under option_foo.
  892. boost::shared_ptr<OptionInt<uint8_t> > option_bar =
  893. boost::dynamic_pointer_cast<OptionInt<uint8_t> >(option_foo->getOption(1));
  894. ASSERT_TRUE(option_bar);
  895. EXPECT_EQ(1, option_bar->getType());
  896. EXPECT_EQ(0x0, option_bar->getValue());
  897. }
  898. TEST_F(LibDhcpTest, isStandardOption4) {
  899. // Get all option codes that are not occupied by standard options.
  900. const uint16_t unassigned_codes[] = { 84, 96, 102, 103, 104, 105, 106, 107, 108,
  901. 109, 110, 111, 115, 126, 127, 147, 148, 149,
  902. 178, 179, 180, 181, 182, 183, 184, 185, 186,
  903. 187, 188, 189, 190, 191, 192, 193, 194, 195,
  904. 196, 197, 198, 199, 200, 201, 202, 203, 204,
  905. 205, 206, 207, 214, 215, 216, 217, 218, 219,
  906. 222, 223, 224, 225, 226, 227, 228, 229, 230,
  907. 231, 232, 233, 234, 235, 236, 237, 238, 239,
  908. 240, 241, 242, 243, 244, 245, 246, 247, 248,
  909. 249, 250, 251, 252, 253, 254 };
  910. const size_t unassigned_num = sizeof(unassigned_codes) / sizeof(unassigned_codes[0]);
  911. // Try all possible option codes.
  912. for (size_t i = 0; i < 256; ++i) {
  913. // Some ranges of option codes are unassigned and thus the isStandardOption
  914. // should return false for them.
  915. bool check_unassigned = false;
  916. // Check the array of unassigned options to find out whether option code
  917. // is assigned to standard option or unassigned.
  918. for (size_t j = 0; j < unassigned_num; ++j) {
  919. // If option code is found within the array of unassigned options
  920. // we the isStandardOption function should return false.
  921. if (unassigned_codes[j] == i) {
  922. check_unassigned = true;
  923. EXPECT_FALSE(LibDHCP::isStandardOption(Option::V4,
  924. unassigned_codes[j]))
  925. << "Test failed for option code " << unassigned_codes[j];
  926. break;
  927. }
  928. }
  929. // If the option code belongs to the standard option then the
  930. // isStandardOption should return true.
  931. if (!check_unassigned) {
  932. EXPECT_TRUE(LibDHCP::isStandardOption(Option::V4, i))
  933. << "Test failed for the option code " << i;
  934. }
  935. }
  936. }
  937. TEST_F(LibDhcpTest, isStandardOption6) {
  938. // All option codes in the range from 0 to 78 (except 10 and 35)
  939. // identify the standard options.
  940. for (uint16_t code = 0; code < 79; ++code) {
  941. if (code != 10 && code != 35) {
  942. EXPECT_TRUE(LibDHCP::isStandardOption(Option::V6, code))
  943. << "Test failed for option code " << code;
  944. }
  945. }
  946. // Check the option codes 10 and 35. They are unassigned.
  947. EXPECT_FALSE(LibDHCP::isStandardOption(Option::V6, 10));
  948. EXPECT_FALSE(LibDHCP::isStandardOption(Option::V6, 35));
  949. // Check a range of option codes above 78. Those are option codes
  950. // identifying non-standard options.
  951. for (uint16_t code = 79; code < 512; ++code) {
  952. EXPECT_FALSE(LibDHCP::isStandardOption(Option::V6, code))
  953. << "Test failed for option code " << code;
  954. }
  955. }
  956. TEST_F(LibDhcpTest, stdOptionDefs4) {
  957. // Create a buffer that holds dummy option data.
  958. // It will be used to create most of the options.
  959. std::vector<uint8_t> buf(48, 1);
  960. OptionBufferConstIter begin = buf.begin();
  961. OptionBufferConstIter end = buf.end();
  962. LibDhcpTest::testStdOptionDefs4(DHO_SUBNET_MASK, begin, end,
  963. typeid(OptionCustom));
  964. LibDhcpTest::testStdOptionDefs4(DHO_TIME_OFFSET, begin, begin + 4,
  965. typeid(OptionInt<int32_t>));
  966. LibDhcpTest::testStdOptionDefs4(DHO_ROUTERS, begin, end,
  967. typeid(Option4AddrLst));
  968. LibDhcpTest::testStdOptionDefs4(DHO_TIME_SERVERS, begin, end,
  969. typeid(Option4AddrLst));
  970. LibDhcpTest::testStdOptionDefs4(DHO_NAME_SERVERS, begin, end,
  971. typeid(Option4AddrLst));
  972. LibDhcpTest::testStdOptionDefs4(DHO_DOMAIN_NAME_SERVERS, begin, end,
  973. typeid(Option4AddrLst));
  974. LibDhcpTest::testStdOptionDefs4(DHO_LOG_SERVERS, begin, end,
  975. typeid(Option4AddrLst));
  976. LibDhcpTest::testStdOptionDefs4(DHO_COOKIE_SERVERS, begin, end,
  977. typeid(Option4AddrLst));
  978. LibDhcpTest::testStdOptionDefs4(DHO_LPR_SERVERS, begin, end,
  979. typeid(Option4AddrLst));
  980. LibDhcpTest::testStdOptionDefs4(DHO_IMPRESS_SERVERS, begin, end,
  981. typeid(Option4AddrLst));
  982. LibDhcpTest::testStdOptionDefs4(DHO_RESOURCE_LOCATION_SERVERS, begin, end,
  983. typeid(Option4AddrLst));
  984. LibDhcpTest::testStdOptionDefs4(DHO_HOST_NAME, begin, end,
  985. typeid(OptionString));
  986. LibDhcpTest::testStdOptionDefs4(DHO_BOOT_SIZE, begin, begin + 2,
  987. typeid(OptionInt<uint16_t>));
  988. LibDhcpTest::testStdOptionDefs4(DHO_MERIT_DUMP, begin, end,
  989. typeid(OptionString));
  990. LibDhcpTest::testStdOptionDefs4(DHO_DOMAIN_NAME, begin, end,
  991. typeid(OptionString));
  992. LibDhcpTest::testStdOptionDefs4(DHO_SWAP_SERVER, begin, end,
  993. typeid(OptionCustom));
  994. LibDhcpTest::testStdOptionDefs4(DHO_ROOT_PATH, begin, end,
  995. typeid(OptionString));
  996. LibDhcpTest::testStdOptionDefs4(DHO_EXTENSIONS_PATH, begin, end,
  997. typeid(OptionString));
  998. LibDhcpTest::testStdOptionDefs4(DHO_IP_FORWARDING, begin, end,
  999. typeid(OptionCustom));
  1000. LibDhcpTest::testStdOptionDefs4(DHO_NON_LOCAL_SOURCE_ROUTING, begin, end,
  1001. typeid(OptionCustom));
  1002. LibDhcpTest::testStdOptionDefs4(DHO_POLICY_FILTER, begin, end,
  1003. typeid(Option4AddrLst));
  1004. LibDhcpTest::testStdOptionDefs4(DHO_MAX_DGRAM_REASSEMBLY, begin, begin + 2,
  1005. typeid(OptionInt<uint16_t>));
  1006. LibDhcpTest::testStdOptionDefs4(DHO_DEFAULT_IP_TTL, begin, begin + 1,
  1007. typeid(OptionInt<uint8_t>));
  1008. LibDhcpTest::testStdOptionDefs4(DHO_PATH_MTU_AGING_TIMEOUT, begin, begin + 4,
  1009. typeid(OptionInt<uint32_t>));
  1010. LibDhcpTest::testStdOptionDefs4(DHO_PATH_MTU_PLATEAU_TABLE, begin, begin + 10,
  1011. typeid(OptionIntArray<uint16_t>));
  1012. LibDhcpTest::testStdOptionDefs4(DHO_INTERFACE_MTU, begin, begin + 2,
  1013. typeid(OptionInt<uint16_t>));
  1014. LibDhcpTest::testStdOptionDefs4(DHO_ALL_SUBNETS_LOCAL, begin, end,
  1015. typeid(OptionCustom));
  1016. LibDhcpTest::testStdOptionDefs4(DHO_BROADCAST_ADDRESS, begin, end,
  1017. typeid(OptionCustom));
  1018. LibDhcpTest::testStdOptionDefs4(DHO_PERFORM_MASK_DISCOVERY, begin, end,
  1019. typeid(OptionCustom));
  1020. LibDhcpTest::testStdOptionDefs4(DHO_MASK_SUPPLIER, begin, end,
  1021. typeid(OptionCustom));
  1022. LibDhcpTest::testStdOptionDefs4(DHO_ROUTER_DISCOVERY, begin, end,
  1023. typeid(OptionCustom));
  1024. LibDhcpTest::testStdOptionDefs4(DHO_ROUTER_SOLICITATION_ADDRESS, begin, end,
  1025. typeid(OptionCustom));
  1026. LibDhcpTest::testStdOptionDefs4(DHO_STATIC_ROUTES, begin, end,
  1027. typeid(Option4AddrLst));
  1028. LibDhcpTest::testStdOptionDefs4(DHO_TRAILER_ENCAPSULATION, begin, end,
  1029. typeid(OptionCustom));
  1030. LibDhcpTest::testStdOptionDefs4(DHO_ARP_CACHE_TIMEOUT, begin, begin + 4,
  1031. typeid(OptionInt<uint32_t>));
  1032. LibDhcpTest::testStdOptionDefs4(DHO_IEEE802_3_ENCAPSULATION, begin, end,
  1033. typeid(OptionCustom));
  1034. LibDhcpTest::testStdOptionDefs4(DHO_DEFAULT_TCP_TTL, begin, begin + 1,
  1035. typeid(OptionInt<uint8_t>));
  1036. LibDhcpTest::testStdOptionDefs4(DHO_TCP_KEEPALIVE_INTERVAL, begin,
  1037. begin + 4, typeid(OptionInt<uint32_t>));
  1038. LibDhcpTest::testStdOptionDefs4(DHO_TCP_KEEPALIVE_GARBAGE, begin, begin + 1,
  1039. typeid(OptionCustom));
  1040. LibDhcpTest::testStdOptionDefs4(DHO_NIS_DOMAIN, begin, end,
  1041. typeid(OptionString));
  1042. LibDhcpTest::testStdOptionDefs4(DHO_NIS_SERVERS, begin, end,
  1043. typeid(Option4AddrLst));
  1044. LibDhcpTest::testStdOptionDefs4(DHO_NTP_SERVERS, begin, end,
  1045. typeid(Option4AddrLst));
  1046. // The following option requires well formed buffer to be created from.
  1047. // Not just a dummy one. This buffer includes some suboptions.
  1048. OptionBuffer vendor_opts_buf = createVendorOption();
  1049. LibDhcpTest::testStdOptionDefs4(DHO_VENDOR_ENCAPSULATED_OPTIONS,
  1050. vendor_opts_buf.begin(),
  1051. vendor_opts_buf.end(),
  1052. typeid(OptionCustom),
  1053. "vendor-encapsulated-options-space");
  1054. LibDhcpTest::testStdOptionDefs4(DHO_NETBIOS_NAME_SERVERS, begin, end,
  1055. typeid(Option4AddrLst));
  1056. LibDhcpTest::testStdOptionDefs4(DHO_NETBIOS_DD_SERVER, begin, end,
  1057. typeid(Option4AddrLst));
  1058. LibDhcpTest::testStdOptionDefs4(DHO_NETBIOS_NODE_TYPE, begin, begin + 1,
  1059. typeid(OptionInt<uint8_t>));
  1060. LibDhcpTest::testStdOptionDefs4(DHO_NETBIOS_SCOPE, begin, end,
  1061. typeid(OptionString));
  1062. LibDhcpTest::testStdOptionDefs4(DHO_FONT_SERVERS, begin, end,
  1063. typeid(Option4AddrLst));
  1064. LibDhcpTest::testStdOptionDefs4(DHO_X_DISPLAY_MANAGER, begin, end,
  1065. typeid(Option4AddrLst));
  1066. LibDhcpTest::testStdOptionDefs4(DHO_DHCP_REQUESTED_ADDRESS, begin, end,
  1067. typeid(OptionCustom));
  1068. LibDhcpTest::testStdOptionDefs4(DHO_DHCP_LEASE_TIME, begin, begin + 4,
  1069. typeid(OptionInt<uint32_t>));
  1070. LibDhcpTest::testStdOptionDefs4(DHO_DHCP_OPTION_OVERLOAD, begin, begin + 1,
  1071. typeid(OptionInt<uint8_t>));
  1072. LibDhcpTest::testStdOptionDefs4(DHO_DHCP_MESSAGE_TYPE, begin, begin + 1,
  1073. typeid(OptionInt<uint8_t>));
  1074. LibDhcpTest::testStdOptionDefs4(DHO_DHCP_SERVER_IDENTIFIER, begin, end,
  1075. typeid(OptionCustom));
  1076. LibDhcpTest::testStdOptionDefs4(DHO_DHCP_PARAMETER_REQUEST_LIST, begin, end,
  1077. typeid(OptionUint8Array));
  1078. LibDhcpTest::testStdOptionDefs4(DHO_DHCP_MESSAGE, begin, end,
  1079. typeid(OptionString));
  1080. LibDhcpTest::testStdOptionDefs4(DHO_DHCP_MAX_MESSAGE_SIZE, begin, begin + 2,
  1081. typeid(OptionInt<uint16_t>));
  1082. LibDhcpTest::testStdOptionDefs4(DHO_DHCP_RENEWAL_TIME, begin, begin + 4,
  1083. typeid(OptionInt<uint32_t>));
  1084. LibDhcpTest::testStdOptionDefs4(DHO_DHCP_REBINDING_TIME, begin, begin + 4,
  1085. typeid(OptionInt<uint32_t>));
  1086. LibDhcpTest::testStdOptionDefs4(DHO_VENDOR_CLASS_IDENTIFIER, begin, end,
  1087. typeid(OptionString));
  1088. LibDhcpTest::testStdOptionDefs4(DHO_DHCP_CLIENT_IDENTIFIER, begin, end,
  1089. typeid(Option));
  1090. LibDhcpTest::testStdOptionDefs4(DHO_NWIP_DOMAIN_NAME, begin, end,
  1091. typeid(OptionString));
  1092. LibDhcpTest::testStdOptionDefs4(DHO_NWIP_SUBOPTIONS, begin, end,
  1093. typeid(Option));
  1094. LibDhcpTest::testStdOptionDefs4(DHO_NISP_DOMAIN_NAME, begin, end,
  1095. typeid(OptionString));
  1096. LibDhcpTest::testStdOptionDefs4(DHO_NISP_SERVER_ADDR, begin, end,
  1097. typeid(Option4AddrLst));
  1098. LibDhcpTest::testStdOptionDefs4(DHO_TFTP_SERVER_NAME, begin, end,
  1099. typeid(OptionString));
  1100. LibDhcpTest::testStdOptionDefs4(DHO_BOOT_FILE_NAME, begin, end,
  1101. typeid(OptionString));
  1102. LibDhcpTest::testStdOptionDefs4(DHO_HOME_AGENT_ADDRS, begin, end,
  1103. typeid(Option4AddrLst));
  1104. LibDhcpTest::testStdOptionDefs4(DHO_SMTP_SERVER, begin, end,
  1105. typeid(Option4AddrLst));
  1106. LibDhcpTest::testStdOptionDefs4(DHO_POP3_SERVER, begin, end,
  1107. typeid(Option4AddrLst));
  1108. LibDhcpTest::testStdOptionDefs4(DHO_NNTP_SERVER, begin, end,
  1109. typeid(Option4AddrLst));
  1110. LibDhcpTest::testStdOptionDefs4(DHO_WWW_SERVER, begin, end,
  1111. typeid(Option4AddrLst));
  1112. LibDhcpTest::testStdOptionDefs4(DHO_FINGER_SERVER, begin, end,
  1113. typeid(Option4AddrLst));
  1114. LibDhcpTest::testStdOptionDefs4(DHO_IRC_SERVER, begin, end,
  1115. typeid(Option4AddrLst));
  1116. LibDhcpTest::testStdOptionDefs4(DHO_STREETTALK_SERVER, begin, end,
  1117. typeid(Option4AddrLst));
  1118. LibDhcpTest::testStdOptionDefs4(DHO_STDASERVER, begin, end,
  1119. typeid(Option4AddrLst));
  1120. LibDhcpTest::testStdOptionDefs4(DHO_USER_CLASS, begin, end,
  1121. typeid(Option));
  1122. LibDhcpTest::testStdOptionDefs4(DHO_FQDN, begin, begin + 3,
  1123. typeid(Option4ClientFqdn));
  1124. // The following option requires well formed buffer to be created from.
  1125. // Not just a dummy one. This buffer includes some suboptions.
  1126. OptionBuffer agent_info_buf = createAgentInformationOption();
  1127. LibDhcpTest::testStdOptionDefs4(DHO_DHCP_AGENT_OPTIONS,
  1128. agent_info_buf.begin(),
  1129. agent_info_buf.end(),
  1130. typeid(OptionCustom),
  1131. "dhcp-agent-options-space");
  1132. LibDhcpTest::testStdOptionDefs4(DHO_AUTHENTICATE, begin, end,
  1133. typeid(Option));
  1134. LibDhcpTest::testStdOptionDefs4(DHO_CLIENT_LAST_TRANSACTION_TIME,
  1135. begin, begin + 4,
  1136. typeid(OptionInt<uint32_t>));
  1137. LibDhcpTest::testStdOptionDefs4(DHO_ASSOCIATED_IP, begin, end,
  1138. typeid(Option4AddrLst));
  1139. LibDhcpTest::testStdOptionDefs4(DHO_SUBNET_SELECTION, begin, end,
  1140. typeid(OptionCustom));
  1141. LibDhcpTest::testStdOptionDefs4(DHO_SYSTEM, begin, end,
  1142. typeid(OptionIntArray<uint16_t>));
  1143. LibDhcpTest::testStdOptionDefs4(DHO_NDI, begin, begin + 3,
  1144. typeid(OptionCustom));
  1145. LibDhcpTest::testStdOptionDefs4(DHO_UUID_GUID, begin, begin + 17,
  1146. typeid(OptionCustom));
  1147. LibDhcpTest::testStdOptionDefs4(DHO_DOMAIN_SEARCH, begin, end,
  1148. typeid(Option));
  1149. // V-I Vendor option requires specially crafted data.
  1150. const char vivco_data[] = {
  1151. 1, 2, 3, 4, // enterprise id
  1152. 3, 1, 2, 3 // first byte is opaque data length, the rest is opaque data
  1153. };
  1154. std::vector<uint8_t> vivco_buf(vivco_data, vivco_data + sizeof(vivco_data));
  1155. const char vivsio_data[] = {
  1156. 1, 2, 3, 4, // enterprise id
  1157. 4, // first byte is vendor block length
  1158. 1, 2, 3, 4 // option type=1 length=2
  1159. };
  1160. std::vector<uint8_t> vivsio_buf(vivsio_data, vivsio_data + sizeof(vivsio_data));
  1161. LibDhcpTest::testStdOptionDefs4(DHO_VIVCO_SUBOPTIONS, vivco_buf.begin(),
  1162. vivco_buf.end(), typeid(OptionVendorClass));
  1163. LibDhcpTest::testStdOptionDefs4(DHO_VIVSO_SUBOPTIONS, vivsio_buf.begin(),
  1164. vivsio_buf.end(), typeid(OptionVendor));
  1165. }
  1166. // Test that definitions of standard options have been initialized
  1167. // correctly.
  1168. // @todo Only limited number of option definitions are now created
  1169. // This test have to be extended once all option definitions are
  1170. // created.
  1171. TEST_F(LibDhcpTest, stdOptionDefs6) {
  1172. // Create a buffer that holds dummy option data.
  1173. // It will be used to create most of the options.
  1174. std::vector<uint8_t> buf(48, 1);
  1175. OptionBufferConstIter begin = buf.begin();
  1176. OptionBufferConstIter end = buf.end();
  1177. // Prepare buffer holding an array of FQDNs.
  1178. const char data[] = {
  1179. 8, 109, 121, 100, 111, 109, 97, 105, 110, // "mydomain"
  1180. 7, 101, 120, 97, 109, 112, 108, 101, // "example"
  1181. 3, 99, 111, 109, // "com"
  1182. 0,
  1183. 7, 101, 120, 97, 109, 112, 108, 101, // "example"
  1184. 3, 99, 111, 109, // "com"
  1185. 0
  1186. };
  1187. // Initialize a vector with the FQDN data.
  1188. std::vector<uint8_t> fqdn_buf(data, data + sizeof(data));
  1189. // Prepare buffer holding a vendor option
  1190. const char vopt_data[] = {
  1191. 1, 2, 3, 4, // enterprise=0x1020304
  1192. 0, 100, // type=100
  1193. 0, 6, // length=6
  1194. 102, 111, 111, 98, 97, 114 // data="foobar"
  1195. };
  1196. // Initialize a vector with the suboption data.
  1197. std::vector<uint8_t> vopt_buf(vopt_data, vopt_data + sizeof(vopt_data));
  1198. // The CLIENT_FQDN holds a uint8_t value and FQDN. We have
  1199. // to add the uint8_t value to it and then append the buffer
  1200. // holding some valid FQDN.
  1201. std::vector<uint8_t> client_fqdn_buf(1);
  1202. client_fqdn_buf.insert(client_fqdn_buf.end(), fqdn_buf.begin(),
  1203. fqdn_buf.end());
  1204. // Initialize test buffer for Vendor Class option.
  1205. const char vclass_data[] = {
  1206. 0x00, 0x01, 0x02, 0x03,
  1207. 0x00, 0x01, 0x02
  1208. };
  1209. std::vector<uint8_t> vclass_buf(vclass_data,
  1210. vclass_data + sizeof(vclass_data));;
  1211. // Initialize test buffer for Bootfile Param option.
  1212. const char bparam_data[] = {
  1213. 0x00, 0x01, 0x02
  1214. };
  1215. std::vector<uint8_t> bparam_buf(bparam_data,
  1216. bparam_data + sizeof(bparam_data));;
  1217. // The actual test starts here for all supported option codes.
  1218. LibDhcpTest::testStdOptionDefs6(D6O_CLIENTID, begin, end,
  1219. typeid(Option));
  1220. LibDhcpTest::testStdOptionDefs6(D6O_SERVERID, begin, end,
  1221. typeid(Option));
  1222. LibDhcpTest::testStdOptionDefs6(D6O_IA_NA, begin, end,
  1223. typeid(Option6IA));
  1224. LibDhcpTest::testStdOptionDefs6(D6O_IA_TA, begin, begin + 4,
  1225. typeid(OptionInt<uint32_t>));
  1226. LibDhcpTest::testStdOptionDefs6(D6O_IAADDR, begin, end,
  1227. typeid(Option6IAAddr));
  1228. LibDhcpTest::testStdOptionDefs6(D6O_ORO, begin, end,
  1229. typeid(OptionIntArray<uint16_t>));
  1230. LibDhcpTest::testStdOptionDefs6(D6O_PREFERENCE, begin, begin + 1,
  1231. typeid(OptionInt<uint8_t>));
  1232. LibDhcpTest::testStdOptionDefs6(D6O_ELAPSED_TIME, begin, begin + 2,
  1233. typeid(OptionInt<uint16_t>));
  1234. LibDhcpTest::testStdOptionDefs6(D6O_RELAY_MSG, begin, end,
  1235. typeid(Option));
  1236. LibDhcpTest::testStdOptionDefs6(D6O_STATUS_CODE, begin, end,
  1237. typeid(Option6StatusCode));
  1238. LibDhcpTest::testStdOptionDefs6(D6O_RAPID_COMMIT, begin, end,
  1239. typeid(Option));
  1240. LibDhcpTest::testStdOptionDefs6(D6O_USER_CLASS, begin, end,
  1241. typeid(Option));
  1242. LibDhcpTest::testStdOptionDefs6(D6O_VENDOR_CLASS, vclass_buf.begin(),
  1243. vclass_buf.end(),
  1244. typeid(OptionVendorClass));
  1245. LibDhcpTest::testStdOptionDefs6(D6O_VENDOR_OPTS, vopt_buf.begin(),
  1246. vopt_buf.end(),
  1247. typeid(OptionVendor),
  1248. "vendor-opts-space");
  1249. LibDhcpTest::testStdOptionDefs6(D6O_INTERFACE_ID, begin, end,
  1250. typeid(Option));
  1251. LibDhcpTest::testStdOptionDefs6(D6O_RECONF_MSG, begin, begin + 1,
  1252. typeid(OptionInt<uint8_t>));
  1253. LibDhcpTest::testStdOptionDefs6(D6O_RECONF_ACCEPT, begin, end,
  1254. typeid(Option));
  1255. LibDhcpTest::testStdOptionDefs6(D6O_SIP_SERVERS_DNS, fqdn_buf.begin(),
  1256. fqdn_buf.end(),
  1257. typeid(OptionCustom));
  1258. LibDhcpTest::testStdOptionDefs6(D6O_SIP_SERVERS_ADDR, begin, end,
  1259. typeid(Option6AddrLst));
  1260. LibDhcpTest::testStdOptionDefs6(D6O_NAME_SERVERS, begin, end,
  1261. typeid(Option6AddrLst));
  1262. LibDhcpTest::testStdOptionDefs6(D6O_DOMAIN_SEARCH, fqdn_buf.begin(),
  1263. fqdn_buf.end(), typeid(OptionCustom));
  1264. LibDhcpTest::testStdOptionDefs6(D6O_IA_PD, begin, end,
  1265. typeid(Option6IA));
  1266. LibDhcpTest::testStdOptionDefs6(D6O_IAPREFIX, begin, begin + 25,
  1267. typeid(Option6IAPrefix));
  1268. LibDhcpTest::testStdOptionDefs6(D6O_NIS_SERVERS, begin, end,
  1269. typeid(Option6AddrLst));
  1270. LibDhcpTest::testStdOptionDefs6(D6O_NISP_SERVERS, begin, end,
  1271. typeid(Option6AddrLst));
  1272. LibDhcpTest::testStdOptionDefs6(D6O_NIS_DOMAIN_NAME, fqdn_buf.begin(),
  1273. fqdn_buf.end(),
  1274. typeid(OptionCustom));
  1275. LibDhcpTest::testStdOptionDefs6(D6O_NISP_DOMAIN_NAME, fqdn_buf.begin(),
  1276. fqdn_buf.end(),
  1277. typeid(OptionCustom));
  1278. LibDhcpTest::testStdOptionDefs6(D6O_SNTP_SERVERS, begin, end,
  1279. typeid(Option6AddrLst));
  1280. LibDhcpTest::testStdOptionDefs6(D6O_INFORMATION_REFRESH_TIME,
  1281. begin, begin + 4,
  1282. typeid(OptionInt<uint32_t>));
  1283. LibDhcpTest::testStdOptionDefs6(D6O_BCMCS_SERVER_D, fqdn_buf.begin(),
  1284. fqdn_buf.end(),
  1285. typeid(OptionCustom));
  1286. LibDhcpTest::testStdOptionDefs6(D6O_BCMCS_SERVER_A, begin, end,
  1287. typeid(Option6AddrLst));
  1288. LibDhcpTest::testStdOptionDefs6(D6O_GEOCONF_CIVIC, begin, end,
  1289. typeid(OptionCustom));
  1290. LibDhcpTest::testStdOptionDefs6(D6O_REMOTE_ID, begin, end,
  1291. typeid(OptionCustom));
  1292. LibDhcpTest::testStdOptionDefs6(D6O_SUBSCRIBER_ID, begin, end,
  1293. typeid(Option));
  1294. LibDhcpTest::testStdOptionDefs6(D6O_CLIENT_FQDN, client_fqdn_buf.begin(),
  1295. client_fqdn_buf.end(),
  1296. typeid(Option6ClientFqdn));
  1297. LibDhcpTest::testStdOptionDefs6(D6O_PANA_AGENT, begin, end,
  1298. typeid(Option6AddrLst));
  1299. LibDhcpTest::testStdOptionDefs6(D6O_PANA_AGENT, begin, end,
  1300. typeid(Option6AddrLst));
  1301. LibDhcpTest::testStdOptionDefs6(D6O_NEW_POSIX_TIMEZONE, begin, end,
  1302. typeid(OptionString));
  1303. LibDhcpTest::testStdOptionDefs6(D6O_NEW_TZDB_TIMEZONE, begin, end,
  1304. typeid(OptionString));
  1305. LibDhcpTest::testStdOptionDefs6(D6O_ERO, begin, end,
  1306. typeid(OptionIntArray<uint16_t>));
  1307. LibDhcpTest::testStdOptionDefs6(D6O_LQ_QUERY, begin, end,
  1308. typeid(OptionCustom));
  1309. LibDhcpTest::testStdOptionDefs6(D6O_CLIENT_DATA, begin, end,
  1310. typeid(Option));
  1311. LibDhcpTest::testStdOptionDefs6(D6O_CLT_TIME, begin, begin + 4,
  1312. typeid(OptionInt<uint32_t>));
  1313. LibDhcpTest::testStdOptionDefs6(D6O_LQ_RELAY_DATA, begin, end,
  1314. typeid(OptionCustom));
  1315. LibDhcpTest::testStdOptionDefs6(D6O_LQ_CLIENT_LINK, begin, end,
  1316. typeid(Option6AddrLst));
  1317. LibDhcpTest::testStdOptionDefs6(D6O_BOOTFILE_URL, begin, end,
  1318. typeid(OptionString));
  1319. LibDhcpTest::testStdOptionDefs6(D6O_BOOTFILE_PARAM, bparam_buf.begin(),
  1320. bparam_buf.end(),
  1321. typeid(OptionOpaqueDataTuples));
  1322. LibDhcpTest::testStdOptionDefs6(D6O_CLIENT_ARCH_TYPE, begin, end,
  1323. typeid(OptionIntArray<uint16_t>));
  1324. LibDhcpTest::testStdOptionDefs6(D6O_NII, begin, begin + 3,
  1325. typeid(OptionCustom));
  1326. LibDhcpTest::testStdOptionDefs6(D6O_RSOO, begin, end,
  1327. typeid(OptionCustom),
  1328. "rsoo-opts");
  1329. LibDhcpTest::testStdOptionDefs6(D6O_ERP_LOCAL_DOMAIN_NAME,
  1330. fqdn_buf.begin(), fqdn_buf.end(),
  1331. typeid(OptionCustom));
  1332. LibDhcpTest::testStdOptionDefs6(D6O_DHCPV4_MSG, begin, end,
  1333. typeid(Option));
  1334. LibDhcpTest::testStdOptionDefs6(D6O_DHCPV4_O_DHCPV6_SERVER, begin, end,
  1335. typeid(Option6AddrLst));
  1336. LibDhcpTest::testStdOptionDefs6(D6O_PUBLIC_KEY, begin, end,
  1337. typeid(Option));
  1338. LibDhcpTest::testStdOptionDefs6(D6O_CERTIFICATE, begin, end,
  1339. typeid(Option));
  1340. LibDhcpTest::testStdOptionDefs6(D6O_SIGNATURE, begin, end,
  1341. typeid(OptionCustom));
  1342. LibDhcpTest::testStdOptionDefs6(D6O_TIMESTAMP, begin, begin + 8,
  1343. typeid(Option));
  1344. }
  1345. // This test checks if the DHCPv6 option definition can be searched by
  1346. // an option name.
  1347. TEST_F(LibDhcpTest, getOptionDefByName6) {
  1348. // Get all definitions.
  1349. const OptionDefContainerPtr defs = LibDHCP::getOptionDefs(Option::V6);
  1350. // For each definition try to find it using option name.
  1351. for (OptionDefContainer::const_iterator def = defs->begin();
  1352. def != defs->end(); ++def) {
  1353. OptionDefinitionPtr def_by_name =
  1354. LibDHCP::getOptionDef(Option::V6, (*def)->getName());
  1355. ASSERT_TRUE(def_by_name);
  1356. ASSERT_TRUE(**def == *def_by_name);
  1357. }
  1358. }
  1359. // This test checks if the DHCPv4 option definition can be searched by
  1360. // an option name.
  1361. TEST_F(LibDhcpTest, getOptionDefByName4) {
  1362. // Get all definitions.
  1363. const OptionDefContainerPtr defs = LibDHCP::getOptionDefs(Option::V4);
  1364. // For each definition try to find it using option name.
  1365. for (OptionDefContainer::const_iterator def = defs->begin();
  1366. def != defs->end(); ++def) {
  1367. OptionDefinitionPtr def_by_name =
  1368. LibDHCP::getOptionDef(Option::V4, (*def)->getName());
  1369. ASSERT_TRUE(def_by_name);
  1370. ASSERT_TRUE(**def == *def_by_name);
  1371. }
  1372. }
  1373. // This test checks if the definition of the DHCPv6 vendor option can
  1374. // be searched by option name.
  1375. TEST_F(LibDhcpTest, getVendorOptionDefByName6) {
  1376. const OptionDefContainerPtr& defs =
  1377. LibDHCP::getVendorOption6Defs(VENDOR_ID_CABLE_LABS);
  1378. ASSERT_TRUE(defs);
  1379. for (OptionDefContainer::const_iterator def = defs->begin();
  1380. def != defs->end(); ++def) {
  1381. OptionDefinitionPtr def_by_name =
  1382. LibDHCP::getVendorOptionDef(Option::V6, VENDOR_ID_CABLE_LABS,
  1383. (*def)->getName());
  1384. ASSERT_TRUE(def_by_name);
  1385. ASSERT_TRUE(**def == *def_by_name);
  1386. }
  1387. }
  1388. // This test checks if the definition of the DHCPv4 vendor option can
  1389. // be searched by option name.
  1390. TEST_F(LibDhcpTest, getVendorOptionDefByName4) {
  1391. const OptionDefContainerPtr& defs =
  1392. LibDHCP::getVendorOption4Defs(VENDOR_ID_CABLE_LABS);
  1393. ASSERT_TRUE(defs);
  1394. for (OptionDefContainer::const_iterator def = defs->begin();
  1395. def != defs->end(); ++def) {
  1396. OptionDefinitionPtr def_by_name =
  1397. LibDHCP::getVendorOptionDef(Option::V4, VENDOR_ID_CABLE_LABS,
  1398. (*def)->getName());
  1399. ASSERT_TRUE(def_by_name);
  1400. ASSERT_TRUE(**def == *def_by_name);
  1401. }
  1402. }
  1403. // tests whether v6 vendor-class option can be parsed properly.
  1404. TEST_F(LibDhcpTest, vendorClass6) {
  1405. isc::dhcp::OptionCollection options; // Will store parsed option here
  1406. // Exported from wireshark: vendor-class option with enterprise-id = 4491
  1407. // and a single data entry containing "eRouter1.0"
  1408. string vendor_class_hex = "001000100000118b000a65526f75746572312e30";
  1409. OptionBuffer bin;
  1410. // Decode the hex string and store it in bin (which happens
  1411. // to be OptionBuffer format)
  1412. isc::util::encode::decodeHex(vendor_class_hex, bin);
  1413. ASSERT_NO_THROW ({
  1414. LibDHCP::unpackOptions6(bin, "dhcp6", options);
  1415. });
  1416. EXPECT_EQ(options.size(), 1); // There should be 1 option.
  1417. // Option vendor-class should be there
  1418. ASSERT_FALSE(options.find(D6O_VENDOR_CLASS) == options.end());
  1419. // It should be of type OptionVendorClass
  1420. boost::shared_ptr<OptionVendorClass> vclass =
  1421. boost::dynamic_pointer_cast<OptionVendorClass>(options.begin()->second);
  1422. ASSERT_TRUE(vclass);
  1423. // Let's investigate if the option content is correct
  1424. // 3 fields expected: vendor-id, data-len and data
  1425. EXPECT_EQ(4491, vclass->getVendorId());
  1426. EXPECT_EQ(20, vclass->len());
  1427. ASSERT_EQ(1, vclass->getTuplesNum());
  1428. EXPECT_EQ("eRouter1.0", vclass->getTuple(0).getText());
  1429. }
  1430. // This test verifies that it is possible to add runtime option definitions,
  1431. // retrieve them and remove them.
  1432. TEST_F(LibDhcpTest, setRuntimeOptionDefs) {
  1433. // Create option definitions in 5 namespaces.
  1434. OptionDefSpaceContainer defs;
  1435. createRuntimeOptionDefs(5, 100, defs);
  1436. // Apply option definitions.
  1437. ASSERT_NO_THROW(LibDHCP::setRuntimeOptionDefs(defs));
  1438. // Retrieve all inserted option definitions.
  1439. testRuntimeOptionDefs(5, 100, true);
  1440. // Attempting to retrieve non existing definitions.
  1441. EXPECT_FALSE(LibDHCP::getRuntimeOptionDef("option-space-non-existent", 1));
  1442. EXPECT_FALSE(LibDHCP::getRuntimeOptionDef("option-space-0", 145));
  1443. // Remove all runtime option definitions.
  1444. ASSERT_NO_THROW(LibDHCP::clearRuntimeOptionDefs());
  1445. // All option definitions should be gone now.
  1446. testRuntimeOptionDefs(5, 100, false);
  1447. }
  1448. } // end of anonymous space