confirm_unittest.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  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/tests/iface_mgr_test_config.h>
  10. #include <dhcp6/json_config_parser.h>
  11. #include <dhcp6/tests/dhcp6_message_test.h>
  12. #include <dhcpsrv/utils.h>
  13. using namespace isc;
  14. using namespace isc::asiolink;
  15. using namespace isc::data;
  16. using namespace isc::dhcp;
  17. using namespace isc::dhcp::test;
  18. namespace {
  19. /// @brief Set of JSON configurations used throughout the Confirm tests.
  20. ///
  21. /// - Configuration 0:
  22. /// - only addresses (no prefixes)
  23. /// - 2 subnets with 2001:db8:1::/64 and 2001:db8:2::/64
  24. /// - 1 subnet for eth0 and 1 subnet for eth1
  25. ///
  26. /// - Configuration 1:
  27. /// - similar to Configuration 0
  28. /// - pools configured: 3000:1::/64 and 3000:2::/64
  29. /// - this specific configuration is used by tests using relays
  30. ///
  31. const char* CONFIRM_CONFIGS[] = {
  32. // Configuration 0
  33. "{ \"interfaces-config\": {"
  34. " \"interfaces\": [ \"*\" ]"
  35. "},"
  36. "\"preferred-lifetime\": 3000,"
  37. "\"rebind-timer\": 2000, "
  38. "\"renew-timer\": 1000, "
  39. "\"subnet6\": [ { "
  40. " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
  41. " \"subnet\": \"2001:db8:1::/48\", "
  42. " \"interface-id\": \"\","
  43. " \"interface\": \"eth0\""
  44. " },"
  45. " {"
  46. " \"pools\": [ { \"pool\": \"2001:db8:2::/64\" } ],"
  47. " \"subnet\": \"2001:db8:2::/48\", "
  48. " \"interface-id\": \"\","
  49. " \"interface\": \"eth1\""
  50. " } ],"
  51. "\"valid-lifetime\": 4000 }",
  52. // Configuration 1
  53. "{ \"interfaces-config\": {"
  54. " \"interfaces\": [ \"*\" ]"
  55. "},"
  56. "\"preferred-lifetime\": 3000,"
  57. "\"rebind-timer\": 2000, "
  58. "\"renew-timer\": 1000, "
  59. "\"subnet6\": [ { "
  60. " \"pools\": [ { \"pool\": \"3000:1::/64\" } ],"
  61. " \"subnet\": \"3000:1::/48\", "
  62. " \"interface-id\": \"\","
  63. " \"interface\": \"eth0\""
  64. " },"
  65. " {"
  66. " \"pools\": [ { \"pool\": \"3000:2::/64\" } ],"
  67. " \"subnet\": \"3000:2::/48\", "
  68. " \"interface-id\": \"\","
  69. " \"interface\": \"eth1\""
  70. " } ],"
  71. "\"valid-lifetime\": 4000 }"
  72. };
  73. /// @brief Test fixture class for testing Confirm..
  74. class ConfirmTest : public isc::dhcp::test::Dhcpv6MessageTest {
  75. public:
  76. /// @brief Constructor.
  77. ///
  78. /// Sets up fake interfaces.
  79. ConfirmTest()
  80. : Dhcpv6MessageTest() {
  81. }
  82. };
  83. // Test that client-id is mandatory and server-id forbidden for Confirm messages
  84. TEST_F(ConfirmTest, sanityCheck) {
  85. NakedDhcpv6Srv srv(0);
  86. // A message with no client-id should fail
  87. Pkt6Ptr confirm = Pkt6Ptr(new Pkt6(DHCPV6_CONFIRM, 1234));
  88. EXPECT_THROW(srv.processConfirm(confirm), RFCViolation);
  89. // A message with a single client-id should succeed
  90. OptionPtr clientid = generateClientId();
  91. confirm->addOption(clientid);
  92. EXPECT_NO_THROW(srv.processConfirm(confirm));
  93. // A message with server-id present should fail
  94. confirm->addOption(srv.getServerID());
  95. EXPECT_THROW(srv.processConfirm(confirm), RFCViolation);
  96. }
  97. // Test that directly connected client's Confirm message is processed and Reply
  98. // message is sent back. In this test case, the client sends Confirm for two
  99. // addresses that belong to the same IAID and are sent within the same IA_NA
  100. // option (RFC3315, section 18.2.2).
  101. TEST_F(ConfirmTest, directClientSameIAID) {
  102. Dhcp6Client client;
  103. // Configure client to request IA_NA.
  104. client.requestAddress();
  105. // Make 4-way exchange to get the lease.
  106. ASSERT_NO_FATAL_FAILURE(requestLease(CONFIRM_CONFIGS[0], 2, client));
  107. // Keep the client's lease for future reference.
  108. Lease6 lease_client1 = client.getLease(0);
  109. // Clone the lease and modify its address so as it is still in the range
  110. // of the subnet to which the first lease belongs. When the client sends
  111. // the Confirm it should include both addresses and the server should
  112. // send Success because both of these addresses are on-link, regardless
  113. // what the server has in the lease database.
  114. Lease6 lease_client2 = lease_client1;
  115. lease_client2.addr_ = bumpAddress(lease_client2.addr_);
  116. client.createLease(lease_client2);
  117. ASSERT_EQ(2, client.getLeaseNum());
  118. // Send Confirm message to the server.
  119. ASSERT_NO_THROW(client.doConfirm());
  120. // Client should have received a status code option and this option should
  121. // indicate the success.
  122. ASSERT_TRUE(client.receivedStatusCode());
  123. ASSERT_EQ(STATUS_Success, client.getStatusCode());
  124. ASSERT_EQ(2, client.getLeaseNum());
  125. lease_client2 = client.getLease(1);
  126. lease_client2.addr_ = bumpSubnet(lease_client2.addr_);
  127. client.createLease(lease_client2);
  128. // Send confirm to the server. This time, one of the leases contains the
  129. // address which doesn't belong to the configured subnet and the server
  130. // should respond with STATUS_NotOnLink.
  131. ASSERT_NO_THROW(client.doConfirm());
  132. ASSERT_TRUE(client.receivedStatusCode());
  133. ASSERT_EQ(STATUS_NotOnLink, client.getStatusCode());
  134. // Make sure that the server id has been included.
  135. EXPECT_TRUE(client.getContext().response_->getOption(D6O_SERVERID));
  136. }
  137. // Test that directly connected client's Confirm message is processed and Reply
  138. // message is sent back. In this test case, the client sends Confirm for two
  139. // addresses that belong to different IAIDs and are sent within the different
  140. // IA_NA options (RFC3315, section 18.2.2).
  141. TEST_F(ConfirmTest, directClientDifferentIAID) {
  142. Dhcp6Client client;
  143. // Configure client to request IA_NA.
  144. client.requestAddress();
  145. // Make 4-way exchange to get the lease.
  146. ASSERT_NO_FATAL_FAILURE(requestLease(CONFIRM_CONFIGS[0], 2, client));
  147. // Keep the client's lease for future reference.
  148. Lease6 lease_client1 = client.getLease(0);
  149. // Clone the lease and modify its address so as it is still in the range
  150. // of the subnet to which the first lease belongs. When the client sends
  151. // the Confirm it should include both addresses and the server should
  152. // send Success because both of these addresses are on-link, regardless
  153. // what the server has in the lease database.
  154. Lease6 lease_client2 = lease_client1;
  155. ++lease_client2.iaid_;
  156. lease_client2.addr_ = bumpAddress(lease_client2.addr_);
  157. client.createLease(lease_client2);
  158. ASSERT_EQ(2, client.getLeaseNum());
  159. // Send Confirm message to the server.
  160. ASSERT_NO_THROW(client.doConfirm());
  161. // Client should have received a status code option and this option should
  162. // indicate the success.
  163. ASSERT_TRUE(client.receivedStatusCode());
  164. ASSERT_EQ(STATUS_Success, client.getStatusCode());
  165. // Make sure that the server id and client id have been included.
  166. EXPECT_TRUE(client.getContext().response_->getOption(D6O_SERVERID));
  167. EXPECT_TRUE(client.getContext().response_->getOption(D6O_CLIENTID));
  168. ASSERT_EQ(2, client.getLeaseNum());
  169. lease_client2 = client.getLease(1);
  170. lease_client2.addr_ = bumpSubnet(lease_client2.addr_);
  171. client.createLease(lease_client2);
  172. // Send confirm to the server. This time, one of the leases contains the
  173. // address which doesn't belong to the configured subnet and the server
  174. // should respond with STATUS_NotOnLink.
  175. ASSERT_NO_THROW(client.doConfirm());
  176. ASSERT_TRUE(client.receivedStatusCode());
  177. ASSERT_EQ(STATUS_NotOnLink, client.getStatusCode());
  178. // Make sure that the server id have been included.
  179. EXPECT_TRUE(client.getContext().response_->getOption(D6O_SERVERID));
  180. EXPECT_TRUE(client.getContext().response_->getOption(D6O_CLIENTID));
  181. }
  182. // Test that relayed client's Confirm message is processed and Reply message
  183. // is sent back (RFC3315, section 18.2.2).
  184. TEST_F(ConfirmTest, relayedClient) {
  185. Dhcp6Client client;
  186. // Client to send relayed message.
  187. client.useRelay();
  188. // Configure client to request IA_NA.
  189. client.requestAddress();
  190. // Make 4-way exchange to get the lease.
  191. ASSERT_NO_FATAL_FAILURE(requestLease(CONFIRM_CONFIGS[1], 2, client));
  192. // Keep the client's lease for future reference.
  193. Lease6 lease_client1 = client.getLease(0);
  194. // Clone the lease and modify its address so as it is still in the range
  195. // of the subnet to which the first lease belongs. When the client sends
  196. // the Confirm it should include both addresses and the server should
  197. // send Success because both of these addresses are on-link, regardless
  198. // what the server has in the lease database.
  199. Lease6 lease_client2 = lease_client1;
  200. lease_client2.addr_ = bumpAddress(lease_client2.addr_);
  201. ++lease_client2.iaid_;
  202. client.createLease(lease_client2);
  203. // Send Confirm message to the server.
  204. ASSERT_NO_THROW(client.doConfirm());
  205. // Client should have received a status code option and this option should
  206. // indicate the success.
  207. ASSERT_TRUE(client.receivedStatusCode());
  208. ASSERT_EQ(STATUS_Success, client.getStatusCode());
  209. lease_client2 = client.getLease(1);
  210. lease_client2.addr_ = bumpSubnet(lease_client2.addr_);
  211. client.createLease(lease_client2);
  212. // Send confirm to the server. This time, one of the leases contains the
  213. // address which doesn't belong to the configured subnet and the server
  214. // should respond with STATUS_NotOnLink.
  215. ASSERT_NO_THROW(client.doConfirm());
  216. ASSERT_TRUE(client.receivedStatusCode());
  217. ASSERT_EQ(STATUS_NotOnLink, client.getStatusCode());
  218. // Make sure that the server id and client id have been included.
  219. EXPECT_TRUE(client.getContext().response_->getOption(D6O_SERVERID));
  220. EXPECT_TRUE(client.getContext().response_->getOption(D6O_CLIENTID));
  221. }
  222. // Test that the Confirm message without any addresses is discarded
  223. // (RFC3315, section 18.2.2).
  224. TEST_F(ConfirmTest, relayedClientNoAddress) {
  225. Dhcp6Client client;
  226. // Configure the server.
  227. configure(CONFIRM_CONFIGS[1], *client.getServer());
  228. // Make sure we ended-up having expected number of subnets configured.
  229. const Subnet6Collection* subnets =
  230. CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
  231. ASSERT_EQ(2, subnets->size());
  232. // Client to send relayed message.
  233. client.useRelay();
  234. // Send Confirm message to the server. This message will contain no
  235. // addresses because client has no leases.
  236. ASSERT_NO_THROW(client.doConfirm());
  237. EXPECT_FALSE(client.getContext().response_);
  238. }
  239. // This test checks that the server processes Confirm message correctly if
  240. // the subnet can't be selected for the client (RFC3315, section 18.2.2).
  241. TEST_F(ConfirmTest, relayedClientNoSubnet) {
  242. Dhcp6Client client;
  243. // Client to send relayed message.
  244. client.useRelay();
  245. // Configure client to request IA_NA.
  246. client.requestAddress();
  247. // Make 4-way exchange to get the lease.
  248. ASSERT_NO_FATAL_FAILURE(requestLease(CONFIRM_CONFIGS[1], 2, client));
  249. // Now that the client has a lease, let's remove any subnets to check
  250. // how the server would respond to the Confirm.
  251. ASSERT_NO_THROW(CfgMgr::instance().clear());
  252. // Send Confirm message to the server.
  253. ASSERT_NO_THROW(client.doConfirm());
  254. // Client should have received a status code option and this option should
  255. // indicate that the client is NotOnLink becuase subnet could not be
  256. // selected.
  257. ASSERT_TRUE(client.receivedStatusCode());
  258. ASSERT_EQ(STATUS_NotOnLink, client.getStatusCode());
  259. // Let's test another case that the client sends no addresses in the Confirm
  260. // message. The subnet can't be selected for that client as in the previous
  261. // case but this time the server must discard the client's message because
  262. // it contains no addresses (is invalid).
  263. // Set lifetimes to 0 so as the Confirm will ignore the specific address
  264. // and send an empty IA_NA.
  265. client.config_.leases_[0].preferred_lft_ = 0;
  266. client.config_.leases_[0].valid_lft_ = 0;
  267. ASSERT_NO_THROW(client.doConfirm());
  268. EXPECT_FALSE(client.getContext().response_);
  269. // Do similar test but this time remove the lease so as no IA_NA option
  270. // is sent.
  271. client.config_.clear();
  272. ASSERT_NO_THROW(client.doConfirm());
  273. EXPECT_FALSE(client.getContext().response_);
  274. }
  275. // This test checks that the relayed Confirm message is processed by the server
  276. // when sent to unicast address RFC3315, section 18.2.8).
  277. TEST_F(ConfirmTest, relayedUnicast) {
  278. Dhcp6Client client;
  279. // Client to send relayed message.
  280. client.useRelay();
  281. // Configure client to request IA_NA.
  282. client.requestAddress();
  283. // Make 4-way exchange to get the lease.
  284. ASSERT_NO_FATAL_FAILURE(requestLease(CONFIRM_CONFIGS[1], 2, client));
  285. // Make sure we have got the lease.
  286. ASSERT_GT(client.getLeaseNum(), 0);
  287. client.setDestAddress(IOAddress("2001:db8:1::1"));
  288. // Send Confirm message to the server.
  289. ASSERT_NO_THROW(client.doConfirm());
  290. // Client should have received a response.
  291. ASSERT_TRUE(client.getContext().response_);
  292. // Client should have received a status code option and this option should
  293. // indicate the success.
  294. ASSERT_TRUE(client.receivedStatusCode());
  295. ASSERT_EQ(STATUS_Success, client.getStatusCode());
  296. // Make sure that the server id and client id have been included.
  297. EXPECT_TRUE(client.getContext().response_->getOption(D6O_SERVERID));
  298. EXPECT_TRUE(client.getContext().response_->getOption(D6O_CLIENTID));
  299. }
  300. // This test checks that the Confirm message is discarded by the server if it
  301. // has been sent to unicast address (RFC3315, section 15).
  302. TEST_F(ConfirmTest, unicast) {
  303. Dhcp6Client client;
  304. // Configure client to request IA_NA.
  305. client.requestAddress();
  306. // Make 4-way exchange to get the lease.
  307. ASSERT_NO_FATAL_FAILURE(requestLease(CONFIRM_CONFIGS[0], 2, client));
  308. // Make sure the client has got the lease.
  309. ASSERT_GT(client.getLeaseNum(), 0);
  310. // Send Confirm message to the server to the unicast address.
  311. client.setDestAddress(IOAddress("2001:db8:1::1"));
  312. ASSERT_NO_THROW(client.doConfirm());
  313. // Mak sure that the server discarded client's Confirm message.
  314. EXPECT_FALSE(client.getContext().response_);
  315. }
  316. } // end of anonymous namespace