pkt4_unittest.cc 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880
  1. // Copyright (C) 2011-2014 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/libdhcp++.h>
  18. #include <dhcp/docsis3_option_defs.h>
  19. #include <dhcp/option_string.h>
  20. #include <dhcp/pkt4.h>
  21. #include <exceptions/exceptions.h>
  22. #include <util/buffer.h>
  23. #include <boost/shared_array.hpp>
  24. #include <boost/shared_ptr.hpp>
  25. #include <boost/static_assert.hpp>
  26. #include <gtest/gtest.h>
  27. #include <iostream>
  28. #include <sstream>
  29. #include <arpa/inet.h>
  30. using namespace std;
  31. using namespace isc;
  32. using namespace isc::asiolink;
  33. using namespace isc::dhcp;
  34. using namespace isc::util;
  35. // Don't import the entire boost namespace. It will unexpectedly hide uint8_t
  36. // for some systems.
  37. using boost::scoped_ptr;
  38. namespace {
  39. /// @brief A class which contains a custom callback function to unpack options.
  40. ///
  41. /// This is a class used by the tests which verify that the custom callback
  42. /// functions can be installed to unpack options from a message. When the
  43. /// callback function is called, the executed_ member is set to true to allow
  44. /// verification that the callback was really called. Internally, this class
  45. /// uses libdhcp++ to unpack options so the options parsing algorithm remains
  46. /// unchanged after installation of the callback.
  47. class CustomUnpackCallback {
  48. public:
  49. /// @brief Constructor
  50. ///
  51. /// Marks that callback hasn't been called.
  52. CustomUnpackCallback()
  53. : executed_(false) {
  54. }
  55. /// @brief A callback
  56. ///
  57. /// Contains custom implementation of the callback.
  58. ///
  59. /// @param buf a A buffer holding options in on-wire format.
  60. /// @param option_space A name of the option space being encapsulated by
  61. /// the option being parsed.
  62. /// @param [out] options A reference to the collection where parsed options
  63. /// will be stored.
  64. /// @return An offset to the first byte after last parsed option.
  65. size_t execute(const OptionBuffer& buf,
  66. const std::string& option_space,
  67. isc::dhcp::OptionCollection& options) {
  68. // Set the executed_ member to true to allow verification that the
  69. // callback has been actually called.
  70. executed_ = true;
  71. // Use default implementation of the unpack algorithm to parse options.
  72. return (LibDHCP::unpackOptions4(buf, option_space, options));
  73. }
  74. /// A flag which indicates if callback function has been called.
  75. bool executed_;
  76. };
  77. /// V4 Options being used for pack/unpack testing.
  78. /// For test simplicity, all selected options have
  79. /// variable length data so as there are no restrictions
  80. /// on a length of their data.
  81. static uint8_t v4_opts[] = {
  82. 12, 3, 0, 1, 2, // Hostname
  83. 14, 3, 10, 11, 12, // Merit Dump File
  84. 53, 1, 2, // Message Type (required to not throw exception during unpack)
  85. 60, 3, 20, 21, 22, // Class Id
  86. 128, 3, 30, 31, 32, // Vendor specific
  87. 254, 3, 40, 41, 42, // Reserved
  88. };
  89. // Sample data
  90. const uint8_t dummyOp = BOOTREQUEST;
  91. const uint8_t dummyHtype = 6;
  92. const uint8_t dummyHlen = 6;
  93. const uint8_t dummyHops = 13;
  94. const uint32_t dummyTransid = 0x12345678;
  95. const uint16_t dummySecs = 42;
  96. const uint16_t dummyFlags = BOOTP_BROADCAST;
  97. const IOAddress dummyCiaddr("192.0.2.1");
  98. const IOAddress dummyYiaddr("1.2.3.4");
  99. const IOAddress dummySiaddr("192.0.2.255");
  100. const IOAddress dummyGiaddr("255.255.255.255");
  101. // a dummy MAC address
  102. const uint8_t dummyMacAddr[] = {0, 1, 2, 3, 4, 5};
  103. // A dummy MAC address, padded with 0s
  104. const uint8_t dummyChaddr[16] = {0, 1, 2, 3, 4, 5, 0, 0,
  105. 0, 0, 0, 0, 0, 0, 0, 0 };
  106. // Let's use some creative test content here (128 chars + \0)
  107. const uint8_t dummyFile[] = "Lorem ipsum dolor sit amet, consectetur "
  108. "adipiscing elit. Proin mollis placerat metus, at "
  109. "lacinia orci ornare vitae. Mauris amet.";
  110. // Yet another type of test content (64 chars + \0)
  111. const uint8_t dummySname[] = "Lorem ipsum dolor sit amet, consectetur "
  112. "adipiscing elit posuere.";
  113. BOOST_STATIC_ASSERT(sizeof(dummyFile) == Pkt4::MAX_FILE_LEN + 1);
  114. BOOST_STATIC_ASSERT(sizeof(dummySname) == Pkt4::MAX_SNAME_LEN + 1);
  115. class Pkt4Test : public ::testing::Test {
  116. public:
  117. Pkt4Test() {
  118. }
  119. /// @brief Generates test packet.
  120. ///
  121. /// Allocates and generates test packet, with all fixed fields set to non-zero
  122. /// values. Content is not always reasonable.
  123. ///
  124. /// See generateTestPacket2() function that returns exactly the same packet in
  125. /// on-wire format.
  126. ///
  127. /// @return pointer to allocated Pkt4 object.
  128. Pkt4Ptr generateTestPacket1() {
  129. boost::shared_ptr<Pkt4> pkt(new Pkt4(DHCPDISCOVER, dummyTransid));
  130. vector<uint8_t> vectorMacAddr(dummyMacAddr, dummyMacAddr
  131. + sizeof(dummyMacAddr));
  132. // hwType = 6(ETHERNET), hlen = 6(MAC address len)
  133. pkt->setHWAddr(dummyHtype, dummyHlen, vectorMacAddr);
  134. pkt->setHops(dummyHops); // 13 relays. Wow!
  135. // Transaction-id is already set.
  136. pkt->setSecs(dummySecs);
  137. pkt->setFlags(dummyFlags); // all flags set
  138. pkt->setCiaddr(dummyCiaddr);
  139. pkt->setYiaddr(dummyYiaddr);
  140. pkt->setSiaddr(dummySiaddr);
  141. pkt->setGiaddr(dummyGiaddr);
  142. // Chaddr already set with setHWAddr().
  143. pkt->setSname(dummySname, 64);
  144. pkt->setFile(dummyFile, 128);
  145. return (pkt);
  146. }
  147. /// @brief Generates test packet.
  148. ///
  149. /// Allocates and generates on-wire buffer that represents test packet, with all
  150. /// fixed fields set to non-zero values. Content is not always reasonable.
  151. ///
  152. /// See generateTestPacket1() function that returns exactly the same packet as
  153. /// Pkt4 object.
  154. ///
  155. /// @return pointer to allocated Pkt4 object
  156. // Returns a vector containing a DHCPv4 packet header.
  157. vector<uint8_t> generateTestPacket2() {
  158. // That is only part of the header. It contains all "short" fields,
  159. // larger fields are constructed separately.
  160. uint8_t hdr[] = {
  161. 1, 6, 6, 13, // op, htype, hlen, hops,
  162. 0x12, 0x34, 0x56, 0x78, // transaction-id
  163. 0, 42, 0x80, 0x00, // 42 secs, BROADCAST flags
  164. 192, 0, 2, 1, // ciaddr
  165. 1, 2, 3, 4, // yiaddr
  166. 192, 0, 2, 255, // siaddr
  167. 255, 255, 255, 255, // giaddr
  168. };
  169. // Initialize the vector with the header fields defined above.
  170. vector<uint8_t> buf(hdr, hdr + sizeof(hdr));
  171. // Append the large header fields.
  172. copy(dummyChaddr, dummyChaddr + Pkt4::MAX_CHADDR_LEN, back_inserter(buf));
  173. copy(dummySname, dummySname + Pkt4::MAX_SNAME_LEN, back_inserter(buf));
  174. copy(dummyFile, dummyFile + Pkt4::MAX_FILE_LEN, back_inserter(buf));
  175. // Should now have all the header, so check. The "static_cast" is used
  176. // to get round an odd bug whereby the linker appears not to find the
  177. // definition of DHCPV4_PKT_HDR_LEN if it appears within an EXPECT_EQ().
  178. EXPECT_EQ(static_cast<size_t>(Pkt4::DHCPV4_PKT_HDR_LEN), buf.size());
  179. return (buf);
  180. }
  181. /// @brief Verify that the options are correct after parsing.
  182. ///
  183. /// @param pkt A packet holding parsed options.
  184. void verifyParsedOptions(const Pkt4Ptr& pkt) {
  185. EXPECT_TRUE(pkt->getOption(12));
  186. EXPECT_TRUE(pkt->getOption(60));
  187. EXPECT_TRUE(pkt->getOption(14));
  188. EXPECT_TRUE(pkt->getOption(128));
  189. EXPECT_TRUE(pkt->getOption(254));
  190. boost::shared_ptr<Option> x = pkt->getOption(12);
  191. ASSERT_TRUE(x); // option 1 should exist
  192. // Option 12 is represented by the OptionString class so let's do
  193. // the appropriate conversion.
  194. OptionStringPtr option12 = boost::static_pointer_cast<OptionString>(x);
  195. ASSERT_TRUE(option12);
  196. EXPECT_EQ(12, option12->getType()); // this should be option 12
  197. ASSERT_EQ(3, option12->getValue().length()); // it should be of length 3
  198. EXPECT_EQ(5, option12->len()); // total option length 5
  199. EXPECT_EQ(0, memcmp(&option12->getValue()[0], v4_opts + 2, 3)); // data len=3
  200. x = pkt->getOption(14);
  201. ASSERT_TRUE(x); // option 14 should exist
  202. // Option 14 is represented by the OptionString class so let's do
  203. // the appropriate conversion.
  204. OptionStringPtr option14 = boost::static_pointer_cast<OptionString>(x);
  205. ASSERT_TRUE(option14);
  206. EXPECT_EQ(14, option14->getType()); // this should be option 14
  207. ASSERT_EQ(3, option14->getValue().length()); // it should be of length 3
  208. EXPECT_EQ(5, option14->len()); // total option length 5
  209. EXPECT_EQ(0, memcmp(&option14->getValue()[0], v4_opts + 7, 3)); // data len=3
  210. x = pkt->getOption(60);
  211. ASSERT_TRUE(x); // option 60 should exist
  212. EXPECT_EQ(60, x->getType()); // this should be option 60
  213. ASSERT_EQ(3, x->getData().size()); // it should be of length 3
  214. EXPECT_EQ(5, x->len()); // total option length 5
  215. EXPECT_EQ(0, memcmp(&x->getData()[0], v4_opts + 15, 3)); // data len=3
  216. x = pkt->getOption(128);
  217. ASSERT_TRUE(x); // option 3 should exist
  218. EXPECT_EQ(128, x->getType()); // this should be option 254
  219. ASSERT_EQ(3, x->getData().size()); // it should be of length 3
  220. EXPECT_EQ(5, x->len()); // total option length 5
  221. EXPECT_EQ(0, memcmp(&x->getData()[0], v4_opts + 20, 3)); // data len=3
  222. x = pkt->getOption(254);
  223. ASSERT_TRUE(x); // option 3 should exist
  224. EXPECT_EQ(254, x->getType()); // this should be option 254
  225. ASSERT_EQ(3, x->getData().size()); // it should be of length 3
  226. EXPECT_EQ(5, x->len()); // total option length 5
  227. EXPECT_EQ(0, memcmp(&x->getData()[0], v4_opts + 25, 3)); // data len=3
  228. }
  229. };
  230. TEST_F(Pkt4Test, constructor) {
  231. ASSERT_EQ(236U, static_cast<size_t>(Pkt4::DHCPV4_PKT_HDR_LEN) );
  232. scoped_ptr<Pkt4> pkt;
  233. // Just some dummy payload.
  234. uint8_t testData[250];
  235. for (int i = 0; i < 250; i++) {
  236. testData[i] = i;
  237. }
  238. // Positive case1. Normal received packet.
  239. EXPECT_NO_THROW(pkt.reset(new Pkt4(testData, Pkt4::DHCPV4_PKT_HDR_LEN)));
  240. EXPECT_EQ(static_cast<size_t>(Pkt4::DHCPV4_PKT_HDR_LEN), pkt->len());
  241. EXPECT_NO_THROW(pkt.reset());
  242. // Positive case2. Normal outgoing packet.
  243. EXPECT_NO_THROW(pkt.reset(new Pkt4(DHCPDISCOVER, 0xffffffff)));
  244. // DHCPv4 packet must be at least 236 bytes long, with Message Type
  245. // Option taking extra 3 bytes it is 239
  246. EXPECT_EQ(static_cast<size_t>(Pkt4::DHCPV4_PKT_HDR_LEN) + 3, pkt->len());
  247. EXPECT_EQ(DHCPDISCOVER, pkt->getType());
  248. EXPECT_EQ(0xffffffff, pkt->getTransid());
  249. EXPECT_NO_THROW(pkt.reset());
  250. // Negative case. Should drop truncated messages.
  251. EXPECT_THROW(
  252. pkt.reset(new Pkt4(testData, Pkt4::DHCPV4_PKT_HDR_LEN - 1)),
  253. OutOfRange
  254. );
  255. }
  256. TEST_F(Pkt4Test, fixedFields) {
  257. boost::shared_ptr<Pkt4> pkt = generateTestPacket1();
  258. // OK, let's check packet values
  259. EXPECT_EQ(dummyOp, pkt->getOp());
  260. EXPECT_EQ(dummyHtype, pkt->getHtype());
  261. EXPECT_EQ(dummyHlen, pkt->getHlen());
  262. EXPECT_EQ(dummyHops, pkt->getHops());
  263. EXPECT_EQ(dummyTransid, pkt->getTransid());
  264. EXPECT_EQ(dummySecs, pkt->getSecs());
  265. EXPECT_EQ(dummyFlags, pkt->getFlags());
  266. EXPECT_EQ(dummyCiaddr, pkt->getCiaddr());
  267. EXPECT_EQ(dummyYiaddr, pkt->getYiaddr());
  268. EXPECT_EQ(dummySiaddr, pkt->getSiaddr());
  269. EXPECT_EQ(dummyGiaddr, pkt->getGiaddr());
  270. // Chaddr contains link-layer addr (MAC). It is no longer always 16 bytes
  271. // long and its length depends on hlen value (it is up to 16 bytes now).
  272. ASSERT_EQ(pkt->getHWAddr()->hwaddr_.size(), dummyHlen);
  273. EXPECT_EQ(0, memcmp(dummyChaddr, &pkt->getHWAddr()->hwaddr_[0], dummyHlen));
  274. EXPECT_EQ(0, memcmp(dummySname, &pkt->getSname()[0], 64));
  275. EXPECT_EQ(0, memcmp(dummyFile, &pkt->getFile()[0], 128));
  276. EXPECT_EQ(DHCPDISCOVER, pkt->getType());
  277. }
  278. TEST_F(Pkt4Test, fixedFieldsPack) {
  279. boost::shared_ptr<Pkt4> pkt = generateTestPacket1();
  280. vector<uint8_t> expectedFormat = generateTestPacket2();
  281. EXPECT_NO_THROW(
  282. pkt->pack();
  283. );
  284. // Minimum packet size is 236 bytes + 3 bytes of mandatory
  285. // DHCP Message Type Option
  286. ASSERT_EQ(static_cast<size_t>(Pkt4::DHCPV4_PKT_HDR_LEN) + 3, pkt->len());
  287. // Redundant but MUCH easier for debug in gdb
  288. const uint8_t* exp = &expectedFormat[0];
  289. const uint8_t* got = static_cast<const uint8_t*>(pkt->getBuffer().getData());
  290. EXPECT_EQ(0, memcmp(exp, got, Pkt4::DHCPV4_PKT_HDR_LEN));
  291. }
  292. /// TODO Uncomment when ticket #1226 is implemented
  293. TEST_F(Pkt4Test, fixedFieldsUnpack) {
  294. vector<uint8_t> expectedFormat = generateTestPacket2();
  295. expectedFormat.push_back(0x63); // magic cookie
  296. expectedFormat.push_back(0x82);
  297. expectedFormat.push_back(0x53);
  298. expectedFormat.push_back(0x63);
  299. expectedFormat.push_back(0x35); // message-type
  300. expectedFormat.push_back(0x1);
  301. expectedFormat.push_back(0x1);
  302. boost::shared_ptr<Pkt4> pkt(new Pkt4(&expectedFormat[0],
  303. expectedFormat.size()));;
  304. EXPECT_NO_THROW(
  305. pkt->unpack()
  306. );
  307. // OK, let's check packet values
  308. EXPECT_EQ(dummyOp, pkt->getOp());
  309. EXPECT_EQ(dummyHtype, pkt->getHtype());
  310. EXPECT_EQ(dummyHlen, pkt->getHlen());
  311. EXPECT_EQ(dummyHops, pkt->getHops());
  312. EXPECT_EQ(dummyTransid, pkt->getTransid());
  313. EXPECT_EQ(dummySecs, pkt->getSecs());
  314. EXPECT_EQ(dummyFlags, pkt->getFlags());
  315. EXPECT_EQ(dummyCiaddr, pkt->getCiaddr());
  316. EXPECT_EQ("1.2.3.4", pkt->getYiaddr().toText());
  317. EXPECT_EQ("192.0.2.255", pkt->getSiaddr().toText());
  318. EXPECT_EQ("255.255.255.255", pkt->getGiaddr().toText());
  319. // chaddr is always 16 bytes long and contains link-layer addr (MAC)
  320. EXPECT_EQ(0, memcmp(dummyChaddr, &pkt->getHWAddr()->hwaddr_[0], dummyHlen));
  321. ASSERT_EQ(static_cast<size_t>(Pkt4::MAX_SNAME_LEN), pkt->getSname().size());
  322. EXPECT_EQ(0, memcmp(dummySname, &pkt->getSname()[0], Pkt4::MAX_SNAME_LEN));
  323. ASSERT_EQ(static_cast<size_t>(Pkt4::MAX_FILE_LEN), pkt->getFile().size());
  324. EXPECT_EQ(0, memcmp(dummyFile, &pkt->getFile()[0], Pkt4::MAX_FILE_LEN));
  325. EXPECT_EQ(DHCPDISCOVER, pkt->getType());
  326. }
  327. // This test is for hardware addresses (htype, hlen and chaddr fields)
  328. TEST_F(Pkt4Test, hwAddr) {
  329. vector<uint8_t> mac;
  330. uint8_t expectedChaddr[Pkt4::MAX_CHADDR_LEN];
  331. // We resize vector to specified length. It is more natural for fixed-length
  332. // field, than clear it (shrink size to 0) and push_back each element
  333. // (growing length back to MAX_CHADDR_LEN).
  334. mac.resize(Pkt4::MAX_CHADDR_LEN);
  335. scoped_ptr<Pkt4> pkt;
  336. // let's test each hlen, from 0 till 16
  337. for (int macLen = 0; macLen < Pkt4::MAX_CHADDR_LEN; macLen++) {
  338. for (int i = 0; i < Pkt4::MAX_CHADDR_LEN; i++) {
  339. mac[i] = 0;
  340. expectedChaddr[i] = 0;
  341. }
  342. for (int i = 0; i < macLen; i++) {
  343. mac[i] = 128 + i;
  344. expectedChaddr[i] = 128 + i;
  345. }
  346. // type and transaction doesn't matter in this test
  347. pkt.reset(new Pkt4(DHCPOFFER, 1234));
  348. pkt->setHWAddr(255 - macLen * 10, // just weird htype
  349. macLen,
  350. mac);
  351. EXPECT_EQ(0, memcmp(expectedChaddr, &pkt->getHWAddr()->hwaddr_[0],
  352. Pkt4::MAX_CHADDR_LEN));
  353. EXPECT_NO_THROW(
  354. pkt->pack();
  355. );
  356. // CHADDR starts at offset 28 in DHCP packet
  357. const uint8_t* ptr =
  358. static_cast<const uint8_t*>(pkt->getBuffer().getData()) + 28;
  359. EXPECT_EQ(0, memcmp(ptr, expectedChaddr, Pkt4::MAX_CHADDR_LEN));
  360. pkt.reset();
  361. }
  362. /// TODO: extend this test once options support is implemented. HW address
  363. /// longer than 16 bytes should be stored in client-identifier option
  364. }
  365. TEST_F(Pkt4Test, msgTypes) {
  366. struct msgType {
  367. uint8_t dhcp;
  368. uint8_t bootp;
  369. };
  370. msgType types[] = {
  371. {DHCPDISCOVER, BOOTREQUEST},
  372. {DHCPOFFER, BOOTREPLY},
  373. {DHCPREQUEST, BOOTREQUEST},
  374. {DHCPDECLINE, BOOTREQUEST},
  375. {DHCPACK, BOOTREPLY},
  376. {DHCPNAK, BOOTREPLY},
  377. {DHCPRELEASE, BOOTREQUEST},
  378. {DHCPINFORM, BOOTREQUEST},
  379. {DHCPLEASEQUERY, BOOTREQUEST},
  380. {DHCPLEASEUNASSIGNED, BOOTREPLY},
  381. {DHCPLEASEUNKNOWN, BOOTREPLY},
  382. {DHCPLEASEACTIVE, BOOTREPLY}
  383. };
  384. scoped_ptr<Pkt4> pkt;
  385. for (int i = 0; i < sizeof(types) / sizeof(msgType); i++) {
  386. pkt.reset(new Pkt4(types[i].dhcp, 0));
  387. EXPECT_EQ(types[i].dhcp, pkt->getType());
  388. EXPECT_EQ(types[i].bootp, pkt->getOp());
  389. pkt.reset();
  390. }
  391. EXPECT_THROW(
  392. pkt.reset(new Pkt4(100, 0)), // There's no message type 100
  393. OutOfRange
  394. );
  395. }
  396. // This test verifies handling of sname field
  397. TEST_F(Pkt4Test, sname) {
  398. uint8_t sname[Pkt4::MAX_SNAME_LEN];
  399. scoped_ptr<Pkt4> pkt;
  400. // Let's test each sname length, from 0 till 64
  401. for (int snameLen = 0; snameLen < Pkt4::MAX_SNAME_LEN; ++snameLen) {
  402. for (int i = 0; i < snameLen; ++i) {
  403. sname[i] = i + 1;
  404. }
  405. for (int i = snameLen; i < Pkt4::MAX_SNAME_LEN; ++i) {
  406. sname[i] = 0;
  407. }
  408. // Type and transaction doesn't matter in this test
  409. pkt.reset(new Pkt4(DHCPOFFER, 1234));
  410. pkt->setSname(sname, snameLen);
  411. EXPECT_EQ(0, memcmp(sname, &pkt->getSname()[0], Pkt4::MAX_SNAME_LEN));
  412. EXPECT_NO_THROW(
  413. pkt->pack();
  414. );
  415. // SNAME starts at offset 44 in DHCP packet
  416. const uint8_t* ptr =
  417. static_cast<const uint8_t*>(pkt->getBuffer().getData()) + 44;
  418. EXPECT_EQ(0, memcmp(ptr, sname, Pkt4::MAX_SNAME_LEN));
  419. pkt.reset();
  420. }
  421. // Check that a null argument generates an exception.
  422. Pkt4 pkt4(DHCPOFFER, 1234);
  423. EXPECT_THROW(pkt4.setSname(NULL, Pkt4::MAX_SNAME_LEN), InvalidParameter);
  424. EXPECT_THROW(pkt4.setSname(NULL, 0), InvalidParameter);
  425. }
  426. TEST_F(Pkt4Test, file) {
  427. uint8_t file[Pkt4::MAX_FILE_LEN];
  428. scoped_ptr<Pkt4> pkt;
  429. // Let's test each file length, from 0 till 128.
  430. for (int fileLen = 0; fileLen < Pkt4::MAX_FILE_LEN; ++fileLen) {
  431. for (int i = 0; i < fileLen; ++i) {
  432. file[i] = i + 1;
  433. }
  434. for (int i = fileLen; i < Pkt4::MAX_FILE_LEN; ++i) {
  435. file[i] = 0;
  436. }
  437. // Type and transaction doesn't matter in this test.
  438. pkt.reset(new Pkt4(DHCPOFFER, 1234));
  439. pkt->setFile(file, fileLen);
  440. EXPECT_EQ(0, memcmp(file, &pkt->getFile()[0], Pkt4::MAX_FILE_LEN));
  441. EXPECT_NO_THROW(
  442. pkt->pack();
  443. );
  444. // FILE starts at offset 108 in DHCP packet.
  445. const uint8_t* ptr =
  446. static_cast<const uint8_t*>(pkt->getBuffer().getData()) + 108;
  447. EXPECT_EQ(0, memcmp(ptr, file, Pkt4::MAX_FILE_LEN));
  448. pkt.reset();
  449. }
  450. // Check that a null argument generates an exception.
  451. Pkt4 pkt4(DHCPOFFER, 1234);
  452. EXPECT_THROW(pkt4.setFile(NULL, Pkt4::MAX_FILE_LEN), InvalidParameter);
  453. EXPECT_THROW(pkt4.setFile(NULL, 0), InvalidParameter);
  454. }
  455. TEST_F(Pkt4Test, options) {
  456. scoped_ptr<Pkt4> pkt(new Pkt4(DHCPOFFER, 0));
  457. vector<uint8_t> payload[5];
  458. for (int i = 0; i < 5; i++) {
  459. payload[i].push_back(i * 10);
  460. payload[i].push_back(i * 10 + 1);
  461. payload[i].push_back(i * 10 + 2);
  462. }
  463. boost::shared_ptr<Option> opt1(new Option(Option::V4, 12, payload[0]));
  464. boost::shared_ptr<Option> opt3(new Option(Option::V4, 14, payload[1]));
  465. boost::shared_ptr<Option> opt2(new Option(Option::V4, 60, payload[2]));
  466. boost::shared_ptr<Option> opt5(new Option(Option::V4,128, payload[3]));
  467. boost::shared_ptr<Option> opt4(new Option(Option::V4,254, payload[4]));
  468. pkt->addOption(opt1);
  469. pkt->addOption(opt2);
  470. pkt->addOption(opt3);
  471. pkt->addOption(opt4);
  472. pkt->addOption(opt5);
  473. EXPECT_TRUE(pkt->getOption(12));
  474. EXPECT_TRUE(pkt->getOption(60));
  475. EXPECT_TRUE(pkt->getOption(14));
  476. EXPECT_TRUE(pkt->getOption(128));
  477. EXPECT_TRUE(pkt->getOption(254));
  478. EXPECT_FALSE(pkt->getOption(127)); // no such option
  479. // Options are unique in DHCPv4. It should not be possible
  480. // to add more than one option of the same type.
  481. EXPECT_THROW(
  482. pkt->addOption(opt1),
  483. BadValue
  484. );
  485. EXPECT_NO_THROW(
  486. pkt->pack();
  487. );
  488. const OutputBuffer& buf = pkt->getBuffer();
  489. // Check that all options are stored, they should take sizeof(v4_opts),
  490. // DHCP magic cookie (4 bytes), and OPTION_END added (just one byte)
  491. ASSERT_EQ(static_cast<size_t>(Pkt4::DHCPV4_PKT_HDR_LEN) +
  492. sizeof(DHCP_OPTIONS_COOKIE) + sizeof(v4_opts) + 1,
  493. buf.getLength());
  494. // That that this extra data actually contain our options
  495. const uint8_t* ptr = static_cast<const uint8_t*>(buf.getData());
  496. // Rewind to end of fixed part.
  497. ptr += Pkt4::DHCPV4_PKT_HDR_LEN + sizeof(DHCP_OPTIONS_COOKIE);
  498. EXPECT_EQ(0, memcmp(ptr, v4_opts, sizeof(v4_opts)));
  499. EXPECT_EQ(DHO_END, static_cast<uint8_t>(*(ptr + sizeof(v4_opts))));
  500. // delOption() checks
  501. EXPECT_TRUE(pkt->getOption(12)); // Sanity check: option 12 is still there
  502. EXPECT_TRUE(pkt->delOption(12)); // We should be able to remove it
  503. EXPECT_FALSE(pkt->getOption(12)); // It should not be there anymore
  504. EXPECT_FALSE(pkt->delOption(12)); // And removal should fail
  505. EXPECT_NO_THROW(pkt.reset());
  506. }
  507. // This test verifies that the options are unpacked from the packet correctly.
  508. TEST_F(Pkt4Test, unpackOptions) {
  509. vector<uint8_t> expectedFormat = generateTestPacket2();
  510. expectedFormat.push_back(0x63);
  511. expectedFormat.push_back(0x82);
  512. expectedFormat.push_back(0x53);
  513. expectedFormat.push_back(0x63);
  514. for (int i = 0; i < sizeof(v4_opts); i++) {
  515. expectedFormat.push_back(v4_opts[i]);
  516. }
  517. // now expectedFormat contains fixed format and 5 options
  518. boost::shared_ptr<Pkt4> pkt(new Pkt4(&expectedFormat[0],
  519. expectedFormat.size()));
  520. EXPECT_NO_THROW(
  521. pkt->unpack()
  522. );
  523. verifyParsedOptions(pkt);
  524. }
  525. // This test verifies that it is possible to specify custom implementation of
  526. // the option parsing algorithm by installing a callback function.
  527. TEST_F(Pkt4Test, unpackOptionsWithCallback) {
  528. vector<uint8_t> expectedFormat = generateTestPacket2();
  529. expectedFormat.push_back(0x63);
  530. expectedFormat.push_back(0x82);
  531. expectedFormat.push_back(0x53);
  532. expectedFormat.push_back(0x63);
  533. for (int i = 0; i < sizeof(v4_opts); i++) {
  534. expectedFormat.push_back(v4_opts[i]);
  535. }
  536. // now expectedFormat contains fixed format and 5 options
  537. boost::shared_ptr<Pkt4> pkt(new Pkt4(&expectedFormat[0],
  538. expectedFormat.size()));
  539. CustomUnpackCallback cb;
  540. pkt->setCallback(boost::bind(&CustomUnpackCallback::execute, &cb,
  541. _1, _2, _3));
  542. ASSERT_FALSE(cb.executed_);
  543. EXPECT_NO_THROW(pkt->unpack());
  544. EXPECT_TRUE(cb.executed_);
  545. verifyParsedOptions(pkt);
  546. // Reset the indicator to perform another check: uninstall the callback.
  547. cb.executed_ = false;
  548. // By setting the callback to NULL we effectively uninstall the callback.
  549. pkt->setCallback(NULL);
  550. // Do another unpack.
  551. EXPECT_NO_THROW(pkt->unpack());
  552. // Callback should not be executed.
  553. EXPECT_FALSE(cb.executed_);
  554. }
  555. // This test verifies methods that are used for manipulating meta fields
  556. // i.e. fields that are not part of DHCPv4 (e.g. interface name).
  557. TEST_F(Pkt4Test, metaFields) {
  558. scoped_ptr<Pkt4> pkt(new Pkt4(DHCPOFFER, 1234));
  559. pkt->setIface("loooopback");
  560. pkt->setIndex(42);
  561. pkt->setRemoteAddr(IOAddress("1.2.3.4"));
  562. pkt->setLocalAddr(IOAddress("4.3.2.1"));
  563. EXPECT_EQ("loooopback", pkt->getIface());
  564. EXPECT_EQ(42, pkt->getIndex());
  565. EXPECT_EQ("1.2.3.4", pkt->getRemoteAddr().toText());
  566. EXPECT_EQ("4.3.2.1", pkt->getLocalAddr().toText());
  567. }
  568. TEST_F(Pkt4Test, Timestamp) {
  569. scoped_ptr<Pkt4> pkt(new Pkt4(DHCPOFFER, 1234));
  570. // Just after construction timestamp is invalid
  571. ASSERT_TRUE(pkt->getTimestamp().is_not_a_date_time());
  572. // Update packet time.
  573. pkt->updateTimestamp();
  574. // Get updated packet time.
  575. boost::posix_time::ptime ts_packet = pkt->getTimestamp();
  576. // After timestamp is updated it should be date-time.
  577. ASSERT_FALSE(ts_packet.is_not_a_date_time());
  578. // Check current time.
  579. boost::posix_time::ptime ts_now =
  580. boost::posix_time::microsec_clock::universal_time();
  581. // Calculate period between packet time and now.
  582. boost::posix_time::time_period ts_period(ts_packet, ts_now);
  583. // Duration should be positive or zero.
  584. EXPECT_TRUE(ts_period.length().total_microseconds() >= 0);
  585. }
  586. TEST_F(Pkt4Test, hwaddr) {
  587. scoped_ptr<Pkt4> pkt(new Pkt4(DHCPOFFER, 1234));
  588. const uint8_t hw[] = { 2, 4, 6, 8, 10, 12 }; // MAC
  589. const uint8_t hw_type = 123; // hardware type
  590. HWAddrPtr hwaddr(new HWAddr(hw, sizeof(hw), hw_type));
  591. // setting NULL hardware address is not allowed
  592. EXPECT_THROW(pkt->setHWAddr(HWAddrPtr()), BadValue);
  593. pkt->setHWAddr(hwaddr);
  594. EXPECT_EQ(hw_type, pkt->getHtype());
  595. EXPECT_EQ(sizeof(hw), pkt->getHlen());
  596. EXPECT_TRUE(hwaddr == pkt->getHWAddr());
  597. }
  598. // This test verifies that the packet remte and local HW address can
  599. // be set and returned.
  600. TEST_F(Pkt4Test, hwaddrSrcRemote) {
  601. scoped_ptr<Pkt4> pkt(new Pkt4(DHCPOFFER, 1234));
  602. const uint8_t src_hw[] = { 1, 2, 3, 4, 5, 6 };
  603. const uint8_t dst_hw[] = { 7, 8, 9, 10, 11, 12 };
  604. const uint8_t hw_type = 123;
  605. HWAddrPtr dst_hwaddr(new HWAddr(dst_hw, sizeof(src_hw), hw_type));
  606. HWAddrPtr src_hwaddr(new HWAddr(src_hw, sizeof(src_hw), hw_type));
  607. // Check that we can set the local address.
  608. EXPECT_NO_THROW(pkt->setLocalHWAddr(dst_hwaddr));
  609. EXPECT_TRUE(dst_hwaddr == pkt->getLocalHWAddr());
  610. // Check that we can set the remote address.
  611. EXPECT_NO_THROW(pkt->setRemoteHWAddr(src_hwaddr));
  612. EXPECT_TRUE(src_hwaddr == pkt->getRemoteHWAddr());
  613. // Can't set the NULL addres.
  614. EXPECT_THROW(pkt->setRemoteHWAddr(HWAddrPtr()), BadValue);
  615. EXPECT_THROW(pkt->setLocalHWAddr(HWAddrPtr()), BadValue);
  616. // Test alternative way to set local address.
  617. const uint8_t dst_hw2[] = { 19, 20, 21, 22, 23, 24 };
  618. std::vector<uint8_t> dst_hw_vec(dst_hw2, dst_hw2 + sizeof(dst_hw2));
  619. const uint8_t hw_type2 = 234;
  620. EXPECT_NO_THROW(pkt->setLocalHWAddr(hw_type2, sizeof(dst_hw2), dst_hw_vec));
  621. HWAddrPtr local_addr = pkt->getLocalHWAddr();
  622. ASSERT_TRUE(local_addr);
  623. EXPECT_EQ(hw_type2, local_addr->htype_);
  624. EXPECT_TRUE(std::equal(dst_hw_vec.begin(), dst_hw_vec.end(),
  625. local_addr->hwaddr_.begin()));
  626. // Set remote address.
  627. const uint8_t src_hw2[] = { 25, 26, 27, 28, 29, 30 };
  628. std::vector<uint8_t> src_hw_vec(src_hw2, src_hw2 + sizeof(src_hw2));
  629. EXPECT_NO_THROW(pkt->setRemoteHWAddr(hw_type2, sizeof(src_hw2), src_hw_vec));
  630. HWAddrPtr remote_addr = pkt->getRemoteHWAddr();
  631. ASSERT_TRUE(remote_addr);
  632. EXPECT_EQ(hw_type2, remote_addr->htype_);
  633. EXPECT_TRUE(std::equal(src_hw_vec.begin(), src_hw_vec.end(),
  634. remote_addr->hwaddr_.begin()));
  635. }
  636. // This test verifies that the check for a message being relayed is correct.
  637. // It also checks that the exception is thrown if the combination of hops and
  638. // giaddr is invalid.
  639. TEST_F(Pkt4Test, isRelayed) {
  640. Pkt4 pkt(DHCPDISCOVER, 1234);
  641. // By default, the hops and giaddr should be 0.
  642. ASSERT_EQ("0.0.0.0", pkt.getGiaddr().toText());
  643. ASSERT_EQ(0, pkt.getHops());
  644. // For hops = 0 and giaddr = 0, the message is non-relayed.
  645. EXPECT_FALSE(pkt.isRelayed());
  646. // Set giaddr but leave hops = 0. This should result in exception.
  647. pkt.setGiaddr(IOAddress("10.0.0.1"));
  648. EXPECT_THROW(pkt.isRelayed(), isc::BadValue);
  649. // Set hops. Now both hops and giaddr is set. The message is relayed.
  650. pkt.setHops(10);
  651. EXPECT_TRUE(pkt.isRelayed());
  652. // Set giaddr to 0. For hops being set to non-zero value the function
  653. // should throw an exception.
  654. pkt.setGiaddr(IOAddress("0.0.0.0"));
  655. EXPECT_THROW(pkt.isRelayed(), isc::BadValue);
  656. }
  657. // Tests whether a packet can be assigned to a class and later
  658. // checked if it belongs to a given class
  659. TEST_F(Pkt4Test, clientClasses) {
  660. Pkt4 pkt(DHCPOFFER, 1234);
  661. // Default values (do not belong to any class)
  662. EXPECT_FALSE(pkt.inClass(DOCSIS3_CLASS_EROUTER));
  663. EXPECT_FALSE(pkt.inClass(DOCSIS3_CLASS_MODEM));
  664. EXPECT_TRUE(pkt.classes_.empty());
  665. // Add to the first class
  666. pkt.addClass(DOCSIS3_CLASS_EROUTER);
  667. EXPECT_TRUE(pkt.inClass(DOCSIS3_CLASS_EROUTER));
  668. EXPECT_FALSE(pkt.inClass(DOCSIS3_CLASS_MODEM));
  669. ASSERT_FALSE(pkt.classes_.empty());
  670. // Add to a second class
  671. pkt.addClass(DOCSIS3_CLASS_MODEM);
  672. EXPECT_TRUE(pkt.inClass(DOCSIS3_CLASS_EROUTER));
  673. EXPECT_TRUE(pkt.inClass(DOCSIS3_CLASS_MODEM));
  674. // Check that it's ok to add to the same class repeatedly
  675. EXPECT_NO_THROW(pkt.addClass("foo"));
  676. EXPECT_NO_THROW(pkt.addClass("foo"));
  677. EXPECT_NO_THROW(pkt.addClass("foo"));
  678. // Check that the packet belongs to 'foo'
  679. EXPECT_TRUE(pkt.inClass("foo"));
  680. }
  681. // Tests whether MAC can be obtained and that MAC sources are not
  682. // confused.
  683. TEST_F(Pkt4Test, getMAC) {
  684. Pkt4 pkt(DHCPOFFER, 1234);
  685. // DHCPv4 packet by default doens't have MAC address specified.
  686. EXPECT_FALSE(pkt.getMAC(Pkt::MAC_SOURCE_ANY));
  687. EXPECT_FALSE(pkt.getMAC(Pkt::MAC_SOURCE_RAW));
  688. // Let's invent a MAC
  689. const uint8_t hw[] = { 2, 4, 6, 8, 10, 12 }; // MAC
  690. const uint8_t hw_type = 123; // hardware type
  691. HWAddrPtr dummy_hwaddr(new HWAddr(hw, sizeof(hw), hw_type));
  692. // Now let's pretend that we obtained it from raw sockets
  693. pkt.setRemoteHWAddr(dummy_hwaddr);
  694. // Now we should be able to get something
  695. ASSERT_TRUE(pkt.getMAC(Pkt::MAC_SOURCE_ANY));
  696. ASSERT_TRUE(pkt.getMAC(Pkt::MAC_SOURCE_RAW));
  697. // Check that the returned MAC is indeed the expected one
  698. ASSERT_TRUE(*dummy_hwaddr == *pkt.getMAC(Pkt::MAC_SOURCE_ANY));
  699. ASSERT_TRUE(*dummy_hwaddr == *pkt.getMAC(Pkt::MAC_SOURCE_RAW));
  700. }
  701. } // end of anonymous namespace