dhcp6_test_utils.cc 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972
  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::testRenewReject(Lease::Type type, const IOAddress& addr) {
  343. NakedDhcpv6Srv srv(0);
  344. const uint32_t transid = 1234;
  345. const uint32_t valid_iaid = 234;
  346. const uint32_t bogus_iaid = 456;
  347. uint32_t code;
  348. uint8_t prefix_len;
  349. if (type == Lease::TYPE_NA) {
  350. code = D6O_IA_NA;
  351. prefix_len = 128;
  352. } else if (type == Lease::TYPE_PD) {
  353. code = D6O_IA_PD;
  354. prefix_len = pd_pool_->getLength();
  355. } else {
  356. isc_throw(BadValue, "Invalid lease type");
  357. }
  358. // Quick sanity check that the address we're about to use is ok
  359. ASSERT_TRUE(subnet_->inPool(type, addr));
  360. // GenerateClientId() also sets duid_
  361. OptionPtr clientid = generateClientId();
  362. // Check that the lease is NOT in the database
  363. Lease6Ptr l = LeaseMgrFactory::instance().getLease6(type, addr);
  364. ASSERT_FALSE(l);
  365. // Let's create a RENEW
  366. Pkt6Ptr req = createMessage(DHCPV6_RENEW, type, IOAddress(addr), prefix_len,
  367. bogus_iaid);
  368. req->addOption(clientid);
  369. req->addOption(srv.getServerID());
  370. // Case 1: No lease known to server
  371. // Pass it to the server and hope for a REPLY
  372. Pkt6Ptr reply = srv.processRenew(req);
  373. // Check if we get response at all
  374. checkResponse(reply, DHCPV6_REPLY, transid);
  375. OptionPtr tmp = reply->getOption(code);
  376. ASSERT_TRUE(tmp);
  377. // Check that IA_?? was returned and that there's proper status code
  378. boost::shared_ptr<Option6IA> ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
  379. ASSERT_TRUE(ia);
  380. if (type == Lease::TYPE_PD) {
  381. // For PD, the check is easy. NoBinding and no prefixes
  382. checkIA_NAStatusCode(ia, STATUS_NoBinding, subnet_->getT1(), subnet_->getT2());
  383. } else {
  384. // For IA, it's more involved, as the server will reject the address
  385. // (and send it with 0 lifetimes), but will also assign a new address.
  386. // First, check that the requested address is rejected.
  387. bool found = false;
  388. dhcp::OptionCollection options = ia->getOptions();
  389. for (isc::dhcp::OptionCollection::iterator opt = options.begin();
  390. opt != options.end(); ++opt) {
  391. if (opt->second->getType() != D6O_IAADDR) {
  392. continue;
  393. }
  394. dhcp::Option6IAAddrPtr opt_addr =
  395. boost::dynamic_pointer_cast<isc::dhcp::Option6IAAddr>(opt->second);
  396. ASSERT_TRUE(opt_addr);
  397. if (opt_addr->getAddress() != addr) {
  398. // There may be other addresses, e.g. the newly assigned one
  399. continue;
  400. }
  401. found = true;
  402. EXPECT_NE(0, opt_addr->getPreferred());
  403. EXPECT_NE(0, opt_addr->getValid());
  404. }
  405. EXPECT_TRUE(found) << "Expected address " << addr.toText()
  406. << " with zero lifetimes not found.";
  407. }
  408. // Check that there is no lease added
  409. l = LeaseMgrFactory::instance().getLease6(type, addr);
  410. ASSERT_FALSE(l);
  411. // CASE 2: Lease is known and belongs to this client, but to a different IAID
  412. // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
  413. // value on purpose. They should be updated during RENEW.
  414. Lease6Ptr lease(new Lease6(type, addr, duid_, valid_iaid,
  415. 501, 502, 503, 504, subnet_->getID(),
  416. HWAddrPtr(), prefix_len));
  417. lease->cltt_ = 123; // Let's use it as an indicator that the lease
  418. // was NOT updated.
  419. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
  420. // Pass it to the server and hope for a REPLY
  421. reply = srv.processRenew(req);
  422. checkResponse(reply, DHCPV6_REPLY, transid);
  423. tmp = reply->getOption(code);
  424. ASSERT_TRUE(tmp);
  425. // Check that IA_?? was returned and that there's proper status code
  426. ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
  427. ASSERT_TRUE(ia);
  428. checkIA_NAStatusCode(ia, STATUS_NoBinding, subnet_->getT1(), subnet_->getT2());
  429. // There is a iaid mis-match, so server should respond that there is
  430. // no such address to renew.
  431. // CASE 3: Lease belongs to a client with different client-id
  432. req->delOption(D6O_CLIENTID);
  433. ia = boost::dynamic_pointer_cast<Option6IA>(req->getOption(code));
  434. ia->setIAID(valid_iaid); // Now iaid in renew matches that in leasemgr
  435. req->addOption(generateClientId(13)); // generate different DUID
  436. // (with length 13)
  437. reply = srv.processRenew(req);
  438. checkResponse(reply, DHCPV6_REPLY, transid);
  439. tmp = reply->getOption(code);
  440. ASSERT_TRUE(tmp);
  441. // Check that IA_?? was returned and that there's proper status code
  442. ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
  443. ASSERT_TRUE(ia);
  444. checkIA_NAStatusCode(ia, STATUS_NoBinding, subnet_->getT1(), subnet_->getT2());
  445. lease = LeaseMgrFactory::instance().getLease6(type, addr);
  446. ASSERT_TRUE(lease);
  447. // Verify that the lease was not updated.
  448. EXPECT_EQ(123, lease->cltt_);
  449. EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease(addr));
  450. }
  451. void
  452. Dhcpv6SrvTest::testReleaseBasic(Lease::Type type, const IOAddress& existing,
  453. const IOAddress& release_addr) {
  454. NakedDhcpv6Srv srv(0);
  455. const uint32_t iaid = 234;
  456. uint32_t code; // option code of the container (IA_NA or IA_PD)
  457. uint8_t prefix_len;
  458. if (type == Lease::TYPE_NA) {
  459. code = D6O_IA_NA;
  460. prefix_len = 128;
  461. } else if (type == Lease::TYPE_PD) {
  462. code = D6O_IA_PD;
  463. prefix_len = pd_pool_->getLength();
  464. } else {
  465. isc_throw(BadValue, "Invalid lease type");
  466. }
  467. // Generate client-id also duid_
  468. OptionPtr clientid = generateClientId();
  469. // Check that the address we are about to use is indeed in pool
  470. ASSERT_TRUE(subnet_->inPool(type, existing));
  471. // Let's prepopulate the database
  472. Lease6Ptr lease(new Lease6(type, existing, duid_, iaid,
  473. 501, 502, 503, 504, subnet_->getID(),
  474. HWAddrPtr(), prefix_len));
  475. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
  476. // Check that the lease is really in the database
  477. Lease6Ptr l = LeaseMgrFactory::instance().getLease6(type, existing);
  478. ASSERT_TRUE(l);
  479. // And prepopulate the stats counter
  480. std::string name = StatsMgr::generateName("subnet", subnet_->getID(),
  481. type == Lease::TYPE_NA ? "assigned-nas" :
  482. "assigned-pds");
  483. StatsMgr::instance().setValue(name, static_cast<int64_t>(1));
  484. // Let's create a RELEASE
  485. Pkt6Ptr rel = createMessage(DHCPV6_RELEASE, type, release_addr, prefix_len,
  486. iaid);
  487. rel->addOption(clientid);
  488. rel->addOption(srv.getServerID());
  489. // Pass it to the server and hope for a REPLY
  490. Pkt6Ptr reply = srv.processRelease(rel);
  491. // Check if we get response at all
  492. checkResponse(reply, DHCPV6_REPLY, 1234);
  493. OptionPtr tmp = reply->getOption(code);
  494. ASSERT_TRUE(tmp);
  495. // Check that IA_NA was returned and that there's an address included
  496. boost::shared_ptr<Option6IA> ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
  497. checkIA_NAStatusCode(ia, STATUS_Success, 0, 0);
  498. checkMsgStatusCode(reply, STATUS_Success);
  499. // There should be no address returned in RELEASE (see RFC3315, 18.2.6)
  500. // There should be no prefix
  501. EXPECT_FALSE(tmp->getOption(D6O_IAADDR));
  502. EXPECT_FALSE(tmp->getOption(D6O_IAPREFIX));
  503. // Check DUIDs
  504. checkServerId(reply, srv.getServerID());
  505. checkClientId(reply, clientid);
  506. // Check that the lease is really gone in the database
  507. // get lease by address
  508. l = LeaseMgrFactory::instance().getLease6(type, release_addr);
  509. ASSERT_FALSE(l);
  510. // get lease by subnetid/duid/iaid combination
  511. l = LeaseMgrFactory::instance().getLease6(type, *duid_, iaid,
  512. subnet_->getID());
  513. ASSERT_FALSE(l);
  514. // We should have decremented the address counter
  515. ObservationPtr stat = StatsMgr::instance().getObservation(name);
  516. ASSERT_TRUE(stat);
  517. EXPECT_EQ(0, stat->getInteger().first);
  518. }
  519. void
  520. Dhcpv6SrvTest::testReleaseReject(Lease::Type type, const IOAddress& addr) {
  521. NakedDhcpv6Srv srv(0);
  522. const uint32_t transid = 1234;
  523. const uint32_t valid_iaid = 234;
  524. const uint32_t bogus_iaid = 456;
  525. uint32_t code; // option code of the container (IA_NA or IA_PD)
  526. uint8_t prefix_len;
  527. if (type == Lease::TYPE_NA) {
  528. code = D6O_IA_NA;
  529. prefix_len = 128;
  530. } else if (type == Lease::TYPE_PD) {
  531. code = D6O_IA_PD;
  532. prefix_len = pd_pool_->getLength();
  533. } else {
  534. isc_throw(BadValue, "Invalid lease type");
  535. }
  536. // Quick sanity check that the address we're about to use is ok
  537. ASSERT_TRUE(subnet_->inPool(type, addr));
  538. // GenerateClientId() also sets duid_
  539. OptionPtr clientid = generateClientId();
  540. // Pretend we have allocated 1 lease
  541. std::string name = StatsMgr::generateName("subnet", subnet_->getID(),
  542. type == Lease::TYPE_NA ? "assigned-nas" :
  543. "assigned-pds");
  544. StatsMgr::instance().setValue(name, static_cast<int64_t>(1));
  545. // Check that the lease is NOT in the database
  546. Lease6Ptr l = LeaseMgrFactory::instance().getLease6(type, addr);
  547. ASSERT_FALSE(l);
  548. // Let's create a RELEASE
  549. Pkt6Ptr rel = createMessage(DHCPV6_RELEASE, type, addr, prefix_len, valid_iaid);
  550. rel->addOption(clientid);
  551. rel->addOption(srv.getServerID());
  552. // Case 1: No lease known to server
  553. SCOPED_TRACE("CASE 1: No lease known to server");
  554. // Pass it to the server and hope for a REPLY
  555. Pkt6Ptr reply = srv.processRelease(rel);
  556. // Check if we get response at all
  557. checkResponse(reply, DHCPV6_REPLY, transid);
  558. OptionPtr tmp = reply->getOption(code);
  559. ASSERT_TRUE(tmp);
  560. // Check that IA_NA/IA_PD was returned and that there's status code in it
  561. boost::shared_ptr<Option6IA> ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
  562. ASSERT_TRUE(ia);
  563. checkIA_NAStatusCode(ia, STATUS_NoBinding, 0, 0);
  564. checkMsgStatusCode(reply, STATUS_NoBinding);
  565. // Check that the lease is not there
  566. l = LeaseMgrFactory::instance().getLease6(type, addr);
  567. ASSERT_FALSE(l);
  568. // Verify we didn't decrement the stats counter
  569. ObservationPtr stat = StatsMgr::instance().getObservation(name);
  570. ASSERT_TRUE(stat);
  571. EXPECT_EQ(1, stat->getInteger().first);
  572. // CASE 2: Lease is known and belongs to this client, but to a different IAID
  573. SCOPED_TRACE("CASE 2: Lease is known and belongs to this client, but to a different IAID");
  574. Lease6Ptr lease(new Lease6(type, addr, duid_, valid_iaid, 501, 502, 503,
  575. 504, subnet_->getID(), HWAddrPtr(), prefix_len));
  576. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
  577. // Let's create a different RELEASE, with a bogus iaid
  578. rel = createMessage(DHCPV6_RELEASE, type, addr, prefix_len, bogus_iaid);
  579. rel->addOption(clientid);
  580. rel->addOption(srv.getServerID());
  581. // Pass it to the server and hope for a REPLY
  582. reply = srv.processRelease(rel);
  583. checkResponse(reply, DHCPV6_REPLY, transid);
  584. tmp = reply->getOption(code);
  585. ASSERT_TRUE(tmp);
  586. // Check that IA_?? was returned and that there's proper status code
  587. ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
  588. ASSERT_TRUE(ia);
  589. checkIA_NAStatusCode(ia, STATUS_NoBinding, 0, 0);
  590. checkMsgStatusCode(reply, STATUS_NoBinding);
  591. // Check that the lease is still there
  592. l = LeaseMgrFactory::instance().getLease6(type, addr);
  593. ASSERT_TRUE(l);
  594. // Verify we didn't decrement the stats counter
  595. EXPECT_EQ(1, stat->getInteger().first);
  596. // CASE 3: Lease belongs to a client with different client-id
  597. SCOPED_TRACE("CASE 3: Lease belongs to a client with different client-id");
  598. rel->delOption(D6O_CLIENTID);
  599. ia = boost::dynamic_pointer_cast<Option6IA>(rel->getOption(code));
  600. ia->setIAID(valid_iaid); // Now iaid in renew matches that in leasemgr
  601. rel->addOption(generateClientId(13)); // generate different DUID
  602. // (with length 13)
  603. reply = srv.processRelease(rel);
  604. checkResponse(reply, DHCPV6_REPLY, transid);
  605. tmp = reply->getOption(code);
  606. ASSERT_TRUE(tmp);
  607. // Check that IA_?? was returned and that there's proper status code
  608. ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
  609. ASSERT_TRUE(ia);
  610. checkIA_NAStatusCode(ia, STATUS_NoBinding, 0, 0);
  611. checkMsgStatusCode(reply, STATUS_NoBinding);
  612. // Check that the lease is still there
  613. l = LeaseMgrFactory::instance().getLease6(type, addr);
  614. ASSERT_TRUE(l);
  615. // Verify we didn't decrement the stats counter
  616. EXPECT_EQ(1, stat->getInteger().first);
  617. // Finally, let's cleanup the database
  618. EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease(addr));
  619. }
  620. void
  621. Dhcpv6SrvTest::testReceiveStats(uint8_t pkt_type, const std::string& stat_name) {
  622. StatsMgr& mgr = StatsMgr::instance();
  623. NakedDhcpv6Srv srv(0);
  624. // Let's get a simple SOLICIT...
  625. Pkt6Ptr pkt = PktCaptures::captureSimpleSolicit();
  626. // And pretend it's packet of a different type
  627. pkt->data_[0] = pkt_type;
  628. // Check that those statistics are not set before the test
  629. ObservationPtr pkt6_rcvd = mgr.getObservation("pkt6-received");
  630. ObservationPtr tested_stat = mgr.getObservation(stat_name);
  631. EXPECT_FALSE(pkt6_rcvd);
  632. EXPECT_FALSE(tested_stat);
  633. // Simulate that we have received that traffic
  634. srv.fakeReceive(pkt);
  635. // Server will now process to run its normal loop, but instead of calling
  636. // IfaceMgr::receive6(), it will read all packets from the list set by
  637. // fakeReceive()
  638. srv.run();
  639. // All expected statstics must be present.
  640. pkt6_rcvd = mgr.getObservation("pkt6-received");
  641. tested_stat = mgr.getObservation(stat_name);
  642. ASSERT_TRUE(pkt6_rcvd);
  643. ASSERT_TRUE(tested_stat);
  644. // They also must have expected values.
  645. EXPECT_EQ(1, pkt6_rcvd->getInteger().first);
  646. EXPECT_EQ(1, tested_stat->getInteger().first);
  647. }
  648. void
  649. Dhcpv6SrvTest::configure(const std::string& config) {
  650. configure(config, srv_);
  651. }
  652. void
  653. Dhcpv6SrvTest::configure(const std::string& config, NakedDhcpv6Srv& srv) {
  654. ElementPtr json = data::Element::fromJSON(config);
  655. ConstElementPtr status;
  656. // Configure the server and make sure the config is accepted
  657. EXPECT_NO_THROW(status = configureDhcp6Server(srv, json));
  658. ASSERT_TRUE(status);
  659. int rcode;
  660. ConstElementPtr comment = isc::config::parseAnswer(rcode, status);
  661. ASSERT_EQ(0, rcode);
  662. CfgMgr::instance().commit();
  663. }
  664. NakedDhcpv6SrvTest::NakedDhcpv6SrvTest()
  665. : rcode_(-1) {
  666. // it's ok if that fails. There should not be such a file anyway
  667. static_cast<void>(remove(DUID_FILE));
  668. const isc::dhcp::IfaceMgr::IfaceCollection& ifaces =
  669. isc::dhcp::IfaceMgr::instance().getIfaces();
  670. // There must be some interface detected
  671. if (ifaces.empty()) {
  672. // We can't use ASSERT in constructor
  673. ADD_FAILURE() << "No interfaces detected.";
  674. }
  675. valid_iface_ = (*ifaces.begin())->getName();
  676. // Let's wipe all existing statistics.
  677. isc::stats::StatsMgr::instance().removeAll();
  678. }
  679. NakedDhcpv6SrvTest::~NakedDhcpv6SrvTest() {
  680. // Let's wipe all existing statistics.
  681. isc::stats::StatsMgr::instance().removeAll();
  682. // Let's clean up if there is such a file.
  683. static_cast<void>(remove(DUID_FILE));
  684. isc::hooks::HooksManager::preCalloutsLibraryHandle()
  685. .deregisterAllCallouts("buffer6_receive");
  686. isc::hooks::HooksManager::preCalloutsLibraryHandle()
  687. .deregisterAllCallouts("buffer6_send");
  688. isc::hooks::HooksManager::preCalloutsLibraryHandle()
  689. .deregisterAllCallouts("lease6_renew");
  690. isc::hooks::HooksManager::preCalloutsLibraryHandle()
  691. .deregisterAllCallouts("lease6_release");
  692. isc::hooks::HooksManager::preCalloutsLibraryHandle()
  693. .deregisterAllCallouts("pkt6_receive");
  694. isc::hooks::HooksManager::preCalloutsLibraryHandle()
  695. .deregisterAllCallouts("pkt6_send");
  696. isc::hooks::HooksManager::preCalloutsLibraryHandle()
  697. .deregisterAllCallouts("subnet6_select");
  698. }
  699. // Generate IA_NA option with specified parameters
  700. boost::shared_ptr<Option6IA>
  701. NakedDhcpv6SrvTest::generateIA(uint16_t type, uint32_t iaid, uint32_t t1,
  702. uint32_t t2) {
  703. boost::shared_ptr<Option6IA> ia =
  704. boost::shared_ptr<Option6IA>(new Option6IA(type, iaid));
  705. ia->setT1(t1);
  706. ia->setT2(t2);
  707. return (ia);
  708. }
  709. bool
  710. Dhcpv6SrvTest::compareOptions(const isc::dhcp::OptionPtr& option1,
  711. const isc::dhcp::OptionPtr& option2) {
  712. if ((!option1 && option2) || (option1 && !option2)) {
  713. return (false);
  714. }
  715. if (!option1 && !option2) {
  716. return (true);
  717. }
  718. // We could start by comparing option codes and option lengths
  719. // here, but it's just a waste of time. These are tests, so they
  720. // don't have to be super performant. The pack+memcmp approach
  721. // verifies all in one go.
  722. isc::util::OutputBuffer buf1(0);
  723. isc::util::OutputBuffer buf2(0);
  724. option1->pack(buf1);
  725. option2->pack(buf2);
  726. if (buf1.getLength() != buf2.getLength()) {
  727. return (false);
  728. }
  729. // memcmp returns 0 when equal.
  730. return (!memcmp(buf1.getData(), buf2.getData(), buf1.getLength()));
  731. }
  732. void
  733. NakedDhcpv6SrvTest::checkIA_NAStatusCode(
  734. const boost::shared_ptr<isc::dhcp::Option6IA>& ia,
  735. uint16_t expected_status_code, uint32_t expected_t1, uint32_t expected_t2,
  736. bool check_addr)
  737. {
  738. // Make sure there is no address assigned. Depending on the situation,
  739. // the server will either not return the address at all and sometimes
  740. // it will return it with zeroed lifetimes.
  741. if (check_addr) {
  742. dhcp::OptionCollection options = ia->getOptions();
  743. for (isc::dhcp::OptionCollection::iterator opt = options.begin();
  744. opt != options.end(); ++opt) {
  745. if (opt->second->getType() != D6O_IAADDR) {
  746. continue;
  747. }
  748. dhcp::Option6IAAddrPtr addr =
  749. boost::dynamic_pointer_cast<isc::dhcp::Option6IAAddr>(opt->second);
  750. ASSERT_TRUE(addr);
  751. EXPECT_EQ(0, addr->getPreferred());
  752. EXPECT_EQ(0, addr->getValid());
  753. }
  754. }
  755. // T1, T2 should NOT be zeroed. draft-ietf-dhc-dhcpv6-stateful-issues-10,
  756. // section 4.4.6 says says that T1,T2 should be consistent along all
  757. // provided IA options.
  758. EXPECT_EQ(expected_t1, ia->getT1());
  759. EXPECT_EQ(expected_t2, ia->getT2());
  760. isc::dhcp::Option6StatusCodePtr status =
  761. boost::dynamic_pointer_cast<isc::dhcp::Option6StatusCode>
  762. (ia->getOption(D6O_STATUS_CODE));
  763. // It is ok to not include status success as this is the default
  764. // behavior
  765. if (expected_status_code == STATUS_Success && !status) {
  766. return;
  767. }
  768. EXPECT_TRUE(status);
  769. if (status) {
  770. // We don't have dedicated class for status code, so let's
  771. // just interpret first 2 bytes as status. Remainder of the
  772. // status code option content is just a text explanation
  773. // what went wrong.
  774. EXPECT_EQ(static_cast<uint16_t>(expected_status_code),
  775. status->getStatusCode());
  776. }
  777. }
  778. }; // end of isc::test namespace
  779. }; // end of isc namespace