pkt4_unittest.cc 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148
  1. // Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this
  5. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. #include <config.h>
  7. #include <asiolink/io_address.h>
  8. #include <dhcp/dhcp4.h>
  9. #include <dhcp/libdhcp++.h>
  10. #include <dhcp/docsis3_option_defs.h>
  11. #include <dhcp/option_int.h>
  12. #include <dhcp/option_string.h>
  13. #include <dhcp/option4_addrlst.h>
  14. #include <dhcp/pkt4.h>
  15. #include <exceptions/exceptions.h>
  16. #include <util/buffer.h>
  17. #include <boost/shared_array.hpp>
  18. #include <boost/shared_ptr.hpp>
  19. #include <boost/scoped_ptr.hpp>
  20. #include <boost/static_assert.hpp>
  21. #include <gtest/gtest.h>
  22. #include <iostream>
  23. #include <sstream>
  24. #include <arpa/inet.h>
  25. using namespace std;
  26. using namespace isc;
  27. using namespace isc::asiolink;
  28. using namespace isc::dhcp;
  29. using namespace isc::util;
  30. // Don't import the entire boost namespace. It will unexpectedly hide uint8_t
  31. // for some systems.
  32. using boost::scoped_ptr;
  33. namespace {
  34. /// @brief A class which contains a custom callback function to unpack options.
  35. ///
  36. /// This is a class used by the tests which verify that the custom callback
  37. /// functions can be installed to unpack options from a message. When the
  38. /// callback function is called, the executed_ member is set to true to allow
  39. /// verification that the callback was really called. Internally, this class
  40. /// uses libdhcp++ to unpack options so the options parsing algorithm remains
  41. /// unchanged after installation of the callback.
  42. class CustomUnpackCallback {
  43. public:
  44. /// @brief Constructor
  45. ///
  46. /// Marks that callback hasn't been called.
  47. CustomUnpackCallback()
  48. : executed_(false) {
  49. }
  50. /// @brief A callback
  51. ///
  52. /// Contains custom implementation of the callback.
  53. ///
  54. /// @param buf a A buffer holding options in on-wire format.
  55. /// @param option_space A name of the option space being encapsulated by
  56. /// the option being parsed.
  57. /// @param [out] options A reference to the collection where parsed options
  58. /// will be stored.
  59. /// @return An offset to the first byte after last parsed option.
  60. size_t execute(const OptionBuffer& buf,
  61. const std::string& option_space,
  62. isc::dhcp::OptionCollection& options) {
  63. // Set the executed_ member to true to allow verification that the
  64. // callback has been actually called.
  65. executed_ = true;
  66. // Use default implementation of the unpack algorithm to parse options.
  67. return (LibDHCP::unpackOptions4(buf, option_space, options));
  68. }
  69. /// A flag which indicates if callback function has been called.
  70. bool executed_;
  71. };
  72. /// V4 Options being used for pack/unpack testing.
  73. /// For test simplicity, all selected options have
  74. /// variable length data so as there are no restrictions
  75. /// on a length of their data.
  76. static uint8_t v4_opts[] = {
  77. 12, 3, 0, 1, 2, // Hostname
  78. 14, 3, 10, 11, 12, // Merit Dump File
  79. 53, 1, 2, // Message Type (required to not throw exception during unpack)
  80. 60, 3, 20, 21, 22, // Class Id
  81. 128, 3, 30, 31, 32, // Vendor specific
  82. 254, 3, 40, 41, 42, // Reserved
  83. };
  84. // Sample data
  85. const uint8_t dummyOp = BOOTREQUEST;
  86. const uint8_t dummyHtype = 6;
  87. const uint8_t dummyHlen = 6;
  88. const uint8_t dummyHops = 13;
  89. const uint32_t dummyTransid = 0x12345678;
  90. const uint16_t dummySecs = 42;
  91. const uint16_t dummyFlags = BOOTP_BROADCAST;
  92. const IOAddress dummyCiaddr("192.0.2.1");
  93. const IOAddress dummyYiaddr("1.2.3.4");
  94. const IOAddress dummySiaddr("192.0.2.255");
  95. const IOAddress dummyGiaddr("255.255.255.255");
  96. // a dummy MAC address
  97. const uint8_t dummyMacAddr[] = {0, 1, 2, 3, 4, 5};
  98. // A dummy MAC address, padded with 0s
  99. const uint8_t dummyChaddr[16] = {0, 1, 2, 3, 4, 5, 0, 0,
  100. 0, 0, 0, 0, 0, 0, 0, 0 };
  101. // Let's use some creative test content here (128 chars + \0)
  102. const uint8_t dummyFile[] = "Lorem ipsum dolor sit amet, consectetur "
  103. "adipiscing elit. Proin mollis placerat metus, at "
  104. "lacinia orci ornare vitae. Mauris amet.";
  105. // Yet another type of test content (64 chars + \0)
  106. const uint8_t dummySname[] = "Lorem ipsum dolor sit amet, consectetur "
  107. "adipiscing elit posuere.";
  108. BOOST_STATIC_ASSERT(sizeof(dummyFile) == Pkt4::MAX_FILE_LEN + 1);
  109. BOOST_STATIC_ASSERT(sizeof(dummySname) == Pkt4::MAX_SNAME_LEN + 1);
  110. class Pkt4Test : public ::testing::Test {
  111. public:
  112. Pkt4Test() {
  113. }
  114. /// @brief Generates test packet.
  115. ///
  116. /// Allocates and generates test packet, with all fixed fields set to non-zero
  117. /// values. Content is not always reasonable.
  118. ///
  119. /// See generateTestPacket2() function that returns exactly the same packet in
  120. /// on-wire format.
  121. ///
  122. /// @return pointer to allocated Pkt4 object.
  123. Pkt4Ptr generateTestPacket1() {
  124. boost::shared_ptr<Pkt4> pkt(new Pkt4(DHCPDISCOVER, dummyTransid));
  125. vector<uint8_t> vectorMacAddr(dummyMacAddr, dummyMacAddr
  126. + sizeof(dummyMacAddr));
  127. // hwType = 6(ETHERNET), hlen = 6(MAC address len)
  128. pkt->setHWAddr(dummyHtype, dummyHlen, vectorMacAddr);
  129. pkt->setHops(dummyHops); // 13 relays. Wow!
  130. // Transaction-id is already set.
  131. pkt->setSecs(dummySecs);
  132. pkt->setFlags(dummyFlags); // all flags set
  133. pkt->setCiaddr(dummyCiaddr);
  134. pkt->setYiaddr(dummyYiaddr);
  135. pkt->setSiaddr(dummySiaddr);
  136. pkt->setGiaddr(dummyGiaddr);
  137. // Chaddr already set with setHWAddr().
  138. pkt->setSname(dummySname, 64);
  139. pkt->setFile(dummyFile, 128);
  140. return (pkt);
  141. }
  142. /// @brief Generates test packet.
  143. ///
  144. /// Allocates and generates on-wire buffer that represents test packet, with all
  145. /// fixed fields set to non-zero values. Content is not always reasonable.
  146. ///
  147. /// See generateTestPacket1() function that returns exactly the same packet as
  148. /// Pkt4 object.
  149. ///
  150. /// @return pointer to allocated Pkt4 object
  151. // Returns a vector containing a DHCPv4 packet header.
  152. vector<uint8_t> generateTestPacket2() {
  153. // That is only part of the header. It contains all "short" fields,
  154. // larger fields are constructed separately.
  155. uint8_t hdr[] = {
  156. 1, 6, 6, 13, // op, htype, hlen, hops,
  157. 0x12, 0x34, 0x56, 0x78, // transaction-id
  158. 0, 42, 0x80, 0x00, // 42 secs, BROADCAST flags
  159. 192, 0, 2, 1, // ciaddr
  160. 1, 2, 3, 4, // yiaddr
  161. 192, 0, 2, 255, // siaddr
  162. 255, 255, 255, 255, // giaddr
  163. };
  164. // Initialize the vector with the header fields defined above.
  165. vector<uint8_t> buf(hdr, hdr + sizeof(hdr));
  166. // Append the large header fields.
  167. copy(dummyChaddr, dummyChaddr + Pkt4::MAX_CHADDR_LEN, back_inserter(buf));
  168. copy(dummySname, dummySname + Pkt4::MAX_SNAME_LEN, back_inserter(buf));
  169. copy(dummyFile, dummyFile + Pkt4::MAX_FILE_LEN, back_inserter(buf));
  170. // Should now have all the header, so check. The "static_cast" is used
  171. // to get round an odd bug whereby the linker appears not to find the
  172. // definition of DHCPV4_PKT_HDR_LEN if it appears within an EXPECT_EQ().
  173. EXPECT_EQ(static_cast<size_t>(Pkt4::DHCPV4_PKT_HDR_LEN), buf.size());
  174. return (buf);
  175. }
  176. /// @brief Verify that the options are correct after parsing.
  177. ///
  178. /// @param pkt A packet holding parsed options.
  179. void verifyParsedOptions(const Pkt4Ptr& pkt) {
  180. EXPECT_TRUE(pkt->getOption(12));
  181. EXPECT_TRUE(pkt->getOption(60));
  182. EXPECT_TRUE(pkt->getOption(14));
  183. EXPECT_TRUE(pkt->getOption(128));
  184. EXPECT_TRUE(pkt->getOption(254));
  185. boost::shared_ptr<Option> x = pkt->getOption(12);
  186. ASSERT_TRUE(x); // option 1 should exist
  187. // Option 12 is represented by the OptionString class so let's do
  188. // the appropriate conversion.
  189. OptionStringPtr option12 = boost::static_pointer_cast<OptionString>(x);
  190. ASSERT_TRUE(option12);
  191. EXPECT_EQ(12, option12->getType()); // this should be option 12
  192. ASSERT_EQ(3, option12->getValue().length()); // it should be of length 3
  193. EXPECT_EQ(5, option12->len()); // total option length 5
  194. EXPECT_EQ(0, memcmp(&option12->getValue()[0], v4_opts + 2, 3)); // data len=3
  195. x = pkt->getOption(14);
  196. ASSERT_TRUE(x); // option 14 should exist
  197. // Option 14 is represented by the OptionString class so let's do
  198. // the appropriate conversion.
  199. OptionStringPtr option14 = boost::static_pointer_cast<OptionString>(x);
  200. ASSERT_TRUE(option14);
  201. EXPECT_EQ(14, option14->getType()); // this should be option 14
  202. ASSERT_EQ(3, option14->getValue().length()); // it should be of length 3
  203. EXPECT_EQ(5, option14->len()); // total option length 5
  204. EXPECT_EQ(0, memcmp(&option14->getValue()[0], v4_opts + 7, 3)); // data len=3
  205. x = pkt->getOption(60);
  206. ASSERT_TRUE(x); // option 60 should exist
  207. EXPECT_EQ(60, x->getType()); // this should be option 60
  208. ASSERT_EQ(3, x->getData().size()); // it should be of length 3
  209. EXPECT_EQ(5, x->len()); // total option length 5
  210. EXPECT_EQ(0, memcmp(&x->getData()[0], v4_opts + 15, 3)); // data len=3
  211. x = pkt->getOption(128);
  212. ASSERT_TRUE(x); // option 3 should exist
  213. EXPECT_EQ(128, x->getType()); // this should be option 254
  214. ASSERT_EQ(3, x->getData().size()); // it should be of length 3
  215. EXPECT_EQ(5, x->len()); // total option length 5
  216. EXPECT_EQ(0, memcmp(&x->getData()[0], v4_opts + 20, 3)); // data len=3
  217. x = pkt->getOption(254);
  218. ASSERT_TRUE(x); // option 3 should exist
  219. EXPECT_EQ(254, x->getType()); // this should be option 254
  220. ASSERT_EQ(3, x->getData().size()); // it should be of length 3
  221. EXPECT_EQ(5, x->len()); // total option length 5
  222. EXPECT_EQ(0, memcmp(&x->getData()[0], v4_opts + 25, 3)); // data len=3
  223. }
  224. };
  225. TEST_F(Pkt4Test, constructor) {
  226. ASSERT_EQ(236U, static_cast<size_t>(Pkt4::DHCPV4_PKT_HDR_LEN) );
  227. scoped_ptr<Pkt4> pkt;
  228. // Just some dummy payload.
  229. uint8_t testData[250];
  230. for (uint8_t i = 0; i < 250; i++) {
  231. testData[i] = i;
  232. }
  233. // Positive case1. Normal received packet.
  234. EXPECT_NO_THROW(pkt.reset(new Pkt4(testData, Pkt4::DHCPV4_PKT_HDR_LEN)));
  235. EXPECT_EQ(static_cast<size_t>(Pkt4::DHCPV4_PKT_HDR_LEN), pkt->len());
  236. EXPECT_NO_THROW(pkt.reset());
  237. // Positive case2. Normal outgoing packet.
  238. EXPECT_NO_THROW(pkt.reset(new Pkt4(DHCPDISCOVER, 0xffffffff)));
  239. // DHCPv4 packet must be at least 236 bytes long, with Message Type
  240. // Option taking extra 3 bytes it is 239
  241. EXPECT_EQ(static_cast<size_t>(Pkt4::DHCPV4_PKT_HDR_LEN) + 3, pkt->len());
  242. EXPECT_EQ(DHCPDISCOVER, pkt->getType());
  243. EXPECT_EQ(0xffffffff, pkt->getTransid());
  244. EXPECT_NO_THROW(pkt.reset());
  245. // Negative case. Should drop truncated messages.
  246. EXPECT_THROW(
  247. pkt.reset(new Pkt4(testData, Pkt4::DHCPV4_PKT_HDR_LEN - 1)),
  248. OutOfRange
  249. );
  250. }
  251. TEST_F(Pkt4Test, fixedFields) {
  252. boost::shared_ptr<Pkt4> pkt = generateTestPacket1();
  253. // OK, let's check packet values
  254. EXPECT_EQ(dummyOp, pkt->getOp());
  255. EXPECT_EQ(dummyHtype, pkt->getHtype());
  256. EXPECT_EQ(dummyHlen, pkt->getHlen());
  257. EXPECT_EQ(dummyHops, pkt->getHops());
  258. EXPECT_EQ(dummyTransid, pkt->getTransid());
  259. EXPECT_EQ(dummySecs, pkt->getSecs());
  260. EXPECT_EQ(dummyFlags, pkt->getFlags());
  261. EXPECT_EQ(dummyCiaddr, pkt->getCiaddr());
  262. EXPECT_EQ(dummyYiaddr, pkt->getYiaddr());
  263. EXPECT_EQ(dummySiaddr, pkt->getSiaddr());
  264. EXPECT_EQ(dummyGiaddr, pkt->getGiaddr());
  265. // Chaddr contains link-layer addr (MAC). It is no longer always 16 bytes
  266. // long and its length depends on hlen value (it is up to 16 bytes now).
  267. ASSERT_EQ(pkt->getHWAddr()->hwaddr_.size(), dummyHlen);
  268. EXPECT_EQ(0, memcmp(dummyChaddr, &pkt->getHWAddr()->hwaddr_[0], dummyHlen));
  269. EXPECT_EQ(0, memcmp(dummySname, &pkt->getSname()[0], 64));
  270. EXPECT_EQ(0, memcmp(dummyFile, &pkt->getFile()[0], 128));
  271. EXPECT_EQ(DHCPDISCOVER, pkt->getType());
  272. }
  273. TEST_F(Pkt4Test, fixedFieldsPack) {
  274. boost::shared_ptr<Pkt4> pkt = generateTestPacket1();
  275. vector<uint8_t> expectedFormat = generateTestPacket2();
  276. EXPECT_NO_THROW(
  277. pkt->pack();
  278. );
  279. // Minimum packet size is 236 bytes + 3 bytes of mandatory
  280. // DHCP Message Type Option
  281. ASSERT_EQ(static_cast<size_t>(Pkt4::DHCPV4_PKT_HDR_LEN) + 3, pkt->len());
  282. // Redundant but MUCH easier for debug in gdb
  283. const uint8_t* exp = &expectedFormat[0];
  284. const uint8_t* got = static_cast<const uint8_t*>(pkt->getBuffer().getData());
  285. EXPECT_EQ(0, memcmp(exp, got, Pkt4::DHCPV4_PKT_HDR_LEN));
  286. }
  287. /// TODO Uncomment when ticket #1226 is implemented
  288. TEST_F(Pkt4Test, fixedFieldsUnpack) {
  289. vector<uint8_t> expectedFormat = generateTestPacket2();
  290. expectedFormat.push_back(0x63); // magic cookie
  291. expectedFormat.push_back(0x82);
  292. expectedFormat.push_back(0x53);
  293. expectedFormat.push_back(0x63);
  294. expectedFormat.push_back(0x35); // message-type
  295. expectedFormat.push_back(0x1);
  296. expectedFormat.push_back(0x1);
  297. boost::shared_ptr<Pkt4> pkt(new Pkt4(&expectedFormat[0],
  298. expectedFormat.size()));;
  299. EXPECT_NO_THROW(
  300. pkt->unpack()
  301. );
  302. // OK, let's check packet values
  303. EXPECT_EQ(dummyOp, pkt->getOp());
  304. EXPECT_EQ(dummyHtype, pkt->getHtype());
  305. EXPECT_EQ(dummyHlen, pkt->getHlen());
  306. EXPECT_EQ(dummyHops, pkt->getHops());
  307. EXPECT_EQ(dummyTransid, pkt->getTransid());
  308. EXPECT_EQ(dummySecs, pkt->getSecs());
  309. EXPECT_EQ(dummyFlags, pkt->getFlags());
  310. EXPECT_EQ(dummyCiaddr, pkt->getCiaddr());
  311. EXPECT_EQ("1.2.3.4", pkt->getYiaddr().toText());
  312. EXPECT_EQ("192.0.2.255", pkt->getSiaddr().toText());
  313. EXPECT_EQ("255.255.255.255", pkt->getGiaddr().toText());
  314. // chaddr is always 16 bytes long and contains link-layer addr (MAC)
  315. EXPECT_EQ(0, memcmp(dummyChaddr, &pkt->getHWAddr()->hwaddr_[0], dummyHlen));
  316. ASSERT_EQ(static_cast<size_t>(Pkt4::MAX_SNAME_LEN), pkt->getSname().size());
  317. EXPECT_EQ(0, memcmp(dummySname, &pkt->getSname()[0], Pkt4::MAX_SNAME_LEN));
  318. ASSERT_EQ(static_cast<size_t>(Pkt4::MAX_FILE_LEN), pkt->getFile().size());
  319. EXPECT_EQ(0, memcmp(dummyFile, &pkt->getFile()[0], Pkt4::MAX_FILE_LEN));
  320. EXPECT_EQ(DHCPDISCOVER, pkt->getType());
  321. }
  322. // This test is for hardware addresses (htype, hlen and chaddr fields)
  323. TEST_F(Pkt4Test, hwAddr) {
  324. vector<uint8_t> mac;
  325. uint8_t expectedChaddr[Pkt4::MAX_CHADDR_LEN];
  326. // We resize vector to specified length. It is more natural for fixed-length
  327. // field, than clear it (shrink size to 0) and push_back each element
  328. // (growing length back to MAX_CHADDR_LEN).
  329. mac.resize(Pkt4::MAX_CHADDR_LEN);
  330. scoped_ptr<Pkt4> pkt;
  331. // let's test each hlen, from 0 till 16
  332. for (size_t macLen = 0; macLen < Pkt4::MAX_CHADDR_LEN; macLen++) {
  333. for (size_t i = 0; i < Pkt4::MAX_CHADDR_LEN; i++) {
  334. mac[i] = 0;
  335. expectedChaddr[i] = 0;
  336. }
  337. for (size_t i = 0; i < macLen; i++) {
  338. mac[i] = 128 + i;
  339. expectedChaddr[i] = 128 + i;
  340. }
  341. // type and transaction doesn't matter in this test
  342. pkt.reset(new Pkt4(DHCPOFFER, 1234));
  343. pkt->setHWAddr(255 - macLen * 10, // just weird htype
  344. macLen,
  345. mac);
  346. EXPECT_EQ(0, memcmp(expectedChaddr, &pkt->getHWAddr()->hwaddr_[0],
  347. Pkt4::MAX_CHADDR_LEN));
  348. EXPECT_NO_THROW(
  349. pkt->pack();
  350. );
  351. // CHADDR starts at offset 28 in DHCP packet
  352. const uint8_t* ptr =
  353. static_cast<const uint8_t*>(pkt->getBuffer().getData()) + 28;
  354. EXPECT_EQ(0, memcmp(ptr, expectedChaddr, Pkt4::MAX_CHADDR_LEN));
  355. pkt.reset();
  356. }
  357. /// TODO: extend this test once options support is implemented. HW address
  358. /// longer than 16 bytes should be stored in client-identifier option
  359. }
  360. TEST_F(Pkt4Test, msgTypes) {
  361. struct msgType {
  362. uint8_t dhcp;
  363. uint8_t bootp;
  364. };
  365. msgType types[] = {
  366. {DHCPDISCOVER, BOOTREQUEST},
  367. {DHCPOFFER, BOOTREPLY},
  368. {DHCPREQUEST, BOOTREQUEST},
  369. {DHCPDECLINE, BOOTREQUEST},
  370. {DHCPACK, BOOTREPLY},
  371. {DHCPNAK, BOOTREPLY},
  372. {DHCPRELEASE, BOOTREQUEST},
  373. {DHCPINFORM, BOOTREQUEST},
  374. {DHCPLEASEQUERY, BOOTREQUEST},
  375. {DHCPLEASEUNASSIGNED, BOOTREPLY},
  376. {DHCPLEASEUNKNOWN, BOOTREPLY},
  377. {DHCPLEASEACTIVE, BOOTREPLY}
  378. };
  379. scoped_ptr<Pkt4> pkt;
  380. for (size_t i = 0; i < sizeof(types) / sizeof(msgType); i++) {
  381. pkt.reset(new Pkt4(types[i].dhcp, 0));
  382. EXPECT_EQ(types[i].dhcp, pkt->getType());
  383. EXPECT_EQ(types[i].bootp, pkt->getOp());
  384. pkt.reset();
  385. }
  386. EXPECT_THROW(
  387. pkt.reset(new Pkt4(100, 0)), // There's no message type 100
  388. OutOfRange
  389. );
  390. }
  391. // This test verifies handling of sname field
  392. TEST_F(Pkt4Test, sname) {
  393. uint8_t sname[Pkt4::MAX_SNAME_LEN];
  394. scoped_ptr<Pkt4> pkt;
  395. // Let's test each sname length, from 0 till 64
  396. for (size_t snameLen = 0; snameLen < Pkt4::MAX_SNAME_LEN; ++snameLen) {
  397. for (size_t i = 0; i < snameLen; ++i) {
  398. sname[i] = i + 1;
  399. }
  400. for (size_t i = snameLen; i < Pkt4::MAX_SNAME_LEN; ++i) {
  401. sname[i] = 0;
  402. }
  403. // Type and transaction doesn't matter in this test
  404. pkt.reset(new Pkt4(DHCPOFFER, 1234));
  405. pkt->setSname(sname, snameLen);
  406. EXPECT_EQ(0, memcmp(sname, &pkt->getSname()[0], Pkt4::MAX_SNAME_LEN));
  407. EXPECT_NO_THROW(
  408. pkt->pack();
  409. );
  410. // SNAME starts at offset 44 in DHCP packet
  411. const uint8_t* ptr =
  412. static_cast<const uint8_t*>(pkt->getBuffer().getData()) + 44;
  413. EXPECT_EQ(0, memcmp(ptr, sname, Pkt4::MAX_SNAME_LEN));
  414. pkt.reset();
  415. }
  416. // Check that a null argument generates an exception.
  417. Pkt4 pkt4(DHCPOFFER, 1234);
  418. EXPECT_THROW(pkt4.setSname(NULL, Pkt4::MAX_SNAME_LEN), InvalidParameter);
  419. EXPECT_THROW(pkt4.setSname(NULL, 0), InvalidParameter);
  420. }
  421. TEST_F(Pkt4Test, file) {
  422. uint8_t file[Pkt4::MAX_FILE_LEN];
  423. scoped_ptr<Pkt4> pkt;
  424. // Let's test each file length, from 0 till 128.
  425. for (size_t fileLen = 0; fileLen < Pkt4::MAX_FILE_LEN; ++fileLen) {
  426. for (size_t i = 0; i < fileLen; ++i) {
  427. file[i] = i + 1;
  428. }
  429. for (size_t i = fileLen; i < Pkt4::MAX_FILE_LEN; ++i) {
  430. file[i] = 0;
  431. }
  432. // Type and transaction doesn't matter in this test.
  433. pkt.reset(new Pkt4(DHCPOFFER, 1234));
  434. pkt->setFile(file, fileLen);
  435. EXPECT_EQ(0, memcmp(file, &pkt->getFile()[0], Pkt4::MAX_FILE_LEN));
  436. EXPECT_NO_THROW(
  437. pkt->pack();
  438. );
  439. // FILE starts at offset 108 in DHCP packet.
  440. const uint8_t* ptr =
  441. static_cast<const uint8_t*>(pkt->getBuffer().getData()) + 108;
  442. EXPECT_EQ(0, memcmp(ptr, file, Pkt4::MAX_FILE_LEN));
  443. pkt.reset();
  444. }
  445. // Check that a null argument generates an exception.
  446. Pkt4 pkt4(DHCPOFFER, 1234);
  447. EXPECT_THROW(pkt4.setFile(NULL, Pkt4::MAX_FILE_LEN), InvalidParameter);
  448. EXPECT_THROW(pkt4.setFile(NULL, 0), InvalidParameter);
  449. }
  450. TEST_F(Pkt4Test, options) {
  451. scoped_ptr<Pkt4> pkt(new Pkt4(DHCPOFFER, 0));
  452. vector<uint8_t> payload[5];
  453. for (uint8_t i = 0; i < 5; i++) {
  454. payload[i].push_back(i * 10);
  455. payload[i].push_back(i * 10 + 1);
  456. payload[i].push_back(i * 10 + 2);
  457. }
  458. boost::shared_ptr<Option> opt1(new Option(Option::V4, 12, payload[0]));
  459. boost::shared_ptr<Option> opt3(new Option(Option::V4, 14, payload[1]));
  460. boost::shared_ptr<Option> opt2(new Option(Option::V4, 60, payload[2]));
  461. boost::shared_ptr<Option> opt5(new Option(Option::V4,128, payload[3]));
  462. boost::shared_ptr<Option> opt4(new Option(Option::V4,254, payload[4]));
  463. pkt->addOption(opt1);
  464. pkt->addOption(opt2);
  465. pkt->addOption(opt3);
  466. pkt->addOption(opt4);
  467. pkt->addOption(opt5);
  468. EXPECT_TRUE(pkt->getOption(12));
  469. EXPECT_TRUE(pkt->getOption(60));
  470. EXPECT_TRUE(pkt->getOption(14));
  471. EXPECT_TRUE(pkt->getOption(128));
  472. EXPECT_TRUE(pkt->getOption(254));
  473. EXPECT_FALSE(pkt->getOption(127)); // no such option
  474. // Options are unique in DHCPv4. It should not be possible
  475. // to add more than one option of the same type.
  476. EXPECT_THROW(
  477. pkt->addOption(opt1),
  478. BadValue
  479. );
  480. EXPECT_NO_THROW(
  481. pkt->pack();
  482. );
  483. const OutputBuffer& buf = pkt->getBuffer();
  484. // Check that all options are stored, they should take sizeof(v4_opts),
  485. // DHCP magic cookie (4 bytes), and OPTION_END added (just one byte)
  486. ASSERT_EQ(static_cast<size_t>(Pkt4::DHCPV4_PKT_HDR_LEN) +
  487. sizeof(DHCP_OPTIONS_COOKIE) + sizeof(v4_opts) + 1,
  488. buf.getLength());
  489. // That that this extra data actually contain our options
  490. const uint8_t* ptr = static_cast<const uint8_t*>(buf.getData());
  491. // Rewind to end of fixed part.
  492. ptr += Pkt4::DHCPV4_PKT_HDR_LEN + sizeof(DHCP_OPTIONS_COOKIE);
  493. EXPECT_EQ(0, memcmp(ptr, v4_opts, sizeof(v4_opts)));
  494. EXPECT_EQ(DHO_END, static_cast<uint8_t>(*(ptr + sizeof(v4_opts))));
  495. // delOption() checks
  496. EXPECT_TRUE(pkt->getOption(12)); // Sanity check: option 12 is still there
  497. EXPECT_TRUE(pkt->delOption(12)); // We should be able to remove it
  498. EXPECT_FALSE(pkt->getOption(12)); // It should not be there anymore
  499. EXPECT_FALSE(pkt->delOption(12)); // And removal should fail
  500. EXPECT_NO_THROW(pkt.reset());
  501. }
  502. // This test verifies that the options are unpacked from the packet correctly.
  503. TEST_F(Pkt4Test, unpackOptions) {
  504. vector<uint8_t> expectedFormat = generateTestPacket2();
  505. expectedFormat.push_back(0x63);
  506. expectedFormat.push_back(0x82);
  507. expectedFormat.push_back(0x53);
  508. expectedFormat.push_back(0x63);
  509. for (size_t i = 0; i < sizeof(v4_opts); i++) {
  510. expectedFormat.push_back(v4_opts[i]);
  511. }
  512. // now expectedFormat contains fixed format and 5 options
  513. boost::shared_ptr<Pkt4> pkt(new Pkt4(&expectedFormat[0],
  514. expectedFormat.size()));
  515. EXPECT_NO_THROW(
  516. pkt->unpack()
  517. );
  518. verifyParsedOptions(pkt);
  519. }
  520. // Checks if the code is able to handle a malformed option
  521. TEST_F(Pkt4Test, unpackMalformed) {
  522. vector<uint8_t> orig = generateTestPacket2();
  523. orig.push_back(0x63);
  524. orig.push_back(0x82);
  525. orig.push_back(0x53);
  526. orig.push_back(0x63);
  527. orig.push_back(53); // Message Type
  528. orig.push_back(1); // length=1
  529. orig.push_back(2); // type=2
  530. orig.push_back(12); // Hostname
  531. orig.push_back(3); // length=3
  532. orig.push_back(102); // data="foo"
  533. orig.push_back(111);
  534. orig.push_back(111);
  535. // That's our original content. It should be sane.
  536. Pkt4Ptr success(new Pkt4(&orig[0], orig.size()));
  537. EXPECT_NO_THROW(success->unpack());
  538. // With the exception of END and PAD an option must have a length byte
  539. vector<uint8_t> nolength = orig;
  540. nolength.resize(orig.size() - 4);
  541. Pkt4Ptr no_length_pkt(new Pkt4(&nolength[0], nolength.size()));
  542. EXPECT_NO_THROW(no_length_pkt->unpack());
  543. // The unpack() operation doesn't throw but there is no option 12
  544. EXPECT_FALSE(no_length_pkt->getOption(12));
  545. // Truncated data is not accepted too but doesn't throw
  546. vector<uint8_t> shorty = orig;
  547. shorty.resize(orig.size() - 1);
  548. Pkt4Ptr too_short_pkt(new Pkt4(&shorty[0], shorty.size()));
  549. EXPECT_NO_THROW(too_short_pkt->unpack());
  550. // The unpack() operation doesn't throw but there is no option 12
  551. EXPECT_FALSE(no_length_pkt->getOption(12));
  552. }
  553. // Checks if the code is able to handle a malformed vendor option
  554. TEST_F(Pkt4Test, unpackVendorMalformed) {
  555. vector<uint8_t> orig = generateTestPacket2();
  556. orig.push_back(0x63);
  557. orig.push_back(0x82);
  558. orig.push_back(0x53);
  559. orig.push_back(0x63);
  560. orig.push_back(53); // Message Type
  561. orig.push_back(1); // length=1
  562. orig.push_back(2); // type=2
  563. orig.push_back(125); // vivso suboptions
  564. size_t full_len_index = orig.size();
  565. orig.push_back(15); // length=15
  566. orig.push_back(1); // vendor_id=0x1020304
  567. orig.push_back(2);
  568. orig.push_back(3);
  569. orig.push_back(4);
  570. size_t data_len_index = orig.size();
  571. orig.push_back(10); // data-len=10
  572. orig.push_back(128); // suboption type=128
  573. orig.push_back(3); // suboption length=3
  574. orig.push_back(102); // data="foo"
  575. orig.push_back(111);
  576. orig.push_back(111);
  577. orig.push_back(129); // suboption type=129
  578. orig.push_back(3); // suboption length=3
  579. orig.push_back(99); // data="bar"
  580. orig.push_back(98);
  581. orig.push_back(114);
  582. // That's our original content. It should be sane.
  583. Pkt4Ptr success(new Pkt4(&orig[0], orig.size()));
  584. EXPECT_NO_THROW(success->unpack());
  585. // Data-len must match
  586. vector<uint8_t> baddatalen = orig;
  587. baddatalen.resize(orig.size() - 5);
  588. baddatalen[full_len_index] = 10;
  589. Pkt4Ptr bad_data_len_pkt(new Pkt4(&baddatalen[0], baddatalen.size()));
  590. EXPECT_THROW(bad_data_len_pkt->unpack(), InvalidOptionValue);
  591. // A suboption must have a length byte
  592. vector<uint8_t> nolength = orig;
  593. nolength.resize(orig.size() - 4);
  594. nolength[full_len_index] = 11;
  595. nolength[data_len_index] = 6;
  596. Pkt4Ptr no_length_pkt(new Pkt4(&nolength[0], nolength.size()));
  597. EXPECT_THROW(no_length_pkt->unpack(), InvalidOptionValue);
  598. // Truncated data is not accepted either
  599. vector<uint8_t> shorty = orig;
  600. shorty.resize(orig.size() - 1);
  601. shorty[full_len_index] = 14;
  602. shorty[data_len_index] = 9;
  603. Pkt4Ptr too_short_pkt(new Pkt4(&shorty[0], shorty.size()));
  604. EXPECT_THROW(too_short_pkt->unpack(), InvalidOptionValue);
  605. }
  606. // This test verifies that it is possible to specify custom implementation of
  607. // the option parsing algorithm by installing a callback function.
  608. TEST_F(Pkt4Test, unpackOptionsWithCallback) {
  609. vector<uint8_t> expectedFormat = generateTestPacket2();
  610. expectedFormat.push_back(0x63);
  611. expectedFormat.push_back(0x82);
  612. expectedFormat.push_back(0x53);
  613. expectedFormat.push_back(0x63);
  614. for (size_t i = 0; i < sizeof(v4_opts); i++) {
  615. expectedFormat.push_back(v4_opts[i]);
  616. }
  617. // now expectedFormat contains fixed format and 5 options
  618. boost::shared_ptr<Pkt4> pkt(new Pkt4(&expectedFormat[0],
  619. expectedFormat.size()));
  620. CustomUnpackCallback cb;
  621. pkt->setCallback(boost::bind(&CustomUnpackCallback::execute, &cb,
  622. _1, _2, _3));
  623. ASSERT_FALSE(cb.executed_);
  624. EXPECT_NO_THROW(pkt->unpack());
  625. EXPECT_TRUE(cb.executed_);
  626. verifyParsedOptions(pkt);
  627. // Reset the indicator to perform another check: uninstall the callback.
  628. cb.executed_ = false;
  629. // By setting the callback to NULL we effectively uninstall the callback.
  630. pkt->setCallback(NULL);
  631. // Do another unpack.
  632. EXPECT_NO_THROW(pkt->unpack());
  633. // Callback should not be executed.
  634. EXPECT_FALSE(cb.executed_);
  635. }
  636. // This test verifies methods that are used for manipulating meta fields
  637. // i.e. fields that are not part of DHCPv4 (e.g. interface name).
  638. TEST_F(Pkt4Test, metaFields) {
  639. scoped_ptr<Pkt4> pkt(new Pkt4(DHCPOFFER, 1234));
  640. pkt->setIface("loooopback");
  641. pkt->setIndex(42);
  642. pkt->setRemoteAddr(IOAddress("1.2.3.4"));
  643. pkt->setLocalAddr(IOAddress("4.3.2.1"));
  644. EXPECT_EQ("loooopback", pkt->getIface());
  645. EXPECT_EQ(42, pkt->getIndex());
  646. EXPECT_EQ("1.2.3.4", pkt->getRemoteAddr().toText());
  647. EXPECT_EQ("4.3.2.1", pkt->getLocalAddr().toText());
  648. }
  649. TEST_F(Pkt4Test, Timestamp) {
  650. scoped_ptr<Pkt4> pkt(new Pkt4(DHCPOFFER, 1234));
  651. // Just after construction timestamp is invalid
  652. ASSERT_TRUE(pkt->getTimestamp().is_not_a_date_time());
  653. // Update packet time.
  654. pkt->updateTimestamp();
  655. // Get updated packet time.
  656. boost::posix_time::ptime ts_packet = pkt->getTimestamp();
  657. // After timestamp is updated it should be date-time.
  658. ASSERT_FALSE(ts_packet.is_not_a_date_time());
  659. // Check current time.
  660. boost::posix_time::ptime ts_now =
  661. boost::posix_time::microsec_clock::universal_time();
  662. // Calculate period between packet time and now.
  663. boost::posix_time::time_period ts_period(ts_packet, ts_now);
  664. // Duration should be positive or zero.
  665. EXPECT_TRUE(ts_period.length().total_microseconds() >= 0);
  666. }
  667. TEST_F(Pkt4Test, hwaddr) {
  668. scoped_ptr<Pkt4> pkt(new Pkt4(DHCPOFFER, 1234));
  669. const uint8_t hw[] = { 2, 4, 6, 8, 10, 12 }; // MAC
  670. const uint8_t hw_type = 123; // hardware type
  671. HWAddrPtr hwaddr(new HWAddr(hw, sizeof(hw), hw_type));
  672. // setting NULL hardware address is not allowed
  673. EXPECT_THROW(pkt->setHWAddr(HWAddrPtr()), BadValue);
  674. pkt->setHWAddr(hwaddr);
  675. EXPECT_EQ(hw_type, pkt->getHtype());
  676. EXPECT_EQ(sizeof(hw), pkt->getHlen());
  677. EXPECT_TRUE(hwaddr == pkt->getHWAddr());
  678. }
  679. // This test verifies that the packet remte and local HW address can
  680. // be set and returned.
  681. TEST_F(Pkt4Test, hwaddrSrcRemote) {
  682. scoped_ptr<Pkt4> pkt(new Pkt4(DHCPOFFER, 1234));
  683. const uint8_t src_hw[] = { 1, 2, 3, 4, 5, 6 };
  684. const uint8_t dst_hw[] = { 7, 8, 9, 10, 11, 12 };
  685. const uint8_t hw_type = 123;
  686. HWAddrPtr dst_hwaddr(new HWAddr(dst_hw, sizeof(src_hw), hw_type));
  687. HWAddrPtr src_hwaddr(new HWAddr(src_hw, sizeof(src_hw), hw_type));
  688. // Check that we can set the local address.
  689. EXPECT_NO_THROW(pkt->setLocalHWAddr(dst_hwaddr));
  690. EXPECT_TRUE(dst_hwaddr == pkt->getLocalHWAddr());
  691. // Check that we can set the remote address.
  692. EXPECT_NO_THROW(pkt->setRemoteHWAddr(src_hwaddr));
  693. EXPECT_TRUE(src_hwaddr == pkt->getRemoteHWAddr());
  694. // Can't set the NULL addres.
  695. EXPECT_THROW(pkt->setRemoteHWAddr(HWAddrPtr()), BadValue);
  696. EXPECT_THROW(pkt->setLocalHWAddr(HWAddrPtr()), BadValue);
  697. // Test alternative way to set local address.
  698. const uint8_t dst_hw2[] = { 19, 20, 21, 22, 23, 24 };
  699. std::vector<uint8_t> dst_hw_vec(dst_hw2, dst_hw2 + sizeof(dst_hw2));
  700. const uint8_t hw_type2 = 234;
  701. EXPECT_NO_THROW(pkt->setLocalHWAddr(hw_type2, sizeof(dst_hw2), dst_hw_vec));
  702. HWAddrPtr local_addr = pkt->getLocalHWAddr();
  703. ASSERT_TRUE(local_addr);
  704. EXPECT_EQ(hw_type2, local_addr->htype_);
  705. EXPECT_TRUE(std::equal(dst_hw_vec.begin(), dst_hw_vec.end(),
  706. local_addr->hwaddr_.begin()));
  707. // Set remote address.
  708. const uint8_t src_hw2[] = { 25, 26, 27, 28, 29, 30 };
  709. std::vector<uint8_t> src_hw_vec(src_hw2, src_hw2 + sizeof(src_hw2));
  710. EXPECT_NO_THROW(pkt->setRemoteHWAddr(hw_type2, sizeof(src_hw2), src_hw_vec));
  711. HWAddrPtr remote_addr = pkt->getRemoteHWAddr();
  712. ASSERT_TRUE(remote_addr);
  713. EXPECT_EQ(hw_type2, remote_addr->htype_);
  714. EXPECT_TRUE(std::equal(src_hw_vec.begin(), src_hw_vec.end(),
  715. remote_addr->hwaddr_.begin()));
  716. }
  717. // This test verifies that the check for a message being relayed is correct.
  718. TEST_F(Pkt4Test, isRelayed) {
  719. Pkt4 pkt(DHCPDISCOVER, 1234);
  720. // By default, the hops and giaddr should be 0.
  721. ASSERT_TRUE(pkt.getGiaddr().isV4Zero());
  722. ASSERT_EQ(0, pkt.getHops());
  723. // For zero giaddr the packet is non-relayed.
  724. EXPECT_FALSE(pkt.isRelayed());
  725. // Set giaddr but leave hops = 0.
  726. pkt.setGiaddr(IOAddress("10.0.0.1"));
  727. EXPECT_TRUE(pkt.isRelayed());
  728. // After setting hops the message should still be relayed.
  729. pkt.setHops(10);
  730. EXPECT_TRUE(pkt.isRelayed());
  731. // Set giaddr to 0. The message is now not-relayed.
  732. pkt.setGiaddr(IOAddress(IOAddress::IPV4_ZERO_ADDRESS()));
  733. EXPECT_FALSE(pkt.isRelayed());
  734. // Setting the giaddr to 255.255.255.255 should not cause it to
  735. // be relayed message.
  736. pkt.setGiaddr(IOAddress(IOAddress::IPV4_BCAST_ADDRESS()));
  737. EXPECT_FALSE(pkt.isRelayed());
  738. }
  739. // Tests whether a packet can be assigned to a class and later
  740. // checked if it belongs to a given class
  741. TEST_F(Pkt4Test, clientClasses) {
  742. Pkt4 pkt(DHCPOFFER, 1234);
  743. // Default values (do not belong to any class)
  744. EXPECT_FALSE(pkt.inClass(DOCSIS3_CLASS_EROUTER));
  745. EXPECT_FALSE(pkt.inClass(DOCSIS3_CLASS_MODEM));
  746. EXPECT_TRUE(pkt.classes_.empty());
  747. // Add to the first class
  748. pkt.addClass(DOCSIS3_CLASS_EROUTER);
  749. EXPECT_TRUE(pkt.inClass(DOCSIS3_CLASS_EROUTER));
  750. EXPECT_FALSE(pkt.inClass(DOCSIS3_CLASS_MODEM));
  751. ASSERT_FALSE(pkt.classes_.empty());
  752. // Add to a second class
  753. pkt.addClass(DOCSIS3_CLASS_MODEM);
  754. EXPECT_TRUE(pkt.inClass(DOCSIS3_CLASS_EROUTER));
  755. EXPECT_TRUE(pkt.inClass(DOCSIS3_CLASS_MODEM));
  756. // Check that it's ok to add to the same class repeatedly
  757. EXPECT_NO_THROW(pkt.addClass("foo"));
  758. EXPECT_NO_THROW(pkt.addClass("foo"));
  759. EXPECT_NO_THROW(pkt.addClass("foo"));
  760. // Check that the packet belongs to 'foo'
  761. EXPECT_TRUE(pkt.inClass("foo"));
  762. }
  763. // Tests whether MAC can be obtained and that MAC sources are not
  764. // confused.
  765. TEST_F(Pkt4Test, getMAC) {
  766. Pkt4 pkt(DHCPOFFER, 1234);
  767. // DHCPv4 packet by default doens't have MAC address specified.
  768. EXPECT_FALSE(pkt.getMAC(HWAddr::HWADDR_SOURCE_ANY));
  769. EXPECT_FALSE(pkt.getMAC(HWAddr::HWADDR_SOURCE_RAW));
  770. // Let's invent a MAC
  771. const uint8_t hw[] = { 2, 4, 6, 8, 10, 12 }; // MAC
  772. const uint8_t hw_type = 123; // hardware type
  773. HWAddrPtr dummy_hwaddr(new HWAddr(hw, sizeof(hw), hw_type));
  774. // Now let's pretend that we obtained it from raw sockets
  775. pkt.setRemoteHWAddr(dummy_hwaddr);
  776. // Now we should be able to get something
  777. ASSERT_TRUE(pkt.getMAC(HWAddr::HWADDR_SOURCE_ANY));
  778. ASSERT_TRUE(pkt.getMAC(HWAddr::HWADDR_SOURCE_RAW));
  779. // Check that the returned MAC is indeed the expected one
  780. ASSERT_TRUE(*dummy_hwaddr == *pkt.getMAC(HWAddr::HWADDR_SOURCE_ANY));
  781. ASSERT_TRUE(*dummy_hwaddr == *pkt.getMAC(HWAddr::HWADDR_SOURCE_RAW));
  782. }
  783. // Tests that getLabel/makeLabel methods produces the expected strings based on
  784. // packet content.
  785. TEST_F(Pkt4Test, getLabel) {
  786. Pkt4 pkt(DHCPOFFER, 1234);
  787. // Verify makeLabel() handles empty values
  788. EXPECT_EQ ("[no hwaddr info], cid=[no info], tid=0x0",
  789. Pkt4::makeLabel(HWAddrPtr(), ClientIdPtr(), 0));
  790. // Verify an "empty" packet label is as we expect
  791. EXPECT_EQ ("[hwtype=1 ], cid=[no info], tid=0x4d2",
  792. pkt.getLabel());
  793. // Set that packet hardware address, then verify getLabel
  794. const uint8_t hw[] = { 2, 4, 6, 8, 10, 12 }; // MAC
  795. const uint8_t hw_type = 123; // hardware type
  796. HWAddrPtr dummy_hwaddr(new HWAddr(hw, sizeof(hw), hw_type));
  797. pkt.setHWAddr(dummy_hwaddr);
  798. EXPECT_EQ ("[hwtype=123 02:04:06:08:0a:0c],"
  799. " cid=[no info], tid=0x4d2", pkt.getLabel());
  800. // Add a client id to the packet then verify getLabel
  801. OptionBuffer clnt_id(4);
  802. for (uint8_t i = 0; i < 4; i++) {
  803. clnt_id[i] = 100 + i;
  804. }
  805. OptionPtr opt(new Option(Option::V4, DHO_DHCP_CLIENT_IDENTIFIER,
  806. clnt_id.begin(), clnt_id.begin() + 4));
  807. pkt.addOption(opt);
  808. EXPECT_EQ ("[hwtype=123 02:04:06:08:0a:0c],"
  809. " cid=[64:65:66:67], tid=0x4d2",
  810. pkt.getLabel());
  811. }
  812. // Test that empty client identifier option doesn't cause an exception from
  813. // Pkt4::getLabel.
  814. TEST_F(Pkt4Test, getLabelEmptyClientId) {
  815. Pkt4 pkt(DHCPOFFER, 1234);
  816. // Create empty client identifier option.
  817. OptionPtr empty_opt(new Option(Option::V4, DHO_DHCP_CLIENT_IDENTIFIER));
  818. pkt.addOption(empty_opt);
  819. EXPECT_EQ("[hwtype=1 ], cid=[no info], tid=0x4d2"
  820. " (malformed client-id)", pkt.getLabel());
  821. }
  822. // Tests that the variant of makeLabel which doesn't include transaction
  823. // id produces expected output.
  824. TEST_F(Pkt4Test, makeLabelWithoutTransactionId) {
  825. EXPECT_EQ("[no hwaddr info], cid=[no info]",
  826. Pkt4::makeLabel(HWAddrPtr(), ClientIdPtr()));
  827. // Test non-null hardware address.
  828. HWAddrPtr hwaddr(new HWAddr(HWAddr::fromText("01:02:03:04:05:06", 123)));
  829. EXPECT_EQ("[hwtype=123 01:02:03:04:05:06], cid=[no info]",
  830. Pkt4::makeLabel(hwaddr, ClientIdPtr()));
  831. // Test non-null client identifier and non-null hardware address.
  832. ClientIdPtr cid = ClientId::fromText("01:02:03:04");
  833. EXPECT_EQ("[hwtype=123 01:02:03:04:05:06], cid=[01:02:03:04]",
  834. Pkt4::makeLabel(hwaddr, cid));
  835. // Test non-nnull client identifier and null hardware address.
  836. EXPECT_EQ("[no hwaddr info], cid=[01:02:03:04]",
  837. Pkt4::makeLabel(HWAddrPtr(), cid));
  838. }
  839. // Tests that the correct DHCPv4 message name is returned for various
  840. // message types.
  841. TEST_F(Pkt4Test, getName) {
  842. // Check all possible packet types
  843. for (int itype = 0; itype < 256; ++itype) {
  844. uint8_t type = itype;
  845. switch (type) {
  846. case DHCPDISCOVER:
  847. EXPECT_STREQ("DHCPDISCOVER", Pkt4::getName(type));
  848. break;
  849. case DHCPOFFER:
  850. EXPECT_STREQ("DHCPOFFER", Pkt4::getName(type));
  851. break;
  852. case DHCPREQUEST:
  853. EXPECT_STREQ("DHCPREQUEST", Pkt4::getName(type));
  854. break;
  855. case DHCPDECLINE:
  856. EXPECT_STREQ("DHCPDECLINE", Pkt4::getName(type));
  857. break;
  858. case DHCPACK:
  859. EXPECT_STREQ("DHCPACK", Pkt4::getName(type));
  860. break;
  861. case DHCPNAK:
  862. EXPECT_STREQ("DHCPNAK", Pkt4::getName(type));
  863. break;
  864. case DHCPRELEASE:
  865. EXPECT_STREQ("DHCPRELEASE", Pkt4::getName(type));
  866. break;
  867. case DHCPINFORM:
  868. EXPECT_STREQ("DHCPINFORM", Pkt4::getName(type));
  869. break;
  870. default:
  871. EXPECT_STREQ("UNKNOWN", Pkt4::getName(type));
  872. }
  873. }
  874. }
  875. // This test checks that the packet data are correctly converted to the
  876. // textual format.
  877. TEST_F(Pkt4Test, toText) {
  878. Pkt4 pkt(DHCPDISCOVER, 2543);
  879. pkt.setLocalAddr(IOAddress("192.0.2.34"));
  880. pkt.setRemoteAddr(IOAddress("192.10.33.4"));
  881. pkt.addOption(OptionPtr(new Option4AddrLst(123, IOAddress("192.0.2.3"))));
  882. pkt.addOption(OptionPtr(new OptionUint32(Option::V4, 156, 123456)));
  883. pkt.addOption(OptionPtr(new OptionString(Option::V4, 87, "lorem ipsum")));
  884. EXPECT_EQ("local_address=192.0.2.34:67, remote_adress=192.10.33.4:68, "
  885. "msg_type=DHCPDISCOVER (1), transid=0x9ef,\n"
  886. "options:\n"
  887. " type=053, len=001: 1 (uint8)\n"
  888. " type=087, len=011: \"lorem ipsum\" (string)\n"
  889. " type=123, len=004: 192.0.2.3\n"
  890. " type=156, len=004: 123456 (uint32)",
  891. pkt.toText());
  892. // Now remove all options, including Message Type and check if the
  893. // information about lack of any options is displayed properly.
  894. pkt.delOption(123);
  895. pkt.delOption(156);
  896. pkt.delOption(87);
  897. pkt.delOption(53);
  898. EXPECT_EQ("local_address=192.0.2.34:67, remote_adress=192.10.33.4:68, "
  899. "msg_type=(missing), transid=0x9ef, "
  900. "message contains no options",
  901. pkt.toText());
  902. }
  903. // Sanity check. Verifies that the getName() and getType()
  904. // don't throw.
  905. TEST_F(Pkt4Test, getType) {
  906. Pkt4 pkt(DHCPDISCOVER, 2543);
  907. pkt.delOption(DHO_DHCP_MESSAGE_TYPE);
  908. ASSERT_NO_THROW(pkt.getType());
  909. ASSERT_NO_THROW(pkt.getName());
  910. // The method has to return something that is not NULL,
  911. // even if the packet doesn't have Message Type option.
  912. EXPECT_TRUE(pkt.getName());
  913. }
  914. } // end of anonymous namespace