option6_client_fqdn_unittest.cc 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809
  1. // Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <config.h>
  15. #include <dhcp/option6_client_fqdn.h>
  16. #include <dns/name.h>
  17. #include <util/buffer.h>
  18. #include <boost/scoped_ptr.hpp>
  19. #include <gtest/gtest.h>
  20. namespace {
  21. using namespace isc;
  22. using namespace isc::dhcp;
  23. // This test verifies that constructor accepts empty partial domain-name but
  24. // does not accept empty fully qualified domain name.
  25. TEST(Option6ClientFqdnTest, constructEmptyName) {
  26. // Create an instance of the source option.
  27. boost::scoped_ptr<Option6ClientFqdn> option;
  28. ASSERT_NO_THROW(
  29. option.reset(new Option6ClientFqdn(Option6ClientFqdn::FLAG_S, "",
  30. Option6ClientFqdn::PARTIAL))
  31. );
  32. ASSERT_TRUE(option);
  33. EXPECT_FALSE(option->getFlag(Option6ClientFqdn::FLAG_O));
  34. EXPECT_FALSE(option->getFlag(Option6ClientFqdn::FLAG_N));
  35. EXPECT_TRUE(option->getFlag(Option6ClientFqdn::FLAG_S));
  36. EXPECT_TRUE(option->getDomainName().empty());
  37. EXPECT_EQ(Option6ClientFqdn::PARTIAL, option->getDomainNameType());
  38. // Constructor should not accept empty fully qualified domain name.
  39. EXPECT_THROW(Option6ClientFqdn(Option6ClientFqdn::FLAG_S, "",
  40. Option6ClientFqdn::FULL),
  41. InvalidOption6FqdnDomainName);
  42. // This check is similar to previous one, but using domain-name comprising
  43. // a single space character. This should be treated as empty domain-name.
  44. EXPECT_THROW(Option6ClientFqdn(Option6ClientFqdn::FLAG_S, " ",
  45. Option6ClientFqdn::FULL),
  46. InvalidOption6FqdnDomainName);
  47. // Try different constructor.
  48. ASSERT_NO_THROW(
  49. option.reset(new Option6ClientFqdn(Option6ClientFqdn::FLAG_O))
  50. );
  51. ASSERT_TRUE(option);
  52. EXPECT_TRUE(option->getFlag(Option6ClientFqdn::FLAG_O));
  53. EXPECT_FALSE(option->getFlag(Option6ClientFqdn::FLAG_N));
  54. EXPECT_FALSE(option->getFlag(Option6ClientFqdn::FLAG_S));
  55. EXPECT_TRUE(option->getDomainName().empty());
  56. EXPECT_EQ(Option6ClientFqdn::PARTIAL, option->getDomainNameType());
  57. }
  58. // This test verifies that copy constructor makes a copy of the option and
  59. // the source option instance can be deleted (both instances don't share
  60. // any resources).
  61. TEST(Option6ClientFqdnTest, copyConstruct) {
  62. // Create an instance of the source option.
  63. boost::scoped_ptr<Option6ClientFqdn> option;
  64. ASSERT_NO_THROW(
  65. option.reset(new Option6ClientFqdn(Option6ClientFqdn::FLAG_S,
  66. "myhost.example.com",
  67. Option6ClientFqdn::FULL))
  68. );
  69. ASSERT_TRUE(option);
  70. // Use copy constructor to create a second instance of the option.
  71. boost::scoped_ptr<Option6ClientFqdn> option_copy;
  72. ASSERT_NO_THROW(
  73. option_copy.reset(new Option6ClientFqdn(*option))
  74. );
  75. ASSERT_TRUE(option_copy);
  76. // Copy construction should result in no shared resources between
  77. // two objects. In particular, pointer to implementation should not
  78. // be shared. Thus, we can release the source object now.
  79. option.reset();
  80. // Verify that all parameters have been copied to the target object.
  81. EXPECT_TRUE(option_copy->getFlag(Option6ClientFqdn::FLAG_S));
  82. EXPECT_FALSE(option_copy->getFlag(Option6ClientFqdn::FLAG_O));
  83. EXPECT_FALSE(option_copy->getFlag(Option6ClientFqdn::FLAG_N));
  84. EXPECT_EQ("myhost.example.com.", option_copy->getDomainName());
  85. EXPECT_EQ(Option6ClientFqdn::FULL, option_copy->getDomainNameType());
  86. // Do another test with different parameters to verify that parameters
  87. // change when copied object is changed.
  88. // Create an option with different parameters.
  89. ASSERT_NO_THROW(
  90. option.reset(new Option6ClientFqdn(Option6ClientFqdn::FLAG_O,
  91. "example",
  92. Option6ClientFqdn::PARTIAL))
  93. );
  94. ASSERT_TRUE(option);
  95. // Call copy-constructor to copy the option.
  96. ASSERT_NO_THROW(
  97. option_copy.reset(new Option6ClientFqdn(*option))
  98. );
  99. ASSERT_TRUE(option_copy);
  100. option.reset();
  101. EXPECT_FALSE(option_copy->getFlag(Option6ClientFqdn::FLAG_S));
  102. EXPECT_TRUE(option_copy->getFlag(Option6ClientFqdn::FLAG_O));
  103. EXPECT_FALSE(option_copy->getFlag(Option6ClientFqdn::FLAG_N));
  104. EXPECT_EQ("example", option_copy->getDomainName());
  105. EXPECT_EQ(Option6ClientFqdn::PARTIAL, option_copy->getDomainNameType());
  106. }
  107. // This test verifies that copy constructor makes a copy of the option, when
  108. // domain-name is empty.
  109. TEST(Option6ClientFqdnTest, copyConstructEmptyDomainName) {
  110. // Create an instance of the source option.
  111. boost::scoped_ptr<Option6ClientFqdn> option;
  112. ASSERT_NO_THROW(
  113. option.reset(new Option6ClientFqdn(Option6ClientFqdn::FLAG_S));
  114. );
  115. ASSERT_TRUE(option);
  116. // Use copy constructor to create a second instance of the option.
  117. boost::scoped_ptr<Option6ClientFqdn> option_copy;
  118. ASSERT_NO_THROW(
  119. option_copy.reset(new Option6ClientFqdn(*option))
  120. );
  121. ASSERT_TRUE(option_copy);
  122. // Copy construction should result in no shared resources between
  123. // two objects. In particular, pointer to implementation should not
  124. // be shared. Thus, we can release the source object now.
  125. option.reset();
  126. // Verify that all parameters have been copied to the target object.
  127. EXPECT_TRUE(option_copy->getFlag(Option6ClientFqdn::FLAG_S));
  128. EXPECT_FALSE(option_copy->getFlag(Option6ClientFqdn::FLAG_O));
  129. EXPECT_FALSE(option_copy->getFlag(Option6ClientFqdn::FLAG_N));
  130. EXPECT_EQ("", option_copy->getDomainName());
  131. EXPECT_EQ(Option6ClientFqdn::PARTIAL, option_copy->getDomainNameType());
  132. }
  133. // This test verifies that the option in the on-wire format is parsed correctly.
  134. TEST(Option6ClientFqdnTest, constructFromWire) {
  135. const uint8_t in_data[] = {
  136. Option6ClientFqdn::FLAG_S, // flags
  137. 6, 109, 121, 104, 111, 115, 116, // myhost.
  138. 7, 101, 120, 97, 109, 112, 108, 101, // example.
  139. 3, 99, 111, 109, 0 // com.
  140. };
  141. size_t in_data_size = sizeof(in_data) / sizeof(in_data[0]);
  142. OptionBuffer in_buf(in_data, in_data + in_data_size);
  143. // Create option instance. Check that constructor doesn't throw.
  144. boost::scoped_ptr<Option6ClientFqdn> option;
  145. ASSERT_NO_THROW(
  146. option.reset(new Option6ClientFqdn(in_buf.begin(), in_buf.end()))
  147. );
  148. ASSERT_TRUE(option);
  149. EXPECT_TRUE(option->getFlag(Option6ClientFqdn::FLAG_S));
  150. EXPECT_FALSE(option->getFlag(Option6ClientFqdn::FLAG_O));
  151. EXPECT_FALSE(option->getFlag(Option6ClientFqdn::FLAG_N));
  152. EXPECT_EQ("myhost.example.com.", option->getDomainName());
  153. EXPECT_EQ(Option6ClientFqdn::FULL, option->getDomainNameType());
  154. }
  155. // Verify that exception is thrown if the domain-name label is
  156. // longer than 63.
  157. TEST(Option6ClientFqdnTest, constructFromWireTooLongLabel) {
  158. OptionBuffer in_buf(Option6ClientFqdn::FLAG_S);
  159. in_buf.push_back(70);
  160. in_buf.insert(in_buf.end(), 70, 109);
  161. in_buf.push_back(0);
  162. EXPECT_THROW(Option6ClientFqdn(in_buf.begin(), in_buf.end()),
  163. InvalidOption6FqdnDomainName);
  164. }
  165. // Verify that exception is thrown if the overall length of the domain-name
  166. // is over 255.
  167. TEST(Option6ClientFqdnTest, constructFromWireTooLongDomainName) {
  168. OptionBuffer in_buf(Option6ClientFqdn::FLAG_S);
  169. for (int i = 0; i < 26; ++i) {
  170. in_buf.push_back(10);
  171. in_buf.insert(in_buf.end(), 10, 109);
  172. }
  173. in_buf.push_back(0);
  174. try {
  175. Option6ClientFqdn(in_buf.begin(), in_buf.end());
  176. } catch (const Exception& ex) {
  177. std::cout << ex.what() << std::endl;
  178. }
  179. EXPECT_THROW(Option6ClientFqdn(in_buf.begin(), in_buf.end()),
  180. InvalidOption6FqdnDomainName);
  181. }
  182. // This test verifies that truncated option is rejected.
  183. TEST(Option6ClientFqdnTest, constructFromWireTruncated) {
  184. // Empty buffer is invalid. It should be at least one octet long.
  185. OptionBuffer in_buf;
  186. ASSERT_THROW(Option6ClientFqdn(in_buf.begin(), in_buf.end()),
  187. OutOfRange);
  188. }
  189. // This test verifies that the option in the on-wire format with partial
  190. // domain-name is parsed correctly.
  191. TEST(Option6ClientFqdnTest, constructFromWirePartial) {
  192. const uint8_t in_data[] = {
  193. Option6ClientFqdn::FLAG_N, // flags
  194. 6, 109, 121, 104, 111, 115, 116 // myhost
  195. };
  196. size_t in_data_size = sizeof(in_data) / sizeof(in_data[0]);
  197. OptionBuffer in_buf(in_data, in_data + in_data_size);
  198. // Create option instance. Check that constructor doesn't throw.
  199. boost::scoped_ptr<Option6ClientFqdn> option;
  200. ASSERT_NO_THROW(
  201. option.reset(new Option6ClientFqdn(in_buf.begin(), in_buf.end()))
  202. );
  203. ASSERT_TRUE(option);
  204. EXPECT_FALSE(option->getFlag(Option6ClientFqdn::FLAG_S));
  205. EXPECT_FALSE(option->getFlag(Option6ClientFqdn::FLAG_O));
  206. EXPECT_TRUE(option->getFlag(Option6ClientFqdn::FLAG_N));
  207. EXPECT_EQ("myhost", option->getDomainName());
  208. EXPECT_EQ(Option6ClientFqdn::PARTIAL, option->getDomainNameType());
  209. }
  210. // This test verifies that the option in the on-wire format with empty
  211. // domain-name is parsed correctly.
  212. TEST(Option6ClientFqdnTest, constructFromWireEmpty) {
  213. OptionBuffer in_buf(Option6ClientFqdn::FLAG_S);
  214. // Create option instance. Check that constructor doesn't throw.
  215. boost::scoped_ptr<Option6ClientFqdn> option;
  216. ASSERT_NO_THROW(
  217. option.reset(new Option6ClientFqdn(in_buf.begin(), in_buf.end()))
  218. );
  219. ASSERT_TRUE(option);
  220. // domain-name field should be empty because on-wire data comprised
  221. // flags field only.
  222. EXPECT_TRUE(option->getDomainName().empty());
  223. }
  224. // This test verifies that assignment operator can be used to assign one
  225. // instance of the option to another.
  226. TEST(Option6ClientFqdnTest, assignment) {
  227. // Usually the smart pointer is used to declare options and call
  228. // constructor within assert. Thanks to this approach, the option instance
  229. // is in the function scope and only initialization is done within assert.
  230. // In this particular test we can't use smart pointers because we are
  231. // testing assignment operator like this:
  232. //
  233. // option2 = option;
  234. //
  235. // The two asserts below do not create the instances that we will used to
  236. // test assignment. They just attempt to create instances of the options
  237. // with the same parameters as those that will be created for the actual
  238. // assignment test. If these asserts do not fail, we can create options
  239. // for the assignment test, do not surround them with asserts and be sure
  240. // they will not throw.
  241. ASSERT_NO_THROW(Option6ClientFqdn(Option6ClientFqdn::FLAG_S,
  242. "myhost.example.com",
  243. Option6ClientFqdn::FULL));
  244. ASSERT_NO_THROW(Option6ClientFqdn(Option6ClientFqdn::FLAG_N,
  245. "myhost",
  246. Option6ClientFqdn::PARTIAL));
  247. // Create options with the same parameters as tested above.
  248. // Create first option.
  249. Option6ClientFqdn option(Option6ClientFqdn::FLAG_S,
  250. "myhost.example.com",
  251. Option6ClientFqdn::FULL);
  252. // Verify that the values have been set correctly.
  253. ASSERT_TRUE(option.getFlag(Option6ClientFqdn::FLAG_S));
  254. ASSERT_FALSE(option.getFlag(Option6ClientFqdn::FLAG_O));
  255. ASSERT_FALSE(option.getFlag(Option6ClientFqdn::FLAG_N));
  256. ASSERT_EQ("myhost.example.com.", option.getDomainName());
  257. ASSERT_EQ(Option6ClientFqdn::FULL, option.getDomainNameType());
  258. // Create a second option.
  259. Option6ClientFqdn option2(Option6ClientFqdn::FLAG_N,
  260. "myhost",
  261. Option6ClientFqdn::PARTIAL);
  262. // Verify tha the values have been set correctly.
  263. ASSERT_FALSE(option2.getFlag(Option6ClientFqdn::FLAG_S));
  264. ASSERT_FALSE(option2.getFlag(Option6ClientFqdn::FLAG_O));
  265. ASSERT_TRUE(option2.getFlag(Option6ClientFqdn::FLAG_N));
  266. ASSERT_EQ("myhost", option2.getDomainName());
  267. ASSERT_EQ(Option6ClientFqdn::PARTIAL, option2.getDomainNameType());
  268. // Make the assignment.
  269. ASSERT_NO_THROW(option2 = option);
  270. // Both options should now have the same values.
  271. EXPECT_TRUE(option2.getFlag(Option6ClientFqdn::FLAG_S));
  272. EXPECT_FALSE(option2.getFlag(Option6ClientFqdn::FLAG_O));
  273. EXPECT_FALSE(option2.getFlag(Option6ClientFqdn::FLAG_N));
  274. EXPECT_EQ(option.getDomainName(), option2.getDomainName());
  275. EXPECT_EQ(option.getDomainNameType(), option2.getDomainNameType());
  276. }
  277. // This test verifies that assignment operator can be used to assign one
  278. // instance of the option to another, when the domain-name is empty.
  279. TEST(Option6ClientFqdnTest, assignmentEmptyDomainName) {
  280. ASSERT_NO_THROW(
  281. Option6ClientFqdn(static_cast<uint8_t>(Option6ClientFqdn::FLAG_S))
  282. );
  283. ASSERT_NO_THROW(Option6ClientFqdn(Option6ClientFqdn::FLAG_N,
  284. "myhost",
  285. Option6ClientFqdn::PARTIAL));
  286. // Create options with the same parameters as tested above.
  287. // Create first option.
  288. Option6ClientFqdn option(Option6ClientFqdn::FLAG_S);
  289. // Verify that the values have been set correctly.
  290. ASSERT_TRUE(option.getFlag(Option6ClientFqdn::FLAG_S));
  291. ASSERT_FALSE(option.getFlag(Option6ClientFqdn::FLAG_O));
  292. ASSERT_FALSE(option.getFlag(Option6ClientFqdn::FLAG_N));
  293. ASSERT_EQ("", option.getDomainName());
  294. ASSERT_EQ(Option6ClientFqdn::PARTIAL, option.getDomainNameType());
  295. // Create a second option.
  296. Option6ClientFqdn option2(Option6ClientFqdn::FLAG_N,
  297. "myhost",
  298. Option6ClientFqdn::PARTIAL);
  299. // Verify that the values have been set correctly.
  300. ASSERT_FALSE(option2.getFlag(Option6ClientFqdn::FLAG_S));
  301. ASSERT_FALSE(option2.getFlag(Option6ClientFqdn::FLAG_O));
  302. ASSERT_TRUE(option2.getFlag(Option6ClientFqdn::FLAG_N));
  303. ASSERT_EQ("myhost", option2.getDomainName());
  304. ASSERT_EQ(Option6ClientFqdn::PARTIAL, option2.getDomainNameType());
  305. // Make the assignment.
  306. ASSERT_NO_THROW(option2 = option);
  307. // Both options should now have the same values.
  308. EXPECT_TRUE(option2.getFlag(Option6ClientFqdn::FLAG_S));
  309. EXPECT_FALSE(option2.getFlag(Option6ClientFqdn::FLAG_O));
  310. EXPECT_FALSE(option2.getFlag(Option6ClientFqdn::FLAG_N));
  311. EXPECT_EQ("", option2.getDomainName());
  312. EXPECT_EQ(option.getDomainNameType(), option2.getDomainNameType());
  313. }
  314. // This test verifies that constructor will throw an exception if invalid
  315. // DHCPv6 Client FQDN Option flags are specified.
  316. TEST(Option6ClientFqdnTest, constructInvalidFlags) {
  317. // First, check that constructor does not throw an exception when
  318. // valid flags values are provided. That way we eliminate the issue
  319. // that constructor always throws exception.
  320. uint8_t flags = 0;
  321. ASSERT_NO_THROW(Option6ClientFqdn(flags, "myhost.example.com"));
  322. // Invalid flags: The maximal value is 0x7 when all flag bits are set
  323. // (00000111b). The flag value of 0x14 sets the bit from the Must Be
  324. // Zero (MBZ) bitset (00001100b).
  325. flags = 0x14;
  326. EXPECT_THROW(Option6ClientFqdn(flags, "myhost.example.com"),
  327. InvalidOption6FqdnFlags);
  328. // According to RFC 4704, section 4.1. if the N bit is set the S bit MUST
  329. // be zero. If both are set, constructor is expected to throw.
  330. flags = Option6ClientFqdn::FLAG_N | Option6ClientFqdn::FLAG_S;
  331. EXPECT_THROW(Option6ClientFqdn(flags, "myhost.example.com"),
  332. InvalidOption6FqdnFlags);
  333. }
  334. // This test verifies that constructor which parses option from on-wire format
  335. // will throw exception if parsed flags field is invalid.
  336. TEST(Option6ClientFqdnTest, constructFromWireInvalidFlags) {
  337. // Create a buffer which holds flags field only. Set valid flag field at
  338. // at first to make sure that constructor doesn't always throw an exception.
  339. OptionBuffer in_buf(Option6ClientFqdn::FLAG_N);
  340. ASSERT_NO_THROW(Option6ClientFqdn(in_buf.begin(), in_buf.end()));
  341. // Replace the flags with invalid value and verify that constructor throws
  342. // appropriate exception.
  343. in_buf[0] = Option6ClientFqdn::FLAG_N | Option6ClientFqdn::FLAG_S;
  344. EXPECT_THROW(Option6ClientFqdn(in_buf.begin(), in_buf.end()),
  345. InvalidOption6FqdnFlags);
  346. }
  347. // This test verifies that if invalid domain name is used the constructor
  348. // will throw appropriate exception.
  349. TEST(Option6ClientFqdnTest, constructInvalidName) {
  350. // First, check that constructor does not throw when valid domain name
  351. // is specified. That way we eliminate the possibility that constructor
  352. // always throws exception.
  353. ASSERT_NO_THROW(Option6ClientFqdn(0, "myhost.example.com"));
  354. // Specify invalid domain name and expect that exception is thrown.
  355. EXPECT_THROW(Option6ClientFqdn(0, "my...host.example.com"),
  356. InvalidOption6FqdnDomainName);
  357. }
  358. // This test verifies that getFlag throws an exception if flag value other
  359. // than FLAG_N, FLAG_S, FLAG_O is specified.
  360. TEST(Option6ClientFqdnTest, getFlag) {
  361. boost::scoped_ptr<Option6ClientFqdn> option;
  362. ASSERT_NO_THROW(
  363. option.reset(new Option6ClientFqdn(0, "myhost.example.com"))
  364. );
  365. ASSERT_TRUE(option);
  366. // The 0x3 (binary 011) specifies two distinct bits in the flags field.
  367. // This value is ambiguous for getFlag function and this function doesn't
  368. // know which flag the caller is attempting to check.
  369. EXPECT_THROW(option->getFlag(0x3), InvalidOption6FqdnFlags);
  370. }
  371. // This test verifies that flags can be modified and that incorrect flags
  372. // are rejected.
  373. TEST(Option6ClientFqdnTest, setFlag) {
  374. // Create option instance. Check that constructor doesn't throw.
  375. boost::scoped_ptr<Option6ClientFqdn> option;
  376. ASSERT_NO_THROW(
  377. option.reset(new Option6ClientFqdn(0, "myhost.example.com"))
  378. );
  379. ASSERT_TRUE(option);
  380. // All flags should be set to 0 initially.
  381. ASSERT_FALSE(option->getFlag(Option6ClientFqdn::FLAG_N));
  382. ASSERT_FALSE(option->getFlag(Option6ClientFqdn::FLAG_S));
  383. ASSERT_FALSE(option->getFlag(Option6ClientFqdn::FLAG_O));
  384. // Set N = 1
  385. ASSERT_NO_THROW(option->setFlag(Option6ClientFqdn::FLAG_N, true));
  386. ASSERT_TRUE(option->getFlag(Option6ClientFqdn::FLAG_N));
  387. // Set O = 1
  388. ASSERT_NO_THROW(option->setFlag(Option6ClientFqdn::FLAG_O, true));
  389. ASSERT_TRUE(option->getFlag(Option6ClientFqdn::FLAG_O));
  390. // Set S = 1, this should throw exception because S and N must not
  391. // be set in the same time.
  392. ASSERT_THROW(option->setFlag(Option6ClientFqdn::FLAG_S, true),
  393. InvalidOption6FqdnFlags);
  394. // Set N = 0
  395. ASSERT_NO_THROW(option->setFlag(Option6ClientFqdn::FLAG_N, false));
  396. ASSERT_FALSE(option->getFlag(Option6ClientFqdn::FLAG_N));
  397. // Set S = 1, this should not result in exception because N has been
  398. // cleared.
  399. ASSERT_NO_THROW(option->setFlag(Option6ClientFqdn::FLAG_S, true));
  400. ASSERT_TRUE(option->getFlag(Option6ClientFqdn::FLAG_S));
  401. // Set N = 1, this should result in exception because S = 1
  402. ASSERT_THROW(option->setFlag(Option6ClientFqdn::FLAG_N, true),
  403. InvalidOption6FqdnFlags);
  404. // Set O = 0
  405. ASSERT_NO_THROW(option->setFlag(Option6ClientFqdn::FLAG_O, false));
  406. ASSERT_FALSE(option->getFlag(Option6ClientFqdn::FLAG_O));
  407. // Try out of bounds settings.
  408. uint8_t flags = 0;
  409. ASSERT_THROW(option->setFlag(flags, true), InvalidOption6FqdnFlags);
  410. flags = 0x14;
  411. ASSERT_THROW(option->setFlag(flags, true), InvalidOption6FqdnFlags);
  412. }
  413. // This test verifies that flags field of the option is set to 0 when resetFlags
  414. // function is called.
  415. TEST(Option6ClientFqdnTest, resetFlags) {
  416. boost::scoped_ptr<Option6ClientFqdn> option;
  417. ASSERT_NO_THROW(
  418. option.reset(new Option6ClientFqdn(Option6ClientFqdn::FLAG_S |
  419. Option6ClientFqdn::FLAG_O,
  420. "myhost.example.com",
  421. Option6ClientFqdn::FULL))
  422. );
  423. ASSERT_TRUE(option);
  424. // Check that flags we set in the constructor are set.
  425. ASSERT_TRUE(option->getFlag(Option6ClientFqdn::FLAG_S));
  426. ASSERT_TRUE(option->getFlag(Option6ClientFqdn::FLAG_O));
  427. ASSERT_FALSE(option->getFlag(Option6ClientFqdn::FLAG_N));
  428. option->resetFlags();
  429. // After reset, all flags should be 0.
  430. EXPECT_FALSE(option->getFlag(Option6ClientFqdn::FLAG_S));
  431. EXPECT_FALSE(option->getFlag(Option6ClientFqdn::FLAG_O));
  432. EXPECT_FALSE(option->getFlag(Option6ClientFqdn::FLAG_N));
  433. }
  434. // This test verifies that current domain-name can be replaced with a new
  435. // domain-name.
  436. TEST(Option6ClientFqdnTest, setDomainName) {
  437. boost::scoped_ptr<Option6ClientFqdn> option;
  438. ASSERT_NO_THROW(
  439. option.reset(new Option6ClientFqdn(Option6ClientFqdn::FLAG_S,
  440. "myhost.example.com",
  441. Option6ClientFqdn::FULL))
  442. );
  443. ASSERT_TRUE(option);
  444. ASSERT_EQ("myhost.example.com.", option->getDomainName());
  445. ASSERT_EQ(Option6ClientFqdn::FULL, option->getDomainNameType());
  446. // Partial domain-name.
  447. ASSERT_NO_THROW(option->setDomainName("myhost",
  448. Option6ClientFqdn::PARTIAL));
  449. EXPECT_EQ("myhost", option->getDomainName());
  450. EXPECT_EQ(Option6ClientFqdn::PARTIAL, option->getDomainNameType());
  451. // Fully qualified domain-name.
  452. ASSERT_NO_THROW(option->setDomainName("example.com",
  453. Option6ClientFqdn::FULL));
  454. EXPECT_EQ("example.com.", option->getDomainName());
  455. EXPECT_EQ(Option6ClientFqdn::FULL, option->getDomainNameType());
  456. // Empty domain name (partial). This should be successful.
  457. ASSERT_NO_THROW(option->setDomainName("", Option6ClientFqdn::PARTIAL));
  458. EXPECT_TRUE(option->getDomainName().empty());
  459. // Fully qualified domain-names must not be empty.
  460. EXPECT_THROW(option->setDomainName("", Option6ClientFqdn::FULL),
  461. InvalidOption6FqdnDomainName);
  462. EXPECT_THROW(option->setDomainName(" ", Option6ClientFqdn::FULL),
  463. InvalidOption6FqdnDomainName);
  464. }
  465. // This test verifies that current domain-name can be reset to empty one.
  466. TEST(Option6ClientFqdnTest, resetDomainName) {
  467. boost::scoped_ptr<Option6ClientFqdn> option;
  468. ASSERT_NO_THROW(
  469. option.reset(new Option6ClientFqdn(Option6ClientFqdn::FLAG_S,
  470. "myhost.example.com",
  471. Option6ClientFqdn::FULL))
  472. );
  473. ASSERT_TRUE(option);
  474. ASSERT_EQ("myhost.example.com.", option->getDomainName());
  475. ASSERT_EQ(Option6ClientFqdn::FULL, option->getDomainNameType());
  476. // Set the domain-name to empty one.
  477. ASSERT_NO_THROW(option->resetDomainName());
  478. EXPECT_TRUE(option->getDomainName().empty());
  479. }
  480. // This test verifies on-wire format of the option is correctly created.
  481. TEST(Option6ClientFqdnTest, pack) {
  482. // Create option instance. Check that constructor doesn't throw.
  483. const uint8_t flags = Option6ClientFqdn::FLAG_S;
  484. boost::scoped_ptr<Option6ClientFqdn> option;
  485. ASSERT_NO_THROW(
  486. option.reset(new Option6ClientFqdn(flags, "myhost.example.com"))
  487. );
  488. ASSERT_TRUE(option);
  489. // Prepare on-wire format of the option.
  490. isc::util::OutputBuffer buf(10);
  491. ASSERT_NO_THROW(option->pack(buf));
  492. // Prepare reference data.
  493. const uint8_t ref_data[] = {
  494. 0, 39, 0, 21, // header
  495. Option6ClientFqdn::FLAG_S, // flags
  496. 6, 109, 121, 104, 111, 115, 116, // myhost.
  497. 7, 101, 120, 97, 109, 112, 108, 101, // example.
  498. 3, 99, 111, 109, 0 // com.
  499. };
  500. size_t ref_data_size = sizeof(ref_data) / sizeof(ref_data[0]);
  501. // Check if the buffer has the same length as the reference data,
  502. // so as they can be compared directly.
  503. ASSERT_EQ(ref_data_size, buf.getLength());
  504. EXPECT_EQ(0, memcmp(ref_data, buf.getData(), buf.getLength()));
  505. }
  506. // This test verifies on-wire format of the option with partial domain name
  507. // is correctly created.
  508. TEST(Option6ClientFqdnTest, packPartial) {
  509. // Create option instance. Check that constructor doesn't throw.
  510. const uint8_t flags = Option6ClientFqdn::FLAG_S;
  511. boost::scoped_ptr<Option6ClientFqdn> option;
  512. ASSERT_NO_THROW(
  513. option.reset(new Option6ClientFqdn(flags, "myhost",
  514. Option6ClientFqdn::PARTIAL))
  515. );
  516. ASSERT_TRUE(option);
  517. // Prepare on-wire format of the option.
  518. isc::util::OutputBuffer buf(10);
  519. ASSERT_NO_THROW(option->pack(buf));
  520. // Prepare reference data.
  521. const uint8_t ref_data[] = {
  522. 0, 39, 0, 8, // header
  523. Option6ClientFqdn::FLAG_S, // flags
  524. 6, 109, 121, 104, 111, 115, 116 // myhost
  525. };
  526. size_t ref_data_size = sizeof(ref_data) / sizeof(ref_data[0]);
  527. // Check if the buffer has the same length as the reference data,
  528. // so as they can be compared directly.
  529. ASSERT_EQ(ref_data_size, buf.getLength());
  530. EXPECT_EQ(0, memcmp(ref_data, buf.getData(), buf.getLength()));
  531. }
  532. // This test verifies that it is possible to encode the option which carries
  533. // empty domain-name in the wire format.
  534. TEST(Option6ClientFqdnTest, packEmpty) {
  535. // Create option instance. Check that constructor doesn't throw.
  536. const uint8_t flags = Option6ClientFqdn::FLAG_S;
  537. boost::scoped_ptr<Option6ClientFqdn> option;
  538. ASSERT_NO_THROW(
  539. option.reset(new Option6ClientFqdn(flags))
  540. );
  541. ASSERT_TRUE(option);
  542. // Prepare on-wire format of the option.
  543. isc::util::OutputBuffer buf(5);
  544. ASSERT_NO_THROW(option->pack(buf));
  545. // Prepare reference data.
  546. const uint8_t ref_data[] = {
  547. 0, 39, 0, 1, // header
  548. Option6ClientFqdn::FLAG_S // flags
  549. };
  550. size_t ref_data_size = sizeof(ref_data) / sizeof(ref_data[0]);
  551. // Check if the buffer has the same length as the reference data,
  552. // so as they can be compared directly.
  553. ASSERT_EQ(ref_data_size, buf.getLength());
  554. EXPECT_EQ(0, memcmp(ref_data, buf.getData(), buf.getLength()));
  555. }
  556. // This test verifies that on-wire option data holding fully qualified domain
  557. // name is parsed correctly.
  558. TEST(Option6ClientFqdnTest, unpack) {
  559. // Create option instance. Check that constructor doesn't throw.
  560. boost::scoped_ptr<Option6ClientFqdn> option;
  561. ASSERT_NO_THROW(
  562. option.reset(new Option6ClientFqdn(Option6ClientFqdn::FLAG_O,
  563. "myhost",
  564. Option6ClientFqdn::PARTIAL))
  565. );
  566. ASSERT_TRUE(option);
  567. // Make sure that the parameters have been set correctly. Later in this
  568. // test we will check that they will be replaced with new values when
  569. // unpack is called.
  570. EXPECT_FALSE(option->getFlag(Option6ClientFqdn::FLAG_S));
  571. EXPECT_FALSE(option->getFlag(Option6ClientFqdn::FLAG_N));
  572. EXPECT_TRUE(option->getFlag(Option6ClientFqdn::FLAG_O));
  573. EXPECT_EQ("myhost", option->getDomainName());
  574. EXPECT_EQ(Option6ClientFqdn::PARTIAL, option->getDomainNameType());
  575. const uint8_t in_data[] = {
  576. Option6ClientFqdn::FLAG_S, // flags
  577. 6, 109, 121, 104, 111, 115, 116, // myhost.
  578. 7, 101, 120, 97, 109, 112, 108, 101, // example.
  579. 3, 99, 111, 109, 0 // com.
  580. };
  581. size_t in_data_size = sizeof(in_data) / sizeof(in_data[0]);
  582. OptionBuffer in_buf(in_data, in_data + in_data_size);
  583. // Initialize new values from the on-wire format.
  584. ASSERT_NO_THROW(option->unpack(in_buf.begin(), in_buf.end()));
  585. // Check that new values are correct.
  586. EXPECT_TRUE(option->getFlag(Option6ClientFqdn::FLAG_S));
  587. EXPECT_FALSE(option->getFlag(Option6ClientFqdn::FLAG_N));
  588. EXPECT_FALSE(option->getFlag(Option6ClientFqdn::FLAG_O));
  589. EXPECT_EQ("myhost.example.com.", option->getDomainName());
  590. EXPECT_EQ(Option6ClientFqdn::FULL, option->getDomainNameType());
  591. }
  592. // This test verifies that on-wire option data holding partial domain name
  593. // is parsed correctly.
  594. TEST(Option6ClientFqdnTest, unpackPartial) {
  595. // Create option instance. Check that constructor doesn't throw.
  596. boost::scoped_ptr<Option6ClientFqdn> option;
  597. ASSERT_NO_THROW(
  598. option.reset(new Option6ClientFqdn(Option6ClientFqdn::FLAG_O,
  599. "myhost.example.com"))
  600. );
  601. ASSERT_TRUE(option);
  602. // Make sure that the parameters have been set correctly. Later in this
  603. // test we will check that they will be replaced with new values when
  604. // unpack is called.
  605. EXPECT_FALSE(option->getFlag(Option6ClientFqdn::FLAG_S));
  606. EXPECT_FALSE(option->getFlag(Option6ClientFqdn::FLAG_N));
  607. EXPECT_TRUE(option->getFlag(Option6ClientFqdn::FLAG_O));
  608. EXPECT_EQ("myhost.example.com.", option->getDomainName());
  609. EXPECT_EQ(Option6ClientFqdn::FULL, option->getDomainNameType());
  610. const uint8_t in_data[] = {
  611. Option6ClientFqdn::FLAG_S, // flags
  612. 6, 109, 121, 104, 111, 115, 116 // myhost
  613. };
  614. size_t in_data_size = sizeof(in_data) / sizeof(in_data[0]);
  615. OptionBuffer in_buf(in_data, in_data + in_data_size);
  616. // Initialize new values from the on-wire format.
  617. ASSERT_NO_THROW(option->unpack(in_buf.begin(), in_buf.end()));
  618. // Check that new values are correct.
  619. EXPECT_TRUE(option->getFlag(Option6ClientFqdn::FLAG_S));
  620. EXPECT_FALSE(option->getFlag(Option6ClientFqdn::FLAG_N));
  621. EXPECT_FALSE(option->getFlag(Option6ClientFqdn::FLAG_O));
  622. EXPECT_EQ("myhost", option->getDomainName());
  623. EXPECT_EQ(Option6ClientFqdn::PARTIAL, option->getDomainNameType());
  624. }
  625. // This test verifies that the empty buffer is rejected when decoding an option
  626. // from on-wire format.
  627. TEST(Option6ClientFqdnTest, unpackTruncated) {
  628. boost::scoped_ptr<Option6ClientFqdn> option;
  629. ASSERT_NO_THROW(
  630. option.reset(new Option6ClientFqdn(Option6ClientFqdn::FLAG_O))
  631. );
  632. ASSERT_TRUE(option);
  633. // Empty buffer is invalid. It should be at least 1 octet long.
  634. OptionBuffer in_buf;
  635. EXPECT_THROW(option->unpack(in_buf.begin(), in_buf.end()), OutOfRange);
  636. }
  637. // This test verifies that string representation of the option returned by
  638. // toText method is correctly formatted.
  639. TEST(Option6ClientFqdnTest, toText) {
  640. // Create option instance. Check that constructor doesn't throw.
  641. uint8_t flags = Option6ClientFqdn::FLAG_N | Option6ClientFqdn::FLAG_O;
  642. boost::scoped_ptr<Option6ClientFqdn> option;
  643. ASSERT_NO_THROW(
  644. option.reset(new Option6ClientFqdn(flags,
  645. "myhost.example.com"))
  646. );
  647. ASSERT_TRUE(option);
  648. // The base indentation of the option will be set to 2. It should appear
  649. // as follows.
  650. std::string ref_string =
  651. " type=39(CLIENT_FQDN), flags: (N=1, O=1, S=0), "
  652. "domain-name='myhost.example.com.' (full)";
  653. const int indent = 2;
  654. EXPECT_EQ(ref_string, option->toText(indent));
  655. // Create another option with different parameters:
  656. // - flags set to 0
  657. // - domain-name is now partial, not fully qualified
  658. // Also, remove base indentation.
  659. flags = 0;
  660. ASSERT_NO_THROW(
  661. option.reset(new Option6ClientFqdn(flags, "myhost",
  662. Option6ClientFqdn::PARTIAL))
  663. );
  664. ref_string =
  665. "type=39(CLIENT_FQDN), flags: (N=0, O=0, S=0), "
  666. "domain-name='myhost' (partial)";
  667. EXPECT_EQ(ref_string, option->toText());
  668. }
  669. // This test verifies that the correct length of the option in on-wire
  670. // format is returned.
  671. TEST(Option6ClientFqdnTest, len) {
  672. // Create option instance. Check that constructor doesn't throw.
  673. boost::scoped_ptr<Option6ClientFqdn> option;
  674. ASSERT_NO_THROW(
  675. option.reset(new Option6ClientFqdn(0, "myhost.example.com"))
  676. );
  677. ASSERT_TRUE(option);
  678. // This option comprises a header (4 octets), flag field (1 octet),
  679. // and wire representation of the domain name (length equal to the
  680. // length of the string representation of the domain name + 1).
  681. EXPECT_EQ(25, option->len());
  682. // Let's check that the size will change when domain name of a different
  683. // size is used.
  684. ASSERT_NO_THROW(
  685. option.reset(new Option6ClientFqdn(0, "example.com"))
  686. );
  687. ASSERT_TRUE(option);
  688. EXPECT_EQ(18, option->len());
  689. ASSERT_NO_THROW(
  690. option.reset(new Option6ClientFqdn(0, "myhost",
  691. Option6ClientFqdn::PARTIAL))
  692. );
  693. ASSERT_TRUE(option);
  694. EXPECT_EQ(12, option->len());
  695. }
  696. } // anonymous namespace