dhcp6_test_utils.cc 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832
  1. // Copyright (C) 2013-2015 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 <gtest/gtest.h>
  16. #include <dhcp/option6_status_code.h>
  17. #include <dhcp6/tests/dhcp6_test_utils.h>
  18. #include <dhcp6/json_config_parser.h>
  19. #include <dhcp/tests/pkt_captures.h>
  20. #include <util/pointer_util.h>
  21. #include <cc/command_interpreter.h>
  22. #include <stats/stats_mgr.h>
  23. #include <string.h>
  24. using namespace isc::data;
  25. using namespace isc::dhcp;
  26. using namespace isc::asiolink;
  27. using namespace isc::stats;
  28. namespace isc {
  29. namespace test {
  30. const char* NakedDhcpv6SrvTest::DUID_FILE = "server-id-test.txt";
  31. Dhcpv6SrvTest::Dhcpv6SrvTest()
  32. :srv_(0) {
  33. subnet_ = isc::dhcp::Subnet6Ptr
  34. (new isc::dhcp::Subnet6(isc::asiolink::IOAddress("2001:db8:1::"),
  35. 48, 1000, 2000, 3000, 4000));
  36. subnet_->setIface("eth0");
  37. pool_ = isc::dhcp::Pool6Ptr
  38. (new isc::dhcp::Pool6(isc::dhcp::Lease::TYPE_NA,
  39. isc::asiolink::IOAddress("2001:db8:1:1::"),
  40. 64));
  41. subnet_->addPool(pool_);
  42. isc::dhcp::CfgMgr::instance().clear();
  43. isc::dhcp::CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet_);
  44. isc::dhcp::CfgMgr::instance().commit();
  45. // configure PD pool
  46. pd_pool_ = isc::dhcp::Pool6Ptr
  47. (new isc::dhcp::Pool6(isc::dhcp::Lease::TYPE_PD,
  48. isc::asiolink::IOAddress("2001:db8:1:2::"),
  49. 64, 80));
  50. subnet_->addPool(pd_pool_);
  51. }
  52. // Checks that server response (ADVERTISE or REPLY) contains proper IA_NA option
  53. // It returns IAADDR option for each chaining with checkIAAddr method.
  54. boost::shared_ptr<Option6IAAddr>
  55. Dhcpv6SrvTest::checkIA_NA(const Pkt6Ptr& rsp, uint32_t expected_iaid,
  56. uint32_t expected_t1, uint32_t expected_t2) {
  57. OptionPtr tmp = rsp->getOption(D6O_IA_NA);
  58. // Can't use ASSERT_TRUE() in method that returns something
  59. if (!tmp) {
  60. ADD_FAILURE() << "IA_NA option not present in response";
  61. return (boost::shared_ptr<Option6IAAddr>());
  62. }
  63. boost::shared_ptr<Option6IA> ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
  64. if (!ia) {
  65. ADD_FAILURE() << "IA_NA cannot convert option ptr to Option6";
  66. return (boost::shared_ptr<Option6IAAddr>());
  67. }
  68. EXPECT_EQ(expected_iaid, ia->getIAID());
  69. EXPECT_EQ(expected_t1, ia->getT1());
  70. EXPECT_EQ(expected_t2, ia->getT2());
  71. tmp = ia->getOption(D6O_IAADDR);
  72. boost::shared_ptr<Option6IAAddr> addr = boost::dynamic_pointer_cast<Option6IAAddr>(tmp);
  73. return (addr);
  74. }
  75. boost::shared_ptr<Option6IAPrefix>
  76. Dhcpv6SrvTest::checkIA_PD(const Pkt6Ptr& rsp, uint32_t expected_iaid,
  77. uint32_t expected_t1, uint32_t expected_t2) {
  78. OptionPtr tmp = rsp->getOption(D6O_IA_PD);
  79. // Can't use ASSERT_TRUE() in method that returns something
  80. if (!tmp) {
  81. ADD_FAILURE() << "IA_PD option not present in response";
  82. return (boost::shared_ptr<Option6IAPrefix>());
  83. }
  84. boost::shared_ptr<Option6IA> ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
  85. if (!ia) {
  86. ADD_FAILURE() << "IA_PD cannot convert option ptr to Option6";
  87. return (boost::shared_ptr<Option6IAPrefix>());
  88. }
  89. EXPECT_EQ(expected_iaid, ia->getIAID());
  90. EXPECT_EQ(expected_t1, ia->getT1());
  91. EXPECT_EQ(expected_t2, ia->getT2());
  92. tmp = ia->getOption(D6O_IAPREFIX);
  93. boost::shared_ptr<Option6IAPrefix> addr = boost::dynamic_pointer_cast<Option6IAPrefix>(tmp);
  94. return (addr);
  95. }
  96. // Checks if the lease sent to client is present in the database
  97. // and is valid when checked against the configured subnet
  98. Lease6Ptr
  99. Dhcpv6SrvTest::checkLease(const DuidPtr& duid, const OptionPtr& ia_na,
  100. boost::shared_ptr<Option6IAAddr> addr) {
  101. boost::shared_ptr<Option6IA> ia = boost::dynamic_pointer_cast<Option6IA>(ia_na);
  102. Lease6Ptr lease = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
  103. addr->getAddress());
  104. if (!lease) {
  105. std::cout << "Lease for " << addr->getAddress()
  106. << " not found in the database backend.";
  107. return (Lease6Ptr());
  108. }
  109. EXPECT_EQ(addr->getAddress(), lease->addr_);
  110. EXPECT_TRUE(*lease->duid_ == *duid);
  111. EXPECT_EQ(ia->getIAID(), lease->iaid_);
  112. EXPECT_EQ(subnet_->getID(), lease->subnet_id_);
  113. return (lease);
  114. }
  115. isc::dhcp::Lease6Ptr
  116. Dhcpv6SrvTest::checkLease(const isc::dhcp::Lease6& lease) {
  117. Lease6Ptr lease_db = LeaseMgrFactory::instance().getLease6(lease.type_,
  118. lease.addr_);
  119. if (!lease_db) {
  120. return (Lease6Ptr());
  121. }
  122. EXPECT_TRUE(util::nullOrEqualValues(lease_db->hwaddr_, lease.hwaddr_));
  123. EXPECT_TRUE(util::nullOrEqualValues(lease_db->duid_, lease.duid_));
  124. return (lease_db);
  125. }
  126. Lease6Ptr
  127. Dhcpv6SrvTest::checkPdLease(const DuidPtr& duid, const OptionPtr& ia_pd,
  128. boost::shared_ptr<Option6IAPrefix> prefix){
  129. boost::shared_ptr<Option6IA> ia = boost::dynamic_pointer_cast<Option6IA>(ia_pd);
  130. Lease6Ptr lease = LeaseMgrFactory::instance().getLease6(Lease::TYPE_PD,
  131. prefix->getAddress());
  132. if (!lease) {
  133. std::cout << "PD lease for " << prefix->getAddress()
  134. << " not found in the database backend.";
  135. return (Lease6Ptr());
  136. }
  137. EXPECT_EQ(prefix->getAddress(), lease->addr_);
  138. EXPECT_TRUE(*lease->duid_ == *duid);
  139. EXPECT_EQ(ia->getIAID(), lease->iaid_);
  140. EXPECT_EQ(subnet_->getID(), lease->subnet_id_);
  141. return (lease);
  142. }
  143. Pkt6Ptr
  144. Dhcpv6SrvTest::createMessage(uint8_t message_type, Lease::Type lease_type,
  145. const IOAddress& addr, const uint8_t prefix_len,
  146. const uint32_t iaid) {
  147. Pkt6Ptr msg = Pkt6Ptr(new Pkt6(message_type, 1234));
  148. msg->setRemoteAddr(IOAddress("fe80::abcd"));
  149. msg->setIface("eth0");
  150. msg->addOption(createIA(lease_type, addr, prefix_len, iaid));
  151. return (msg);
  152. }
  153. Option6IAPtr
  154. Dhcpv6SrvTest::createIA(isc::dhcp::Lease::Type lease_type,
  155. const isc::asiolink::IOAddress& addr,
  156. const uint8_t prefix_len, const uint32_t iaid) {
  157. uint16_t code;
  158. OptionPtr subopt;
  159. switch (lease_type) {
  160. case Lease::TYPE_NA:
  161. code = D6O_IA_NA;
  162. subopt.reset(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
  163. break;
  164. case Lease::TYPE_PD:
  165. code = D6O_IA_PD;
  166. subopt.reset(new Option6IAPrefix(D6O_IAPREFIX, addr, prefix_len,
  167. 300, 500));
  168. break;
  169. default:
  170. isc_throw(BadValue, "Invalid lease type specified "
  171. << static_cast<int>(lease_type));
  172. }
  173. Option6IAPtr ia = generateIA(code, iaid, 1500, 3000);
  174. ia->addOption(subopt);
  175. return (ia);
  176. }
  177. void
  178. Dhcpv6SrvTest::testRenewBasic(Lease::Type type, const std::string& existing_addr,
  179. const std::string& renew_addr,
  180. const uint8_t prefix_len, bool insert_before_renew) {
  181. NakedDhcpv6Srv srv(0);
  182. const IOAddress existing(existing_addr);
  183. const IOAddress renew(renew_addr);
  184. const uint32_t iaid = 234;
  185. // Generate client-id also duid_
  186. OptionPtr clientid = generateClientId();
  187. // Check that the address we are about to use is indeed in pool
  188. ASSERT_TRUE(subnet_->inPool(type, existing));
  189. Lease6Ptr l;
  190. if (insert_before_renew) {
  191. // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
  192. // value on purpose. They should be updated during RENEW.
  193. Lease6Ptr lease(new Lease6(type, existing, duid_, iaid, 501, 502, 503, 504,
  194. subnet_->getID(), HWAddrPtr(), prefix_len));
  195. lease->cltt_ = 1234;
  196. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
  197. // Check that the lease is really in the database
  198. l = LeaseMgrFactory::instance().getLease6(type, existing);
  199. ASSERT_TRUE(l);
  200. // Check that T1, T2, preferred, valid and cltt really set and not using
  201. // previous (500, 501, etc.) values
  202. EXPECT_NE(l->t1_, subnet_->getT1());
  203. EXPECT_NE(l->t2_, subnet_->getT2());
  204. EXPECT_NE(l->preferred_lft_, subnet_->getPreferred());
  205. EXPECT_NE(l->valid_lft_, subnet_->getValid());
  206. EXPECT_NE(l->cltt_, time(NULL));
  207. }
  208. Pkt6Ptr req = createMessage(DHCPV6_RENEW, type, IOAddress(renew_addr),
  209. prefix_len, iaid);
  210. req->addOption(clientid);
  211. req->addOption(srv.getServerID());
  212. // Pass it to the server and hope for a REPLY
  213. Pkt6Ptr reply = srv.processRenew(req);
  214. // Check if we get response at all
  215. checkResponse(reply, DHCPV6_REPLY, 1234);
  216. // Check DUIDs
  217. checkServerId(reply, srv.getServerID());
  218. checkClientId(reply, clientid);
  219. switch (type) {
  220. case Lease::TYPE_NA: {
  221. // Check that IA_NA was returned and that there's an address included
  222. boost::shared_ptr<Option6IAAddr>
  223. addr_opt = checkIA_NA(reply, 234, subnet_->getT1(), subnet_->getT2());
  224. ASSERT_TRUE(addr_opt);
  225. // Check that we've got the address we requested
  226. checkIAAddr(addr_opt, renew, Lease::TYPE_NA);
  227. // Check that the lease is really in the database
  228. l = checkLease(duid_, reply->getOption(D6O_IA_NA), addr_opt);
  229. ASSERT_TRUE(l);
  230. break;
  231. }
  232. case Lease::TYPE_PD: {
  233. // Check that IA_NA was returned and that there's an address included
  234. boost::shared_ptr<Option6IAPrefix> prefix_opt
  235. = checkIA_PD(reply, 234, subnet_->getT1(), subnet_->getT2());
  236. ASSERT_TRUE(prefix_opt);
  237. // Check that we've got the address we requested
  238. checkIAAddr(prefix_opt, renew, Lease::TYPE_PD);
  239. EXPECT_EQ(pd_pool_->getLength(), prefix_opt->getLength());
  240. // Check that the lease is really in the database
  241. l = checkPdLease(duid_, reply->getOption(D6O_IA_PD), prefix_opt);
  242. ASSERT_TRUE(l);
  243. break;
  244. }
  245. default:
  246. isc_throw(BadValue, "Invalid lease type");
  247. }
  248. // Check that T1, T2, preferred, valid and cltt were really updated
  249. EXPECT_EQ(subnet_->getT1(), l->t1_);
  250. EXPECT_EQ(subnet_->getT2(), l->t2_);
  251. EXPECT_EQ(subnet_->getPreferred(), l->preferred_lft_);
  252. EXPECT_EQ(subnet_->getValid(), l->valid_lft_);
  253. // Checking for CLTT is a bit tricky if we want to avoid off by 1 errors
  254. int32_t cltt = static_cast<int32_t>(l->cltt_);
  255. int32_t expected = static_cast<int32_t>(time(NULL));
  256. // equality or difference by 1 between cltt and expected is ok.
  257. EXPECT_GE(1, abs(cltt - expected));
  258. EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease(renew_addr));
  259. }
  260. void
  261. Dhcpv6SrvTest::testRenewWrongIAID(Lease::Type type, const IOAddress& addr) {
  262. NakedDhcpv6Srv srv(0);
  263. const uint32_t transid = 1234;
  264. const uint32_t valid_iaid = 234;
  265. const uint32_t bogus_iaid = 456;
  266. uint8_t prefix_len = (type == Lease::TYPE_PD) ? 128 : pd_pool_->getLength();
  267. // Quick sanity check that the address we're about to use is ok
  268. ASSERT_TRUE(subnet_->inPool(type, addr));
  269. // Check that the lease is NOT in the database
  270. Lease6Ptr l = LeaseMgrFactory::instance().getLease6(type, addr);
  271. ASSERT_FALSE(l);
  272. // GenerateClientId() also sets duid_
  273. OptionPtr clientid = generateClientId();
  274. // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
  275. // value on purpose. They should be updated during RENEW.
  276. Lease6Ptr lease(new Lease6(type, addr, duid_, valid_iaid,
  277. 501, 502, 503, 504, subnet_->getID(),
  278. HWAddrPtr(), prefix_len));
  279. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
  280. // Pass it to the server and hope for a REPLY
  281. // Let's create a RENEW
  282. Pkt6Ptr renew = createMessage(DHCPV6_RENEW, type, IOAddress(addr), prefix_len,
  283. bogus_iaid);
  284. renew->addOption(clientid);
  285. renew->addOption(srv.getServerID());
  286. // The duid and address matches, but the iaid is different. The server could
  287. // respond with NoBinding. However, according to
  288. // draft-ietf-dhc-dhcpv6-stateful-issues-10, the server can also assign a
  289. // new address. And that's what we expect here.
  290. Pkt6Ptr reply = srv.processRenew(renew);
  291. checkResponse(reply, DHCPV6_REPLY, transid);
  292. // Check that IA_NA was returned and that there's an address included
  293. boost::shared_ptr<Option6IAAddr>
  294. addr_opt = checkIA_NA(reply, bogus_iaid, subnet_->getT1(), subnet_->getT2());
  295. ASSERT_TRUE(addr_opt);
  296. // Check that we've got the an address
  297. checkIAAddr(addr_opt, addr_opt->getAddress(), Lease::TYPE_NA);
  298. // Check that we got a different address than was in the database.
  299. EXPECT_NE(addr_opt->getAddress().toText(), addr.toText());
  300. // Check that the lease is really in the database
  301. l = checkLease(duid_, reply->getOption(D6O_IA_NA), addr_opt);
  302. ASSERT_TRUE(l);
  303. }
  304. void
  305. Dhcpv6SrvTest::testRenewSomeoneElsesLease(Lease::Type type, const IOAddress& addr) {
  306. NakedDhcpv6Srv srv(0);
  307. const uint32_t valid_iaid = 234;
  308. const uint32_t transid = 1234;
  309. uint8_t prefix_len = (type == Lease::TYPE_PD) ? 128 : pd_pool_->getLength();
  310. // GenerateClientId() also sets duid_
  311. OptionPtr clientid = generateClientId();
  312. // Let's create a lease.
  313. Lease6Ptr lease(new Lease6(type, addr, duid_, valid_iaid,
  314. 501, 502, 503, 504, subnet_->getID(),
  315. HWAddrPtr(), prefix_len));
  316. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
  317. // CASE 3: Lease belongs to a client with different client-id
  318. Pkt6Ptr renew = createMessage(DHCPV6_RENEW, type, IOAddress(addr), prefix_len,
  319. valid_iaid);
  320. renew->addOption(generateClientId(13)); // generate different DUID (length 13)
  321. renew->addOption(srv.getServerID());
  322. // The iaid and address matches, but the duid is different.
  323. // The server should not renew it, but assign something else.
  324. Pkt6Ptr reply = srv.processRenew(renew);
  325. checkResponse(reply, DHCPV6_REPLY, transid);
  326. OptionPtr tmp = reply->getOption(D6O_IA_NA);
  327. ASSERT_TRUE(tmp);
  328. // Check that IA_?? was returned and that there's proper status code
  329. // Check that IA_NA was returned and that there's an address included
  330. boost::shared_ptr<Option6IAAddr>
  331. addr_opt = checkIA_NA(reply, valid_iaid, subnet_->getT1(), subnet_->getT2());
  332. ASSERT_TRUE(addr_opt);
  333. // Check that we've got the an address
  334. checkIAAddr(addr_opt, addr_opt->getAddress(), Lease::TYPE_NA);
  335. // Check that we got a different address than was in the database.
  336. EXPECT_NE(addr_opt->getAddress().toText(), addr.toText());
  337. // Check that the lease is really in the database
  338. Lease6Ptr l = checkLease(duid_, reply->getOption(D6O_IA_NA), addr_opt);
  339. ASSERT_TRUE(l);
  340. }
  341. void
  342. Dhcpv6SrvTest::testReleaseBasic(Lease::Type type, const IOAddress& existing,
  343. const IOAddress& release_addr) {
  344. NakedDhcpv6Srv srv(0);
  345. const uint32_t iaid = 234;
  346. uint32_t code; // option code of the container (IA_NA or IA_PD)
  347. uint8_t prefix_len;
  348. if (type == Lease::TYPE_NA) {
  349. code = D6O_IA_NA;
  350. prefix_len = 128;
  351. } else if (type == Lease::TYPE_PD) {
  352. code = D6O_IA_PD;
  353. prefix_len = pd_pool_->getLength();
  354. } else {
  355. isc_throw(BadValue, "Invalid lease type");
  356. }
  357. // Generate client-id also duid_
  358. OptionPtr clientid = generateClientId();
  359. // Check that the address we are about to use is indeed in pool
  360. ASSERT_TRUE(subnet_->inPool(type, existing));
  361. // Let's prepopulate the database
  362. Lease6Ptr lease(new Lease6(type, existing, duid_, iaid,
  363. 501, 502, 503, 504, subnet_->getID(),
  364. HWAddrPtr(), prefix_len));
  365. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
  366. // Check that the lease is really in the database
  367. Lease6Ptr l = LeaseMgrFactory::instance().getLease6(type, existing);
  368. ASSERT_TRUE(l);
  369. // And prepopulate the stats counter
  370. std::string name = StatsMgr::generateName("subnet", subnet_->getID(),
  371. type == Lease::TYPE_NA ? "assigned-nas" :
  372. "assigned-pds");
  373. StatsMgr::instance().setValue(name, static_cast<int64_t>(1));
  374. // Let's create a RELEASE
  375. Pkt6Ptr rel = createMessage(DHCPV6_RELEASE, type, release_addr, prefix_len,
  376. iaid);
  377. rel->addOption(clientid);
  378. rel->addOption(srv.getServerID());
  379. // Pass it to the server and hope for a REPLY
  380. Pkt6Ptr reply = srv.processRelease(rel);
  381. // Check if we get response at all
  382. checkResponse(reply, DHCPV6_REPLY, 1234);
  383. OptionPtr tmp = reply->getOption(code);
  384. ASSERT_TRUE(tmp);
  385. // Check that IA_NA was returned and that there's an address included
  386. boost::shared_ptr<Option6IA> ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
  387. checkIA_NAStatusCode(ia, STATUS_Success, 0, 0);
  388. checkMsgStatusCode(reply, STATUS_Success);
  389. // There should be no address returned in RELEASE (see RFC3315, 18.2.6)
  390. // There should be no prefix
  391. EXPECT_FALSE(tmp->getOption(D6O_IAADDR));
  392. EXPECT_FALSE(tmp->getOption(D6O_IAPREFIX));
  393. // Check DUIDs
  394. checkServerId(reply, srv.getServerID());
  395. checkClientId(reply, clientid);
  396. // Check that the lease is really gone in the database
  397. // get lease by address
  398. l = LeaseMgrFactory::instance().getLease6(type, release_addr);
  399. ASSERT_FALSE(l);
  400. // get lease by subnetid/duid/iaid combination
  401. l = LeaseMgrFactory::instance().getLease6(type, *duid_, iaid,
  402. subnet_->getID());
  403. ASSERT_FALSE(l);
  404. // We should have decremented the address counter
  405. ObservationPtr stat = StatsMgr::instance().getObservation(name);
  406. ASSERT_TRUE(stat);
  407. EXPECT_EQ(0, stat->getInteger().first);
  408. }
  409. void
  410. Dhcpv6SrvTest::testReleaseReject(Lease::Type type, const IOAddress& addr) {
  411. NakedDhcpv6Srv srv(0);
  412. const uint32_t transid = 1234;
  413. const uint32_t valid_iaid = 234;
  414. const uint32_t bogus_iaid = 456;
  415. uint32_t code; // option code of the container (IA_NA or IA_PD)
  416. uint8_t prefix_len;
  417. if (type == Lease::TYPE_NA) {
  418. code = D6O_IA_NA;
  419. prefix_len = 128;
  420. } else if (type == Lease::TYPE_PD) {
  421. code = D6O_IA_PD;
  422. prefix_len = pd_pool_->getLength();
  423. } else {
  424. isc_throw(BadValue, "Invalid lease type");
  425. }
  426. // Quick sanity check that the address we're about to use is ok
  427. ASSERT_TRUE(subnet_->inPool(type, addr));
  428. // GenerateClientId() also sets duid_
  429. OptionPtr clientid = generateClientId();
  430. // Pretend we have allocated 1 lease
  431. std::string name = StatsMgr::generateName("subnet", subnet_->getID(),
  432. type == Lease::TYPE_NA ? "assigned-nas" :
  433. "assigned-pds");
  434. StatsMgr::instance().setValue(name, static_cast<int64_t>(1));
  435. // Check that the lease is NOT in the database
  436. Lease6Ptr l = LeaseMgrFactory::instance().getLease6(type, addr);
  437. ASSERT_FALSE(l);
  438. // Let's create a RELEASE
  439. Pkt6Ptr rel = createMessage(DHCPV6_RELEASE, type, addr, prefix_len, valid_iaid);
  440. rel->addOption(clientid);
  441. rel->addOption(srv.getServerID());
  442. // Case 1: No lease known to server
  443. SCOPED_TRACE("CASE 1: No lease known to server");
  444. // Pass it to the server and hope for a REPLY
  445. Pkt6Ptr reply = srv.processRelease(rel);
  446. // Check if we get response at all
  447. checkResponse(reply, DHCPV6_REPLY, transid);
  448. OptionPtr tmp = reply->getOption(code);
  449. ASSERT_TRUE(tmp);
  450. // Check that IA_NA/IA_PD was returned and that there's status code in it
  451. boost::shared_ptr<Option6IA> ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
  452. ASSERT_TRUE(ia);
  453. checkIA_NAStatusCode(ia, STATUS_NoBinding, 0, 0);
  454. checkMsgStatusCode(reply, STATUS_NoBinding);
  455. // Check that the lease is not there
  456. l = LeaseMgrFactory::instance().getLease6(type, addr);
  457. ASSERT_FALSE(l);
  458. // Verify we didn't decrement the stats counter
  459. ObservationPtr stat = StatsMgr::instance().getObservation(name);
  460. ASSERT_TRUE(stat);
  461. EXPECT_EQ(1, stat->getInteger().first);
  462. // CASE 2: Lease is known and belongs to this client, but to a different IAID
  463. SCOPED_TRACE("CASE 2: Lease is known and belongs to this client, but to a different IAID");
  464. Lease6Ptr lease(new Lease6(type, addr, duid_, valid_iaid, 501, 502, 503,
  465. 504, subnet_->getID(), HWAddrPtr(), prefix_len));
  466. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
  467. // Let's create a different RELEASE, with a bogus iaid
  468. rel = createMessage(DHCPV6_RELEASE, type, addr, prefix_len, bogus_iaid);
  469. rel->addOption(clientid);
  470. rel->addOption(srv.getServerID());
  471. // Pass it to the server and hope for a REPLY
  472. reply = srv.processRelease(rel);
  473. checkResponse(reply, DHCPV6_REPLY, transid);
  474. tmp = reply->getOption(code);
  475. ASSERT_TRUE(tmp);
  476. // Check that IA_?? was returned and that there's proper status code
  477. ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
  478. ASSERT_TRUE(ia);
  479. checkIA_NAStatusCode(ia, STATUS_NoBinding, 0, 0);
  480. checkMsgStatusCode(reply, STATUS_NoBinding);
  481. // Check that the lease is still there
  482. l = LeaseMgrFactory::instance().getLease6(type, addr);
  483. ASSERT_TRUE(l);
  484. // Verify we didn't decrement the stats counter
  485. EXPECT_EQ(1, stat->getInteger().first);
  486. // CASE 3: Lease belongs to a client with different client-id
  487. SCOPED_TRACE("CASE 3: Lease belongs to a client with different client-id");
  488. rel->delOption(D6O_CLIENTID);
  489. ia = boost::dynamic_pointer_cast<Option6IA>(rel->getOption(code));
  490. ia->setIAID(valid_iaid); // Now iaid in renew matches that in leasemgr
  491. rel->addOption(generateClientId(13)); // generate different DUID
  492. // (with length 13)
  493. reply = srv.processRelease(rel);
  494. checkResponse(reply, DHCPV6_REPLY, transid);
  495. tmp = reply->getOption(code);
  496. ASSERT_TRUE(tmp);
  497. // Check that IA_?? was returned and that there's proper status code
  498. ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
  499. ASSERT_TRUE(ia);
  500. checkIA_NAStatusCode(ia, STATUS_NoBinding, 0, 0);
  501. checkMsgStatusCode(reply, STATUS_NoBinding);
  502. // Check that the lease is still there
  503. l = LeaseMgrFactory::instance().getLease6(type, addr);
  504. ASSERT_TRUE(l);
  505. // Verify we didn't decrement the stats counter
  506. EXPECT_EQ(1, stat->getInteger().first);
  507. // Finally, let's cleanup the database
  508. EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease(addr));
  509. }
  510. void
  511. Dhcpv6SrvTest::testReceiveStats(uint8_t pkt_type, const std::string& stat_name) {
  512. StatsMgr& mgr = StatsMgr::instance();
  513. NakedDhcpv6Srv srv(0);
  514. // Let's get a simple SOLICIT...
  515. Pkt6Ptr pkt = PktCaptures::captureSimpleSolicit();
  516. // And pretend it's packet of a different type
  517. pkt->data_[0] = pkt_type;
  518. // Check that those statistics are not set before the test
  519. ObservationPtr pkt6_rcvd = mgr.getObservation("pkt6-received");
  520. ObservationPtr tested_stat = mgr.getObservation(stat_name);
  521. EXPECT_FALSE(pkt6_rcvd);
  522. EXPECT_FALSE(tested_stat);
  523. // Simulate that we have received that traffic
  524. srv.fakeReceive(pkt);
  525. // Server will now process to run its normal loop, but instead of calling
  526. // IfaceMgr::receive6(), it will read all packets from the list set by
  527. // fakeReceive()
  528. srv.run();
  529. // All expected statstics must be present.
  530. pkt6_rcvd = mgr.getObservation("pkt6-received");
  531. tested_stat = mgr.getObservation(stat_name);
  532. ASSERT_TRUE(pkt6_rcvd);
  533. ASSERT_TRUE(tested_stat);
  534. // They also must have expected values.
  535. EXPECT_EQ(1, pkt6_rcvd->getInteger().first);
  536. EXPECT_EQ(1, tested_stat->getInteger().first);
  537. }
  538. void
  539. Dhcpv6SrvTest::configure(const std::string& config) {
  540. configure(config, srv_);
  541. }
  542. void
  543. Dhcpv6SrvTest::configure(const std::string& config, NakedDhcpv6Srv& srv) {
  544. ElementPtr json = data::Element::fromJSON(config);
  545. ConstElementPtr status;
  546. // Configure the server and make sure the config is accepted
  547. EXPECT_NO_THROW(status = configureDhcp6Server(srv, json));
  548. ASSERT_TRUE(status);
  549. int rcode;
  550. ConstElementPtr comment = isc::config::parseAnswer(rcode, status);
  551. ASSERT_EQ(0, rcode);
  552. CfgMgr::instance().commit();
  553. }
  554. NakedDhcpv6SrvTest::NakedDhcpv6SrvTest()
  555. : rcode_(-1) {
  556. // it's ok if that fails. There should not be such a file anyway
  557. remove(DUID_FILE);
  558. const isc::dhcp::IfaceMgr::IfaceCollection& ifaces =
  559. isc::dhcp::IfaceMgr::instance().getIfaces();
  560. // There must be some interface detected
  561. if (ifaces.empty()) {
  562. // We can't use ASSERT in constructor
  563. ADD_FAILURE() << "No interfaces detected.";
  564. }
  565. valid_iface_ = (*ifaces.begin())->getName();
  566. // Let's wipe all existing statistics.
  567. isc::stats::StatsMgr::instance().removeAll();
  568. }
  569. NakedDhcpv6SrvTest::~NakedDhcpv6SrvTest() {
  570. // Let's wipe all existing statistics.
  571. isc::stats::StatsMgr::instance().removeAll();
  572. // Let's clean up if there is such a file.
  573. remove(DUID_FILE);
  574. isc::hooks::HooksManager::preCalloutsLibraryHandle()
  575. .deregisterAllCallouts("buffer6_receive");
  576. isc::hooks::HooksManager::preCalloutsLibraryHandle()
  577. .deregisterAllCallouts("buffer6_send");
  578. isc::hooks::HooksManager::preCalloutsLibraryHandle()
  579. .deregisterAllCallouts("lease6_renew");
  580. isc::hooks::HooksManager::preCalloutsLibraryHandle()
  581. .deregisterAllCallouts("lease6_release");
  582. isc::hooks::HooksManager::preCalloutsLibraryHandle()
  583. .deregisterAllCallouts("pkt6_receive");
  584. isc::hooks::HooksManager::preCalloutsLibraryHandle()
  585. .deregisterAllCallouts("pkt6_send");
  586. isc::hooks::HooksManager::preCalloutsLibraryHandle()
  587. .deregisterAllCallouts("subnet6_select");
  588. }
  589. // Generate IA_NA option with specified parameters
  590. boost::shared_ptr<Option6IA>
  591. NakedDhcpv6SrvTest::generateIA(uint16_t type, uint32_t iaid, uint32_t t1,
  592. uint32_t t2) {
  593. boost::shared_ptr<Option6IA> ia =
  594. boost::shared_ptr<Option6IA>(new Option6IA(type, iaid));
  595. ia->setT1(t1);
  596. ia->setT2(t2);
  597. return (ia);
  598. }
  599. bool
  600. Dhcpv6SrvTest::compareOptions(const isc::dhcp::OptionPtr& option1,
  601. const isc::dhcp::OptionPtr& option2) {
  602. if ((!option1 && option2) || (option1 && !option2)) {
  603. return (false);
  604. }
  605. if (!option1 && !option2) {
  606. return (true);
  607. }
  608. // We could start by comparing option codes and option lengths
  609. // here, but it's just a waste of time. These are tests, so they
  610. // don't have to be super performant. The pack+memcmp approach
  611. // verifies all in one go.
  612. isc::util::OutputBuffer buf1(0);
  613. isc::util::OutputBuffer buf2(0);
  614. option1->pack(buf1);
  615. option2->pack(buf2);
  616. if (buf1.getLength() != buf2.getLength()) {
  617. return (false);
  618. }
  619. // memcmp returns 0 when equal.
  620. return (!memcmp(buf1.getData(), buf2.getData(), buf1.getLength()));
  621. }
  622. void
  623. NakedDhcpv6SrvTest::checkIA_NAStatusCode(
  624. const boost::shared_ptr<isc::dhcp::Option6IA>& ia,
  625. uint16_t expected_status_code, uint32_t expected_t1, uint32_t expected_t2,
  626. bool check_addr)
  627. {
  628. // Make sure there is no address assigned. Depending on the situation,
  629. // the server will either not return the address at all and sometimes
  630. // it will return it with zeroed lifetimes.
  631. if (check_addr) {
  632. dhcp::OptionCollection options = ia->getOptions();
  633. for (isc::dhcp::OptionCollection::iterator opt = options.begin();
  634. opt != options.end(); ++opt) {
  635. if (opt->second->getType() != D6O_IAADDR) {
  636. continue;
  637. }
  638. dhcp::Option6IAAddrPtr addr =
  639. boost::dynamic_pointer_cast<isc::dhcp::Option6IAAddr>(opt->second);
  640. ASSERT_TRUE(addr);
  641. EXPECT_EQ(0, addr->getPreferred());
  642. EXPECT_EQ(0, addr->getValid());
  643. }
  644. }
  645. // T1, T2 should NOT be zeroed. draft-ietf-dhc-dhcpv6-stateful-issues-10,
  646. // section 4.4.6 says says that T1,T2 should be consistent along all
  647. // provided IA options.
  648. EXPECT_EQ(expected_t1, ia->getT1());
  649. EXPECT_EQ(expected_t2, ia->getT2());
  650. isc::dhcp::Option6StatusCodePtr status =
  651. boost::dynamic_pointer_cast<isc::dhcp::Option6StatusCode>
  652. (ia->getOption(D6O_STATUS_CODE));
  653. // It is ok to not include status success as this is the default
  654. // behavior
  655. if (expected_status_code == STATUS_Success && !status) {
  656. return;
  657. }
  658. EXPECT_TRUE(status);
  659. if (status) {
  660. // We don't have dedicated class for status code, so let's
  661. // just interpret first 2 bytes as status. Remainder of the
  662. // status code option content is just a text explanation
  663. // what went wrong.
  664. EXPECT_EQ(static_cast<uint16_t>(expected_status_code),
  665. status->getStatusCode());
  666. }
  667. }
  668. }; // end of isc::test namespace
  669. }; // end of isc namespace