decline_unittest.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. // Copyright (C) 2014-2016 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 <cc/data.h>
  9. #include <dhcp/dhcp4.h>
  10. #include <dhcp/tests/iface_mgr_test_config.h>
  11. #include <dhcpsrv/cfgmgr.h>
  12. #include <dhcpsrv/subnet_id.h>
  13. #include <dhcp4/tests/dhcp4_test_utils.h>
  14. #include <dhcp4/tests/dhcp4_client.h>
  15. #include <stats/stats_mgr.h>
  16. #include <boost/shared_ptr.hpp>
  17. #include <sstream>
  18. using namespace isc;
  19. using namespace isc::asiolink;
  20. using namespace isc::data;
  21. using namespace isc::dhcp;
  22. using namespace isc::dhcp::test;
  23. using namespace isc::stats;
  24. namespace {
  25. /// @brief Set of JSON configurations used throughout the Decline tests.
  26. ///
  27. /// - Configuration 0:
  28. /// - Used for testing Decline message processing
  29. /// - 1 subnet: 10.0.0.0/24
  30. /// - 1 pool: 10.0.0.10-10.0.0.100
  31. /// - Router option present: 10.0.0.200 and 10.0.0.201
  32. const char* DECLINE_CONFIGS[] = {
  33. // Configuration 0
  34. "{ \"interfaces-config\": {"
  35. " \"interfaces\": [ \"*\" ]"
  36. "},"
  37. "\"valid-lifetime\": 600,"
  38. "\"subnet4\": [ { "
  39. " \"subnet\": \"10.0.0.0/24\", "
  40. " \"id\": 1,"
  41. " \"pools\": [ { \"pool\": \"10.0.0.10-10.0.0.100\" } ],"
  42. " \"option-data\": [ {"
  43. " \"name\": \"routers\","
  44. " \"data\": \"10.0.0.200,10.0.0.201\""
  45. " } ]"
  46. " } ]"
  47. "}"
  48. };
  49. };
  50. namespace isc {
  51. namespace dhcp {
  52. namespace test {
  53. void
  54. Dhcpv4SrvTest::acquireLease(Dhcp4Client& client) {
  55. // Perform 4-way exchange with the server but to not request any
  56. // specific address in the DHCPDISCOVER message.
  57. ASSERT_NO_THROW(client.doDORA());
  58. // Make sure that the server responded.
  59. ASSERT_TRUE(client.getContext().response_);
  60. Pkt4Ptr resp = client.getContext().response_;
  61. // Make sure that the server has responded with DHCPACK.
  62. ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
  63. // Response must not be relayed.
  64. EXPECT_FALSE(resp->isRelayed());
  65. // Make sure that the server id is present.
  66. EXPECT_EQ("10.0.0.1", client.config_.serverid_.toText());
  67. // Make sure that the client has got the lease with the requested address.
  68. ASSERT_NE(client.config_.lease_.addr_.toText(), "0.0.0.0");
  69. Lease4Ptr lease = LeaseMgrFactory::instance().getLease4(client.config_.lease_.addr_);
  70. ASSERT_TRUE(lease);
  71. }
  72. void
  73. Dhcpv4SrvTest::acquireAndDecline(Dhcp4Client& client,
  74. const std::string& hw_address_1,
  75. const std::string& client_id_1,
  76. const std::string& hw_address_2,
  77. const std::string& client_id_2,
  78. ExpectedResult expected_result) {
  79. // Set this global statistic explicitly to zero.
  80. isc::stats::StatsMgr::instance().setValue("declined-addresses",
  81. static_cast<int64_t>(0));
  82. // Ok, do the normal lease acquisition.
  83. CfgMgr::instance().clear();
  84. // Configure DHCP server.
  85. configure(DECLINE_CONFIGS[0], *client.getServer());
  86. // Explicitly set the client id.
  87. client.includeClientId(client_id_1);
  88. // Explicitly set the HW address.
  89. client.setHWAddress(hw_address_1);
  90. // Perform 4-way exchange to obtain a new lease.
  91. acquireLease(client);
  92. // Let's get the subnet-id and generate statistics name out of it.
  93. const Subnet4Collection* subnets =
  94. CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getAll();
  95. ASSERT_EQ(1, subnets->size());
  96. std::stringstream name;
  97. name << "subnet[" << subnets->at(0)->getID() << "].declined-addresses";
  98. // Set the subnet specific statistic explicitly to zero.
  99. isc::stats::StatsMgr::instance().setValue(name.str(), static_cast<int64_t>(0));
  100. // Check the declined-addresses (subnet) statistic before the Decline operation.
  101. ObservationPtr declined_cnt = StatsMgr::instance().getObservation(name.str());
  102. ASSERT_TRUE(declined_cnt);
  103. uint64_t before = declined_cnt->getInteger().first;
  104. // Check the global declined-addresses statistic before the Decline.
  105. ObservationPtr declined_global = StatsMgr::instance()
  106. .getObservation("declined-addresses");
  107. ASSERT_TRUE(declined_global);
  108. uint64_t before_global = declined_cnt->getInteger().first;
  109. // Remember the acquired address.
  110. IOAddress declined_address = client.config_.lease_.addr_;
  111. // Explicitly set the client id for DHCPDECLINE.
  112. client.includeClientId(client_id_2);
  113. // Explicitly set the HW address for DHCPDECLINE.
  114. client.setHWAddress(hw_address_2);
  115. // Send the decline and make sure that the lease is removed from the
  116. // server.
  117. ASSERT_NO_THROW(client.doDecline());
  118. Lease4Ptr lease = LeaseMgrFactory::instance().getLease4(declined_address);
  119. declined_cnt = StatsMgr::instance().getObservation(name.str());
  120. ASSERT_TRUE(declined_cnt);
  121. uint64_t after = declined_cnt->getInteger().first;
  122. declined_global = StatsMgr::instance().getObservation("declined-addresses");
  123. ASSERT_TRUE(declined_global);
  124. uint64_t after_global = declined_global->getInteger().first;
  125. ASSERT_TRUE(lease);
  126. // We check if the decline process was successful by checking if the
  127. // lease is in the database and what is its state.
  128. if (expected_result == SHOULD_PASS) {
  129. EXPECT_EQ(Lease::STATE_DECLINED, lease->state_);
  130. // The decline succeeded, so the declined-addresses statistic should
  131. // be increased by one
  132. EXPECT_EQ(after, before + 1);
  133. EXPECT_EQ(after_global, before_global + 1);
  134. } else {
  135. // the decline was supposed, to be rejected.
  136. EXPECT_EQ(Lease::STATE_DEFAULT, lease->state_);
  137. // The decline failed, so the declined-addresses should be the same
  138. // as before
  139. EXPECT_EQ(before, after);
  140. EXPECT_EQ(before_global, after_global);
  141. }
  142. }
  143. }; // end of isc::dhcp::test namespace
  144. }; // end of isc::dhcp namespace
  145. }; // end of isc namespace
  146. namespace {
  147. /// @brief Test fixture class for testing DHCPDECLINE message handling.
  148. ///
  149. /// @todo This class is very similar to ReleaseTest. Maybe we could
  150. /// merge those two classes one day and use derived classes?
  151. class DeclineTest : public Dhcpv4SrvTest {
  152. public:
  153. /// @brief Constructor.
  154. ///
  155. /// Sets up fake interfaces.
  156. DeclineTest()
  157. : Dhcpv4SrvTest(),
  158. iface_mgr_test_config_(true) {
  159. IfaceMgr::instance().openSockets4();
  160. }
  161. /// @brief Interface Manager's fake configuration control.
  162. IfaceMgrTestConfig iface_mgr_test_config_;
  163. };
  164. // This test checks that the client can acquire and decline the lease.
  165. TEST_F(DeclineTest, declineNoIdentifierChange) {
  166. Dhcp4Client client(Dhcp4Client::SELECTING);
  167. acquireAndDecline(client, "01:02:03:04:05:06", "12:14",
  168. "01:02:03:04:05:06", "12:14",
  169. SHOULD_PASS);
  170. }
  171. // This test verifies the decline correctness in the following case:
  172. // - Client acquires new lease using HW address only
  173. // - Client sends the DHCPDECLINE with valid HW address and without
  174. // client identifier.
  175. // - The server successfully declines the lease.
  176. TEST_F(DeclineTest, declineHWAddressOnly) {
  177. Dhcp4Client client(Dhcp4Client::SELECTING);
  178. acquireAndDecline(client, "01:02:03:04:05:06", "",
  179. "01:02:03:04:05:06", "",
  180. SHOULD_PASS);
  181. }
  182. // This test verifies the decline correctness in the following case:
  183. // - Client acquires new lease using the client identifier and HW address
  184. // - Client sends the DHCPDECLINE with valid HW address but with no
  185. // client identifier.
  186. // - The server successfully declines the lease.
  187. TEST_F(DeclineTest, declineNoClientId) {
  188. Dhcp4Client client(Dhcp4Client::SELECTING);
  189. acquireAndDecline(client, "01:02:03:04:05:06", "12:14",
  190. "01:02:03:04:05:06", "",
  191. SHOULD_PASS);
  192. }
  193. // This test verifies the decline correctness in the following case:
  194. // - Client acquires new lease using HW address
  195. // - Client sends the DHCPDECLINE with valid HW address and some
  196. // client identifier.
  197. // - The server identifies the lease using HW address and declines
  198. // this lease.
  199. TEST_F(DeclineTest, declineNoClientId2) {
  200. Dhcp4Client client(Dhcp4Client::SELECTING);
  201. acquireAndDecline(client, "01:02:03:04:05:06", "",
  202. "01:02:03:04:05:06", "12:14",
  203. SHOULD_PASS);
  204. }
  205. // This test checks the server's behavior in the following case:
  206. // - Client acquires new lease using the client identifier and HW address
  207. // - Client sends the DHCPDECLINE with the valid HW address but with invalid
  208. // client identifier.
  209. // - The server should not remove the lease.
  210. TEST_F(DeclineTest, declineNonMatchingClientId) {
  211. Dhcp4Client client(Dhcp4Client::SELECTING);
  212. acquireAndDecline(client, "01:02:03:04:05:06", "12:14",
  213. "01:02:03:04:05:06", "12:15:16",
  214. SHOULD_FAIL);
  215. }
  216. // This test checks the server's behavior in the following case:
  217. // - Client acquires new lease using client identifier and HW address
  218. // - Client sends the DHCPDECLINE with the same client identifier but
  219. // different HW address.
  220. // - The server uses client identifier to find the client's lease and
  221. // declines it.
  222. TEST_F(DeclineTest, declineNonMatchingHWAddress) {
  223. Dhcp4Client client(Dhcp4Client::SELECTING);
  224. acquireAndDecline(client, "01:02:03:04:05:06", "12:14",
  225. "06:06:06:06:06:06", "12:14",
  226. SHOULD_PASS);
  227. }
  228. // This test checks the server's behavior in the following case:
  229. // - Client acquires new lease (address A).
  230. // - Client sends DHCPDECLINE with the requested IP address set to a different
  231. // address B than it has acquired from the server.
  232. // - Server determines that the client is trying to decline a
  233. // wrong address and will refuse to decline.
  234. TEST_F(DeclineTest, declineNonMatchingIPAddress) {
  235. Dhcp4Client client(Dhcp4Client::SELECTING);
  236. // Configure DHCP server.
  237. configure(DECLINE_CONFIGS[0], *client.getServer());
  238. // Perform 4-way exchange to obtain a new lease.
  239. acquireLease(client);
  240. // Remember the acquired address.
  241. IOAddress leased_address = client.config_.lease_.addr_;
  242. // Modify the client's address to force it to decline a different address
  243. // than it has obtained from the server.
  244. client.config_.lease_.addr_ = IOAddress(leased_address.toUint32() + 1);
  245. // Send DHCPDECLINE and make sure it was unsuccessful, i.e. the lease
  246. // remains in the database.
  247. ASSERT_NO_THROW(client.doDecline());
  248. Lease4Ptr lease = LeaseMgrFactory::instance().getLease4(leased_address);
  249. ASSERT_TRUE(lease);
  250. EXPECT_EQ(Lease::STATE_DEFAULT, lease->state_);
  251. }
  252. }; // end of anonymous namespace