perf_pkt6_unittest.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. // Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <config.h>
  15. #include <iostream>
  16. #include <sstream>
  17. #include <arpa/inet.h>
  18. #include <gtest/gtest.h>
  19. #include <asiolink/io_address.h>
  20. #include <dhcp/option.h>
  21. #include <dhcp/dhcp6.h>
  22. #include "../localized_option.h"
  23. #include "../perf_pkt6.h"
  24. using namespace std;
  25. using namespace isc;
  26. using namespace isc::dhcp;
  27. using namespace isc::perfdhcp;
  28. typedef PerfPkt6::LocalizedOptionPtr LocalizedOptionPtr;
  29. namespace {
  30. class PerfPkt6Test : public ::testing::Test {
  31. public:
  32. PerfPkt6Test() {
  33. }
  34. /// \brief Returns captured SOLICIT packet.
  35. ///
  36. /// Captured SOLICIT packet with transid=0x3d79fb and options: client-id,
  37. /// in_na, dns-server, elapsed-time, option-request
  38. /// This code was autogenerated
  39. /// (see src/bin/dhcp6/tests/iface_mgr_unittest.c),
  40. /// but we spent some time to make is less ugly than it used to be.
  41. ///
  42. /// \return pointer to Pkt6 that represents received SOLICIT
  43. PerfPkt6* capture() {
  44. uint8_t data[98];
  45. data[0] = 1;
  46. data[1] = 1; data[2] = 2; data[3] = 3; data[4] = 0;
  47. data[5] = 1; data[6] = 0; data[7] = 14; data[8] = 0;
  48. data[9] = 1; data[10] = 0; data[11] = 1; data[12] = 21;
  49. data[13] = 158; data[14] = 60; data[15] = 22; data[16] = 0;
  50. data[17] = 30; data[18] = 140; data[19] = 155; data[20] = 115;
  51. data[21] = 73; data[22] = 0; data[23] = 3; data[24] = 0;
  52. data[25] = 40; data[26] = 0; data[27] = 0; data[28] = 0;
  53. data[29] = 1; data[30] = 255; data[31] = 255; data[32] = 255;
  54. data[33] = 255; data[34] = 255; data[35] = 255; data[36] = 255;
  55. data[37] = 255; data[38] = 0; data[39] = 5; data[40] = 0;
  56. data[41] = 24; data[42] = 32; data[43] = 1; data[44] = 13;
  57. data[45] = 184; data[46] = 0; data[47] = 1; data[48] = 0;
  58. data[49] = 0; data[50] = 0; data[51] = 0; data[52] = 0;
  59. data[53] = 0; data[54] = 0; data[55] = 0; data[56] = 18;
  60. data[57] = 52; data[58] = 255; data[59] = 255; data[60] = 255;
  61. data[61] = 255; data[62] = 255; data[63] = 255; data[64] = 255;
  62. data[65] = 255; data[66] = 0; data[67] = 23; data[68] = 0;
  63. data[69] = 16; data[70] = 32; data[71] = 1; data[72] = 13;
  64. data[73] = 184; data[74] = 0; data[75] = 1; data[76] = 0;
  65. data[77] = 0; data[78] = 0; data[79] = 0; data[80] = 0;
  66. data[81] = 0; data[82] = 0; data[83] = 0; data[84] = 221;
  67. data[85] = 221; data[86] = 0; data[87] = 8; data[88] = 0;
  68. data[89] = 2; data[90] = 0; data[91] = 100; data[92] = 0;
  69. data[93] = 6; data[94] = 0; data[95] = 2; data[96] = 0;
  70. data[97] = 23;
  71. PerfPkt6* pkt = new PerfPkt6(data, sizeof(data));
  72. return (pkt);
  73. }
  74. /// \brief Returns truncated SOLICIT packet.
  75. ///
  76. /// Returns truncated SOLICIT packet which will be used for
  77. /// negative tests: e.g. pack options out of packet.
  78. ///
  79. /// \return pointer to Pkt6 that represents truncated SOLICIT
  80. PerfPkt6* captureTruncated() {
  81. uint8_t data[17];
  82. data[0] = 1;
  83. data[1] = 1; data[2] = 2; data[3] = 3; data[4] = 0;
  84. data[5] = 1; data[6] = 0; data[7] = 14; data[8] = 0;
  85. data[9] = 1; data[10] = 0; data[11] = 1; data[12] = 21;
  86. data[13] = 158; data[14] = 60; data[15] = 22; data[16] = 0;
  87. PerfPkt6* pkt = new PerfPkt6(data, sizeof(data));
  88. return (pkt);
  89. }
  90. };
  91. TEST_F(PerfPkt6Test, Constructor) {
  92. // Data to be used to create packet.
  93. uint8_t data[] = { 0, 1, 2, 3, 4, 5 };
  94. // Test constructor to be used for incoming messages.
  95. // Use default (1) offset value and don't specify transaction id.
  96. boost::scoped_ptr<PerfPkt6> pkt1(new PerfPkt6(data, sizeof(data)));
  97. EXPECT_EQ(sizeof(data), pkt1->data_.size());
  98. EXPECT_EQ(0, memcmp(&pkt1->data_[0], data, sizeof(data)));
  99. EXPECT_EQ(1, pkt1->getTransidOffset());
  100. // Test constructor to be used for outgoing messages.
  101. // Use non-zero offset and specify transaction id.
  102. const size_t offset_transid = 10;
  103. const uint32_t transid = 0x010203;
  104. boost::scoped_ptr<PerfPkt6> pkt2(new PerfPkt6(data, sizeof(data),
  105. offset_transid, transid));
  106. EXPECT_EQ(sizeof(data), pkt2->data_.size());
  107. EXPECT_EQ(0, memcmp(&pkt2->data_[0], data, sizeof(data)));
  108. EXPECT_EQ(0x010203, pkt2->getTransid());
  109. EXPECT_EQ(10, pkt2->getTransidOffset());
  110. }
  111. TEST_F(PerfPkt6Test, RawPackUnpack) {
  112. // Create first packet.
  113. boost::scoped_ptr<PerfPkt6> pkt1(capture());
  114. // Create some input buffers to initialize options.
  115. uint8_t buf_elapsed_time[] = { 1, 1 };
  116. uint8_t buf_duid[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 };
  117. // Create options.
  118. const size_t offset_elapsed_time = 86;
  119. OptionBuffer vec_elapsed_time(buf_elapsed_time,
  120. buf_elapsed_time + sizeof(buf_elapsed_time));
  121. LocalizedOptionPtr pkt1_elapsed_time(new LocalizedOption(Option::V6,
  122. D6O_ELAPSED_TIME,
  123. vec_elapsed_time,
  124. offset_elapsed_time));
  125. const size_t offset_duid = 4;
  126. OptionBuffer vec_duid(buf_duid, buf_duid + sizeof(buf_duid));
  127. LocalizedOptionPtr pkt1_duid(new LocalizedOption(Option::V6,
  128. D6O_CLIENTID,
  129. vec_duid,
  130. offset_duid));
  131. // Add option to packet and create on-wire format from added options.
  132. // Contents of options will override contents of packet buffer.
  133. ASSERT_NO_THROW(pkt1->addOption(pkt1_elapsed_time));
  134. ASSERT_NO_THROW(pkt1->addOption(pkt1_duid));
  135. ASSERT_TRUE(pkt1->rawPack());
  136. // Reset so as we can reuse them for another packet.
  137. vec_elapsed_time.clear();
  138. vec_duid.clear();
  139. // Get output buffer from packet 1 to create new packet
  140. // that will be later validated.
  141. util::OutputBuffer pkt1_output = pkt1->getBuffer();
  142. ASSERT_EQ(pkt1_output.getLength(), pkt1->data_.size());
  143. const uint8_t* pkt1_output_data = static_cast<const uint8_t*>
  144. (pkt1_output.getData());
  145. boost::scoped_ptr<PerfPkt6> pkt2(new PerfPkt6(pkt1_output_data,
  146. pkt1_output.getLength()));
  147. // Create objects specifying options offset in a packet.
  148. // Offsets will inform pkt2 object where to read data from.
  149. LocalizedOptionPtr pkt2_elapsed_time(new LocalizedOption(Option::V6,
  150. D6O_ELAPSED_TIME,
  151. vec_elapsed_time,
  152. offset_elapsed_time));
  153. LocalizedOptionPtr pkt2_duid(new LocalizedOption(Option::V6,
  154. D6O_CLIENTID,
  155. vec_duid,
  156. offset_duid));
  157. // Add options to packet to pass their offsets.
  158. pkt2->addOption(pkt2_elapsed_time);
  159. pkt2->addOption(pkt2_duid);
  160. // Unpack: get relevant parts of buffer data into option objects.
  161. ASSERT_TRUE(pkt2->rawUnpack());
  162. // Once option data is stored in options objects we pull it out.
  163. pkt2_elapsed_time = boost::dynamic_pointer_cast<LocalizedOption>
  164. (pkt2->getOption(D6O_ELAPSED_TIME));
  165. pkt2_duid = boost::dynamic_pointer_cast<LocalizedOption>
  166. (pkt2->getOption(D6O_CLIENTID));
  167. // Check if options are present. They have to be there since
  168. // we have added them ourselfs.
  169. ASSERT_TRUE(pkt2_elapsed_time);
  170. ASSERT_TRUE(pkt2_duid);
  171. // Expecting option contents be the same as original.
  172. OptionBuffer pkt2_elapsed_time_data = pkt2_elapsed_time->getData();
  173. OptionBuffer pkt2_duid_data = pkt2_duid->getData();
  174. EXPECT_EQ(0x0101, pkt2_elapsed_time->getUint16());
  175. EXPECT_TRUE(std::equal(pkt2_duid_data.begin(),
  176. pkt2_duid_data.end(),
  177. buf_duid));
  178. }
  179. TEST_F(PerfPkt6Test, InvalidOptions) {
  180. // Create packet.
  181. boost::scoped_ptr<PerfPkt6> pkt1(capture());
  182. OptionBuffer vec_server_id;
  183. vec_server_id.resize(10);
  184. // Testing invalid offset of the option (greater than packet size)
  185. const size_t offset_serverid[] = { 150, 85 };
  186. LocalizedOptionPtr pkt1_serverid(new LocalizedOption(Option::V6,
  187. D6O_SERVERID,
  188. vec_server_id,
  189. offset_serverid[0]));
  190. pkt1->addOption(pkt1_serverid);
  191. // Pack has to fail due to invalid offset.
  192. EXPECT_FALSE(pkt1->rawPack());
  193. // Create packet.
  194. boost::scoped_ptr<PerfPkt6> pkt2(capture());
  195. // Testing offset of the option (lower than pakcet size but
  196. // tail of the option out of bounds).
  197. LocalizedOptionPtr pkt2_serverid(new LocalizedOption(Option::V6,
  198. D6O_SERVERID,
  199. vec_server_id,
  200. offset_serverid[1]));
  201. pkt2->addOption(pkt2_serverid);
  202. // Pack must fail due to invalid offset.
  203. EXPECT_FALSE(pkt2->rawPack());
  204. }
  205. TEST_F(PerfPkt6Test, TruncatedPacket) {
  206. cout << "Testing parsing options from truncated packet."
  207. << "This may produce spurious errors" << endl;
  208. // Create truncated (in the middle of duid options)
  209. boost::scoped_ptr<PerfPkt6> pkt1(captureTruncated());
  210. OptionBuffer vec_duid;
  211. vec_duid.resize(30);
  212. const size_t offset_duid = 4;
  213. LocalizedOptionPtr pkt1_duid(new LocalizedOption(Option::V6,
  214. D6O_CLIENTID,
  215. vec_duid,
  216. offset_duid));
  217. pkt1->addOption(pkt1_duid);
  218. // Pack/unpack must fail because length of the option read from buffer
  219. // will extend over the actual packet length.
  220. EXPECT_FALSE(pkt1->rawUnpack());
  221. EXPECT_FALSE(pkt1->rawPack());
  222. }
  223. TEST_F(PerfPkt6Test, PackTransactionId) {
  224. uint8_t data[100];
  225. memset(&data, 0, sizeof(data));
  226. const size_t offset_transid[] = { 50, 100 };
  227. const uint32_t transid = 0x010203;
  228. // Create dummy packet that is simply filled with zeros.
  229. boost::scoped_ptr<PerfPkt6> pkt1(new PerfPkt6(data,
  230. sizeof(data),
  231. offset_transid[0],
  232. transid));
  233. // Reference data are non zero so we can detect them in dummy packet.
  234. uint8_t ref_data[3] = { 1, 2, 3 };
  235. // This will store given transaction id in the packet data at
  236. // offset of 50.
  237. ASSERT_TRUE(pkt1->rawPack());
  238. // Get the output buffer so we can validate it.
  239. util::OutputBuffer out_buf = pkt1->getBuffer();
  240. ASSERT_EQ(sizeof(data), out_buf.getLength());
  241. const uint8_t *out_buf_data = static_cast<const uint8_t*>
  242. (out_buf.getData());
  243. // Validate transaction id.
  244. EXPECT_EQ(0, memcmp(out_buf_data + offset_transid[0], ref_data, 3));
  245. // Out of bounds transaction id offset.
  246. boost::scoped_ptr<PerfPkt6> pkt2(new PerfPkt6(data,
  247. sizeof(data),
  248. offset_transid[1],
  249. transid));
  250. cout << "Testing out of bounds offset. "
  251. "This may produce spurious errors ..." << endl;
  252. EXPECT_FALSE(pkt2->rawPack());
  253. }
  254. TEST_F(PerfPkt6Test, UnpackTransactionId) {
  255. // Initialize data for dummy packet (zeros only).
  256. uint8_t data[100] = { 0 };
  257. // Generate transaction id = 0x010203 and inject at offset = 50.
  258. for (int i = 50; i < 53; ++i) {
  259. data[i] = i - 49;
  260. }
  261. // Create packet and point out that transaction id is at offset 50.
  262. const size_t offset_transid[] = { 50, 300 };
  263. boost::scoped_ptr<PerfPkt6> pkt1(new PerfPkt6(data,
  264. sizeof(data),
  265. offset_transid[0]));
  266. // Get transaction id out of buffer and store in class member.
  267. ASSERT_TRUE(pkt1->rawUnpack());
  268. // Test value of transaction id.
  269. EXPECT_EQ(0x010203, pkt1->getTransid());
  270. // Out of bounds transaction id offset.
  271. boost::scoped_ptr<PerfPkt6> pkt2(new PerfPkt6(data,
  272. sizeof(data),
  273. offset_transid[1]));
  274. cout << "Testing out of bounds offset. "
  275. "This may produce spurious errors ..." << endl;
  276. EXPECT_FALSE(pkt2->rawUnpack());
  277. }
  278. }