dhcp4_test_utils.cc 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597
  1. // Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <config.h>
  15. #include <asiolink/io_address.h>
  16. #include <config/ccsession.h>
  17. #include <dhcp4/tests/dhcp4_test_utils.h>
  18. #include <dhcp/option4_addrlst.h>
  19. #include <dhcp/option_int_array.h>
  20. #include <dhcp/option_custom.h>
  21. #include <dhcp/iface_mgr.h>
  22. #include <dhcpsrv/cfgmgr.h>
  23. #include <dhcpsrv/lease.h>
  24. #include <dhcpsrv/lease_mgr.h>
  25. #include <dhcpsrv/lease_mgr_factory.h>
  26. using namespace std;
  27. using namespace isc::asiolink;
  28. namespace isc {
  29. namespace dhcp {
  30. namespace test {
  31. /// dummy server-id file location
  32. static const char* SRVID_FILE = "server-id-test.txt";
  33. Dhcpv4SrvTest::Dhcpv4SrvTest()
  34. :rcode_(-1) {
  35. subnet_ = Subnet4Ptr(new Subnet4(IOAddress("192.0.2.0"), 24, 1000,
  36. 2000, 3000));
  37. pool_ = Pool4Ptr(new Pool4(IOAddress("192.0.2.100"), IOAddress("192.0.2.110")));
  38. subnet_->addPool(pool_);
  39. CfgMgr::instance().deleteActiveIfaces();
  40. CfgMgr::instance().deleteSubnets4();
  41. CfgMgr::instance().addSubnet4(subnet_);
  42. // Add Router option.
  43. Option4AddrLstPtr opt_routers(new Option4AddrLst(DHO_ROUTERS));
  44. opt_routers->setAddress(IOAddress("192.0.2.2"));
  45. subnet_->addOption(opt_routers, false, "dhcp4");
  46. // it's ok if that fails. There should not be such a file anyway
  47. unlink(SRVID_FILE);
  48. }
  49. void Dhcpv4SrvTest::addPrlOption(Pkt4Ptr& pkt) {
  50. OptionUint8ArrayPtr option_prl =
  51. OptionUint8ArrayPtr(new OptionUint8Array(Option::V4,
  52. DHO_DHCP_PARAMETER_REQUEST_LIST));
  53. // Let's request options that have been configured for the subnet.
  54. option_prl->addValue(DHO_DOMAIN_NAME_SERVERS);
  55. option_prl->addValue(DHO_DOMAIN_NAME);
  56. option_prl->addValue(DHO_LOG_SERVERS);
  57. option_prl->addValue(DHO_COOKIE_SERVERS);
  58. // Let's also request the option that hasn't been configured. In such
  59. // case server should ignore request for this particular option.
  60. option_prl->addValue(DHO_LPR_SERVERS);
  61. // And add 'Parameter Request List' option into the DISCOVER packet.
  62. pkt->addOption(option_prl);
  63. }
  64. void Dhcpv4SrvTest::configureRequestedOptions() {
  65. // dns-servers
  66. Option4AddrLstPtr
  67. option_dns_servers(new Option4AddrLst(DHO_DOMAIN_NAME_SERVERS));
  68. option_dns_servers->addAddress(IOAddress("192.0.2.1"));
  69. option_dns_servers->addAddress(IOAddress("192.0.2.100"));
  70. ASSERT_NO_THROW(subnet_->addOption(option_dns_servers, false, "dhcp4"));
  71. // domain-name
  72. OptionDefinition def("domain-name", DHO_DOMAIN_NAME, OPT_FQDN_TYPE);
  73. OptionCustomPtr option_domain_name(new OptionCustom(def, Option::V4));
  74. option_domain_name->writeFqdn("example.com");
  75. subnet_->addOption(option_domain_name, false, "dhcp4");
  76. // log-servers
  77. Option4AddrLstPtr option_log_servers(new Option4AddrLst(DHO_LOG_SERVERS));
  78. option_log_servers->addAddress(IOAddress("192.0.2.2"));
  79. option_log_servers->addAddress(IOAddress("192.0.2.10"));
  80. ASSERT_NO_THROW(subnet_->addOption(option_log_servers, false, "dhcp4"));
  81. // cookie-servers
  82. Option4AddrLstPtr option_cookie_servers(new Option4AddrLst(DHO_COOKIE_SERVERS));
  83. option_cookie_servers->addAddress(IOAddress("192.0.2.1"));
  84. ASSERT_NO_THROW(subnet_->addOption(option_cookie_servers, false, "dhcp4"));
  85. }
  86. void Dhcpv4SrvTest::messageCheck(const Pkt4Ptr& q, const Pkt4Ptr& a) {
  87. ASSERT_TRUE(q);
  88. ASSERT_TRUE(a);
  89. EXPECT_EQ(q->getHops(), a->getHops());
  90. EXPECT_EQ(q->getIface(), a->getIface());
  91. EXPECT_EQ(q->getIndex(), a->getIndex());
  92. EXPECT_EQ(q->getGiaddr(), a->getGiaddr());
  93. // When processing an incoming packet the remote address
  94. // is copied as a src address, and the source address is
  95. // copied as a remote address to the response.
  96. EXPECT_TRUE(q->getLocalHWAddr() == a->getLocalHWAddr());
  97. EXPECT_TRUE(q->getRemoteHWAddr() == a->getRemoteHWAddr());
  98. // Check that the server identifier is present in the response.
  99. // Presence (or absence) of other options is checked elsewhere.
  100. EXPECT_TRUE(a->getOption(DHO_DHCP_SERVER_IDENTIFIER));
  101. // Check that something is offered
  102. EXPECT_TRUE(a->getYiaddr().toText() != "0.0.0.0");
  103. }
  104. ::testing::AssertionResult
  105. Dhcpv4SrvTest::basicOptionsPresent(const Pkt4Ptr& pkt) {
  106. std::ostringstream errmsg;
  107. errmsg << "option missing in the response";
  108. if (!pkt->getOption(DHO_DOMAIN_NAME)) {
  109. return (::testing::AssertionFailure(::testing::Message()
  110. << "domain-name " << errmsg));
  111. } else if (!pkt->getOption(DHO_DOMAIN_NAME_SERVERS)) {
  112. return (::testing::AssertionFailure(::testing::Message()
  113. << "dns-servers " << errmsg));
  114. } else if (!pkt->getOption(DHO_SUBNET_MASK)) {
  115. return (::testing::AssertionFailure(::testing::Message()
  116. << "subnet-mask " << errmsg));
  117. } else if (!pkt->getOption(DHO_ROUTERS)) {
  118. return (::testing::AssertionFailure(::testing::Message() << "routers "
  119. << errmsg));
  120. } else if (!pkt->getOption(DHO_DHCP_LEASE_TIME)) {
  121. return (::testing::AssertionFailure(::testing::Message() <<
  122. "dhcp-lease-time " << errmsg));
  123. }
  124. return (::testing::AssertionSuccess());
  125. }
  126. ::testing::AssertionResult
  127. Dhcpv4SrvTest::noBasicOptions(const Pkt4Ptr& pkt) {
  128. std::ostringstream errmsg;
  129. errmsg << "option present in the response";
  130. if (pkt->getOption(DHO_DOMAIN_NAME)) {
  131. return (::testing::AssertionFailure(::testing::Message()
  132. << "domain-name " << errmsg));
  133. } else if (pkt->getOption(DHO_DOMAIN_NAME_SERVERS)) {
  134. return (::testing::AssertionFailure(::testing::Message()
  135. << "dns-servers " << errmsg));
  136. } else if (pkt->getOption(DHO_SUBNET_MASK)) {
  137. return (::testing::AssertionFailure(::testing::Message()
  138. << "subnet-mask " << errmsg));
  139. } else if (pkt->getOption(DHO_ROUTERS)) {
  140. return (::testing::AssertionFailure(::testing::Message() << "routers "
  141. << errmsg));
  142. } else if (pkt->getOption(DHO_DHCP_LEASE_TIME)) {
  143. return (::testing::AssertionFailure(::testing::Message()
  144. << "dhcp-lease-time " << errmsg));
  145. }
  146. return (::testing::AssertionSuccess());
  147. }
  148. ::testing::AssertionResult
  149. Dhcpv4SrvTest::requestedOptionsPresent(const Pkt4Ptr& pkt) {
  150. std::ostringstream errmsg;
  151. errmsg << "option missing in the response";
  152. if (!pkt->getOption(DHO_LOG_SERVERS)) {
  153. return (::testing::AssertionFailure(::testing::Message()
  154. << "log-servers " << errmsg));
  155. } else if (!pkt->getOption(DHO_COOKIE_SERVERS)) {
  156. return (::testing::AssertionFailure(::testing::Message()
  157. << "cookie-servers " << errmsg));
  158. }
  159. return (::testing::AssertionSuccess());
  160. }
  161. ::testing::AssertionResult
  162. Dhcpv4SrvTest::noRequestedOptions(const Pkt4Ptr& pkt) {
  163. std::ostringstream errmsg;
  164. errmsg << "option present in the response";
  165. if (pkt->getOption(DHO_LOG_SERVERS)) {
  166. return (::testing::AssertionFailure(::testing::Message()
  167. << "log-servers " << errmsg));
  168. } else if (pkt->getOption(DHO_COOKIE_SERVERS)) {
  169. return (::testing::AssertionFailure(::testing::Message()
  170. << "cookie-servers " << errmsg));
  171. }
  172. return (::testing::AssertionSuccess());
  173. }
  174. OptionPtr Dhcpv4SrvTest::generateClientId(size_t size /*= 4*/) {
  175. OptionBuffer clnt_id(size);
  176. for (int i = 0; i < size; i++) {
  177. clnt_id[i] = 100 + i;
  178. }
  179. client_id_ = ClientIdPtr(new ClientId(clnt_id));
  180. return (OptionPtr(new Option(Option::V4, DHO_DHCP_CLIENT_IDENTIFIER,
  181. clnt_id.begin(),
  182. clnt_id.begin() + size)));
  183. }
  184. HWAddrPtr Dhcpv4SrvTest::generateHWAddr(size_t size /*= 6*/) {
  185. const uint8_t hw_type = 123; // Just a fake number (typically 6=HTYPE_ETHER, see dhcp4.h)
  186. OptionBuffer mac(size);
  187. for (int i = 0; i < size; ++i) {
  188. mac[i] = 50 + i;
  189. }
  190. return (HWAddrPtr(new HWAddr(mac, hw_type)));
  191. }
  192. void Dhcpv4SrvTest::checkAddressParams(const Pkt4Ptr& rsp, const SubnetPtr subnet,
  193. bool t1_mandatory /*= false*/,
  194. bool t2_mandatory /*= false*/) {
  195. // Technically inPool implies inRange, but let's be on the safe
  196. // side and check both.
  197. EXPECT_TRUE(subnet->inRange(rsp->getYiaddr()));
  198. EXPECT_TRUE(subnet->inPool(Lease::TYPE_V4, rsp->getYiaddr()));
  199. // Check lease time
  200. OptionPtr opt = rsp->getOption(DHO_DHCP_LEASE_TIME);
  201. if (!opt) {
  202. ADD_FAILURE() << "Lease time option missing in response";
  203. } else {
  204. EXPECT_EQ(opt->getUint32(), subnet->getValid());
  205. }
  206. // Check T1 timer
  207. opt = rsp->getOption(DHO_DHCP_RENEWAL_TIME);
  208. if (opt) {
  209. EXPECT_EQ(opt->getUint32(), subnet->getT1());
  210. } else {
  211. if (t1_mandatory) {
  212. ADD_FAILURE() << "Required T1 option missing";
  213. }
  214. }
  215. // Check T2 timer
  216. opt = rsp->getOption(DHO_DHCP_REBINDING_TIME);
  217. if (opt) {
  218. EXPECT_EQ(opt->getUint32(), subnet->getT2());
  219. } else {
  220. if (t2_mandatory) {
  221. ADD_FAILURE() << "Required T2 option missing";
  222. }
  223. }
  224. }
  225. void Dhcpv4SrvTest::checkResponse(const Pkt4Ptr& rsp, uint8_t expected_message_type,
  226. uint32_t expected_transid) {
  227. ASSERT_TRUE(rsp);
  228. EXPECT_EQ(expected_message_type, rsp->getType());
  229. EXPECT_EQ(expected_transid, rsp->getTransid());
  230. }
  231. Lease4Ptr Dhcpv4SrvTest::checkLease(const Pkt4Ptr& rsp,
  232. const OptionPtr& client_id,
  233. const HWAddrPtr&,
  234. const IOAddress& expected_addr) {
  235. ClientIdPtr id;
  236. if (client_id) {
  237. OptionBuffer data = client_id->getData();
  238. id.reset(new ClientId(data));
  239. }
  240. Lease4Ptr lease = LeaseMgrFactory::instance().getLease4(expected_addr);
  241. if (!lease) {
  242. cout << "Lease for " << expected_addr.toText()
  243. << " not found in the database backend.";
  244. return (Lease4Ptr());
  245. }
  246. EXPECT_EQ(rsp->getYiaddr().toText(), expected_addr.toText());
  247. EXPECT_EQ(expected_addr.toText(), lease->addr_.toText());
  248. if (client_id) {
  249. EXPECT_TRUE(*lease->client_id_ == *id);
  250. }
  251. EXPECT_EQ(subnet_->getID(), lease->subnet_id_);
  252. return (lease);
  253. }
  254. void Dhcpv4SrvTest::checkServerId(const Pkt4Ptr& rsp, const OptionPtr& expected_srvid) {
  255. // Check that server included its server-id
  256. OptionPtr opt = rsp->getOption(DHO_DHCP_SERVER_IDENTIFIER);
  257. ASSERT_TRUE(opt);
  258. EXPECT_EQ(opt->getType(), expected_srvid->getType() );
  259. EXPECT_EQ(opt->len(), expected_srvid->len() );
  260. EXPECT_TRUE(opt->getData() == expected_srvid->getData());
  261. }
  262. void Dhcpv4SrvTest::checkClientId(const Pkt4Ptr& rsp, const OptionPtr& expected_clientid) {
  263. // check that server included our own client-id
  264. OptionPtr opt = rsp->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
  265. ASSERT_TRUE(opt);
  266. EXPECT_EQ(expected_clientid->getType(), opt->getType());
  267. EXPECT_EQ(expected_clientid->len(), opt->len());
  268. EXPECT_TRUE(expected_clientid->getData() == opt->getData());
  269. }
  270. ::testing::AssertionResult
  271. Dhcpv4SrvTest::createPacketFromBuffer(const Pkt4Ptr& src_pkt,
  272. Pkt4Ptr& dst_pkt) {
  273. // Create on-wire format of the packet. If pack() has been called
  274. // on this instance of the packet already, the next call to pack()
  275. // should remove all contents of the output buffer.
  276. try {
  277. src_pkt->pack();
  278. } catch (const Exception& ex) {
  279. return (::testing::AssertionFailure(::testing::Message()
  280. << "Failed to parse source packet: "
  281. << ex.what()));
  282. }
  283. // Get the output buffer from the source packet.
  284. const util::OutputBuffer& buf = src_pkt->getBuffer();
  285. // Create a copy of the packet using the output buffer from the source
  286. // packet.
  287. try {
  288. dst_pkt.reset(new Pkt4(static_cast<const uint8_t*>(buf.getData()),
  289. buf.getLength()));
  290. } catch (const Exception& ex) {
  291. return (::testing::AssertionFailure(::testing::Message()
  292. << "Failed to create a"
  293. " destination packet from"
  294. " the buffer: "
  295. << ex.what()));
  296. }
  297. try {
  298. // Parse the new packet and return to the caller.
  299. dst_pkt->unpack();
  300. } catch (const Exception& ex) {
  301. return (::testing::AssertionFailure(::testing::Message()
  302. << "Failed to parse a"
  303. << " destination packet: "
  304. << ex.what()));
  305. }
  306. return (::testing::AssertionSuccess());
  307. }
  308. void Dhcpv4SrvTest::TearDown() {
  309. CfgMgr::instance().deleteSubnets4();
  310. // Let's clean up if there is such a file.
  311. unlink(SRVID_FILE);
  312. // Close all open sockets.
  313. IfaceMgr::instance().closeSockets();
  314. // Some unit tests override the default packet filtering class, used
  315. // by the IfaceMgr. The dummy class, called PktFilterTest, reports the
  316. // capability to directly respond to the clients without IP address
  317. // assigned. This capability is not supported by the default packet
  318. // filtering class: PktFilterInet. Therefore setting the dummy class
  319. // allows to test scenarios, when server responds to the broadcast address
  320. // on client's request, despite having support for direct response.
  321. // The following call restores the use of original packet filtering class
  322. // after the test.
  323. try {
  324. IfaceMgr::instance().setPacketFilter(PktFilterPtr(new PktFilterInet()));
  325. } catch (const Exception& ex) {
  326. FAIL() << "Failed to restore the default (PktFilterInet) packet filtering"
  327. << " class after the test. Exception has been caught: "
  328. << ex.what();
  329. }
  330. }
  331. Dhcpv4SrvFakeIfaceTest::Dhcpv4SrvFakeIfaceTest()
  332. : Dhcpv4SrvTest(), current_pkt_filter_() {
  333. // Remove current interface configuration. Instead we want to add
  334. // a couple of fake interfaces.
  335. IfaceMgr& ifacemgr = IfaceMgr::instance();
  336. ifacemgr.closeSockets();
  337. ifacemgr.clearIfaces();
  338. // Add fake interfaces.
  339. ifacemgr.addInterface(createIface("lo", 0, "127.0.0.1"));
  340. ifacemgr.addInterface(createIface("eth0", 1, "192.0.3.1"));
  341. ifacemgr.addInterface(createIface("eth1", 2, "10.0.0.1"));
  342. // In order to use fake interfaces we have to supply the custom
  343. // packet filtering class, which can mimic opening sockets on
  344. // fake interafaces.
  345. current_pkt_filter_.reset(new PktFilterTest());
  346. ifacemgr.setPacketFilter(current_pkt_filter_);
  347. ifacemgr.openSockets4();
  348. }
  349. void
  350. Dhcpv4SrvFakeIfaceTest::TearDown() {
  351. // The base class function restores the original packet filtering class.
  352. Dhcpv4SrvTest::TearDown();
  353. // The base class however, doesn't re-detect real interfaces.
  354. try {
  355. IfaceMgr::instance().clearIfaces();
  356. IfaceMgr::instance().detectIfaces();
  357. } catch (const Exception& ex) {
  358. FAIL() << "Failed to restore interface configuration after using"
  359. " fake interfaces";
  360. }
  361. }
  362. Iface
  363. Dhcpv4SrvFakeIfaceTest::createIface(const std::string& name, const int ifindex,
  364. const std::string& addr) {
  365. Iface iface(name, ifindex);
  366. iface.addAddress(IOAddress(addr));
  367. if (name == "lo") {
  368. iface.flag_loopback_ = true;
  369. }
  370. iface.flag_up_ = true;
  371. iface.flag_running_ = true;
  372. iface.inactive4_ = false;
  373. return (iface);
  374. }
  375. void
  376. Dhcpv4SrvFakeIfaceTest::testDiscoverRequest(const uint8_t msg_type) {
  377. // Create an instance of the tested class.
  378. boost::scoped_ptr<NakedDhcpv4Srv> srv(new NakedDhcpv4Srv(0));
  379. // Initialize the source HW address.
  380. vector<uint8_t> mac(6);
  381. for (int i = 0; i < 6; ++i) {
  382. mac[i] = i * 10;
  383. }
  384. // Initialized the destination HW address.
  385. vector<uint8_t> dst_mac(6);
  386. for (int i = 0; i < 6; ++i) {
  387. dst_mac[i] = i * 20;
  388. }
  389. // Create a DHCP message. It will be used to simulate the
  390. // incoming message.
  391. boost::shared_ptr<Pkt4> req(new Pkt4(msg_type, 1234));
  392. // Create a response message. It will hold a reponse packet.
  393. // Initially, set it to NULL.
  394. boost::shared_ptr<Pkt4> rsp;
  395. // Set the name of the interface on which packet is received.
  396. req->setIface("eth0");
  397. // Set the interface index. It is just a dummy value and will
  398. // not be interpreted.
  399. req->setIndex(17);
  400. // Set the target HW address. This value is normally used to
  401. // construct the data link layer header.
  402. req->setRemoteHWAddr(1, 6, dst_mac);
  403. // Set the HW address. This value is set on DHCP level (in chaddr).
  404. req->setHWAddr(1, 6, mac);
  405. // Set local HW address. It is used to construct the data link layer
  406. // header.
  407. req->setLocalHWAddr(1, 6, mac);
  408. // Set target IP address.
  409. req->setRemoteAddr(IOAddress("192.0.2.55"));
  410. // Set relay address.
  411. req->setGiaddr(IOAddress("192.0.2.10"));
  412. // We are going to test that certain options are returned
  413. // in the response message when requested using 'Parameter
  414. // Request List' option. Let's configure those options that
  415. // are returned when requested.
  416. configureRequestedOptions();
  417. // Create a copy of the original packet by parsing its wire format.
  418. // This simulates the real life scenario when we process the packet
  419. // which was parsed from its wire format.
  420. Pkt4Ptr received;
  421. ASSERT_TRUE(createPacketFromBuffer(req, received));
  422. // Set interface. It is required for the server to generate server id.
  423. received->setIface("eth0");
  424. if (msg_type == DHCPDISCOVER) {
  425. ASSERT_NO_THROW(
  426. rsp = srv->processDiscover(received);
  427. );
  428. // Should return OFFER
  429. ASSERT_TRUE(rsp);
  430. EXPECT_EQ(DHCPOFFER, rsp->getType());
  431. } else {
  432. ASSERT_NO_THROW(rsp = srv->processRequest(received));
  433. // Should return ACK
  434. ASSERT_TRUE(rsp);
  435. EXPECT_EQ(DHCPACK, rsp->getType());
  436. }
  437. messageCheck(received, rsp);
  438. // Basic options should be present when we got the lease.
  439. EXPECT_TRUE(basicOptionsPresent(rsp));
  440. // We did not request any options so these should not be present
  441. // in the RSP.
  442. EXPECT_TRUE(noRequestedOptions(rsp));
  443. // Repeat the test but request some options.
  444. // Add 'Parameter Request List' option.
  445. addPrlOption(req);
  446. ASSERT_TRUE(createPacketFromBuffer(req, received));
  447. ASSERT_TRUE(received->getOption(DHO_DHCP_PARAMETER_REQUEST_LIST));
  448. // Set interface. It is required for the server to generate server id.
  449. received->setIface("eth0");
  450. if (msg_type == DHCPDISCOVER) {
  451. ASSERT_NO_THROW(rsp = srv->processDiscover(received));
  452. // Should return non-NULL packet.
  453. ASSERT_TRUE(rsp);
  454. EXPECT_EQ(DHCPOFFER, rsp->getType());
  455. } else {
  456. ASSERT_NO_THROW(rsp = srv->processRequest(received));
  457. // Should return non-NULL packet.
  458. ASSERT_TRUE(rsp);
  459. EXPECT_EQ(DHCPACK, rsp->getType());
  460. }
  461. // Check that the requested options are returned.
  462. EXPECT_TRUE(basicOptionsPresent(rsp));
  463. EXPECT_TRUE(requestedOptionsPresent(rsp));
  464. // The following part of the test will test that the NAK is sent when
  465. // there is no address pool configured. In the same time, we expect
  466. // that the requested options are not included in NAK message, but that
  467. // they are only included when yiaddr is set to non-zero value.
  468. ASSERT_NO_THROW(subnet_->delPools(Lease::TYPE_V4));
  469. // There has been a lease allocated for the particular client. So,
  470. // even though we deleted the subnet, the client would get the
  471. // existing lease (not a NAK). Therefore, we have to change the chaddr
  472. // in the packet so as the existing lease is not returned.
  473. req->setHWAddr(1, 6, std::vector<uint8_t>(2, 6));
  474. ASSERT_TRUE(createPacketFromBuffer(req, received));
  475. ASSERT_TRUE(received->getOption(DHO_DHCP_PARAMETER_REQUEST_LIST));
  476. // Set interface. It is required for the server to generate server id.
  477. received->setIface("eth0");
  478. if (msg_type == DHCPDISCOVER) {
  479. ASSERT_NO_THROW(rsp = srv->processDiscover(received));
  480. // Should return non-NULL packet.
  481. ASSERT_TRUE(rsp);
  482. } else {
  483. ASSERT_NO_THROW(rsp = srv->processRequest(received));
  484. // Should return non-NULL packet.
  485. ASSERT_TRUE(rsp);
  486. }
  487. // We should get the NAK packet with yiaddr set to 0.
  488. EXPECT_EQ(DHCPNAK, rsp->getType());
  489. ASSERT_EQ("0.0.0.0", rsp->getYiaddr().toText());
  490. // Make sure that none of the requested options is returned in NAK.
  491. // Also options such as Routers or Subnet Mask should not be there,
  492. // because lease hasn't been acquired.
  493. EXPECT_TRUE(noRequestedOptions(rsp));
  494. EXPECT_TRUE(noBasicOptions(rsp));
  495. }
  496. }; // end of isc::dhcp::test namespace
  497. }; // end of isc::dhcp namespace
  498. }; // end of isc namespace