dhcp4_test_utils.cc 22 KB

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