dhcp4_test_utils.h 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  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 <sstream>
  16. #include <asiolink/io_address.h>
  17. #include <dhcp/dhcp4.h>
  18. #include <dhcp/iface_mgr.h>
  19. #include <dhcp/option.h>
  20. #include <dhcp/option4_addrlst.h>
  21. #include <dhcp/option_custom.h>
  22. #include <dhcp/option_int_array.h>
  23. #include <dhcp/pkt_filter.h>
  24. #include <dhcp/pkt_filter_inet.h>
  25. #include <dhcp4/config_parser.h>
  26. #include <dhcp4/dhcp4_srv.h>
  27. #include <dhcpsrv/cfgmgr.h>
  28. #include <dhcpsrv/lease_mgr.h>
  29. #include <dhcpsrv/lease_mgr_factory.h>
  30. #include <gtest/gtest.h>
  31. #include <boost/scoped_ptr.hpp>
  32. #include <fstream>
  33. #include <iostream>
  34. #include <arpa/inet.h>
  35. namespace isc {
  36. namespace test {
  37. using namespace isc;
  38. using namespace isc::dhcp;
  39. class NakedDhcpv4Srv: public Dhcpv4Srv {
  40. // "Naked" DHCPv4 server, exposes internal fields
  41. public:
  42. /// @brief Constructor.
  43. ///
  44. /// This constructor disables default modes of operation used by the
  45. /// Dhcpv4Srv class:
  46. /// - Send/receive broadcast messages through sockets on interfaces
  47. /// which support broadcast traffic.
  48. /// - Direct DHCPv4 traffic - communication with clients which do not
  49. /// have IP address assigned yet.
  50. ///
  51. /// Enabling these modes requires root privilges so they must be
  52. /// disabled for unit testing.
  53. ///
  54. /// Note, that disabling broadcast options on sockets does not impact
  55. /// the operation of these tests because they use local loopback
  56. /// interface which doesn't have broadcast capability anyway. It rather
  57. /// prevents setting broadcast options on other (broadcast capable)
  58. /// sockets which are opened on other interfaces in Dhcpv4Srv constructor.
  59. ///
  60. /// The Direct DHCPv4 Traffic capability can be disabled here because
  61. /// it is tested with PktFilterLPFTest unittest. The tests which belong
  62. /// to PktFilterLPFTest can be enabled on demand when root privileges can
  63. /// be guaranteed.
  64. ///
  65. /// @param port port number to listen on; the default value 0 indicates
  66. /// that sockets should not be opened.
  67. NakedDhcpv4Srv(uint16_t port = 0)
  68. : Dhcpv4Srv(port, "type=memfile", false, false) {
  69. }
  70. /// @brief fakes packet reception
  71. /// @param timeout ignored
  72. ///
  73. /// The method receives all packets queued in receive queue, one after
  74. /// another. Once the queue is empty, it initiates the shutdown procedure.
  75. ///
  76. /// See fake_received_ field for description
  77. virtual Pkt4Ptr receivePacket(int /*timeout*/) {
  78. // If there is anything prepared as fake incoming traffic, use it
  79. if (!fake_received_.empty()) {
  80. Pkt4Ptr pkt = fake_received_.front();
  81. fake_received_.pop_front();
  82. return (pkt);
  83. }
  84. // If not, just trigger shutdown and return immediately
  85. shutdown();
  86. return (Pkt4Ptr());
  87. }
  88. /// @brief fake packet sending
  89. ///
  90. /// Pretend to send a packet, but instead just store it in fake_send_ list
  91. /// where test can later inspect server's response.
  92. virtual void sendPacket(const Pkt4Ptr& pkt) {
  93. fake_sent_.push_back(pkt);
  94. }
  95. /// @brief adds a packet to fake receive queue
  96. ///
  97. /// See fake_received_ field for description
  98. void fakeReceive(const Pkt4Ptr& pkt) {
  99. fake_received_.push_back(pkt);
  100. }
  101. virtual ~NakedDhcpv4Srv() {
  102. }
  103. /// @brief packets we pretend to receive
  104. ///
  105. /// Instead of setting up sockets on interfaces that change between OSes, it
  106. /// is much easier to fake packet reception. This is a list of packets that
  107. /// we pretend to have received. You can schedule new packets to be received
  108. /// using fakeReceive() and NakedDhcpv4Srv::receivePacket() methods.
  109. std::list<Pkt4Ptr> fake_received_;
  110. std::list<Pkt4Ptr> fake_sent_;
  111. using Dhcpv4Srv::adjustRemoteAddr;
  112. using Dhcpv4Srv::processDiscover;
  113. using Dhcpv4Srv::processRequest;
  114. using Dhcpv4Srv::processRelease;
  115. using Dhcpv4Srv::processDecline;
  116. using Dhcpv4Srv::processInform;
  117. using Dhcpv4Srv::getServerID;
  118. using Dhcpv4Srv::loadServerID;
  119. using Dhcpv4Srv::generateServerID;
  120. using Dhcpv4Srv::writeServerID;
  121. using Dhcpv4Srv::sanityCheck;
  122. using Dhcpv4Srv::srvidToString;
  123. };
  124. /// @brief Dummy Packet Filtering class.
  125. ///
  126. /// This class reports capability to respond directly to the client which
  127. /// doesn't have address configured yet.
  128. ///
  129. /// All packet and socket handling functions do nothing because they are not
  130. /// used in unit tests.
  131. class PktFilterTest : public PktFilter {
  132. public:
  133. /// @brief Reports 'direct response' capability.
  134. ///
  135. /// @return always true.
  136. virtual bool isDirectResponseSupported() const {
  137. return (true);
  138. }
  139. /// Does nothing.
  140. virtual int openSocket(const Iface&, const isc::asiolink::IOAddress&,
  141. const uint16_t, const bool, const bool) {
  142. return (0);
  143. }
  144. /// Does nothing.
  145. virtual Pkt4Ptr receive(const Iface&, const SocketInfo&) {
  146. return Pkt4Ptr();
  147. }
  148. /// Does nothing.
  149. virtual int send(const Iface&, uint16_t, const Pkt4Ptr&) {
  150. return (0);
  151. }
  152. };
  153. static const char* SRVID_FILE = "server-id-test.txt";
  154. class Dhcpv4SrvTest : public ::testing::Test {
  155. public:
  156. /// @brief Constructor
  157. ///
  158. /// Initializes common objects used in many tests.
  159. /// Also sets up initial configuration in CfgMgr.
  160. Dhcpv4SrvTest() :
  161. rcode_(-1)
  162. {
  163. subnet_ = Subnet4Ptr(new Subnet4(isc::asiolink::IOAddress("192.0.2.0"),
  164. 24, 1000, 2000, 3000));
  165. pool_ = Pool4Ptr(new Pool4(isc::asiolink::IOAddress("192.0.2.100"),
  166. isc::asiolink::IOAddress("192.0.2.110")));
  167. subnet_->addPool(pool_);
  168. CfgMgr::instance().deleteSubnets4();
  169. CfgMgr::instance().addSubnet4(subnet_);
  170. // Add Router option.
  171. Option4AddrLstPtr opt_routers(new Option4AddrLst(DHO_ROUTERS));
  172. opt_routers->setAddress(isc::asiolink::IOAddress("192.0.2.2"));
  173. subnet_->addOption(opt_routers, false, "dhcp4");
  174. // it's ok if that fails. There should not be such a file anyway
  175. unlink(SRVID_FILE);
  176. const IfaceMgr::IfaceCollection& ifaces = IfaceMgr::instance().getIfaces();
  177. // There must be some interface detected
  178. if (ifaces.empty()) {
  179. // We can't use ASSERT in constructor
  180. ADD_FAILURE() << "No interfaces detected.";
  181. }
  182. valid_iface_ = ifaces.begin()->getName();
  183. }
  184. virtual ~Dhcpv4SrvTest() {
  185. }
  186. /// @brief Add 'Parameter Request List' option to the packet.
  187. ///
  188. /// This function PRL option comprising the following option codes:
  189. /// - 5 - Name Server
  190. /// - 15 - Domain Name
  191. /// - 7 - Log Server
  192. /// - 8 - Quotes Server
  193. /// - 9 - LPR Server
  194. ///
  195. /// @param pkt packet to add PRL option to.
  196. void addPrlOption(Pkt4Ptr& pkt) {
  197. OptionUint8ArrayPtr option_prl =
  198. OptionUint8ArrayPtr(new OptionUint8Array(Option::V4,
  199. DHO_DHCP_PARAMETER_REQUEST_LIST));
  200. // Let's request options that have been configured for the subnet.
  201. option_prl->addValue(DHO_DOMAIN_NAME_SERVERS);
  202. option_prl->addValue(DHO_DOMAIN_NAME);
  203. option_prl->addValue(DHO_LOG_SERVERS);
  204. option_prl->addValue(DHO_COOKIE_SERVERS);
  205. // Let's also request the option that hasn't been configured. In such
  206. // case server should ignore request for this particular option.
  207. option_prl->addValue(DHO_LPR_SERVERS);
  208. // And add 'Parameter Request List' option into the DISCOVER packet.
  209. pkt->addOption(option_prl);
  210. }
  211. /// @brief Configures options being requested in the PRL option.
  212. ///
  213. /// The lpr-servers option is NOT configured here although it is
  214. /// added to the 'Parameter Request List' option in the
  215. /// \ref addPrlOption. When requested option is not configured
  216. /// the server should not return it in its response. The goal
  217. /// of not configuring the requested option is to verify that
  218. /// the server will not return it.
  219. void configureRequestedOptions() {
  220. // dns-servers
  221. Option4AddrLstPtr
  222. option_dns_servers(new Option4AddrLst(DHO_DOMAIN_NAME_SERVERS));
  223. option_dns_servers->addAddress(isc::asiolink::IOAddress("192.0.2.1"));
  224. option_dns_servers->addAddress(isc::asiolink::IOAddress("192.0.2.100"));
  225. ASSERT_NO_THROW(subnet_->addOption(option_dns_servers, false, "dhcp4"));
  226. // domain-name
  227. OptionDefinition def("domain-name", DHO_DOMAIN_NAME, OPT_FQDN_TYPE);
  228. OptionCustomPtr option_domain_name(new OptionCustom(def, Option::V4));
  229. option_domain_name->writeFqdn("example.com");
  230. subnet_->addOption(option_domain_name, false, "dhcp4");
  231. // log-servers
  232. Option4AddrLstPtr option_log_servers(new Option4AddrLst(DHO_LOG_SERVERS));
  233. option_log_servers->addAddress(isc::asiolink::IOAddress("192.0.2.2"));
  234. option_log_servers->addAddress(isc::asiolink::IOAddress("192.0.2.10"));
  235. ASSERT_NO_THROW(subnet_->addOption(option_log_servers, false, "dhcp4"));
  236. // cookie-servers
  237. Option4AddrLstPtr option_cookie_servers(new Option4AddrLst(DHO_COOKIE_SERVERS));
  238. option_cookie_servers->addAddress(isc::asiolink::IOAddress("192.0.2.1"));
  239. ASSERT_NO_THROW(subnet_->addOption(option_cookie_servers, false,
  240. "dhcp4"));
  241. }
  242. /// @brief checks that the response matches request
  243. /// @param q query (client's message)
  244. /// @param a answer (server's message)
  245. void messageCheck(const Pkt4Ptr& q, const Pkt4Ptr& a) {
  246. ASSERT_TRUE(q);
  247. ASSERT_TRUE(a);
  248. EXPECT_EQ(q->getHops(), a->getHops());
  249. EXPECT_EQ(q->getIface(), a->getIface());
  250. EXPECT_EQ(q->getIndex(), a->getIndex());
  251. EXPECT_EQ(q->getGiaddr(), a->getGiaddr());
  252. // When processing an incoming packet the remote address
  253. // is copied as a src address, and the source address is
  254. // copied as a remote address to the response.
  255. EXPECT_TRUE(q->getLocalHWAddr() == a->getLocalHWAddr());
  256. EXPECT_TRUE(q->getRemoteHWAddr() == a->getRemoteHWAddr());
  257. // Check that bare minimum of required options are there.
  258. // We don't check options requested by a client. Those
  259. // are checked elsewhere.
  260. EXPECT_TRUE(a->getOption(DHO_SUBNET_MASK));
  261. EXPECT_TRUE(a->getOption(DHO_ROUTERS));
  262. EXPECT_TRUE(a->getOption(DHO_DHCP_SERVER_IDENTIFIER));
  263. EXPECT_TRUE(a->getOption(DHO_DHCP_LEASE_TIME));
  264. EXPECT_TRUE(a->getOption(DHO_SUBNET_MASK));
  265. EXPECT_TRUE(a->getOption(DHO_DOMAIN_NAME));
  266. EXPECT_TRUE(a->getOption(DHO_DOMAIN_NAME_SERVERS));
  267. // Check that something is offered
  268. EXPECT_TRUE(a->getYiaddr().toText() != "0.0.0.0");
  269. }
  270. /// @brief Check that requested options are present.
  271. ///
  272. /// @param pkt packet to be checked.
  273. void optionsCheck(const Pkt4Ptr& pkt) {
  274. // Check that the requested and configured options are returned
  275. // in the ACK message.
  276. EXPECT_TRUE(pkt->getOption(DHO_DOMAIN_NAME))
  277. << "domain-name not present in the response";
  278. EXPECT_TRUE(pkt->getOption(DHO_DOMAIN_NAME_SERVERS))
  279. << "dns-servers not present in the response";
  280. EXPECT_TRUE(pkt->getOption(DHO_LOG_SERVERS))
  281. << "log-servers not present in the response";
  282. EXPECT_TRUE(pkt->getOption(DHO_COOKIE_SERVERS))
  283. << "cookie-servers not present in the response";
  284. // Check that the requested but not configured options are not
  285. // returned in the ACK message.
  286. EXPECT_FALSE(pkt->getOption(DHO_LPR_SERVERS))
  287. << "domain-name present in the response but it is"
  288. << " expected not to be present";
  289. }
  290. /// @brief generates client-id option
  291. ///
  292. /// Generate client-id option of specified length
  293. /// Ids with different lengths are sufficent to generate
  294. /// unique ids. If more fine grained control is required,
  295. /// tests generate client-ids on their own.
  296. /// Sets client_id_ field.
  297. /// @param size size of the client-id to be generated
  298. OptionPtr generateClientId(size_t size = 4) {
  299. OptionBuffer clnt_id(size);
  300. for (int i = 0; i < size; i++) {
  301. clnt_id[i] = 100 + i;
  302. }
  303. client_id_ = ClientIdPtr(new ClientId(clnt_id));
  304. return (OptionPtr(new Option(Option::V4, DHO_DHCP_CLIENT_IDENTIFIER,
  305. clnt_id.begin(),
  306. clnt_id.begin() + size)));
  307. }
  308. /// @brief generate hardware address
  309. ///
  310. /// @param size size of the generated MAC address
  311. /// @param pointer to Hardware Address object
  312. HWAddrPtr generateHWAddr(size_t size = 6) {
  313. const uint8_t hw_type = 123; // Just a fake number (typically 6=HTYPE_ETHER, see dhcp4.h)
  314. OptionBuffer mac(size);
  315. for (int i = 0; i < size; ++i) {
  316. mac[i] = 50 + i;
  317. }
  318. return (HWAddrPtr(new HWAddr(mac, hw_type)));
  319. }
  320. /// Check that address was returned from proper range, that its lease
  321. /// lifetime is correct, that T1 and T2 are returned properly
  322. /// @param rsp response to be checked
  323. /// @param subnet subnet that should be used to verify assigned address
  324. /// and options
  325. /// @param t1_mandatory is T1 mandatory?
  326. /// @param t2_mandatory is T2 mandatory?
  327. void checkAddressParams(const Pkt4Ptr& rsp, const SubnetPtr subnet,
  328. bool t1_mandatory = false,
  329. bool t2_mandatory = false) {
  330. // Technically inPool implies inRange, but let's be on the safe
  331. // side and check both.
  332. EXPECT_TRUE(subnet->inRange(rsp->getYiaddr()));
  333. EXPECT_TRUE(subnet->inPool(rsp->getYiaddr()));
  334. // Check lease time
  335. OptionPtr opt = rsp->getOption(DHO_DHCP_LEASE_TIME);
  336. if (!opt) {
  337. ADD_FAILURE() << "Lease time option missing in response";
  338. } else {
  339. EXPECT_EQ(opt->getUint32(), subnet->getValid());
  340. }
  341. // Check T1 timer
  342. opt = rsp->getOption(DHO_DHCP_RENEWAL_TIME);
  343. if (opt) {
  344. EXPECT_EQ(opt->getUint32(), subnet->getT1());
  345. } else {
  346. if (t1_mandatory) {
  347. ADD_FAILURE() << "Required T1 option missing";
  348. }
  349. }
  350. // Check T2 timer
  351. opt = rsp->getOption(DHO_DHCP_REBINDING_TIME);
  352. if (opt) {
  353. EXPECT_EQ(opt->getUint32(), subnet->getT2());
  354. } else {
  355. if (t2_mandatory) {
  356. ADD_FAILURE() << "Required T2 option missing";
  357. }
  358. }
  359. }
  360. /// @brief Basic checks for generated response (message type and trans-id).
  361. ///
  362. /// @param rsp response packet to be validated
  363. /// @param expected_message_type expected message type
  364. /// @param expected_transid expected transaction-id
  365. void checkResponse(const Pkt4Ptr& rsp, uint8_t expected_message_type,
  366. uint32_t expected_transid) {
  367. ASSERT_TRUE(rsp);
  368. EXPECT_EQ(expected_message_type, rsp->getType());
  369. EXPECT_EQ(expected_transid, rsp->getTransid());
  370. }
  371. /// @brief Checks if the lease sent to client is present in the database
  372. ///
  373. /// @param rsp response packet to be validated
  374. /// @param client_id expected client-identifier (or NULL)
  375. /// @param HWAddr expected hardware address (not used now)
  376. /// @param expected_addr expected address
  377. Lease4Ptr checkLease(const Pkt4Ptr& rsp, const OptionPtr& client_id,
  378. const HWAddrPtr&,
  379. const isc::asiolink::IOAddress& expected_addr) {
  380. ClientIdPtr id;
  381. if (client_id) {
  382. OptionBuffer data = client_id->getData();
  383. id.reset(new ClientId(data));
  384. }
  385. Lease4Ptr lease = LeaseMgrFactory::instance().getLease4(expected_addr);
  386. if (!lease) {
  387. std::cout << "Lease for " << expected_addr.toText()
  388. << " not found in the database backend.";
  389. return (Lease4Ptr());
  390. }
  391. EXPECT_EQ(rsp->getYiaddr().toText(), expected_addr.toText());
  392. EXPECT_EQ(expected_addr.toText(), lease->addr_.toText());
  393. if (client_id) {
  394. EXPECT_TRUE(*lease->client_id_ == *id);
  395. }
  396. EXPECT_EQ(subnet_->getID(), lease->subnet_id_);
  397. return (lease);
  398. }
  399. /// @brief Checks if server response (OFFER, ACK, NAK) includes proper server-id
  400. /// @param rsp response packet to be validated
  401. /// @param expected_srvid expected value of server-id
  402. void checkServerId(const Pkt4Ptr& rsp, const OptionPtr& expected_srvid) {
  403. // Check that server included its server-id
  404. OptionPtr opt = rsp->getOption(DHO_DHCP_SERVER_IDENTIFIER);
  405. ASSERT_TRUE(opt);
  406. EXPECT_EQ(opt->getType(), expected_srvid->getType() );
  407. EXPECT_EQ(opt->len(), expected_srvid->len() );
  408. EXPECT_TRUE(opt->getData() == expected_srvid->getData());
  409. }
  410. /// @brief Checks if server response (OFFER, ACK, NAK) includes proper client-id
  411. /// @param rsp response packet to be validated
  412. /// @param expected_clientid expected value of client-id
  413. void checkClientId(const Pkt4Ptr& rsp, const OptionPtr& expected_clientid) {
  414. // check that server included our own client-id
  415. OptionPtr opt = rsp->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
  416. ASSERT_TRUE(opt);
  417. EXPECT_EQ(expected_clientid->getType(), opt->getType());
  418. EXPECT_EQ(expected_clientid->len(), opt->len());
  419. EXPECT_TRUE(expected_clientid->getData() == opt->getData());
  420. }
  421. /// @brief Tests if Discover or Request message is processed correctly
  422. ///
  423. /// @param msg_type DHCPDISCOVER or DHCPREQUEST
  424. void testDiscoverRequest(const uint8_t msg_type) {
  425. // Create an instance of the tested class.
  426. boost::scoped_ptr<NakedDhcpv4Srv> srv(new NakedDhcpv4Srv(0));
  427. // Initialize the source HW address.
  428. std::vector<uint8_t> mac(6);
  429. for (int i = 0; i < 6; ++i) {
  430. mac[i] = i * 10;
  431. }
  432. // Initialized the destination HW address.
  433. std::vector<uint8_t> dst_mac(6);
  434. for (int i = 0; i < 6; ++i) {
  435. dst_mac[i] = i * 20;
  436. }
  437. // Create a DHCP message. It will be used to simulate the
  438. // incoming message.
  439. boost::shared_ptr<Pkt4> req(new Pkt4(msg_type, 1234));
  440. // Create a response message. It will hold a reponse packet.
  441. // Initially, set it to NULL.
  442. boost::shared_ptr<Pkt4> rsp;
  443. // Set the name of the interface on which packet is received.
  444. req->setIface("eth0");
  445. // Set the interface index. It is just a dummy value and will
  446. // not be interpreted.
  447. req->setIndex(17);
  448. // Set the target HW address. This value is normally used to
  449. // construct the data link layer header.
  450. req->setRemoteHWAddr(1, 6, dst_mac);
  451. // Set the HW address. This value is set on DHCP level (in chaddr).
  452. req->setHWAddr(1, 6, mac);
  453. // Set local HW address. It is used to construct the data link layer
  454. // header.
  455. req->setLocalHWAddr(1, 6, mac);
  456. // Set target IP address.
  457. req->setRemoteAddr(isc::asiolink::IOAddress("192.0.2.55"));
  458. // Set relay address.
  459. req->setGiaddr(isc::asiolink::IOAddress("192.0.2.10"));
  460. // We are going to test that certain options are returned
  461. // in the response message when requested using 'Parameter
  462. // Request List' option. Let's configure those options that
  463. // are returned when requested.
  464. configureRequestedOptions();
  465. if (msg_type == DHCPDISCOVER) {
  466. ASSERT_NO_THROW(
  467. rsp = srv->processDiscover(req);
  468. );
  469. // Should return OFFER
  470. ASSERT_TRUE(rsp);
  471. EXPECT_EQ(DHCPOFFER, rsp->getType());
  472. } else {
  473. ASSERT_NO_THROW(
  474. rsp = srv->processRequest(req);
  475. );
  476. // Should return ACK
  477. ASSERT_TRUE(rsp);
  478. EXPECT_EQ(DHCPACK, rsp->getType());
  479. }
  480. messageCheck(req, rsp);
  481. // We did not request any options so these should not be present
  482. // in the RSP.
  483. EXPECT_FALSE(rsp->getOption(DHO_LOG_SERVERS));
  484. EXPECT_FALSE(rsp->getOption(DHO_COOKIE_SERVERS));
  485. EXPECT_FALSE(rsp->getOption(DHO_LPR_SERVERS));
  486. // Repeat the test but request some options.
  487. // Add 'Parameter Request List' option.
  488. addPrlOption(req);
  489. if (msg_type == DHCPDISCOVER) {
  490. ASSERT_NO_THROW(
  491. rsp = srv->processDiscover(req);
  492. );
  493. // Should return non-NULL packet.
  494. ASSERT_TRUE(rsp);
  495. EXPECT_EQ(DHCPOFFER, rsp->getType());
  496. } else {
  497. ASSERT_NO_THROW(
  498. rsp = srv->processRequest(req);
  499. );
  500. // Should return non-NULL packet.
  501. ASSERT_TRUE(rsp);
  502. EXPECT_EQ(DHCPACK, rsp->getType());
  503. }
  504. // Check that the requested options are returned.
  505. optionsCheck(rsp);
  506. }
  507. /// @brief This function cleans up after the test.
  508. virtual void TearDown() {
  509. CfgMgr::instance().deleteSubnets4();
  510. // Let's clean up if there is such a file.
  511. unlink(SRVID_FILE);
  512. // Close all open sockets.
  513. IfaceMgr::instance().closeSockets();
  514. // Some unit tests override the default packet filtering class, used
  515. // by the IfaceMgr. The dummy class, called PktFilterTest, reports the
  516. // capability to directly respond to the clients without IP address
  517. // assigned. This capability is not supported by the default packet
  518. // filtering class: PktFilterInet. Therefore setting the dummy class
  519. // allows to test scenarios, when server responds to the broadcast address
  520. // on client's request, despite having support for direct response.
  521. // The following call restores the use of original packet filtering class
  522. // after the test.
  523. try {
  524. IfaceMgr::instance().setPacketFilter(PktFilterPtr(new PktFilterInet()));
  525. } catch (const Exception& ex) {
  526. FAIL() << "Failed to restore the default (PktFilterInet) packet filtering"
  527. << " class after the test. Exception has been caught: "
  528. << ex.what();
  529. }
  530. }
  531. /// @brief A subnet used in most tests
  532. Subnet4Ptr subnet_;
  533. /// @brief A pool used in most tests
  534. Pool4Ptr pool_;
  535. /// @brief A client-id used in most tests
  536. ClientIdPtr client_id_;
  537. int rcode_;
  538. isc::data::ConstElementPtr comment_;
  539. // Name of a valid network interface
  540. std::string valid_iface_;
  541. };
  542. } // end of test namespace
  543. } // end of isc namespace