hook_unittest.cc 52 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453
  1. // Copyright (C) 2013 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 <asiolink/io_address.h>
  16. #include <dhcp/dhcp6.h>
  17. #include <dhcp/duid.h>
  18. #include <dhcp/option.h>
  19. #include <dhcp/option_custom.h>
  20. #include <dhcp/option6_addrlst.h>
  21. #include <dhcp/iface_mgr.h>
  22. #include <dhcp6/config_parser.h>
  23. #include <dhcp/dhcp6.h>
  24. #include <dhcpsrv/cfgmgr.h>
  25. #include <dhcpsrv/lease_mgr.h>
  26. #include <dhcpsrv/lease_mgr_factory.h>
  27. #include <dhcpsrv/utils.h>
  28. #include <util/buffer.h>
  29. #include <util/range_utilities.h>
  30. #include <hooks/server_hooks.h>
  31. #include <dhcp6/tests/dhcp6_test_utils.h>
  32. #include <boost/scoped_ptr.hpp>
  33. #include <gtest/gtest.h>
  34. #include <unistd.h>
  35. #include <fstream>
  36. #include <iostream>
  37. #include <sstream>
  38. using namespace isc;
  39. using namespace isc::test;
  40. using namespace isc::asiolink;
  41. using namespace isc::dhcp;
  42. using namespace isc::util;
  43. using namespace isc::hooks;
  44. using namespace std;
  45. // namespace has to be named, because friends are defined in Dhcpv6Srv class
  46. // Maybe it should be isc::test?
  47. namespace {
  48. // Checks if hooks are implemented properly.
  49. TEST_F(Dhcpv6SrvTest, Hooks) {
  50. NakedDhcpv6Srv srv(0);
  51. // check if appropriate hooks are registered
  52. int hook_index_buffer6_receive = -1;
  53. int hook_index_buffer6_send = -1;
  54. int hook_index_lease6_renew = -1;
  55. int hook_index_lease6_release = -1;
  56. int hook_index_pkt6_received = -1;
  57. int hook_index_select_subnet = -1;
  58. int hook_index_pkt6_send = -1;
  59. // check if appropriate indexes are set
  60. EXPECT_NO_THROW(hook_index_buffer6_receive = ServerHooks::getServerHooks()
  61. .getIndex("buffer6_receive"));
  62. EXPECT_NO_THROW(hook_index_buffer6_send = ServerHooks::getServerHooks()
  63. .getIndex("buffer6_send"));
  64. EXPECT_NO_THROW(hook_index_lease6_renew = ServerHooks::getServerHooks()
  65. .getIndex("lease6_renew"));
  66. EXPECT_NO_THROW(hook_index_lease6_release = ServerHooks::getServerHooks()
  67. .getIndex("lease6_release"));
  68. EXPECT_NO_THROW(hook_index_pkt6_received = ServerHooks::getServerHooks()
  69. .getIndex("pkt6_receive"));
  70. EXPECT_NO_THROW(hook_index_select_subnet = ServerHooks::getServerHooks()
  71. .getIndex("subnet6_select"));
  72. EXPECT_NO_THROW(hook_index_pkt6_send = ServerHooks::getServerHooks()
  73. .getIndex("pkt6_send"));
  74. EXPECT_TRUE(hook_index_pkt6_received > 0);
  75. EXPECT_TRUE(hook_index_select_subnet > 0);
  76. EXPECT_TRUE(hook_index_pkt6_send > 0);
  77. EXPECT_TRUE(hook_index_buffer6_receive > 0);
  78. EXPECT_TRUE(hook_index_buffer6_send > 0);
  79. EXPECT_TRUE(hook_index_lease6_renew > 0);
  80. EXPECT_TRUE(hook_index_lease6_release > 0);
  81. }
  82. // This function returns buffer for very simple Solicit
  83. Pkt6* captureSimpleSolicit() {
  84. Pkt6* pkt;
  85. uint8_t data[] = {
  86. 1, // type 1 = SOLICIT
  87. 0xca, 0xfe, 0x01, // trans-id = 0xcafe01
  88. 0, 1, // option type 1 (client-id)
  89. 0, 10, // option lenth 10
  90. 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // DUID
  91. 0, 3, // option type 3 (IA_NA)
  92. 0, 12, // option length 12
  93. 0, 0, 0, 1, // iaid = 1
  94. 0, 0, 0, 0, // T1 = 0
  95. 0, 0, 0, 0 // T2 = 0
  96. };
  97. pkt = new Pkt6(data, sizeof(data));
  98. pkt->setRemotePort(546);
  99. pkt->setRemoteAddr(IOAddress("fe80::1"));
  100. pkt->setLocalPort(0);
  101. pkt->setLocalAddr(IOAddress("ff02::1:2"));
  102. pkt->setIndex(2);
  103. pkt->setIface("eth0");
  104. return (pkt);
  105. }
  106. /// @brief a class dedicated to Hooks testing in DHCPv6 server
  107. ///
  108. /// This class has a number of static members, because each non-static
  109. /// method has implicit 'this' parameter, so it does not match callout
  110. /// signature and couldn't be registered. Furthermore, static methods
  111. /// can't modify non-static members (for obvious reasons), so many
  112. /// fields are declared static. It is still better to keep them as
  113. /// one class rather than unrelated collection of global objects.
  114. class HooksDhcpv6SrvTest : public Dhcpv6SrvTest {
  115. public:
  116. /// @brief creates Dhcpv6Srv and prepares buffers for callouts
  117. HooksDhcpv6SrvTest() {
  118. // Allocate new DHCPv6 Server
  119. srv_ = new NakedDhcpv6Srv(0);
  120. // clear static buffers
  121. resetCalloutBuffers();
  122. }
  123. /// @brief destructor (deletes Dhcpv6Srv)
  124. ~HooksDhcpv6SrvTest() {
  125. delete srv_;
  126. }
  127. /// @brief creates an option with specified option code
  128. ///
  129. /// This method is static, because it is used from callouts
  130. /// that do not have a pointer to HooksDhcpv6SSrvTest object
  131. ///
  132. /// @param option_code code of option to be created
  133. ///
  134. /// @return pointer to create option object
  135. static OptionPtr createOption(uint16_t option_code) {
  136. char payload[] = {
  137. 0xa, 0xb, 0xc, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14
  138. };
  139. OptionBuffer tmp(payload, payload + sizeof(payload));
  140. return OptionPtr(new Option(Option::V6, option_code, tmp));
  141. }
  142. /// test callback that stores received callout name and pkt6 value
  143. /// @param callout_handle handle passed by the hooks framework
  144. /// @return always 0
  145. static int
  146. pkt6_receive_callout(CalloutHandle& callout_handle) {
  147. callback_name_ = string("pkt6_receive");
  148. callout_handle.getArgument("query6", callback_pkt6_);
  149. callback_argument_names_ = callout_handle.getArgumentNames();
  150. return (0);
  151. }
  152. /// test callback that changes client-id value
  153. /// @param callout_handle handle passed by the hooks framework
  154. /// @return always 0
  155. static int
  156. pkt6_receive_change_clientid(CalloutHandle& callout_handle) {
  157. Pkt6Ptr pkt;
  158. callout_handle.getArgument("query6", pkt);
  159. // get rid of the old client-id
  160. pkt->delOption(D6O_CLIENTID);
  161. // add a new option
  162. pkt->addOption(createOption(D6O_CLIENTID));
  163. // carry on as usual
  164. return pkt6_receive_callout(callout_handle);
  165. }
  166. /// test callback that deletes client-id
  167. /// @param callout_handle handle passed by the hooks framework
  168. /// @return always 0
  169. static int
  170. pkt6_receive_delete_clientid(CalloutHandle& callout_handle) {
  171. Pkt6Ptr pkt;
  172. callout_handle.getArgument("query6", pkt);
  173. // get rid of the old client-id
  174. pkt->delOption(D6O_CLIENTID);
  175. // carry on as usual
  176. return pkt6_receive_callout(callout_handle);
  177. }
  178. /// test callback that sets skip flag
  179. /// @param callout_handle handle passed by the hooks framework
  180. /// @return always 0
  181. static int
  182. pkt6_receive_skip(CalloutHandle& callout_handle) {
  183. Pkt6Ptr pkt;
  184. callout_handle.getArgument("query6", pkt);
  185. callout_handle.setSkip(true);
  186. // carry on as usual
  187. return pkt6_receive_callout(callout_handle);
  188. }
  189. /// test callback that stores received callout name and pkt6 value
  190. /// @param callout_handle handle passed by the hooks framework
  191. /// @return always 0
  192. static int
  193. buffer6_receive_callout(CalloutHandle& callout_handle) {
  194. callback_name_ = string("buffer6_receive");
  195. callout_handle.getArgument("query6", callback_pkt6_);
  196. callback_argument_names_ = callout_handle.getArgumentNames();
  197. return (0);
  198. }
  199. /// test callback that changes first byte of client-id value
  200. /// @param callout_handle handle passed by the hooks framework
  201. /// @return always 0
  202. static int
  203. buffer6_receive_change_clientid(CalloutHandle& callout_handle) {
  204. Pkt6Ptr pkt;
  205. callout_handle.getArgument("query6", pkt);
  206. // If there is at least one option with data
  207. if (pkt->data_.size()>Pkt6::DHCPV6_PKT_HDR_LEN + Option::OPTION6_HDR_LEN) {
  208. pkt->data_[8] = 0xff;
  209. }
  210. // carry on as usual
  211. return buffer6_receive_callout(callout_handle);
  212. }
  213. /// test callback that deletes client-id
  214. /// @param callout_handle handle passed by the hooks framework
  215. /// @return always 0
  216. static int
  217. buffer6_receive_delete_clientid(CalloutHandle& callout_handle) {
  218. Pkt6Ptr pkt;
  219. callout_handle.getArgument("query6", pkt);
  220. // this is modified SOLICIT (with missing mandatory client-id)
  221. uint8_t data[] = {
  222. 1, // type 1 = SOLICIT
  223. 0xca, 0xfe, 0x01, // trans-id = 0xcafe01
  224. 0, 3, // option type 3 (IA_NA)
  225. 0, 12, // option length 12
  226. 0, 0, 0, 1, // iaid = 1
  227. 0, 0, 0, 0, // T1 = 0
  228. 0, 0, 0, 0 // T2 = 0
  229. };
  230. OptionBuffer modifiedMsg(data, data + sizeof(data));
  231. pkt->data_ = modifiedMsg;
  232. // carry on as usual
  233. return buffer6_receive_callout(callout_handle);
  234. }
  235. /// test callback that sets skip flag
  236. /// @param callout_handle handle passed by the hooks framework
  237. /// @return always 0
  238. static int
  239. buffer6_receive_skip(CalloutHandle& callout_handle) {
  240. Pkt6Ptr pkt;
  241. callout_handle.getArgument("query6", pkt);
  242. callout_handle.setSkip(true);
  243. // carry on as usual
  244. return buffer6_receive_callout(callout_handle);
  245. }
  246. /// Test callback that stores received callout name and pkt6 value
  247. /// @param callout_handle handle passed by the hooks framework
  248. /// @return always 0
  249. static int
  250. pkt6_send_callout(CalloutHandle& callout_handle) {
  251. callback_name_ = string("pkt6_send");
  252. callout_handle.getArgument("response6", callback_pkt6_);
  253. callback_argument_names_ = callout_handle.getArgumentNames();
  254. return (0);
  255. }
  256. // Test callback that changes server-id
  257. /// @param callout_handle handle passed by the hooks framework
  258. /// @return always 0
  259. static int
  260. pkt6_send_change_serverid(CalloutHandle& callout_handle) {
  261. Pkt6Ptr pkt;
  262. callout_handle.getArgument("response6", pkt);
  263. // get rid of the old server-id
  264. pkt->delOption(D6O_SERVERID);
  265. // add a new option
  266. pkt->addOption(createOption(D6O_SERVERID));
  267. // carry on as usual
  268. return pkt6_send_callout(callout_handle);
  269. }
  270. /// test callback that deletes server-id
  271. /// @param callout_handle handle passed by the hooks framework
  272. /// @return always 0
  273. static int
  274. pkt6_send_delete_serverid(CalloutHandle& callout_handle) {
  275. Pkt6Ptr pkt;
  276. callout_handle.getArgument("response6", pkt);
  277. // get rid of the old client-id
  278. pkt->delOption(D6O_SERVERID);
  279. // carry on as usual
  280. return pkt6_send_callout(callout_handle);
  281. }
  282. /// Test callback that sets skip flag
  283. /// @param callout_handle handle passed by the hooks framework
  284. /// @return always 0
  285. static int
  286. pkt6_send_skip(CalloutHandle& callout_handle) {
  287. Pkt6Ptr pkt;
  288. callout_handle.getArgument("response6", pkt);
  289. callout_handle.setSkip(true);
  290. // carry on as usual
  291. return pkt6_send_callout(callout_handle);
  292. }
  293. /// Test callback that stores received callout name and subnet6 values
  294. /// @param callout_handle handle passed by the hooks framework
  295. /// @return always 0
  296. static int
  297. subnet6_select_callout(CalloutHandle& callout_handle) {
  298. callback_name_ = string("subnet6_select");
  299. callout_handle.getArgument("query6", callback_pkt6_);
  300. callout_handle.getArgument("subnet6", callback_subnet6_);
  301. callout_handle.getArgument("subnet6collection", callback_subnet6collection_);
  302. callback_argument_names_ = callout_handle.getArgumentNames();
  303. return (0);
  304. }
  305. /// Test callback that picks the other subnet if possible.
  306. /// @param callout_handle handle passed by the hooks framework
  307. /// @return always 0
  308. static int
  309. subnet6_select_different_subnet_callout(CalloutHandle& callout_handle) {
  310. // Call the basic calllout to record all passed values
  311. subnet6_select_callout(callout_handle);
  312. const Subnet6Collection* subnets;
  313. Subnet6Ptr subnet;
  314. callout_handle.getArgument("subnet6", subnet);
  315. callout_handle.getArgument("subnet6collection", subnets);
  316. // Let's change to a different subnet
  317. if (subnets->size() > 1) {
  318. subnet = (*subnets)[1]; // Let's pick the other subnet
  319. callout_handle.setArgument("subnet6", subnet);
  320. }
  321. return (0);
  322. }
  323. /// test callback that stores received callout name and pkt6 value
  324. /// @param callout_handle handle passed by the hooks framework
  325. /// @return always 0
  326. static int
  327. lease6_renew_callout(CalloutHandle& callout_handle) {
  328. callback_name_ = string("lease6_renew");
  329. callout_handle.getArgument("query6", callback_pkt6_);
  330. callout_handle.getArgument("lease6", callback_lease6_);
  331. callout_handle.getArgument("ia_na", callback_ia_na_);
  332. callback_argument_names_ = callout_handle.getArgumentNames();
  333. return (0);
  334. }
  335. /// The following values are used by the callout to override
  336. /// renewed lease parameters
  337. static const uint32_t override_iaid_;
  338. static const uint32_t override_t1_;
  339. static const uint32_t override_t2_;
  340. static const uint32_t override_preferred_;
  341. static const uint32_t override_valid_;
  342. /// test callback that overrides received lease. It updates
  343. /// T1, T2, preferred and valid lifetimes
  344. /// @param callout_handle handle passed by the hooks framework
  345. /// @return always 0
  346. static int
  347. lease6_renew_update_callout(CalloutHandle& callout_handle) {
  348. callback_name_ = string("lease6_renew");
  349. callout_handle.getArgument("query6", callback_pkt6_);
  350. callout_handle.getArgument("lease6", callback_lease6_);
  351. callout_handle.getArgument("ia_na", callback_ia_na_);
  352. // Let's override some values in the lease
  353. callback_lease6_->iaid_ = override_iaid_;
  354. callback_lease6_->t1_ = override_t1_;
  355. callback_lease6_->t2_ = override_t2_;
  356. callback_lease6_->preferred_lft_ = override_preferred_;
  357. callback_lease6_->valid_lft_ = override_valid_;
  358. // Override the values to be sent to the client as well
  359. callback_ia_na_->setIAID(override_iaid_);
  360. callback_ia_na_->setT1(override_t1_);
  361. callback_ia_na_->setT2(override_t2_);
  362. callback_argument_names_ = callout_handle.getArgumentNames();
  363. return (0);
  364. }
  365. /// test callback that sets the skip flag
  366. /// @param callout_handle handle passed by the hooks framework
  367. /// @return always 0
  368. static int
  369. lease6_renew_skip_callout(CalloutHandle& callout_handle) {
  370. callback_name_ = string("lease6_renew");
  371. callout_handle.setSkip(true);
  372. return (0);
  373. }
  374. /// test callback that stores received callout name passed parameters
  375. /// @param callout_handle handle passed by the hooks framework
  376. /// @return always 0
  377. static int
  378. lease6_release_callout(CalloutHandle& callout_handle) {
  379. callback_name_ = string("lease6_release");
  380. callout_handle.getArgument("query6", callback_pkt6_);
  381. callout_handle.getArgument("lease6", callback_lease6_);
  382. callback_argument_names_ = callout_handle.getArgumentNames();
  383. return (0);
  384. }
  385. /// test callback that sets the skip flag
  386. /// @param callout_handle handle passed by the hooks framework
  387. /// @return always 0
  388. static int
  389. lease6_release_skip_callout(CalloutHandle& callout_handle) {
  390. callback_name_ = string("lease6_release");
  391. callout_handle.setSkip(true);
  392. return (0);
  393. }
  394. /// resets buffers used to store data received by callouts
  395. void resetCalloutBuffers() {
  396. callback_name_ = string("");
  397. callback_pkt6_.reset();
  398. callback_subnet6_.reset();
  399. callback_lease6_.reset();
  400. callback_ia_na_.reset();
  401. callback_subnet6collection_ = NULL;
  402. callback_argument_names_.clear();
  403. }
  404. /// pointer to Dhcpv6Srv that is used in tests
  405. NakedDhcpv6Srv* srv_;
  406. // The following fields are used in testing pkt6_receive_callout
  407. /// String name of the received callout
  408. static string callback_name_;
  409. /// Pkt6 structure returned in the callout
  410. static Pkt6Ptr callback_pkt6_;
  411. /// Pointer to lease6
  412. static Lease6Ptr callback_lease6_;
  413. /// Pointer to IA_NA option being renewed
  414. static boost::shared_ptr<Option6IA> callback_ia_na_;
  415. /// Pointer to a subnet received by callout
  416. static Subnet6Ptr callback_subnet6_;
  417. /// A list of all available subnets (received by callout)
  418. static const Subnet6Collection* callback_subnet6collection_;
  419. /// A list of all received arguments
  420. static vector<string> callback_argument_names_;
  421. };
  422. // The following parameters are used by callouts to override
  423. // renewed lease parameters
  424. const uint32_t HooksDhcpv6SrvTest::override_iaid_ = 1000;
  425. const uint32_t HooksDhcpv6SrvTest::override_t1_ = 1001;
  426. const uint32_t HooksDhcpv6SrvTest::override_t2_ = 1002;
  427. const uint32_t HooksDhcpv6SrvTest::override_preferred_ = 1003;
  428. const uint32_t HooksDhcpv6SrvTest::override_valid_ = 1004;
  429. // The following fields are used in testing pkt6_receive_callout.
  430. // See fields description in the class for details
  431. string HooksDhcpv6SrvTest::callback_name_;
  432. Pkt6Ptr HooksDhcpv6SrvTest::callback_pkt6_;
  433. Subnet6Ptr HooksDhcpv6SrvTest::callback_subnet6_;
  434. const Subnet6Collection* HooksDhcpv6SrvTest::callback_subnet6collection_;
  435. vector<string> HooksDhcpv6SrvTest::callback_argument_names_;
  436. Lease6Ptr HooksDhcpv6SrvTest::callback_lease6_;
  437. boost::shared_ptr<Option6IA> HooksDhcpv6SrvTest::callback_ia_na_;
  438. // Checks if callouts installed on pkt6_receive are indeed called and the
  439. // all necessary parameters are passed.
  440. //
  441. // Note that the test name does not follow test naming convention,
  442. // but the proper hook name is "buffer6_receive".
  443. TEST_F(HooksDhcpv6SrvTest, simple_buffer6_receive) {
  444. // Install pkt6_receive_callout
  445. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  446. "buffer6_receive", buffer6_receive_callout));
  447. // Let's create a simple SOLICIT
  448. Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
  449. // Simulate that we have received that traffic
  450. srv_->fakeReceive(sol);
  451. // Server will now process to run its normal loop, but instead of calling
  452. // IfaceMgr::receive6(), it will read all packets from the list set by
  453. // fakeReceive()
  454. // In particular, it should call registered pkt6_receive callback.
  455. srv_->run();
  456. // check that the callback called is indeed the one we installed
  457. EXPECT_EQ("buffer6_receive", callback_name_);
  458. // check that pkt6 argument passing was successful and returned proper value
  459. EXPECT_TRUE(callback_pkt6_.get() == sol.get());
  460. // Check that all expected parameters are there
  461. vector<string> expected_argument_names;
  462. expected_argument_names.push_back(string("query6"));
  463. EXPECT_TRUE(expected_argument_names == callback_argument_names_);
  464. }
  465. // Checks if callouts installed on pkt6_received is able to change
  466. // the values and the parameters are indeed used by the server.
  467. TEST_F(HooksDhcpv6SrvTest, valueChange_buffer6_receive) {
  468. // Install pkt6_receive_callout
  469. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  470. "buffer6_receive", buffer6_receive_change_clientid));
  471. // Let's create a simple SOLICIT
  472. Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
  473. // Simulate that we have received that traffic
  474. srv_->fakeReceive(sol);
  475. // Server will now process to run its normal loop, but instead of calling
  476. // IfaceMgr::receive6(), it will read all packets from the list set by
  477. // fakeReceive()
  478. // In particular, it should call registered pkt6_receive callback.
  479. srv_->run();
  480. // check that the server did send a reposonce
  481. ASSERT_EQ(1, srv_->fake_sent_.size());
  482. // Make sure that we received a response
  483. Pkt6Ptr adv = srv_->fake_sent_.front();
  484. ASSERT_TRUE(adv);
  485. // Get client-id...
  486. OptionPtr clientid = adv->getOption(D6O_CLIENTID);
  487. ASSERT_TRUE(clientid);
  488. // ... and check if it is the modified value
  489. EXPECT_EQ(0xff, clientid->getData()[0]);
  490. }
  491. // Checks if callouts installed on buffer6_receive is able to delete
  492. // existing options and that change impacts server processing (mandatory
  493. // client-id option is deleted, so the packet is expected to be dropped)
  494. TEST_F(HooksDhcpv6SrvTest, deleteClientId_buffer6_receive) {
  495. // Install pkt6_receive_callout
  496. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  497. "buffer6_receive", buffer6_receive_delete_clientid));
  498. // Let's create a simple SOLICIT
  499. Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
  500. // Simulate that we have received that traffic
  501. srv_->fakeReceive(sol);
  502. // Server will now process to run its normal loop, but instead of calling
  503. // IfaceMgr::receive6(), it will read all packets from the list set by
  504. // fakeReceive()
  505. // In particular, it should call registered pkt6_receive callback.
  506. srv_->run();
  507. // Check that the server dropped the packet and did not send a response
  508. ASSERT_EQ(0, srv_->fake_sent_.size());
  509. }
  510. // Checks if callouts installed on buffer6_received is able to set skip flag that
  511. // will cause the server to not process the packet (drop), even though it is valid.
  512. TEST_F(HooksDhcpv6SrvTest, skip_buffer6_receive) {
  513. // Install pkt6_receive_callout
  514. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  515. "buffer6_receive", buffer6_receive_skip));
  516. // Let's create a simple SOLICIT
  517. Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
  518. // Simulate that we have received that traffic
  519. srv_->fakeReceive(sol);
  520. // Server will now process to run its normal loop, but instead of calling
  521. // IfaceMgr::receive6(), it will read all packets from the list set by
  522. // fakeReceive()
  523. // In particular, it should call registered pkt6_receive callback.
  524. srv_->run();
  525. // check that the server dropped the packet and did not produce any response
  526. ASSERT_EQ(0, srv_->fake_sent_.size());
  527. }
  528. // Checks if callouts installed on pkt6_receive are indeed called and the
  529. // all necessary parameters are passed.
  530. //
  531. // Note that the test name does not follow test naming convention,
  532. // but the proper hook name is "pkt6_receive".
  533. TEST_F(HooksDhcpv6SrvTest, simple_pkt6_receive) {
  534. // Install pkt6_receive_callout
  535. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  536. "pkt6_receive", pkt6_receive_callout));
  537. // Let's create a simple SOLICIT
  538. Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
  539. // Simulate that we have received that traffic
  540. srv_->fakeReceive(sol);
  541. // Server will now process to run its normal loop, but instead of calling
  542. // IfaceMgr::receive6(), it will read all packets from the list set by
  543. // fakeReceive()
  544. // In particular, it should call registered pkt6_receive callback.
  545. srv_->run();
  546. // check that the callback called is indeed the one we installed
  547. EXPECT_EQ("pkt6_receive", callback_name_);
  548. // check that pkt6 argument passing was successful and returned proper value
  549. EXPECT_TRUE(callback_pkt6_.get() == sol.get());
  550. // Check that all expected parameters are there
  551. vector<string> expected_argument_names;
  552. expected_argument_names.push_back(string("query6"));
  553. EXPECT_TRUE(expected_argument_names == callback_argument_names_);
  554. }
  555. // Checks if callouts installed on pkt6_received is able to change
  556. // the values and the parameters are indeed used by the server.
  557. TEST_F(HooksDhcpv6SrvTest, valueChange_pkt6_receive) {
  558. // Install pkt6_receive_callout
  559. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  560. "pkt6_receive", pkt6_receive_change_clientid));
  561. // Let's create a simple SOLICIT
  562. Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
  563. // Simulate that we have received that traffic
  564. srv_->fakeReceive(sol);
  565. // Server will now process to run its normal loop, but instead of calling
  566. // IfaceMgr::receive6(), it will read all packets from the list set by
  567. // fakeReceive()
  568. // In particular, it should call registered pkt6_receive callback.
  569. srv_->run();
  570. // check that the server did send a reposonce
  571. ASSERT_EQ(1, srv_->fake_sent_.size());
  572. // Make sure that we received a response
  573. Pkt6Ptr adv = srv_->fake_sent_.front();
  574. ASSERT_TRUE(adv);
  575. // Get client-id...
  576. OptionPtr clientid = adv->getOption(D6O_CLIENTID);
  577. // ... and check if it is the modified value
  578. OptionPtr expected = createOption(D6O_CLIENTID);
  579. EXPECT_TRUE(clientid->equal(expected));
  580. }
  581. // Checks if callouts installed on pkt6_received is able to delete
  582. // existing options and that change impacts server processing (mandatory
  583. // client-id option is deleted, so the packet is expected to be dropped)
  584. TEST_F(HooksDhcpv6SrvTest, deleteClientId_pkt6_receive) {
  585. // Install pkt6_receive_callout
  586. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  587. "pkt6_receive", pkt6_receive_delete_clientid));
  588. // Let's create a simple SOLICIT
  589. Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
  590. // Simulate that we have received that traffic
  591. srv_->fakeReceive(sol);
  592. // Server will now process to run its normal loop, but instead of calling
  593. // IfaceMgr::receive6(), it will read all packets from the list set by
  594. // fakeReceive()
  595. // In particular, it should call registered pkt6_receive callback.
  596. srv_->run();
  597. // Check that the server dropped the packet and did not send a response
  598. ASSERT_EQ(0, srv_->fake_sent_.size());
  599. }
  600. // Checks if callouts installed on pkt6_received is able to set skip flag that
  601. // will cause the server to not process the packet (drop), even though it is valid.
  602. TEST_F(HooksDhcpv6SrvTest, skip_pkt6_receive) {
  603. // Install pkt6_receive_callout
  604. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  605. "pkt6_receive", pkt6_receive_skip));
  606. // Let's create a simple SOLICIT
  607. Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
  608. // Simulate that we have received that traffic
  609. srv_->fakeReceive(sol);
  610. // Server will now process to run its normal loop, but instead of calling
  611. // IfaceMgr::receive6(), it will read all packets from the list set by
  612. // fakeReceive()
  613. // In particular, it should call registered pkt6_receive callback.
  614. srv_->run();
  615. // check that the server dropped the packet and did not produce any response
  616. ASSERT_EQ(0, srv_->fake_sent_.size());
  617. }
  618. // Checks if callouts installed on pkt6_send are indeed called and the
  619. // all necessary parameters are passed.
  620. TEST_F(HooksDhcpv6SrvTest, simple_pkt6_send) {
  621. // Install pkt6_receive_callout
  622. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  623. "pkt6_send", pkt6_send_callout));
  624. // Let's create a simple SOLICIT
  625. Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
  626. // Simulate that we have received that traffic
  627. srv_->fakeReceive(sol);
  628. // Server will now process to run its normal loop, but instead of calling
  629. // IfaceMgr::receive6(), it will read all packets from the list set by
  630. // fakeReceive()
  631. // In particular, it should call registered pkt6_receive callback.
  632. srv_->run();
  633. // Check that the callback called is indeed the one we installed
  634. EXPECT_EQ("pkt6_send", callback_name_);
  635. // Check that there is one packet sent
  636. ASSERT_EQ(1, srv_->fake_sent_.size());
  637. Pkt6Ptr adv = srv_->fake_sent_.front();
  638. // Check that pkt6 argument passing was successful and returned proper value
  639. EXPECT_TRUE(callback_pkt6_.get() == adv.get());
  640. // Check that all expected parameters are there
  641. vector<string> expected_argument_names;
  642. expected_argument_names.push_back(string("response6"));
  643. EXPECT_TRUE(expected_argument_names == callback_argument_names_);
  644. }
  645. // Checks if callouts installed on pkt6_send is able to change
  646. // the values and the packet sent contains those changes
  647. TEST_F(HooksDhcpv6SrvTest, valueChange_pkt6_send) {
  648. // Install pkt6_receive_callout
  649. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  650. "pkt6_send", pkt6_send_change_serverid));
  651. // Let's create a simple SOLICIT
  652. Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
  653. // Simulate that we have received that traffic
  654. srv_->fakeReceive(sol);
  655. // Server will now process to run its normal loop, but instead of calling
  656. // IfaceMgr::receive6(), it will read all packets from the list set by
  657. // fakeReceive()
  658. // In particular, it should call registered pkt6_receive callback.
  659. srv_->run();
  660. // check that the server did send a reposonce
  661. ASSERT_EQ(1, srv_->fake_sent_.size());
  662. // Make sure that we received a response
  663. Pkt6Ptr adv = srv_->fake_sent_.front();
  664. ASSERT_TRUE(adv);
  665. // Get client-id...
  666. OptionPtr clientid = adv->getOption(D6O_SERVERID);
  667. // ... and check if it is the modified value
  668. OptionPtr expected = createOption(D6O_SERVERID);
  669. EXPECT_TRUE(clientid->equal(expected));
  670. }
  671. // Checks if callouts installed on pkt6_send is able to delete
  672. // existing options and that server applies those changes. In particular,
  673. // we are trying to send a packet without server-id. The packet should
  674. // be sent
  675. TEST_F(HooksDhcpv6SrvTest, deleteServerId_pkt6_send) {
  676. // Install pkt6_receive_callout
  677. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  678. "pkt6_send", pkt6_send_delete_serverid));
  679. // Let's create a simple SOLICIT
  680. Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
  681. // Simulate that we have received that traffic
  682. srv_->fakeReceive(sol);
  683. // Server will now process to run its normal loop, but instead of calling
  684. // IfaceMgr::receive6(), it will read all packets from the list set by
  685. // fakeReceive()
  686. // In particular, it should call registered pkt6_receive callback.
  687. srv_->run();
  688. // Check that the server indeed sent a malformed ADVERTISE
  689. ASSERT_EQ(1, srv_->fake_sent_.size());
  690. // Get that ADVERTISE
  691. Pkt6Ptr adv = srv_->fake_sent_.front();
  692. ASSERT_TRUE(adv);
  693. // Make sure that it does not have server-id
  694. EXPECT_FALSE(adv->getOption(D6O_SERVERID));
  695. }
  696. // Checks if callouts installed on pkt6_skip is able to set skip flag that
  697. // will cause the server to not process the packet (drop), even though it is valid.
  698. TEST_F(HooksDhcpv6SrvTest, skip_pkt6_send) {
  699. // Install pkt6_receive_callout
  700. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  701. "pkt6_send", pkt6_send_skip));
  702. // Let's create a simple REQUEST
  703. Pkt6Ptr sol = Pkt6Ptr(captureSimpleSolicit());
  704. // Simulate that we have received that traffic
  705. srv_->fakeReceive(sol);
  706. // Server will now process to run its normal loop, but instead of calling
  707. // IfaceMgr::receive6(), it will read all packets from the list set by
  708. // fakeReceive()
  709. // In particular, it should call registered pkt6_receive callback.
  710. srv_->run();
  711. // check that the server dropped the packet and did not produce any response
  712. ASSERT_EQ(0, srv_->fake_sent_.size());
  713. }
  714. // This test checks if subnet6_select callout is triggered and reports
  715. // valid parameters
  716. TEST_F(HooksDhcpv6SrvTest, subnet6_select) {
  717. // Install pkt6_receive_callout
  718. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  719. "subnet6_select", subnet6_select_callout));
  720. // Configure 2 subnets, both directly reachable over local interface
  721. // (let's not complicate the matter with relays)
  722. string config = "{ \"interfaces\": [ \"*\" ],"
  723. "\"preferred-lifetime\": 3000,"
  724. "\"rebind-timer\": 2000, "
  725. "\"renew-timer\": 1000, "
  726. "\"subnet6\": [ { "
  727. " \"pool\": [ \"2001:db8:1::/64\" ],"
  728. " \"subnet\": \"2001:db8:1::/48\", "
  729. " \"interface\": \"" + valid_iface_ + "\" "
  730. " }, {"
  731. " \"pool\": [ \"2001:db8:2::/64\" ],"
  732. " \"subnet\": \"2001:db8:2::/48\" "
  733. " } ],"
  734. "\"valid-lifetime\": 4000 }";
  735. ElementPtr json = Element::fromJSON(config);
  736. ConstElementPtr status;
  737. // Configure the server and make sure the config is accepted
  738. EXPECT_NO_THROW(status = configureDhcp6Server(*srv_, json));
  739. ASSERT_TRUE(status);
  740. comment_ = parseAnswer(rcode_, status);
  741. ASSERT_EQ(0, rcode_);
  742. // Prepare solicit packet. Server should select first subnet for it
  743. Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
  744. sol->setRemoteAddr(IOAddress("fe80::abcd"));
  745. sol->setIface(valid_iface_);
  746. sol->addOption(generateIA(234, 1500, 3000));
  747. OptionPtr clientid = generateClientId();
  748. sol->addOption(clientid);
  749. // Pass it to the server and get an advertise
  750. Pkt6Ptr adv = srv_->processSolicit(sol);
  751. // check if we get response at all
  752. ASSERT_TRUE(adv);
  753. // Check that the callback called is indeed the one we installed
  754. EXPECT_EQ("subnet6_select", callback_name_);
  755. // Check that pkt6 argument passing was successful and returned proper value
  756. EXPECT_TRUE(callback_pkt6_.get() == sol.get());
  757. const Subnet6Collection* exp_subnets = CfgMgr::instance().getSubnets6();
  758. // The server is supposed to pick the first subnet, because of matching
  759. // interface. Check that the value is reported properly.
  760. ASSERT_TRUE(callback_subnet6_);
  761. EXPECT_EQ(callback_subnet6_.get(), exp_subnets->front().get());
  762. // Server is supposed to report two subnets
  763. ASSERT_EQ(exp_subnets->size(), callback_subnet6collection_->size());
  764. // Compare that the available subnets are reported as expected
  765. EXPECT_TRUE((*exp_subnets)[0].get() == (*callback_subnet6collection_)[0].get());
  766. EXPECT_TRUE((*exp_subnets)[1].get() == (*callback_subnet6collection_)[1].get());
  767. }
  768. // This test checks if callout installed on subnet6_select hook point can pick
  769. // a different subnet.
  770. TEST_F(HooksDhcpv6SrvTest, subnet_select_change) {
  771. // Install pkt6_receive_callout
  772. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  773. "subnet6_select", subnet6_select_different_subnet_callout));
  774. // Configure 2 subnets, both directly reachable over local interface
  775. // (let's not complicate the matter with relays)
  776. string config = "{ \"interfaces\": [ \"*\" ],"
  777. "\"preferred-lifetime\": 3000,"
  778. "\"rebind-timer\": 2000, "
  779. "\"renew-timer\": 1000, "
  780. "\"subnet6\": [ { "
  781. " \"pool\": [ \"2001:db8:1::/64\" ],"
  782. " \"subnet\": \"2001:db8:1::/48\", "
  783. " \"interface\": \"" + valid_iface_ + "\" "
  784. " }, {"
  785. " \"pool\": [ \"2001:db8:2::/64\" ],"
  786. " \"subnet\": \"2001:db8:2::/48\" "
  787. " } ],"
  788. "\"valid-lifetime\": 4000 }";
  789. ElementPtr json = Element::fromJSON(config);
  790. ConstElementPtr status;
  791. // Configure the server and make sure the config is accepted
  792. EXPECT_NO_THROW(status = configureDhcp6Server(*srv_, json));
  793. ASSERT_TRUE(status);
  794. comment_ = parseAnswer(rcode_, status);
  795. ASSERT_EQ(0, rcode_);
  796. // Prepare solicit packet. Server should select first subnet for it
  797. Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
  798. sol->setRemoteAddr(IOAddress("fe80::abcd"));
  799. sol->setIface(valid_iface_);
  800. sol->addOption(generateIA(234, 1500, 3000));
  801. OptionPtr clientid = generateClientId();
  802. sol->addOption(clientid);
  803. // Pass it to the server and get an advertise
  804. Pkt6Ptr adv = srv_->processSolicit(sol);
  805. // check if we get response at all
  806. ASSERT_TRUE(adv);
  807. // The response should have an address from second pool, so let's check it
  808. OptionPtr tmp = adv->getOption(D6O_IA_NA);
  809. ASSERT_TRUE(tmp);
  810. boost::shared_ptr<Option6IA> ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
  811. ASSERT_TRUE(ia);
  812. tmp = ia->getOption(D6O_IAADDR);
  813. ASSERT_TRUE(tmp);
  814. boost::shared_ptr<Option6IAAddr> addr_opt =
  815. boost::dynamic_pointer_cast<Option6IAAddr>(tmp);
  816. ASSERT_TRUE(addr_opt);
  817. // Get all subnets and use second subnet for verification
  818. const Subnet6Collection* subnets = CfgMgr::instance().getSubnets6();
  819. ASSERT_EQ(2, subnets->size());
  820. // Advertised address must belong to the second pool (in subnet's range,
  821. // in dynamic pool)
  822. EXPECT_TRUE((*subnets)[1]->inRange(addr_opt->getAddress()));
  823. EXPECT_TRUE((*subnets)[1]->inPool(addr_opt->getAddress()));
  824. }
  825. // This test verifies that incoming (positive) RENEW can be handled properly,
  826. // and the lease6_renew callouts are triggered.
  827. TEST_F(HooksDhcpv6SrvTest, basic_lease6_renew) {
  828. NakedDhcpv6Srv srv(0);
  829. // Install pkt6_receive_callout
  830. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  831. "lease6_renew", lease6_renew_callout));
  832. const IOAddress addr("2001:db8:1:1::cafe:babe");
  833. const uint32_t iaid = 234;
  834. // Generate client-id also duid_
  835. OptionPtr clientid = generateClientId();
  836. // Check that the address we are about to use is indeed in pool
  837. ASSERT_TRUE(subnet_->inPool(addr));
  838. // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
  839. // value on purpose. They should be updated during RENEW.
  840. Lease6Ptr lease(new Lease6(Lease6::LEASE_IA_NA, addr, duid_, iaid,
  841. 501, 502, 503, 504, subnet_->getID(), 0));
  842. lease->cltt_ = 1234;
  843. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
  844. // Check that the lease is really in the database
  845. Lease6Ptr l = LeaseMgrFactory::instance().getLease6(addr);
  846. ASSERT_TRUE(l);
  847. // Check that T1, T2, preferred, valid and cltt really set and not using
  848. // previous (500, 501, etc.) values
  849. EXPECT_NE(l->t1_, subnet_->getT1());
  850. EXPECT_NE(l->t2_, subnet_->getT2());
  851. EXPECT_NE(l->preferred_lft_, subnet_->getPreferred());
  852. EXPECT_NE(l->valid_lft_, subnet_->getValid());
  853. EXPECT_NE(l->cltt_, time(NULL));
  854. // Let's create a RENEW
  855. Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RENEW, 1234));
  856. req->setRemoteAddr(IOAddress("fe80::abcd"));
  857. boost::shared_ptr<Option6IA> ia = generateIA(iaid, 1500, 3000);
  858. OptionPtr renewed_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
  859. ia->addOption(renewed_addr_opt);
  860. req->addOption(ia);
  861. req->addOption(clientid);
  862. // Server-id is mandatory in RENEW
  863. req->addOption(srv.getServerID());
  864. // Pass it to the server and hope for a REPLY
  865. Pkt6Ptr reply = srv.processRenew(req);
  866. ASSERT_TRUE(reply);
  867. // Check that the callback called is indeed the one we installed
  868. EXPECT_EQ("lease6_renew", callback_name_);
  869. // Check that appropriate parameters are passed to the callouts
  870. EXPECT_TRUE(callback_pkt6_);
  871. EXPECT_TRUE(callback_lease6_);
  872. EXPECT_TRUE(callback_ia_na_);
  873. // Check if all expected parameters were really received
  874. vector<string> expected_argument_names;
  875. expected_argument_names.push_back("query6");
  876. expected_argument_names.push_back("lease6");
  877. expected_argument_names.push_back("ia_na");
  878. sort(callback_argument_names_.begin(), callback_argument_names_.end());
  879. sort(expected_argument_names.begin(), expected_argument_names.end());
  880. EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
  881. // Check if we get response at all
  882. checkResponse(reply, DHCPV6_REPLY, 1234);
  883. OptionPtr tmp = reply->getOption(D6O_IA_NA);
  884. ASSERT_TRUE(tmp);
  885. // Check that IA_NA was returned and that there's an address included
  886. boost::shared_ptr<Option6IAAddr> addr_opt = checkIA_NA(reply, 234, subnet_->getT1(),
  887. subnet_->getT2());
  888. ASSERT_TRUE(addr_opt);
  889. // Check that the lease is really in the database
  890. l = checkLease(duid_, reply->getOption(D6O_IA_NA), addr_opt);
  891. ASSERT_TRUE(l);
  892. // Check that the lease has been returned
  893. ASSERT_TRUE(callback_lease6_);
  894. // Check that the returned lease6 in callout is the same as the one in the
  895. // database
  896. EXPECT_TRUE(*callback_lease6_ == *l);
  897. }
  898. // This test verifies that incoming (positive) RENEW can be handled properly,
  899. // and the lease6_renew callouts are able to change the lease being updated.
  900. TEST_F(HooksDhcpv6SrvTest, leaseUpdate_lease6_renew) {
  901. NakedDhcpv6Srv srv(0);
  902. // Install pkt6_receive_callout
  903. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  904. "lease6_renew", lease6_renew_update_callout));
  905. const IOAddress addr("2001:db8:1:1::cafe:babe");
  906. const uint32_t iaid = 234;
  907. // Generate client-id also duid_
  908. OptionPtr clientid = generateClientId();
  909. // Check that the address we are about to use is indeed in pool
  910. ASSERT_TRUE(subnet_->inPool(addr));
  911. // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
  912. // value on purpose. They should be updated during RENEW.
  913. Lease6Ptr lease(new Lease6(Lease6::LEASE_IA_NA, addr, duid_, iaid,
  914. 501, 502, 503, 504, subnet_->getID(), 0));
  915. lease->cltt_ = 1234;
  916. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
  917. // Check that the lease is really in the database
  918. Lease6Ptr l = LeaseMgrFactory::instance().getLease6(addr);
  919. ASSERT_TRUE(l);
  920. // Check that T1, T2, preferred, valid and cltt really set and not using
  921. // previous (500, 501, etc.) values
  922. EXPECT_NE(l->t1_, subnet_->getT1());
  923. EXPECT_NE(l->t2_, subnet_->getT2());
  924. EXPECT_NE(l->preferred_lft_, subnet_->getPreferred());
  925. EXPECT_NE(l->valid_lft_, subnet_->getValid());
  926. EXPECT_NE(l->cltt_, time(NULL));
  927. // Let's create a RENEW
  928. Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RENEW, 1234));
  929. req->setRemoteAddr(IOAddress("fe80::abcd"));
  930. boost::shared_ptr<Option6IA> ia = generateIA(iaid, 1500, 3000);
  931. OptionPtr renewed_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
  932. ia->addOption(renewed_addr_opt);
  933. req->addOption(ia);
  934. req->addOption(clientid);
  935. // Server-id is mandatory in RENEW
  936. req->addOption(srv.getServerID());
  937. // Pass it to the server and hope for a REPLY
  938. Pkt6Ptr reply = srv.processRenew(req);
  939. ASSERT_TRUE(reply);
  940. // Check if we get response at all
  941. checkResponse(reply, DHCPV6_REPLY, 1234);
  942. OptionPtr tmp = reply->getOption(D6O_IA_NA);
  943. ASSERT_TRUE(tmp);
  944. // Check that IA_NA was returned and that there's an address included
  945. boost::shared_ptr<Option6IAAddr> addr_opt = checkIA_NA(reply, 1000, 1001, 1002);
  946. ASSERT_TRUE(addr_opt);
  947. // Check that the lease is really in the database
  948. l = checkLease(duid_, reply->getOption(D6O_IA_NA), addr_opt);
  949. ASSERT_TRUE(l);
  950. // Check that we chose the distinct override values
  951. ASSERT_NE(override_t1_, subnet_->getT1());
  952. ASSERT_NE(override_t2_, subnet_->getT2());
  953. ASSERT_NE(override_preferred_, subnet_->getPreferred());
  954. EXPECT_NE(override_valid_, subnet_->getValid());
  955. // Check that T1, T2, preferred, valid were overridden the the callout
  956. EXPECT_EQ(override_t1_, l->t1_);
  957. EXPECT_EQ(override_t2_, l->t2_);
  958. EXPECT_EQ(override_preferred_, l->preferred_lft_);
  959. EXPECT_EQ(override_valid_, l->valid_lft_);
  960. // Checking for CLTT is a bit tricky if we want to avoid off by 1 errors
  961. int32_t cltt = static_cast<int32_t>(l->cltt_);
  962. int32_t expected = static_cast<int32_t>(time(NULL));
  963. // equality or difference by 1 between cltt and expected is ok.
  964. EXPECT_GE(1, abs(cltt - expected));
  965. EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease(addr_opt->getAddress()));
  966. }
  967. // This test verifies that incoming (positive) RENEW can be handled properly,
  968. // and the lease6_renew callouts are able to set the skip flag that will
  969. // reject the renewal
  970. TEST_F(HooksDhcpv6SrvTest, skip_lease6_renew) {
  971. NakedDhcpv6Srv srv(0);
  972. // Install pkt6_receive_callout
  973. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  974. "lease6_renew", lease6_renew_skip_callout));
  975. const IOAddress addr("2001:db8:1:1::cafe:babe");
  976. const uint32_t iaid = 234;
  977. // Generate client-id also duid_
  978. OptionPtr clientid = generateClientId();
  979. // Check that the address we are about to use is indeed in pool
  980. ASSERT_TRUE(subnet_->inPool(addr));
  981. // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
  982. // value on purpose. They should be updated during RENEW.
  983. Lease6Ptr lease(new Lease6(Lease6::LEASE_IA_NA, addr, duid_, iaid,
  984. 501, 502, 503, 504, subnet_->getID(), 0));
  985. lease->cltt_ = 1234;
  986. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
  987. // Check that the lease is really in the database
  988. Lease6Ptr l = LeaseMgrFactory::instance().getLease6(addr);
  989. ASSERT_TRUE(l);
  990. // Check that T1, T2, preferred, valid and cltt really set and not using
  991. // previous (500, 501, etc.) values
  992. EXPECT_NE(l->t1_, subnet_->getT1());
  993. EXPECT_NE(l->t2_, subnet_->getT2());
  994. EXPECT_NE(l->preferred_lft_, subnet_->getPreferred());
  995. EXPECT_NE(l->valid_lft_, subnet_->getValid());
  996. EXPECT_NE(l->cltt_, time(NULL));
  997. // Let's create a RENEW
  998. Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RENEW, 1234));
  999. req->setRemoteAddr(IOAddress("fe80::abcd"));
  1000. boost::shared_ptr<Option6IA> ia = generateIA(iaid, 1500, 3000);
  1001. OptionPtr renewed_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
  1002. ia->addOption(renewed_addr_opt);
  1003. req->addOption(ia);
  1004. req->addOption(clientid);
  1005. // Server-id is mandatory in RENEW
  1006. req->addOption(srv.getServerID());
  1007. // Pass it to the server and hope for a REPLY
  1008. Pkt6Ptr reply = srv.processRenew(req);
  1009. ASSERT_TRUE(reply);
  1010. // Check that our callback was called
  1011. EXPECT_EQ("lease6_renew", callback_name_);
  1012. l = LeaseMgrFactory::instance().getLease6(addr);
  1013. // Check that the old values are still there and they were not
  1014. // updated by the renewal
  1015. EXPECT_NE(l->t1_, subnet_->getT1());
  1016. EXPECT_NE(l->t2_, subnet_->getT2());
  1017. EXPECT_NE(l->preferred_lft_, subnet_->getPreferred());
  1018. EXPECT_NE(l->valid_lft_, subnet_->getValid());
  1019. EXPECT_NE(l->cltt_, time(NULL));
  1020. }
  1021. // This test verifies that incoming (positive) RELEASE can be handled properly,
  1022. // that a REPLY is generated, that the response has status code and that the
  1023. // lease is indeed removed from the database.
  1024. //
  1025. // expected:
  1026. // - returned REPLY message has copy of client-id
  1027. // - returned REPLY message has server-id
  1028. // - returned REPLY message has IA that does not include an IAADDR
  1029. // - lease is actually removed from LeaseMgr
  1030. TEST_F(HooksDhcpv6SrvTest, basic_lease6_release) {
  1031. NakedDhcpv6Srv srv(0);
  1032. // Install pkt6_receive_callout
  1033. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1034. "lease6_release", lease6_release_callout));
  1035. const IOAddress addr("2001:db8:1:1::cafe:babe");
  1036. const uint32_t iaid = 234;
  1037. // Generate client-id also duid_
  1038. OptionPtr clientid = generateClientId();
  1039. // Check that the address we are about to use is indeed in pool
  1040. ASSERT_TRUE(subnet_->inPool(addr));
  1041. // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
  1042. // value on purpose. They should be updated during RENEW.
  1043. Lease6Ptr lease(new Lease6(Lease6::LEASE_IA_NA, addr, duid_, iaid,
  1044. 501, 502, 503, 504, subnet_->getID(), 0));
  1045. lease->cltt_ = 1234;
  1046. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
  1047. // Check that the lease is really in the database
  1048. Lease6Ptr l = LeaseMgrFactory::instance().getLease6(addr);
  1049. ASSERT_TRUE(l);
  1050. // Let's create a RELEASE
  1051. Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RELEASE, 1234));
  1052. req->setRemoteAddr(IOAddress("fe80::abcd"));
  1053. boost::shared_ptr<Option6IA> ia = generateIA(iaid, 1500, 3000);
  1054. OptionPtr released_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
  1055. ia->addOption(released_addr_opt);
  1056. req->addOption(ia);
  1057. req->addOption(clientid);
  1058. // Server-id is mandatory in RELEASE
  1059. req->addOption(srv.getServerID());
  1060. // Pass it to the server and hope for a REPLY
  1061. Pkt6Ptr reply = srv.processRelease(req);
  1062. ASSERT_TRUE(reply);
  1063. // Check that the callback called is indeed the one we installed
  1064. EXPECT_EQ("lease6_release", callback_name_);
  1065. // Check that appropriate parameters are passed to the callouts
  1066. EXPECT_TRUE(callback_pkt6_);
  1067. EXPECT_TRUE(callback_lease6_);
  1068. // Check if all expected parameters were really received
  1069. vector<string> expected_argument_names;
  1070. expected_argument_names.push_back("query6");
  1071. expected_argument_names.push_back("lease6");
  1072. sort(callback_argument_names_.begin(), callback_argument_names_.end());
  1073. sort(expected_argument_names.begin(), expected_argument_names.end());
  1074. EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
  1075. // Check that the lease is really gone in the database
  1076. // get lease by address
  1077. l = LeaseMgrFactory::instance().getLease6(addr);
  1078. ASSERT_FALSE(l);
  1079. // get lease by subnetid/duid/iaid combination
  1080. l = LeaseMgrFactory::instance().getLease6(*duid_, iaid, subnet_->getID());
  1081. ASSERT_FALSE(l);
  1082. }
  1083. // This test verifies that incoming (positive) RELEASE can be handled properly,
  1084. // that a REPLY is generated, that the response has status code and that the
  1085. // lease is indeed removed from the database.
  1086. //
  1087. // expected:
  1088. // - returned REPLY message has copy of client-id
  1089. // - returned REPLY message has server-id
  1090. // - returned REPLY message has IA that does not include an IAADDR
  1091. // - lease is actually removed from LeaseMgr
  1092. TEST_F(HooksDhcpv6SrvTest, skip_lease6_release) {
  1093. NakedDhcpv6Srv srv(0);
  1094. // Install pkt6_receive_callout
  1095. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1096. "lease6_release", lease6_release_skip_callout));
  1097. const IOAddress addr("2001:db8:1:1::cafe:babe");
  1098. const uint32_t iaid = 234;
  1099. // Generate client-id also duid_
  1100. OptionPtr clientid = generateClientId();
  1101. // Check that the address we are about to use is indeed in pool
  1102. ASSERT_TRUE(subnet_->inPool(addr));
  1103. // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
  1104. // value on purpose. They should be updated during RENEW.
  1105. Lease6Ptr lease(new Lease6(Lease6::LEASE_IA_NA, addr, duid_, iaid,
  1106. 501, 502, 503, 504, subnet_->getID(), 0));
  1107. lease->cltt_ = 1234;
  1108. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
  1109. // Check that the lease is really in the database
  1110. Lease6Ptr l = LeaseMgrFactory::instance().getLease6(addr);
  1111. ASSERT_TRUE(l);
  1112. // Let's create a RELEASE
  1113. Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RELEASE, 1234));
  1114. req->setRemoteAddr(IOAddress("fe80::abcd"));
  1115. boost::shared_ptr<Option6IA> ia = generateIA(iaid, 1500, 3000);
  1116. OptionPtr released_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
  1117. ia->addOption(released_addr_opt);
  1118. req->addOption(ia);
  1119. req->addOption(clientid);
  1120. // Server-id is mandatory in RELEASE
  1121. req->addOption(srv.getServerID());
  1122. // Pass it to the server and hope for a REPLY
  1123. Pkt6Ptr reply = srv.processRelease(req);
  1124. ASSERT_TRUE(reply);
  1125. // Check that the callback called is indeed the one we installed
  1126. EXPECT_EQ("lease6_release", callback_name_);
  1127. // Check that the lease is still there
  1128. // get lease by address
  1129. l = LeaseMgrFactory::instance().getLease6(addr);
  1130. ASSERT_TRUE(l);
  1131. // get lease by subnetid/duid/iaid combination
  1132. l = LeaseMgrFactory::instance().getLease6(*duid_, iaid, subnet_->getID());
  1133. ASSERT_TRUE(l);
  1134. }
  1135. } // end of anonymous namespace