dhcp6_test_utils.cc 30 KB

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