pkt4_unittest.cc 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673
  1. // Copyright (C) 2011-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 <asiolink/io_address.h>
  16. #include <dhcp/dhcp4.h>
  17. #include <dhcp/pkt4.h>
  18. #include <exceptions/exceptions.h>
  19. #include <util/buffer.h>
  20. #include <boost/shared_array.hpp>
  21. #include <boost/shared_ptr.hpp>
  22. #include <boost/static_assert.hpp>
  23. #include <gtest/gtest.h>
  24. #include <iostream>
  25. #include <sstream>
  26. #include <arpa/inet.h>
  27. using namespace std;
  28. using namespace isc;
  29. using namespace isc::asiolink;
  30. using namespace isc::dhcp;
  31. using namespace isc::util;
  32. // don't import the entire boost namespace. It will unexpectedly hide uint8_t
  33. // for some systems.
  34. using boost::scoped_ptr;
  35. namespace {
  36. TEST(Pkt4Test, constructor) {
  37. ASSERT_EQ(236U, static_cast<size_t>(Pkt4::DHCPV4_PKT_HDR_LEN) );
  38. Pkt4* pkt = 0;
  39. // Just some dummy payload.
  40. uint8_t testData[250];
  41. for (int i = 0; i < 250; i++) {
  42. testData[i]=i;
  43. }
  44. // Positive case1. Normal received packet.
  45. EXPECT_NO_THROW(
  46. pkt = new Pkt4(testData, Pkt4::DHCPV4_PKT_HDR_LEN);
  47. );
  48. EXPECT_EQ(static_cast<size_t>(Pkt4::DHCPV4_PKT_HDR_LEN), pkt->len());
  49. EXPECT_NO_THROW(
  50. delete pkt;
  51. pkt = 0;
  52. );
  53. // Positive case2. Normal outgoing packet.
  54. EXPECT_NO_THROW(
  55. pkt = new Pkt4(DHCPDISCOVER, 0xffffffff);
  56. );
  57. // DHCPv4 packet must be at least 236 bytes long, with Message Type
  58. // Option taking extra 3 bytes it is 239
  59. EXPECT_EQ(static_cast<size_t>(Pkt4::DHCPV4_PKT_HDR_LEN) + 3, pkt->len());
  60. EXPECT_EQ(DHCPDISCOVER, pkt->getType());
  61. EXPECT_EQ(0xffffffff, pkt->getTransid());
  62. EXPECT_NO_THROW(
  63. delete pkt;
  64. pkt = 0;
  65. );
  66. // Negative case. Should drop truncated messages.
  67. EXPECT_THROW(
  68. pkt = new Pkt4(testData, Pkt4::DHCPV4_PKT_HDR_LEN-1),
  69. OutOfRange
  70. );
  71. if (pkt) {
  72. // Test failed. Exception should have been thrown, but
  73. // object was created instead. Let's clean this up.
  74. delete pkt;
  75. pkt = 0;
  76. }
  77. }
  78. // a sample data
  79. const uint8_t dummyOp = BOOTREQUEST;
  80. const uint8_t dummyHtype = 6;
  81. const uint8_t dummyHlen = 6;
  82. const uint8_t dummyHops = 13;
  83. const uint32_t dummyTransid = 0x12345678;
  84. const uint16_t dummySecs = 42;
  85. const uint16_t dummyFlags = BOOTP_BROADCAST;
  86. const IOAddress dummyCiaddr("192.0.2.1");
  87. const IOAddress dummyYiaddr("1.2.3.4");
  88. const IOAddress dummySiaddr("192.0.2.255");
  89. const IOAddress dummyGiaddr("255.255.255.255");
  90. // a dummy MAC address
  91. const uint8_t dummyMacAddr[] = {0, 1, 2, 3, 4, 5};
  92. // a dummy MAC address, padded with 0s
  93. const uint8_t dummyChaddr[16] = {0, 1, 2, 3, 4, 5, 0, 0,
  94. 0, 0, 0, 0, 0, 0, 0, 0 };
  95. // let's use some creative test content here (128 chars + \0)
  96. const uint8_t dummyFile[] = "Lorem ipsum dolor sit amet, consectetur "
  97. "adipiscing elit. Proin mollis placerat metus, at "
  98. "lacinia orci ornare vitae. Mauris amet.";
  99. // yet another type of test content (64 chars + \0)
  100. const uint8_t dummySname[] = "Lorem ipsum dolor sit amet, consectetur "
  101. "adipiscing elit posuere.";
  102. BOOST_STATIC_ASSERT(sizeof(dummyFile) == Pkt4::MAX_FILE_LEN + 1);
  103. BOOST_STATIC_ASSERT(sizeof(dummySname) == Pkt4::MAX_SNAME_LEN + 1);
  104. /// @brief Generates test packet.
  105. ///
  106. /// Allocates and generates test packet, with all fixed
  107. /// fields set to non-zero values. Content is not always
  108. /// reasonable.
  109. ///
  110. /// See generateTestPacket2() function that returns
  111. /// exactly the same packet in on-wire format.
  112. ///
  113. /// @return pointer to allocated Pkt4 object.
  114. boost::shared_ptr<Pkt4>
  115. generateTestPacket1() {
  116. boost::shared_ptr<Pkt4> pkt(new Pkt4(DHCPDISCOVER, dummyTransid));
  117. vector<uint8_t> vectorMacAddr(dummyMacAddr, dummyMacAddr
  118. +sizeof(dummyMacAddr));
  119. // hwType = 6(ETHERNET), hlen = 6(MAC address len)
  120. pkt->setHWAddr(dummyHtype, dummyHlen, vectorMacAddr);
  121. pkt->setHops(dummyHops); // 13 relays. Wow!
  122. // Transaction-id is already set.
  123. pkt->setSecs(dummySecs);
  124. pkt->setFlags(dummyFlags); // all flags set
  125. pkt->setCiaddr(dummyCiaddr);
  126. pkt->setYiaddr(dummyYiaddr);
  127. pkt->setSiaddr(dummySiaddr);
  128. pkt->setGiaddr(dummyGiaddr);
  129. // Chaddr already set with setHWAddr().
  130. pkt->setSname(dummySname, 64);
  131. pkt->setFile(dummyFile, 128);
  132. return (pkt);
  133. }
  134. /// @brief Generates test packet.
  135. ///
  136. /// Allocates and generates on-wire buffer that represents
  137. /// test packet, with all fixed fields set to non-zero values.
  138. /// Content is not always reasonable.
  139. ///
  140. /// See generateTestPacket1() function that returns
  141. /// exactly the same packet as Pkt4 object.
  142. ///
  143. /// @return pointer to allocated Pkt4 object
  144. // Returns a vector containing a DHCPv4 packet header.
  145. vector<uint8_t>
  146. generateTestPacket2() {
  147. // That is only part of the header. It contains all "short" fields,
  148. // larger fields are constructed separately.
  149. uint8_t hdr[] = {
  150. 1, 6, 6, 13, // op, htype, hlen, hops,
  151. 0x12, 0x34, 0x56, 0x78, // transaction-id
  152. 0, 42, 0x80, 0x00, // 42 secs, BROADCAST flags
  153. 192, 0, 2, 1, // ciaddr
  154. 1, 2, 3, 4, // yiaddr
  155. 192, 0, 2, 255, // siaddr
  156. 255, 255, 255, 255, // giaddr
  157. };
  158. // Initialize the vector with the header fields defined above.
  159. vector<uint8_t> buf(hdr, hdr + sizeof(hdr));
  160. // Append the large header fields.
  161. copy(dummyChaddr, dummyChaddr + Pkt4::MAX_CHADDR_LEN, back_inserter(buf));
  162. copy(dummySname, dummySname + Pkt4::MAX_SNAME_LEN, back_inserter(buf));
  163. copy(dummyFile, dummyFile + Pkt4::MAX_FILE_LEN, back_inserter(buf));
  164. // Should now have all the header, so check. The "static_cast" is used
  165. // to get round an odd bug whereby the linker appears not to find the
  166. // definition of DHCPV4_PKT_HDR_LEN if it appears within an EXPECT_EQ().
  167. EXPECT_EQ(static_cast<size_t>(Pkt4::DHCPV4_PKT_HDR_LEN), buf.size());
  168. return (buf);
  169. }
  170. TEST(Pkt4Test, fixedFields) {
  171. boost::shared_ptr<Pkt4> pkt = generateTestPacket1();
  172. // ok, let's check packet values
  173. EXPECT_EQ(dummyOp, pkt->getOp());
  174. EXPECT_EQ(dummyHtype, pkt->getHtype());
  175. EXPECT_EQ(dummyHlen, pkt->getHlen());
  176. EXPECT_EQ(dummyHops, pkt->getHops());
  177. EXPECT_EQ(dummyTransid, pkt->getTransid());
  178. EXPECT_EQ(dummySecs, pkt->getSecs());
  179. EXPECT_EQ(dummyFlags, pkt->getFlags());
  180. EXPECT_EQ(dummyCiaddr.toText(), pkt->getCiaddr().toText());
  181. EXPECT_EQ(dummyYiaddr.toText(), pkt->getYiaddr().toText());
  182. EXPECT_EQ(dummySiaddr.toText(), pkt->getSiaddr().toText());
  183. EXPECT_EQ(dummyGiaddr.toText(), pkt->getGiaddr().toText());
  184. // Chaddr contains link-layer addr (MAC). It is no longer always 16 bytes
  185. // long and its length depends on hlen value (it is up to 16 bytes now).
  186. ASSERT_EQ(pkt->getHWAddr()->hwaddr_.size(), dummyHlen);
  187. EXPECT_EQ(0, memcmp(dummyChaddr, &pkt->getHWAddr()->hwaddr_[0], dummyHlen));
  188. EXPECT_EQ(0, memcmp(dummySname, &pkt->getSname()[0], 64));
  189. EXPECT_EQ(0, memcmp(dummyFile, &pkt->getFile()[0], 128));
  190. EXPECT_EQ(DHCPDISCOVER, pkt->getType());
  191. }
  192. TEST(Pkt4Test, fixedFieldsPack) {
  193. boost::shared_ptr<Pkt4> pkt = generateTestPacket1();
  194. vector<uint8_t> expectedFormat = generateTestPacket2();
  195. EXPECT_NO_THROW(
  196. pkt->pack();
  197. );
  198. // Minimum packet size is 236 bytes + 3 bytes of mandatory
  199. // DHCP Message Type Option
  200. ASSERT_EQ(static_cast<size_t>(Pkt4::DHCPV4_PKT_HDR_LEN) + 3, pkt->len());
  201. // redundant but MUCH easier for debug in gdb
  202. const uint8_t* exp = &expectedFormat[0];
  203. const uint8_t* got = static_cast<const uint8_t*>(pkt->getBuffer().getData());
  204. EXPECT_EQ(0, memcmp(exp, got, Pkt4::DHCPV4_PKT_HDR_LEN));
  205. }
  206. /// TODO Uncomment when ticket #1226 is implemented
  207. TEST(Pkt4Test, fixedFieldsUnpack) {
  208. vector<uint8_t> expectedFormat = generateTestPacket2();
  209. expectedFormat.push_back(0x63); // magic cookie
  210. expectedFormat.push_back(0x82);
  211. expectedFormat.push_back(0x53);
  212. expectedFormat.push_back(0x63);
  213. expectedFormat.push_back(0x35); // message-type
  214. expectedFormat.push_back(0x1);
  215. expectedFormat.push_back(0x1);
  216. boost::shared_ptr<Pkt4> pkt(new Pkt4(&expectedFormat[0],
  217. expectedFormat.size()));;
  218. EXPECT_NO_THROW(
  219. pkt->unpack()
  220. );
  221. // ok, let's check packet values
  222. EXPECT_EQ(dummyOp, pkt->getOp());
  223. EXPECT_EQ(dummyHtype, pkt->getHtype());
  224. EXPECT_EQ(dummyHlen, pkt->getHlen());
  225. EXPECT_EQ(dummyHops, pkt->getHops());
  226. EXPECT_EQ(dummyTransid, pkt->getTransid());
  227. EXPECT_EQ(dummySecs, pkt->getSecs());
  228. EXPECT_EQ(dummyFlags, pkt->getFlags());
  229. EXPECT_EQ(dummyCiaddr.toText(), pkt->getCiaddr().toText());
  230. EXPECT_EQ(string("1.2.3.4"), pkt->getYiaddr().toText());
  231. EXPECT_EQ(string("192.0.2.255"), pkt->getSiaddr().toText());
  232. EXPECT_EQ(string("255.255.255.255"), pkt->getGiaddr().toText());
  233. // chaddr is always 16 bytes long and contains link-layer addr (MAC)
  234. EXPECT_EQ(0, memcmp(dummyChaddr, &pkt->getHWAddr()->hwaddr_[0], dummyHlen));
  235. ASSERT_EQ(static_cast<size_t>(Pkt4::MAX_SNAME_LEN), pkt->getSname().size());
  236. EXPECT_EQ(0, memcmp(dummySname, &pkt->getSname()[0], Pkt4::MAX_SNAME_LEN));
  237. ASSERT_EQ(static_cast<size_t>(Pkt4::MAX_FILE_LEN), pkt->getFile().size());
  238. EXPECT_EQ(0, memcmp(dummyFile, &pkt->getFile()[0], Pkt4::MAX_FILE_LEN));
  239. EXPECT_EQ(DHCPDISCOVER, pkt->getType());
  240. }
  241. // this test is for hardware addresses (htype, hlen and chaddr fields)
  242. TEST(Pkt4Test, hwAddr) {
  243. vector<uint8_t> mac;
  244. uint8_t expectedChaddr[Pkt4::MAX_CHADDR_LEN];
  245. // We resize vector to specified length. It is more natural for fixed-length
  246. // field, than clear it (shrink size to 0) and push_back each element
  247. // (growing length back to MAX_CHADDR_LEN).
  248. mac.resize(Pkt4::MAX_CHADDR_LEN);
  249. Pkt4* pkt = 0;
  250. // let's test each hlen, from 0 till 16
  251. for (int macLen = 0; macLen < Pkt4::MAX_CHADDR_LEN; macLen++) {
  252. for (int i = 0; i < Pkt4::MAX_CHADDR_LEN; i++) {
  253. mac[i] = 0;
  254. expectedChaddr[i] = 0;
  255. }
  256. for (int i = 0; i < macLen; i++) {
  257. mac[i] = 128 + i;
  258. expectedChaddr[i] = 128 + i;
  259. }
  260. // type and transaction doesn't matter in this test
  261. pkt = new Pkt4(DHCPOFFER, 1234);
  262. pkt->setHWAddr(255-macLen*10, // just weird htype
  263. macLen,
  264. mac);
  265. EXPECT_EQ(0, memcmp(expectedChaddr, &pkt->getHWAddr()->hwaddr_[0],
  266. Pkt4::MAX_CHADDR_LEN));
  267. EXPECT_NO_THROW(
  268. pkt->pack();
  269. );
  270. // CHADDR starts at offset 28 in DHCP packet
  271. const uint8_t* ptr =
  272. static_cast<const uint8_t*>(pkt->getBuffer().getData())+28;
  273. EXPECT_EQ(0, memcmp(ptr, expectedChaddr, Pkt4::MAX_CHADDR_LEN));
  274. delete pkt;
  275. }
  276. /// TODO: extend this test once options support is implemented. HW address
  277. /// longer than 16 bytes should be stored in client-identifier option
  278. }
  279. TEST(Pkt4Test, msgTypes) {
  280. struct msgType {
  281. uint8_t dhcp;
  282. uint8_t bootp;
  283. };
  284. msgType types[] = {
  285. {DHCPDISCOVER, BOOTREQUEST},
  286. {DHCPOFFER, BOOTREPLY},
  287. {DHCPREQUEST, BOOTREQUEST},
  288. {DHCPDECLINE, BOOTREQUEST},
  289. {DHCPACK, BOOTREPLY},
  290. {DHCPNAK, BOOTREPLY},
  291. {DHCPRELEASE, BOOTREQUEST},
  292. {DHCPINFORM, BOOTREQUEST},
  293. {DHCPLEASEQUERY, BOOTREQUEST},
  294. {DHCPLEASEUNASSIGNED, BOOTREPLY},
  295. {DHCPLEASEUNKNOWN, BOOTREPLY},
  296. {DHCPLEASEACTIVE, BOOTREPLY}
  297. };
  298. Pkt4* pkt = 0;
  299. for (int i = 0; i < sizeof(types) / sizeof(msgType); i++) {
  300. pkt = new Pkt4(types[i].dhcp, 0);
  301. EXPECT_EQ(types[i].dhcp, pkt->getType());
  302. EXPECT_EQ(types[i].bootp, pkt->getOp());
  303. delete pkt;
  304. pkt = 0;
  305. }
  306. EXPECT_THROW(
  307. pkt = new Pkt4(100, 0), // there's no message type 100
  308. OutOfRange
  309. );
  310. if (pkt) {
  311. delete pkt;
  312. }
  313. }
  314. // this test verifies handling of sname field
  315. TEST(Pkt4Test, sname) {
  316. uint8_t sname[Pkt4::MAX_SNAME_LEN];
  317. Pkt4* pkt = 0;
  318. // let's test each sname length, from 0 till 64
  319. for (int snameLen=0; snameLen < Pkt4::MAX_SNAME_LEN; snameLen++) {
  320. for (int i = 0; i < Pkt4::MAX_SNAME_LEN; i++) {
  321. sname[i] = 0;
  322. }
  323. for (int i = 0; i < snameLen; i++) {
  324. sname[i] = i;
  325. }
  326. // type and transaction doesn't matter in this test
  327. pkt = new Pkt4(DHCPOFFER, 1234);
  328. pkt->setSname(sname, snameLen);
  329. EXPECT_EQ(0, memcmp(sname, &pkt->getSname()[0], Pkt4::MAX_SNAME_LEN));
  330. EXPECT_NO_THROW(
  331. pkt->pack();
  332. );
  333. // SNAME starts at offset 44 in DHCP packet
  334. const uint8_t* ptr =
  335. static_cast<const uint8_t*>(pkt->getBuffer().getData())+44;
  336. EXPECT_EQ(0, memcmp(ptr, sname, Pkt4::MAX_SNAME_LEN));
  337. delete pkt;
  338. }
  339. // Check that a null argument generates an exception.
  340. Pkt4 pkt4(DHCPOFFER, 1234);
  341. EXPECT_THROW(pkt4.setSname(NULL, Pkt4::MAX_SNAME_LEN), InvalidParameter);
  342. EXPECT_THROW(pkt4.setSname(NULL, 0), InvalidParameter);
  343. }
  344. TEST(Pkt4Test, file) {
  345. uint8_t file[Pkt4::MAX_FILE_LEN];
  346. Pkt4* pkt = 0;
  347. // Let's test each file length, from 0 till 128.
  348. for (int fileLen = 0; fileLen < Pkt4::MAX_FILE_LEN; fileLen++) {
  349. for (int i = 0; i < Pkt4::MAX_FILE_LEN; i++) {
  350. file[i] = 0;
  351. }
  352. for (int i = 0; i < fileLen; i++) {
  353. file[i] = i;
  354. }
  355. // Type and transaction doesn't matter in this test.
  356. pkt = new Pkt4(DHCPOFFER, 1234);
  357. pkt->setFile(file, fileLen);
  358. EXPECT_EQ(0, memcmp(file, &pkt->getFile()[0], Pkt4::MAX_FILE_LEN));
  359. //
  360. EXPECT_NO_THROW(
  361. pkt->pack();
  362. );
  363. // FILE starts at offset 108 in DHCP packet.
  364. const uint8_t* ptr =
  365. static_cast<const uint8_t*>(pkt->getBuffer().getData())+108;
  366. EXPECT_EQ(0, memcmp(ptr, file, Pkt4::MAX_FILE_LEN));
  367. delete pkt;
  368. }
  369. // Check that a null argument generates an exception.
  370. Pkt4 pkt4(DHCPOFFER, 1234);
  371. EXPECT_THROW(pkt4.setFile(NULL, Pkt4::MAX_FILE_LEN), InvalidParameter);
  372. EXPECT_THROW(pkt4.setFile(NULL, 0), InvalidParameter);
  373. }
  374. /// V4 Options being used for pack/unpack testing.
  375. /// For test simplicity, all selected options have
  376. /// variable length data so as there are no restrictions
  377. /// on a length of their data.
  378. static uint8_t v4Opts[] = {
  379. 12, 3, 0, 1, 2, // Hostname
  380. 14, 3, 10, 11, 12, // Merit Dump File
  381. 53, 1, 2, // Message Type (required to not throw exception during unpack)
  382. 60, 3, 20, 21, 22, // Class Id
  383. 128, 3, 30, 31, 32, // Vendor specific
  384. 254, 3, 40, 41, 42, // Reserved
  385. };
  386. TEST(Pkt4Test, options) {
  387. Pkt4* pkt = new Pkt4(DHCPOFFER, 0);
  388. vector<uint8_t> payload[5];
  389. for (int i = 0; i < 5; i++) {
  390. payload[i].push_back(i*10);
  391. payload[i].push_back(i*10+1);
  392. payload[i].push_back(i*10+2);
  393. }
  394. boost::shared_ptr<Option> opt1(new Option(Option::V4, 12, payload[0]));
  395. boost::shared_ptr<Option> opt3(new Option(Option::V4, 14, payload[1]));
  396. boost::shared_ptr<Option> opt2(new Option(Option::V4, 60, payload[2]));
  397. boost::shared_ptr<Option> opt5(new Option(Option::V4,128, payload[3]));
  398. boost::shared_ptr<Option> opt4(new Option(Option::V4,254, payload[4]));
  399. pkt->addOption(opt1);
  400. pkt->addOption(opt2);
  401. pkt->addOption(opt3);
  402. pkt->addOption(opt4);
  403. pkt->addOption(opt5);
  404. EXPECT_TRUE(pkt->getOption(12));
  405. EXPECT_TRUE(pkt->getOption(60));
  406. EXPECT_TRUE(pkt->getOption(14));
  407. EXPECT_TRUE(pkt->getOption(128));
  408. EXPECT_TRUE(pkt->getOption(254));
  409. EXPECT_FALSE(pkt->getOption(127)); // no such option
  410. // options are unique in DHCPv4. It should not be possible
  411. // to add more than one option of the same type.
  412. EXPECT_THROW(
  413. pkt->addOption(opt1),
  414. BadValue
  415. );
  416. EXPECT_NO_THROW(
  417. pkt->pack();
  418. );
  419. const OutputBuffer& buf = pkt->getBuffer();
  420. // check that all options are stored, they should take sizeof(v4Opts),
  421. // DHCP magic cookie (4 bytes), and OPTION_END added (just one byte)
  422. ASSERT_EQ(static_cast<size_t>(Pkt4::DHCPV4_PKT_HDR_LEN) + sizeof(DHCP_OPTIONS_COOKIE)
  423. + sizeof(v4Opts) + 1, buf.getLength());
  424. // that that this extra data actually contain our options
  425. const uint8_t* ptr = static_cast<const uint8_t*>(buf.getData());
  426. ptr += Pkt4::DHCPV4_PKT_HDR_LEN + sizeof(DHCP_OPTIONS_COOKIE); // rewind to end of fixed part
  427. EXPECT_EQ(0, memcmp(ptr, v4Opts, sizeof(v4Opts)));
  428. EXPECT_EQ(DHO_END, static_cast<uint8_t>(*(ptr + sizeof(v4Opts))));
  429. // delOption() checks
  430. EXPECT_TRUE(pkt->getOption(12)); // Sanity check: option 12 is still there
  431. EXPECT_TRUE(pkt->delOption(12)); // We should be able to remove it
  432. EXPECT_FALSE(pkt->getOption(12)); // It should not be there anymore
  433. EXPECT_FALSE(pkt->delOption(12)); // And removal should fail
  434. EXPECT_NO_THROW(
  435. delete pkt;
  436. );
  437. }
  438. TEST(Pkt4Test, unpackOptions) {
  439. vector<uint8_t> expectedFormat = generateTestPacket2();
  440. expectedFormat.push_back(0x63);
  441. expectedFormat.push_back(0x82);
  442. expectedFormat.push_back(0x53);
  443. expectedFormat.push_back(0x63);
  444. for (int i = 0; i < sizeof(v4Opts); i++) {
  445. expectedFormat.push_back(v4Opts[i]);
  446. }
  447. // now expectedFormat contains fixed format and 5 options
  448. boost::shared_ptr<Pkt4> pkt(new Pkt4(&expectedFormat[0],
  449. expectedFormat.size()));
  450. EXPECT_NO_THROW(
  451. pkt->unpack()
  452. );
  453. EXPECT_TRUE(pkt->getOption(12));
  454. EXPECT_TRUE(pkt->getOption(60));
  455. EXPECT_TRUE(pkt->getOption(14));
  456. EXPECT_TRUE(pkt->getOption(128));
  457. EXPECT_TRUE(pkt->getOption(254));
  458. boost::shared_ptr<Option> x = pkt->getOption(12);
  459. ASSERT_TRUE(x); // option 1 should exist
  460. EXPECT_EQ(12, x->getType()); // this should be option 12
  461. ASSERT_EQ(3, x->getData().size()); // it should be of length 3
  462. EXPECT_EQ(5, x->len()); // total option length 5
  463. EXPECT_EQ(0, memcmp(&x->getData()[0], v4Opts+2, 3)); // data len=3
  464. x = pkt->getOption(14);
  465. ASSERT_TRUE(x); // option 13 should exist
  466. EXPECT_EQ(14, x->getType()); // this should be option 13
  467. ASSERT_EQ(3, x->getData().size()); // it should be of length 3
  468. EXPECT_EQ(5, x->len()); // total option length 5
  469. EXPECT_EQ(0, memcmp(&x->getData()[0], v4Opts+7, 3)); // data len=3
  470. x = pkt->getOption(60);
  471. ASSERT_TRUE(x); // option 60 should exist
  472. EXPECT_EQ(60, x->getType()); // this should be option 60
  473. ASSERT_EQ(3, x->getData().size()); // it should be of length 3
  474. EXPECT_EQ(5, x->len()); // total option length 5
  475. EXPECT_EQ(0, memcmp(&x->getData()[0], v4Opts+15, 3)); // data len=3
  476. x = pkt->getOption(128);
  477. ASSERT_TRUE(x); // option 3 should exist
  478. EXPECT_EQ(128, x->getType()); // this should be option 254
  479. ASSERT_EQ(3, x->getData().size()); // it should be of length 3
  480. EXPECT_EQ(5, x->len()); // total option length 5
  481. EXPECT_EQ(0, memcmp(&x->getData()[0], v4Opts+20, 3)); // data len=3
  482. x = pkt->getOption(254);
  483. ASSERT_TRUE(x); // option 3 should exist
  484. EXPECT_EQ(254, x->getType()); // this should be option 254
  485. ASSERT_EQ(3, x->getData().size()); // it should be of length 3
  486. EXPECT_EQ(5, x->len()); // total option length 5
  487. EXPECT_EQ(0, memcmp(&x->getData()[0], v4Opts+25, 3)); // data len=3
  488. }
  489. // This test verifies methods that are used for manipulating meta fields
  490. // i.e. fields that are not part of DHCPv4 (e.g. interface name).
  491. TEST(Pkt4Test, metaFields) {
  492. Pkt4* pkt = new Pkt4(DHCPOFFER, 1234);
  493. pkt->setIface("loooopback");
  494. pkt->setIndex(42);
  495. pkt->setRemoteAddr(IOAddress("1.2.3.4"));
  496. pkt->setLocalAddr(IOAddress("4.3.2.1"));
  497. EXPECT_EQ("loooopback", pkt->getIface());
  498. EXPECT_EQ(42, pkt->getIndex());
  499. EXPECT_EQ("1.2.3.4", pkt->getRemoteAddr().toText());
  500. EXPECT_EQ("4.3.2.1", pkt->getLocalAddr().toText());
  501. delete pkt;
  502. }
  503. TEST(Pkt4Test, Timestamp) {
  504. scoped_ptr<Pkt4> pkt(new Pkt4(DHCPOFFER, 1234));
  505. // Just after construction timestamp is invalid
  506. ASSERT_TRUE(pkt->getTimestamp().is_not_a_date_time());
  507. // Update packet time.
  508. pkt->updateTimestamp();
  509. // Get updated packet time.
  510. boost::posix_time::ptime ts_packet = pkt->getTimestamp();
  511. // After timestamp is updated it should be date-time.
  512. ASSERT_FALSE(ts_packet.is_not_a_date_time());
  513. // Check current time.
  514. boost::posix_time::ptime ts_now =
  515. boost::posix_time::microsec_clock::universal_time();
  516. // Calculate period between packet time and now.
  517. boost::posix_time::time_period ts_period(ts_packet, ts_now);
  518. // Duration should be positive or zero.
  519. EXPECT_TRUE(ts_period.length().total_microseconds() >= 0);
  520. }
  521. TEST(Pkt4Test, hwaddr) {
  522. scoped_ptr<Pkt4> pkt(new Pkt4(DHCPOFFER, 1234));
  523. const uint8_t hw[] = { 2, 4, 6, 8, 10, 12 }; // MAC
  524. const uint8_t hw_type = 123; // hardware type
  525. HWAddrPtr hwaddr(new HWAddr(hw, sizeof(hw), hw_type));
  526. // setting NULL hardware address is not allowed
  527. EXPECT_THROW(pkt->setHWAddr(HWAddrPtr()), BadValue);
  528. pkt->setHWAddr(hwaddr);
  529. EXPECT_EQ(hw_type, pkt->getHtype());
  530. EXPECT_EQ(sizeof(hw), pkt->getHlen());
  531. EXPECT_TRUE(hwaddr == pkt->getHWAddr());
  532. }
  533. } // end of anonymous namespace