dhcp6_test_utils.cc 30 KB

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