hooks_unittest.cc 64 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741
  1. // Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this
  5. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. #include <config.h>
  7. #include <dhcp4/tests/dhcp4_test_utils.h>
  8. #include <dhcp4/tests/dhcp4_client.h>
  9. #include <dhcp4/json_config_parser.h>
  10. #include <cc/command_interpreter.h>
  11. #include <config/command_mgr.h>
  12. #include <hooks/server_hooks.h>
  13. #include <hooks/hooks_manager.h>
  14. #include <dhcpsrv/cfgmgr.h>
  15. #include <dhcp/tests/iface_mgr_test_config.h>
  16. #include <dhcp/option.h>
  17. #include <asiolink/io_address.h>
  18. #include <dhcp4/tests/marker_file.h>
  19. #include <dhcp4/tests/test_libraries.h>
  20. #include <vector>
  21. using namespace std;
  22. using namespace isc::asiolink;
  23. using namespace isc::data;
  24. using namespace isc::hooks;
  25. using namespace isc::config;
  26. using namespace isc::dhcp::test;
  27. using namespace isc::dhcp;
  28. // Checks if hooks are registered properly.
  29. TEST_F(Dhcpv4SrvTest, Hooks) {
  30. NakedDhcpv4Srv srv(0);
  31. // check if appropriate hooks are registered
  32. int hook_index_buffer4_receive = -1;
  33. int hook_index_pkt4_receive = -1;
  34. int hook_index_select_subnet = -1;
  35. int hook_index_lease4_release = -1;
  36. int hook_index_pkt4_send = -1;
  37. int hook_index_buffer4_send = -1;
  38. // check if appropriate indexes are set
  39. EXPECT_NO_THROW(hook_index_buffer4_receive = ServerHooks::getServerHooks()
  40. .getIndex("buffer4_receive"));
  41. EXPECT_NO_THROW(hook_index_pkt4_receive = ServerHooks::getServerHooks()
  42. .getIndex("pkt4_receive"));
  43. EXPECT_NO_THROW(hook_index_select_subnet = ServerHooks::getServerHooks()
  44. .getIndex("subnet4_select"));
  45. EXPECT_NO_THROW(hook_index_lease4_release = ServerHooks::getServerHooks()
  46. .getIndex("lease4_release"));
  47. EXPECT_NO_THROW(hook_index_pkt4_send = ServerHooks::getServerHooks()
  48. .getIndex("pkt4_send"));
  49. EXPECT_NO_THROW(hook_index_buffer4_send = ServerHooks::getServerHooks()
  50. .getIndex("buffer4_send"));
  51. EXPECT_TRUE(hook_index_buffer4_receive > 0);
  52. EXPECT_TRUE(hook_index_pkt4_receive > 0);
  53. EXPECT_TRUE(hook_index_select_subnet > 0);
  54. EXPECT_TRUE(hook_index_lease4_release > 0);
  55. EXPECT_TRUE(hook_index_pkt4_send > 0);
  56. EXPECT_TRUE(hook_index_buffer4_send > 0);
  57. }
  58. // A dummy MAC address, padded with 0s
  59. const uint8_t dummyChaddr[16] = {0, 1, 2, 3, 4, 5, 0, 0,
  60. 0, 0, 0, 0, 0, 0, 0, 0 };
  61. // Let's use some creative test content here (128 chars + \0)
  62. const uint8_t dummyFile[] = "Lorem ipsum dolor sit amet, consectetur "
  63. "adipiscing elit. Proin mollis placerat metus, at "
  64. "lacinia orci ornare vitae. Mauris amet.";
  65. // Yet another type of test content (64 chars + \0)
  66. const uint8_t dummySname[] = "Lorem ipsum dolor sit amet, consectetur "
  67. "adipiscing elit posuere.";
  68. /// @brief a class dedicated to Hooks testing in DHCPv4 server
  69. ///
  70. /// This class has a number of static members, because each non-static
  71. /// method has implicit 'this' parameter, so it does not match callout
  72. /// signature and couldn't be registered. Furthermore, static methods
  73. /// can't modify non-static members (for obvious reasons), so many
  74. /// fields are declared static. It is still better to keep them as
  75. /// one class rather than unrelated collection of global objects.
  76. class HooksDhcpv4SrvTest : public Dhcpv4SrvTest {
  77. public:
  78. /// @brief creates Dhcpv4Srv and prepares buffers for callouts
  79. HooksDhcpv4SrvTest() {
  80. // Allocate new DHCPv6 Server
  81. srv_ = new NakedDhcpv4Srv(0);
  82. // clear static buffers
  83. resetCalloutBuffers();
  84. }
  85. /// @brief destructor (deletes Dhcpv4Srv)
  86. virtual ~HooksDhcpv4SrvTest() {
  87. HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("buffer4_receive");
  88. HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("buffer4_send");
  89. HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("pkt4_receive");
  90. HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("pkt4_send");
  91. HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("subnet4_select");
  92. HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("lease4_renew");
  93. HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("lease4_release");
  94. HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("lease4_decline");
  95. delete srv_;
  96. }
  97. /// @brief creates an option with specified option code
  98. ///
  99. /// This method is static, because it is used from callouts
  100. /// that do not have a pointer to HooksDhcpv4SSrvTest object
  101. ///
  102. /// @param option_code code of option to be created
  103. ///
  104. /// @return pointer to create option object
  105. static OptionPtr createOption(uint16_t option_code) {
  106. char payload[] = {
  107. 0xa, 0xb, 0xc, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14
  108. };
  109. OptionBuffer tmp(payload, payload + sizeof(payload));
  110. return OptionPtr(new Option(Option::V4, option_code, tmp));
  111. }
  112. /// @brief Generates test packet.
  113. ///
  114. /// Allocates and generates on-wire buffer that represents test packet, with all
  115. /// fixed fields set to non-zero values. Content is not always reasonable.
  116. ///
  117. /// See generateTestPacket1() function that returns exactly the same packet as
  118. /// Pkt4 object.
  119. ///
  120. /// @return pointer to allocated Pkt4 object
  121. // Returns a vector containing a DHCPv4 packet header.
  122. Pkt4Ptr
  123. generateSimpleDiscover() {
  124. // That is only part of the header. It contains all "short" fields,
  125. // larger fields are constructed separately.
  126. uint8_t hdr[] = {
  127. 1, 6, 6, 13, // op, htype, hlen, hops,
  128. 0x12, 0x34, 0x56, 0x78, // transaction-id
  129. 0, 42, 0x80, 0x00, // 42 secs, BROADCAST flags
  130. 192, 0, 2, 1, // ciaddr
  131. 1, 2, 3, 4, // yiaddr
  132. 192, 0, 2, 255, // siaddr
  133. 192, 0, 2, 50, // giaddr
  134. };
  135. // Initialize the vector with the header fields defined above.
  136. vector<uint8_t> buf(hdr, hdr + sizeof(hdr));
  137. // Append the large header fields.
  138. copy(dummyChaddr, dummyChaddr + Pkt4::MAX_CHADDR_LEN, back_inserter(buf));
  139. copy(dummySname, dummySname + Pkt4::MAX_SNAME_LEN, back_inserter(buf));
  140. copy(dummyFile, dummyFile + Pkt4::MAX_FILE_LEN, back_inserter(buf));
  141. // Should now have all the header, so check. The "static_cast" is used
  142. // to get round an odd bug whereby the linker appears not to find the
  143. // definition of DHCPV4_PKT_HDR_LEN if it appears within an EXPECT_EQ().
  144. EXPECT_EQ(static_cast<size_t>(Pkt4::DHCPV4_PKT_HDR_LEN), buf.size());
  145. // Add magic cookie
  146. buf.push_back(0x63);
  147. buf.push_back(0x82);
  148. buf.push_back(0x53);
  149. buf.push_back(0x63);
  150. // Add message type DISCOVER
  151. buf.push_back(static_cast<uint8_t>(DHO_DHCP_MESSAGE_TYPE));
  152. buf.push_back(1); // length (just one byte)
  153. buf.push_back(static_cast<uint8_t>(DHCPDISCOVER));
  154. Pkt4Ptr dis(new Pkt4(&buf[0], buf.size()));
  155. // Interface must be selected for a Discover. Server will use the interface
  156. // name to select a subnet for a client. This test is using fake interfaces
  157. // and the fake eth0 interface has IPv4 address matching the subnet
  158. // currently configured for this test.
  159. dis->setIface("eth1");
  160. return (dis);
  161. }
  162. /// Test callback that stores received callout name and pkt4 value
  163. /// @param callout_handle handle passed by the hooks framework
  164. /// @return always 0
  165. static int
  166. buffer4_receive_callout(CalloutHandle& callout_handle) {
  167. callback_name_ = string("buffer4_receive");
  168. callout_handle.getArgument("query4", callback_qry_pkt4_);
  169. callback_argument_names_ = callout_handle.getArgumentNames();
  170. if (callback_qry_pkt4_) {
  171. callback_qry_options_copy_ = callback_qry_pkt4_->isCopyRetrievedOptions();
  172. }
  173. return (0);
  174. }
  175. /// Test callback that changes hwaddr value
  176. /// @param callout_handle handle passed by the hooks framework
  177. /// @return always 0
  178. static int
  179. buffer4_receive_change_hwaddr(CalloutHandle& callout_handle) {
  180. Pkt4Ptr pkt;
  181. callout_handle.getArgument("query4", pkt);
  182. // If there is at least one option with data
  183. if (pkt->data_.size() >= Pkt4::DHCPV4_PKT_HDR_LEN) {
  184. // Offset of the first byte of the CHWADDR field. Let's the first
  185. // byte to some new value that we could later check
  186. pkt->data_[28] = 0xff;
  187. }
  188. // Carry on as usual
  189. return buffer4_receive_callout(callout_handle);
  190. }
  191. /// Test callback that sets skip flag
  192. /// @param callout_handle handle passed by the hooks framework
  193. /// @return always 0
  194. static int
  195. buffer4_receive_skip(CalloutHandle& callout_handle) {
  196. callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
  197. // Carry on as usual
  198. return buffer4_receive_callout(callout_handle);
  199. }
  200. /// test callback that stores received callout name and pkt4 value
  201. /// @param callout_handle handle passed by the hooks framework
  202. /// @return always 0
  203. static int
  204. pkt4_receive_callout(CalloutHandle& callout_handle) {
  205. callback_name_ = string("pkt4_receive");
  206. callout_handle.getArgument("query4", callback_qry_pkt4_);
  207. callback_argument_names_ = callout_handle.getArgumentNames();
  208. if (callback_qry_pkt4_) {
  209. callback_qry_options_copy_ = callback_qry_pkt4_->isCopyRetrievedOptions();
  210. }
  211. return (0);
  212. }
  213. /// test callback that changes client-id value
  214. /// @param callout_handle handle passed by the hooks framework
  215. /// @return always 0
  216. static int
  217. pkt4_receive_change_clientid(CalloutHandle& callout_handle) {
  218. Pkt4Ptr pkt;
  219. callout_handle.getArgument("query4", pkt);
  220. // get rid of the old client-id
  221. pkt->delOption(DHO_DHCP_CLIENT_IDENTIFIER);
  222. // add a new option
  223. pkt->addOption(createOption(DHO_DHCP_CLIENT_IDENTIFIER));
  224. // carry on as usual
  225. return pkt4_receive_callout(callout_handle);
  226. }
  227. /// test callback that deletes client-id
  228. /// @param callout_handle handle passed by the hooks framework
  229. /// @return always 0
  230. static int
  231. pkt4_receive_delete_clientid(CalloutHandle& callout_handle) {
  232. Pkt4Ptr pkt;
  233. callout_handle.getArgument("query4", pkt);
  234. // get rid of the old client-id (and no HWADDR)
  235. vector<uint8_t> mac;
  236. pkt->delOption(DHO_DHCP_CLIENT_IDENTIFIER);
  237. pkt->setHWAddr(1, 0, mac); // HWtype 1, hardware len = 0
  238. // carry on as usual
  239. return pkt4_receive_callout(callout_handle);
  240. }
  241. /// test callback that sets skip flag
  242. /// @param callout_handle handle passed by the hooks framework
  243. /// @return always 0
  244. static int
  245. pkt4_receive_skip(CalloutHandle& callout_handle) {
  246. Pkt4Ptr pkt;
  247. callout_handle.getArgument("query4", pkt);
  248. callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
  249. // carry on as usual
  250. return pkt4_receive_callout(callout_handle);
  251. }
  252. /// Test callback that stores received callout name and pkt4 value
  253. /// @param callout_handle handle passed by the hooks framework
  254. /// @return always 0
  255. static int
  256. pkt4_send_callout(CalloutHandle& callout_handle) {
  257. callback_name_ = string("pkt4_send");
  258. callout_handle.getArgument("response4", callback_resp_pkt4_);
  259. callout_handle.getArgument("query4", callback_qry_pkt4_);
  260. callback_argument_names_ = callout_handle.getArgumentNames();
  261. if (callback_qry_pkt4_) {
  262. callback_qry_options_copy_ = callback_qry_pkt4_->isCopyRetrievedOptions();
  263. }
  264. if (callback_resp_pkt4_) {
  265. callback_resp_options_copy_ = callback_resp_pkt4_->isCopyRetrievedOptions();
  266. }
  267. return (0);
  268. }
  269. // Test callback that changes server-id
  270. /// @param callout_handle handle passed by the hooks framework
  271. /// @return always 0
  272. static int
  273. pkt4_send_change_serverid(CalloutHandle& callout_handle) {
  274. Pkt4Ptr pkt;
  275. callout_handle.getArgument("response4", pkt);
  276. // get rid of the old server-id
  277. pkt->delOption(DHO_DHCP_SERVER_IDENTIFIER);
  278. // add a new option
  279. pkt->addOption(createOption(DHO_DHCP_SERVER_IDENTIFIER));
  280. // carry on as usual
  281. return pkt4_send_callout(callout_handle);
  282. }
  283. /// test callback that deletes server-id
  284. /// @param callout_handle handle passed by the hooks framework
  285. /// @return always 0
  286. static int
  287. pkt4_send_delete_serverid(CalloutHandle& callout_handle) {
  288. Pkt4Ptr pkt;
  289. callout_handle.getArgument("response4", pkt);
  290. // get rid of the old client-id
  291. pkt->delOption(DHO_DHCP_SERVER_IDENTIFIER);
  292. // carry on as usual
  293. return pkt4_send_callout(callout_handle);
  294. }
  295. /// Test callback that sets skip flag
  296. /// @param callout_handle handle passed by the hooks framework
  297. /// @return always 0
  298. static int
  299. pkt4_send_skip(CalloutHandle& callout_handle) {
  300. Pkt4Ptr pkt;
  301. callout_handle.getArgument("response4", pkt);
  302. callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
  303. // carry on as usual
  304. return pkt4_send_callout(callout_handle);
  305. }
  306. /// Test callback that stores received callout name and pkt4 value
  307. /// @param callout_handle handle passed by the hooks framework
  308. /// @return always 0
  309. static int
  310. buffer4_send_callout(CalloutHandle& callout_handle) {
  311. callback_name_ = string("buffer4_send");
  312. callout_handle.getArgument("response4", callback_resp_pkt4_);
  313. callback_argument_names_ = callout_handle.getArgumentNames();
  314. if (callback_resp_pkt4_) {
  315. callback_resp_options_copy_ = callback_resp_pkt4_->isCopyRetrievedOptions();
  316. }
  317. return (0);
  318. }
  319. /// Test callback changes the output buffer to a hardcoded value
  320. /// @param callout_handle handle passed by the hooks framework
  321. /// @return always 0
  322. static int
  323. buffer4_send_change_callout(CalloutHandle& callout_handle) {
  324. Pkt4Ptr pkt;
  325. callout_handle.getArgument("response4", pkt);
  326. // modify buffer to set a different payload
  327. pkt->getBuffer().clear();
  328. pkt->getBuffer().writeData(dummyFile, sizeof(dummyFile));
  329. return (0);
  330. }
  331. /// Test callback that stores received callout name and pkt4 value
  332. /// @param callout_handle handle passed by the hooks framework
  333. /// @return always 0
  334. static int
  335. skip_callout(CalloutHandle& callout_handle) {
  336. callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
  337. return (0);
  338. }
  339. /// Test callback that stores received callout name and subnet4 values
  340. /// @param callout_handle handle passed by the hooks framework
  341. /// @return always 0
  342. static int
  343. subnet4_select_callout(CalloutHandle& callout_handle) {
  344. callback_name_ = string("subnet4_select");
  345. callout_handle.getArgument("query4", callback_qry_pkt4_);
  346. callout_handle.getArgument("subnet4", callback_subnet4_);
  347. callout_handle.getArgument("subnet4collection", callback_subnet4collection_);
  348. callback_argument_names_ = callout_handle.getArgumentNames();
  349. if (callback_qry_pkt4_) {
  350. callback_qry_options_copy_ = callback_qry_pkt4_->isCopyRetrievedOptions();
  351. }
  352. return (0);
  353. }
  354. /// Test callback that picks the other subnet if possible.
  355. /// @param callout_handle handle passed by the hooks framework
  356. /// @return always 0
  357. static int
  358. subnet4_select_different_subnet_callout(CalloutHandle& callout_handle) {
  359. // Call the basic callout to record all passed values
  360. subnet4_select_callout(callout_handle);
  361. const Subnet4Collection* subnets;
  362. Subnet4Ptr subnet;
  363. callout_handle.getArgument("subnet4", subnet);
  364. callout_handle.getArgument("subnet4collection", subnets);
  365. // Let's change to a different subnet
  366. if (subnets->size() > 1) {
  367. subnet = (*subnets)[1]; // Let's pick the other subnet
  368. callout_handle.setArgument("subnet4", subnet);
  369. }
  370. return (0);
  371. }
  372. /// Test callback that stores received callout name passed parameters
  373. /// @param callout_handle handle passed by the hooks framework
  374. /// @return always 0
  375. static int
  376. lease4_release_callout(CalloutHandle& callout_handle) {
  377. callback_name_ = string("lease4_release");
  378. callout_handle.getArgument("query4", callback_qry_pkt4_);
  379. callout_handle.getArgument("lease4", callback_lease4_);
  380. callback_argument_names_ = callout_handle.getArgumentNames();
  381. if (callback_qry_pkt4_) {
  382. callback_qry_options_copy_ = callback_qry_pkt4_->isCopyRetrievedOptions();
  383. }
  384. return (0);
  385. }
  386. /// Test callback that stores received callout name and subnet4 values
  387. /// @param callout_handle handle passed by the hooks framework
  388. /// @return always 0
  389. static int
  390. lease4_renew_callout(CalloutHandle& callout_handle) {
  391. callback_name_ = string("lease4_renew");
  392. callout_handle.getArgument("query4", callback_qry_pkt4_);
  393. callout_handle.getArgument("subnet4", callback_subnet4_);
  394. callout_handle.getArgument("lease4", callback_lease4_);
  395. callout_handle.getArgument("hwaddr", callback_hwaddr_);
  396. callout_handle.getArgument("clientid", callback_clientid_);
  397. callback_argument_names_ = callout_handle.getArgumentNames();
  398. if (callback_qry_pkt4_) {
  399. callback_qry_options_copy_ = callback_qry_pkt4_->isCopyRetrievedOptions();
  400. }
  401. return (0);
  402. }
  403. /// Test lease4_decline callback that stores received parameters.
  404. ///
  405. /// @param callout_handle handle passed by the hooks framework
  406. /// @return always 0
  407. static int
  408. lease4_decline_callout(CalloutHandle& callout_handle) {
  409. callback_name_ = string("lease4_decline");
  410. callout_handle.getArgument("query4", callback_qry_pkt4_);
  411. callout_handle.getArgument("lease4", callback_lease4_);
  412. if (callback_qry_pkt4_) {
  413. callback_qry_options_copy_ = callback_qry_pkt4_->isCopyRetrievedOptions();
  414. }
  415. return (0);
  416. }
  417. /// Test lease4_decline callback that sets next step to DROP.
  418. ///
  419. /// @param callout_handle handle passed by the hooks framework
  420. /// @return always 0
  421. static int
  422. lease4_decline_drop_callout(CalloutHandle& callout_handle) {
  423. callout_handle.setStatus(CalloutHandle::NEXT_STEP_DROP);
  424. return (lease4_decline_callout(callout_handle));
  425. }
  426. /// resets buffers used to store data received by callouts
  427. void resetCalloutBuffers() {
  428. callback_name_ = string("");
  429. callback_qry_pkt4_.reset();
  430. callback_qry_pkt4_.reset();
  431. callback_lease4_.reset();
  432. callback_hwaddr_.reset();
  433. callback_clientid_.reset();
  434. callback_subnet4_.reset();
  435. callback_subnet4collection_ = NULL;
  436. callback_argument_names_.clear();
  437. callback_qry_options_copy_ = false;
  438. callback_resp_options_copy_ = false;
  439. }
  440. /// pointer to Dhcpv4Srv that is used in tests
  441. NakedDhcpv4Srv* srv_;
  442. // The following fields are used in testing pkt4_receive_callout
  443. /// String name of the received callout
  444. static string callback_name_;
  445. /// Client/query Pkt4 structure returned in the callout
  446. static Pkt4Ptr callback_qry_pkt4_;
  447. /// Server/response Pkt4 structure returned in the callout
  448. static Pkt4Ptr callback_resp_pkt4_;
  449. /// Lease4 structure returned in the callout
  450. static Lease4Ptr callback_lease4_;
  451. /// Hardware address returned in the callout
  452. static HWAddrPtr callback_hwaddr_;
  453. /// Client-id returned in the callout
  454. static ClientIdPtr callback_clientid_;
  455. /// Pointer to a subnet received by callout
  456. static Subnet4Ptr callback_subnet4_;
  457. /// A list of all available subnets (received by callout)
  458. static const Subnet4Collection* callback_subnet4collection_;
  459. /// A list of all received arguments
  460. static vector<string> callback_argument_names_;
  461. /// Flag indicating if copying retrieved options was enabled for
  462. /// a query during callout execution.
  463. static bool callback_qry_options_copy_;
  464. /// Flag indicating if copying retrieved options was enabled for
  465. /// a response during callout execution.
  466. static bool callback_resp_options_copy_;
  467. };
  468. // The following fields are used in testing pkt4_receive_callout.
  469. // See fields description in the class for details
  470. string HooksDhcpv4SrvTest::callback_name_;
  471. Pkt4Ptr HooksDhcpv4SrvTest::callback_qry_pkt4_;
  472. Pkt4Ptr HooksDhcpv4SrvTest::callback_resp_pkt4_;
  473. Subnet4Ptr HooksDhcpv4SrvTest::callback_subnet4_;
  474. HWAddrPtr HooksDhcpv4SrvTest::callback_hwaddr_;
  475. ClientIdPtr HooksDhcpv4SrvTest::callback_clientid_;
  476. Lease4Ptr HooksDhcpv4SrvTest::callback_lease4_;
  477. const Subnet4Collection* HooksDhcpv4SrvTest::callback_subnet4collection_;
  478. vector<string> HooksDhcpv4SrvTest::callback_argument_names_;
  479. bool HooksDhcpv4SrvTest::callback_qry_options_copy_;
  480. bool HooksDhcpv4SrvTest::callback_resp_options_copy_;
  481. /// @brief Fixture class used to do basic library load/unload tests
  482. class LoadUnloadDhcpv4SrvTest : public ::testing::Test {
  483. public:
  484. /// @brief Pointer to the tested server object
  485. boost::shared_ptr<NakedDhcpv4Srv> server_;
  486. LoadUnloadDhcpv4SrvTest() {
  487. reset();
  488. }
  489. /// @brief Destructor
  490. ~LoadUnloadDhcpv4SrvTest() {
  491. server_.reset();
  492. reset();
  493. };
  494. /// @brief Reset hooks data
  495. ///
  496. /// Resets the data for the hooks-related portion of the test by ensuring
  497. /// that no libraries are loaded and that any marker files are deleted.
  498. void reset() {
  499. // Unload any previously-loaded libraries.
  500. HooksManager::unloadLibraries();
  501. // Get rid of any marker files.
  502. static_cast<void>(remove(LOAD_MARKER_FILE));
  503. static_cast<void>(remove(UNLOAD_MARKER_FILE));
  504. CfgMgr::instance().clear();
  505. }
  506. };
  507. // Checks if callouts installed on pkt4_receive are indeed called and the
  508. // all necessary parameters are passed.
  509. //
  510. // Note that the test name does not follow test naming convention,
  511. // but the proper hook name is "buffer4_receive".
  512. TEST_F(HooksDhcpv4SrvTest, Buffer4ReceiveSimple) {
  513. IfaceMgrTestConfig test_config(true);
  514. IfaceMgr::instance().openSockets4();
  515. // Install pkt4_receive_callout
  516. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  517. "buffer4_receive", buffer4_receive_callout));
  518. // Let's create a simple DISCOVER
  519. Pkt4Ptr dis = generateSimpleDiscover();
  520. // Simulate that we have received that traffic
  521. srv_->fakeReceive(dis);
  522. // Server will now process to run its normal loop, but instead of calling
  523. // IfaceMgr::receive4(), it will read all packets from the list set by
  524. // fakeReceive()
  525. // In particular, it should call registered buffer4_receive callback.
  526. srv_->run();
  527. // Check that the callback called is indeed the one we installed
  528. EXPECT_EQ("buffer4_receive", callback_name_);
  529. // Check that pkt4 argument passing was successful and returned proper value
  530. EXPECT_TRUE(callback_qry_pkt4_.get() == dis.get());
  531. // Check that all expected parameters are there
  532. vector<string> expected_argument_names;
  533. expected_argument_names.push_back(string("query4"));
  534. EXPECT_TRUE(expected_argument_names == callback_argument_names_);
  535. // Pkt passed to a callout must be configured to copy retrieved options.
  536. EXPECT_TRUE(callback_qry_options_copy_);
  537. }
  538. // Checks if callouts installed on buffer4_receive is able to change
  539. // the values and the parameters are indeed used by the server.
  540. TEST_F(HooksDhcpv4SrvTest, buffer4ReceiveValueChange) {
  541. IfaceMgrTestConfig test_config(true);
  542. IfaceMgr::instance().openSockets4();
  543. // Install callback that modifies MAC addr of incoming packet
  544. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  545. "buffer4_receive", buffer4_receive_change_hwaddr));
  546. // Let's create a simple DISCOVER
  547. Pkt4Ptr discover = generateSimpleDiscover();
  548. // Simulate that we have received that traffic
  549. srv_->fakeReceive(discover);
  550. // Server will now process to run its normal loop, but instead of calling
  551. // IfaceMgr::receive6(), it will read all packets from the list set by
  552. // fakeReceive()
  553. // In particular, it should call registered buffer4_receive callback.
  554. srv_->run();
  555. // Check that the server did send a response
  556. ASSERT_EQ(1, srv_->fake_sent_.size());
  557. // Make sure that we received a response
  558. Pkt4Ptr offer = srv_->fake_sent_.front();
  559. ASSERT_TRUE(offer);
  560. // Get client-id...
  561. HWAddrPtr hwaddr = offer->getHWAddr();
  562. ASSERT_TRUE(hwaddr); // basic sanity check. HWAddr is always present
  563. // ... and check if it is the modified value
  564. ASSERT_FALSE(hwaddr->hwaddr_.empty()); // there must be a MAC address
  565. EXPECT_EQ(0xff, hwaddr->hwaddr_[0]); // check that its first byte was modified
  566. }
  567. // Checks if callouts installed on buffer4_receive is able to set skip flag that
  568. // will cause the server to not parse the packet. Even though the packet is valid,
  569. // the server should eventually drop it, because there won't be mandatory options
  570. // (or rather option objects) in it.
  571. TEST_F(HooksDhcpv4SrvTest, buffer4ReceiveSkip) {
  572. IfaceMgrTestConfig test_config(true);
  573. IfaceMgr::instance().openSockets4();
  574. // Install pkt4_receive_callout
  575. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  576. "buffer4_receive", buffer4_receive_skip));
  577. // Let's create a simple DISCOVER
  578. Pkt4Ptr discover = generateSimpleDiscover();
  579. // Simulate that we have received that traffic
  580. srv_->fakeReceive(discover);
  581. // Server will now process to run its normal loop, but instead of calling
  582. // IfaceMgr::receive6(), it will read all packets from the list set by
  583. // fakeReceive()
  584. // In particular, it should call registered pkt4_receive callback.
  585. srv_->run();
  586. // Check that the server dropped the packet and did not produce any response
  587. ASSERT_EQ(0, srv_->fake_sent_.size());
  588. }
  589. // Checks if callouts installed on pkt4_receive are indeed called and the
  590. // all necessary parameters are passed.
  591. //
  592. // Note that the test name does not follow test naming convention,
  593. // but the proper hook name is "pkt4_receive".
  594. TEST_F(HooksDhcpv4SrvTest, pkt4ReceiveSimple) {
  595. IfaceMgrTestConfig test_config(true);
  596. IfaceMgr::instance().openSockets4();
  597. // Install pkt4_receive_callout
  598. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  599. "pkt4_receive", pkt4_receive_callout));
  600. // Let's create a simple DISCOVER
  601. Pkt4Ptr sol = generateSimpleDiscover();
  602. // Simulate that we have received that traffic
  603. srv_->fakeReceive(sol);
  604. // Server will now process to run its normal loop, but instead of calling
  605. // IfaceMgr::receive4(), it will read all packets from the list set by
  606. // fakeReceive()
  607. // In particular, it should call registered pkt4_receive callback.
  608. srv_->run();
  609. // check that the callback called is indeed the one we installed
  610. EXPECT_EQ("pkt4_receive", callback_name_);
  611. // check that pkt4 argument passing was successful and returned proper value
  612. EXPECT_TRUE(callback_qry_pkt4_.get() == sol.get());
  613. // Check that all expected parameters are there
  614. vector<string> expected_argument_names;
  615. expected_argument_names.push_back(string("query4"));
  616. EXPECT_TRUE(expected_argument_names == callback_argument_names_);
  617. // Pkt passed to a callout must be configured to copy retrieved options.
  618. EXPECT_TRUE(callback_qry_options_copy_);
  619. }
  620. // Checks if callouts installed on pkt4_received is able to change
  621. // the values and the parameters are indeed used by the server.
  622. TEST_F(HooksDhcpv4SrvTest, valueChange_pkt4_receive) {
  623. IfaceMgrTestConfig test_config(true);
  624. IfaceMgr::instance().openSockets4();
  625. // Install pkt4_receive_callout
  626. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  627. "pkt4_receive", pkt4_receive_change_clientid));
  628. // Let's create a simple DISCOVER
  629. Pkt4Ptr sol = generateSimpleDiscover();
  630. // Simulate that we have received that traffic
  631. srv_->fakeReceive(sol);
  632. // Server will now process to run its normal loop, but instead of calling
  633. // IfaceMgr::receive4(), it will read all packets from the list set by
  634. // fakeReceive()
  635. // In particular, it should call registered pkt4_receive callback.
  636. srv_->run();
  637. // check that the server did send a response
  638. ASSERT_EQ(1, srv_->fake_sent_.size());
  639. // Make sure that we received a response
  640. Pkt4Ptr adv = srv_->fake_sent_.front();
  641. ASSERT_TRUE(adv);
  642. // Get client-id...
  643. OptionPtr clientid = adv->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
  644. // ... and check if it is the modified value
  645. OptionPtr expected = createOption(DHO_DHCP_CLIENT_IDENTIFIER);
  646. EXPECT_TRUE(clientid->equals(expected));
  647. }
  648. // Checks if callouts installed on pkt4_received is able to delete
  649. // existing options and that change impacts server processing (mandatory
  650. // client-id option is deleted, so the packet is expected to be dropped)
  651. TEST_F(HooksDhcpv4SrvTest, pkt4ReceiveDeleteClientId) {
  652. IfaceMgrTestConfig test_config(true);
  653. IfaceMgr::instance().openSockets4();
  654. // Install pkt4_receive_callout
  655. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  656. "pkt4_receive", pkt4_receive_delete_clientid));
  657. // Let's create a simple DISCOVER
  658. Pkt4Ptr sol = generateSimpleDiscover();
  659. // Simulate that we have received that traffic
  660. srv_->fakeReceive(sol);
  661. // Server will now process to run its normal loop, but instead of calling
  662. // IfaceMgr::receive4(), it will read all packets from the list set by
  663. // fakeReceive()
  664. // In particular, it should call registered pkt4_receive callback.
  665. srv_->run();
  666. // Check that the server dropped the packet and did not send a response
  667. ASSERT_EQ(0, srv_->fake_sent_.size());
  668. }
  669. // Checks if callouts installed on pkt4_received is able to set skip flag that
  670. // will cause the server to not process the packet (drop), even though it is valid.
  671. TEST_F(HooksDhcpv4SrvTest, pkt4ReceiveSkip) {
  672. IfaceMgrTestConfig test_config(true);
  673. IfaceMgr::instance().openSockets4();
  674. // Install pkt4_receive_callout
  675. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  676. "pkt4_receive", pkt4_receive_skip));
  677. // Let's create a simple DISCOVER
  678. Pkt4Ptr sol = generateSimpleDiscover();
  679. // Simulate that we have received that traffic
  680. srv_->fakeReceive(sol);
  681. // Server will now process to run its normal loop, but instead of calling
  682. // IfaceMgr::receive4(), it will read all packets from the list set by
  683. // fakeReceive()
  684. // In particular, it should call registered pkt4_receive callback.
  685. srv_->run();
  686. // check that the server dropped the packet and did not produce any response
  687. ASSERT_EQ(0, srv_->fake_sent_.size());
  688. }
  689. // Checks if callouts installed on pkt4_send are indeed called and the
  690. // all necessary parameters are passed.
  691. TEST_F(HooksDhcpv4SrvTest, pkt4SendSimple) {
  692. IfaceMgrTestConfig test_config(true);
  693. IfaceMgr::instance().openSockets4();
  694. // Install pkt4_receive_callout
  695. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  696. "pkt4_send", pkt4_send_callout));
  697. // Let's create a simple DISCOVER
  698. Pkt4Ptr sol = generateSimpleDiscover();
  699. // Simulate that we have received that traffic
  700. srv_->fakeReceive(sol);
  701. // Server will now process to run its normal loop, but instead of calling
  702. // IfaceMgr::receive4(), it will read all packets from the list set by
  703. // fakeReceive()
  704. // In particular, it should call registered pkt4_receive callback.
  705. srv_->run();
  706. // Check that the callback called is indeed the one we installed
  707. EXPECT_EQ("pkt4_send", callback_name_);
  708. // Check that there is one packet sent
  709. ASSERT_EQ(1, srv_->fake_sent_.size());
  710. Pkt4Ptr adv = srv_->fake_sent_.front();
  711. // Check that pkt4 argument passing was successful and returned proper value
  712. ASSERT_TRUE(callback_resp_pkt4_);
  713. EXPECT_TRUE(callback_resp_pkt4_.get() == adv.get());
  714. // That that the query4 argument was correctly set to the Discover we sent.
  715. ASSERT_TRUE(callback_qry_pkt4_);
  716. EXPECT_TRUE(callback_qry_pkt4_.get() == sol.get());
  717. // Check that all expected parameters are there
  718. vector<string> expected_argument_names;
  719. expected_argument_names.push_back(string("response4"));
  720. expected_argument_names.push_back(string("query4"));
  721. sort(callback_argument_names_.begin(), callback_argument_names_.end());
  722. sort(expected_argument_names.begin(), expected_argument_names.end());
  723. EXPECT_TRUE(expected_argument_names == callback_argument_names_);
  724. // Pkt passed to a callout must be configured to copy retrieved options.
  725. EXPECT_TRUE(callback_qry_options_copy_);
  726. EXPECT_TRUE(callback_resp_options_copy_);
  727. }
  728. // Checks if callouts installed on pkt4_send is able to change
  729. // the values and the packet sent contains those changes
  730. TEST_F(HooksDhcpv4SrvTest, pkt4SendValueChange) {
  731. IfaceMgrTestConfig test_config(true);
  732. IfaceMgr::instance().openSockets4();
  733. // Install pkt4_receive_callout
  734. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  735. "pkt4_send", pkt4_send_change_serverid));
  736. // Let's create a simple DISCOVER
  737. Pkt4Ptr sol = generateSimpleDiscover();
  738. // Simulate that we have received that traffic
  739. srv_->fakeReceive(sol);
  740. // Server will now process to run its normal loop, but instead of calling
  741. // IfaceMgr::receive4(), it will read all packets from the list set by
  742. // fakeReceive()
  743. // In particular, it should call registered pkt4_receive callback.
  744. srv_->run();
  745. // check that the server did send a response
  746. ASSERT_EQ(1, srv_->fake_sent_.size());
  747. // Make sure that we received a response
  748. Pkt4Ptr adv = srv_->fake_sent_.front();
  749. ASSERT_TRUE(adv);
  750. // Get client-id...
  751. OptionPtr clientid = adv->getOption(DHO_DHCP_SERVER_IDENTIFIER);
  752. // ... and check if it is the modified value
  753. OptionPtr expected = createOption(DHO_DHCP_SERVER_IDENTIFIER);
  754. EXPECT_TRUE(clientid->equals(expected));
  755. }
  756. // Checks if callouts installed on pkt4_send is able to delete
  757. // existing options and that server applies those changes. In particular,
  758. // we are trying to send a packet without server-id. The packet should
  759. // be sent
  760. TEST_F(HooksDhcpv4SrvTest, pkt4SendDeleteServerId) {
  761. IfaceMgrTestConfig test_config(true);
  762. IfaceMgr::instance().openSockets4();
  763. // Install pkt4_receive_callout
  764. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  765. "pkt4_send", pkt4_send_delete_serverid));
  766. // Let's create a simple DISCOVER
  767. Pkt4Ptr sol = generateSimpleDiscover();
  768. // Simulate that we have received that traffic
  769. srv_->fakeReceive(sol);
  770. // Server will now process to run its normal loop, but instead of calling
  771. // IfaceMgr::receive4(), it will read all packets from the list set by
  772. // fakeReceive()
  773. // In particular, it should call registered pkt4_receive callback.
  774. srv_->run();
  775. // Check that the server indeed sent a malformed ADVERTISE
  776. ASSERT_EQ(1, srv_->fake_sent_.size());
  777. // Get that ADVERTISE
  778. Pkt4Ptr adv = srv_->fake_sent_.front();
  779. ASSERT_TRUE(adv);
  780. // Make sure that it does not have server-id
  781. EXPECT_FALSE(adv->getOption(DHO_DHCP_SERVER_IDENTIFIER));
  782. }
  783. // Checks if callouts installed on pkt4_skip is able to set skip flag that
  784. // will cause the server to not process the packet (drop), even though it is valid.
  785. TEST_F(HooksDhcpv4SrvTest, skip_pkt4_send) {
  786. IfaceMgrTestConfig test_config(true);
  787. IfaceMgr::instance().openSockets4();
  788. // Install pkt4_receive_callout
  789. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  790. "pkt4_send", pkt4_send_skip));
  791. // Let's create a simple REQUEST
  792. Pkt4Ptr sol = generateSimpleDiscover();
  793. // Simulate that we have received that traffic
  794. srv_->fakeReceive(sol);
  795. // Server will now process to run its normal loop, but instead of calling
  796. // IfaceMgr::receive4(), it will read all packets from the list set by
  797. // fakeReceive()
  798. // In particular, it should call registered pkt4_send callback.
  799. srv_->run();
  800. // Check that the server sent the message
  801. ASSERT_EQ(1, srv_->fake_sent_.size());
  802. // Get the first packet and check that it has zero length (i.e. the server
  803. // did not do packing on its own)
  804. Pkt4Ptr sent = srv_->fake_sent_.front();
  805. EXPECT_EQ(0, sent->getBuffer().getLength());
  806. }
  807. // Checks if callouts installed on buffer4_send are indeed called and the
  808. // all necessary parameters are passed.
  809. TEST_F(HooksDhcpv4SrvTest, buffer4SendSimple) {
  810. IfaceMgrTestConfig test_config(true);
  811. IfaceMgr::instance().openSockets4();
  812. // Install pkt4_receive_callout
  813. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  814. "buffer4_send", buffer4_send_callout));
  815. // Let's create a simple DISCOVER
  816. Pkt4Ptr discover = generateSimpleDiscover();
  817. // Simulate that we have received that traffic
  818. srv_->fakeReceive(discover);
  819. // Server will now process to run its normal loop, but instead of calling
  820. // IfaceMgr::receive4(), it will read all packets from the list set by
  821. // fakeReceive()
  822. // In particular, it should call registered pkt4_receive callback.
  823. srv_->run();
  824. // Check that the callback called is indeed the one we installed
  825. EXPECT_EQ("buffer4_send", callback_name_);
  826. // Check that there is one packet sent
  827. ASSERT_EQ(1, srv_->fake_sent_.size());
  828. Pkt4Ptr adv = srv_->fake_sent_.front();
  829. // Check that pkt4 argument passing was successful and returned proper value
  830. EXPECT_TRUE(callback_resp_pkt4_.get() == adv.get());
  831. // Check that all expected parameters are there
  832. vector<string> expected_argument_names;
  833. expected_argument_names.push_back(string("response4"));
  834. EXPECT_TRUE(expected_argument_names == callback_argument_names_);
  835. // Pkt passed to a callout must be configured to copy retrieved options.
  836. EXPECT_TRUE(callback_resp_options_copy_);
  837. }
  838. // Checks if callouts installed on buffer4_send are indeed called and that
  839. // the output buffer can be changed.
  840. TEST_F(HooksDhcpv4SrvTest, buffer4Send) {
  841. IfaceMgrTestConfig test_config(true);
  842. IfaceMgr::instance().openSockets4();
  843. // Install pkt4_receive_callout
  844. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  845. "buffer4_send", buffer4_send_change_callout));
  846. // Let's create a simple DISCOVER
  847. Pkt4Ptr discover = generateSimpleDiscover();
  848. // Simulate that we have received that traffic
  849. srv_->fakeReceive(discover);
  850. // Server will now process to run its normal loop, but instead of calling
  851. // IfaceMgr::receive4(), it will read all packets from the list set by
  852. // fakeReceive()
  853. // In particular, it should call registered pkt4_receive callback.
  854. srv_->run();
  855. // Check that there is one packet sent
  856. ASSERT_EQ(1, srv_->fake_sent_.size());
  857. Pkt4Ptr adv = srv_->fake_sent_.front();
  858. // The callout is supposed to fill the output buffer with dummyFile content
  859. ASSERT_EQ(sizeof(dummyFile), adv->getBuffer().getLength());
  860. EXPECT_EQ(0, memcmp(adv->getBuffer().getData(), dummyFile, sizeof(dummyFile)));
  861. }
  862. // Checks if callouts installed on buffer4_send can set skip flag and that flag
  863. // causes the packet to not be sent
  864. TEST_F(HooksDhcpv4SrvTest, buffer4SendSkip) {
  865. IfaceMgrTestConfig test_config(true);
  866. IfaceMgr::instance().openSockets4();
  867. // Install pkt4_receive_callout
  868. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  869. "buffer4_send", skip_callout));
  870. // Let's create a simple DISCOVER
  871. Pkt4Ptr discover = generateSimpleDiscover();
  872. // Simulate that we have received that traffic
  873. srv_->fakeReceive(discover);
  874. // Server will now process to run its normal loop, but instead of calling
  875. // IfaceMgr::receive4(), it will read all packets from the list set by
  876. // fakeReceive()
  877. // In particular, it should call registered pkt4_receive callback.
  878. srv_->run();
  879. // Check that there is no packet sent.
  880. ASSERT_EQ(0, srv_->fake_sent_.size());
  881. }
  882. // This test checks if subnet4_select callout is triggered and reports
  883. // valid parameters
  884. TEST_F(HooksDhcpv4SrvTest, subnet4SelectSimple) {
  885. IfaceMgrTestConfig test_config(true);
  886. IfaceMgr::instance().openSockets4();
  887. // Configure 2 subnets, both directly reachable over local interface
  888. // (let's not complicate the matter with relays)
  889. string config = "{ \"interfaces-config\": {"
  890. " \"interfaces\": [ \"*\" ]"
  891. "},"
  892. "\"rebind-timer\": 2000, "
  893. "\"renew-timer\": 1000, "
  894. "\"subnet4\": [ { "
  895. " \"pools\": [ { \"pool\": \"192.0.2.0/25\" } ],"
  896. " \"subnet\": \"192.0.2.0/24\", "
  897. " \"interface\": \"eth0\" "
  898. " }, {"
  899. " \"pools\": [ { \"pool\": \"192.0.3.0/25\" } ],"
  900. " \"subnet\": \"192.0.3.0/24\" "
  901. " } ],"
  902. "\"valid-lifetime\": 4000 }";
  903. ConstElementPtr json;
  904. EXPECT_NO_THROW(json = parseDHCP4(config));
  905. ConstElementPtr status;
  906. // Configure the server and make sure the config is accepted
  907. EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
  908. ASSERT_TRUE(status);
  909. comment_ = parseAnswer(rcode_, status);
  910. ASSERT_EQ(0, rcode_);
  911. // Commit the config
  912. CfgMgr::instance().commit();
  913. // Install pkt4_receive_callout
  914. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  915. "subnet4_select", subnet4_select_callout));
  916. // Prepare discover packet. Server should select first subnet for it
  917. Pkt4Ptr sol = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
  918. sol->setRemoteAddr(IOAddress("192.0.2.1"));
  919. sol->setIface("eth1");
  920. OptionPtr clientid = generateClientId();
  921. sol->addOption(clientid);
  922. // Pass it to the server and get an advertise
  923. Pkt4Ptr adv = srv_->processDiscover(sol);
  924. // check if we get response at all
  925. ASSERT_TRUE(adv);
  926. // Check that the callback called is indeed the one we installed
  927. EXPECT_EQ("subnet4_select", callback_name_);
  928. // Check that pkt4 argument passing was successful and returned proper value
  929. EXPECT_TRUE(callback_qry_pkt4_.get() == sol.get());
  930. const Subnet4Collection* exp_subnets =
  931. CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getAll();
  932. // The server is supposed to pick the first subnet, because of matching
  933. // interface. Check that the value is reported properly.
  934. ASSERT_TRUE(callback_subnet4_);
  935. EXPECT_EQ(exp_subnets->front().get(), callback_subnet4_.get());
  936. // Server is supposed to report two subnets
  937. ASSERT_EQ(exp_subnets->size(), callback_subnet4collection_->size());
  938. ASSERT_GE(exp_subnets->size(), 2);
  939. // Compare that the available subnets are reported as expected
  940. EXPECT_TRUE((*exp_subnets)[0].get() == (*callback_subnet4collection_)[0].get());
  941. EXPECT_TRUE((*exp_subnets)[1].get() == (*callback_subnet4collection_)[1].get());
  942. // Pkt passed to a callout must be configured to copy retrieved options.
  943. EXPECT_TRUE(callback_qry_options_copy_);
  944. }
  945. // This test checks if callout installed on subnet4_select hook point can pick
  946. // a different subnet.
  947. TEST_F(HooksDhcpv4SrvTest, subnet4SelectChange) {
  948. IfaceMgrTestConfig test_config(true);
  949. IfaceMgr::instance().openSockets4();
  950. // Configure 2 subnets, both directly reachable over local interface
  951. // (let's not complicate the matter with relays)
  952. string config = "{ \"interfaces-config\": {"
  953. " \"interfaces\": [ \"*\" ]"
  954. "},"
  955. "\"rebind-timer\": 2000, "
  956. "\"renew-timer\": 1000, "
  957. "\"subnet4\": [ { "
  958. " \"pools\": [ { \"pool\": \"192.0.2.0/25\" } ],"
  959. " \"subnet\": \"192.0.2.0/24\", "
  960. " \"interface\": \"eth0\" "
  961. " }, {"
  962. " \"pools\": [ { \"pool\": \"192.0.3.0/25\" } ],"
  963. " \"subnet\": \"192.0.3.0/24\" "
  964. " } ],"
  965. "\"valid-lifetime\": 4000 }";
  966. ConstElementPtr json;
  967. EXPECT_NO_THROW(json = parseDHCP4(config));
  968. ConstElementPtr status;
  969. // Configure the server and make sure the config is accepted
  970. EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
  971. ASSERT_TRUE(status);
  972. comment_ = parseAnswer(rcode_, status);
  973. ASSERT_EQ(0, rcode_);
  974. CfgMgr::instance().commit();
  975. // Install a callout
  976. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  977. "subnet4_select", subnet4_select_different_subnet_callout));
  978. // Prepare discover packet. Server should select first subnet for it
  979. Pkt4Ptr sol = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
  980. sol->setRemoteAddr(IOAddress("192.0.2.1"));
  981. sol->setIface("eth0");
  982. OptionPtr clientid = generateClientId();
  983. sol->addOption(clientid);
  984. // Pass it to the server and get an advertise
  985. Pkt4Ptr adv = srv_->processDiscover(sol);
  986. // check if we get response at all
  987. ASSERT_TRUE(adv);
  988. // The response should have an address from second pool, so let's check it
  989. IOAddress addr = adv->getYiaddr();
  990. EXPECT_NE("0.0.0.0", addr.toText());
  991. // Get all subnets and use second subnet for verification
  992. const Subnet4Collection* subnets =
  993. CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getAll();
  994. ASSERT_EQ(2, subnets->size());
  995. // Advertised address must belong to the second pool (in subnet's range,
  996. // in dynamic pool)
  997. EXPECT_TRUE((*subnets)[1]->inRange(addr));
  998. EXPECT_TRUE((*subnets)[1]->inPool(Lease::TYPE_V4, addr));
  999. }
  1000. // This test verifies that incoming (positive) REQUEST/Renewing can be handled
  1001. // properly and that callout installed on lease4_renew is triggered with
  1002. // expected parameters.
  1003. TEST_F(HooksDhcpv4SrvTest, lease4RenewSimple) {
  1004. IfaceMgrTestConfig test_config(true);
  1005. IfaceMgr::instance().openSockets4();
  1006. const IOAddress addr("192.0.2.106");
  1007. const uint32_t temp_t1 = 50;
  1008. const uint32_t temp_t2 = 75;
  1009. const uint32_t temp_valid = 100;
  1010. const time_t temp_timestamp = time(NULL) - 10;
  1011. // Install a callout
  1012. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1013. "lease4_renew", lease4_renew_callout));
  1014. // Generate client-id also sets client_id_ member
  1015. OptionPtr clientid = generateClientId();
  1016. // Check that the address we are about to use is indeed in pool
  1017. ASSERT_TRUE(subnet_->inPool(Lease::TYPE_V4, addr));
  1018. // let's create a lease and put it in the LeaseMgr
  1019. uint8_t hwaddr2_data[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
  1020. HWAddrPtr hwaddr2(new HWAddr(hwaddr2_data, sizeof(hwaddr2_data), HTYPE_ETHER));
  1021. Lease4Ptr used(new Lease4(IOAddress("192.0.2.106"), hwaddr2,
  1022. &client_id_->getDuid()[0], client_id_->getDuid().size(),
  1023. temp_valid, temp_t1, temp_t2, temp_timestamp,
  1024. subnet_->getID()));
  1025. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
  1026. // Check that the lease is really in the database
  1027. Lease4Ptr l = LeaseMgrFactory::instance().getLease4(addr);
  1028. ASSERT_TRUE(l);
  1029. // Let's create a RENEW
  1030. Pkt4Ptr req = Pkt4Ptr(new Pkt4(DHCPREQUEST, 1234));
  1031. req->setRemoteAddr(IOAddress(addr));
  1032. req->setYiaddr(addr);
  1033. req->setCiaddr(addr); // client's address
  1034. req->setIface("eth0");
  1035. req->setHWAddr(hwaddr2);
  1036. req->addOption(clientid);
  1037. req->addOption(srv_->getServerID());
  1038. // Pass it to the server and hope for a REPLY
  1039. Pkt4Ptr ack = srv_->processRequest(req);
  1040. // Check if we get response at all
  1041. checkResponse(ack, DHCPACK, 1234);
  1042. // Check that the lease is really in the database
  1043. l = checkLease(ack, clientid, req->getHWAddr(), addr);
  1044. ASSERT_TRUE(l);
  1045. // Check that T1, T2, preferred, valid and cltt were really updated
  1046. EXPECT_EQ(l->t1_, subnet_->getT1());
  1047. EXPECT_EQ(l->t2_, subnet_->getT2());
  1048. EXPECT_EQ(l->valid_lft_, subnet_->getValid());
  1049. // Check that the callback called is indeed the one we installed
  1050. EXPECT_EQ("lease4_renew", callback_name_);
  1051. // Check that query4 argument passing was successful and
  1052. // returned proper value
  1053. EXPECT_TRUE(callback_qry_pkt4_.get() == req.get());
  1054. // Check that hwaddr parameter is passed properly
  1055. ASSERT_TRUE(callback_hwaddr_);
  1056. EXPECT_TRUE(*callback_hwaddr_ == *req->getHWAddr());
  1057. // Check that the subnet is passed properly
  1058. ASSERT_TRUE(callback_subnet4_);
  1059. EXPECT_EQ(callback_subnet4_->toText(), subnet_->toText());
  1060. ASSERT_TRUE(callback_clientid_);
  1061. ASSERT_TRUE(client_id_);
  1062. EXPECT_TRUE(*client_id_ == *callback_clientid_);
  1063. // Check if all expected parameters were really received
  1064. vector<string> expected_argument_names;
  1065. expected_argument_names.push_back("query4");
  1066. expected_argument_names.push_back("subnet4");
  1067. expected_argument_names.push_back("clientid");
  1068. expected_argument_names.push_back("hwaddr");
  1069. expected_argument_names.push_back("lease4");
  1070. sort(callback_argument_names_.begin(), callback_argument_names_.end());
  1071. sort(expected_argument_names.begin(), expected_argument_names.end());
  1072. EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
  1073. EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease(addr));
  1074. // Pkt passed to a callout must be configured to copy retrieved options.
  1075. EXPECT_TRUE(callback_qry_options_copy_);
  1076. }
  1077. // This test verifies that a callout installed on lease4_renew can trigger
  1078. // the server to not renew a lease.
  1079. TEST_F(HooksDhcpv4SrvTest, lease4RenewSkip) {
  1080. IfaceMgrTestConfig test_config(true);
  1081. IfaceMgr::instance().openSockets4();
  1082. const IOAddress addr("192.0.2.106");
  1083. const uint32_t temp_t1 = 50;
  1084. const uint32_t temp_t2 = 75;
  1085. const uint32_t temp_valid = 100;
  1086. const time_t temp_timestamp = time(NULL) - 10;
  1087. // Install a callout
  1088. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1089. "lease4_renew", skip_callout));
  1090. // Generate client-id also sets client_id_ member
  1091. OptionPtr clientid = generateClientId();
  1092. // Check that the address we are about to use is indeed in pool
  1093. ASSERT_TRUE(subnet_->inPool(Lease::TYPE_V4, addr));
  1094. // let's create a lease and put it in the LeaseMgr
  1095. uint8_t hwaddr2_data[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
  1096. HWAddrPtr hwaddr2(new HWAddr(hwaddr2_data, sizeof(hwaddr2_data), HTYPE_ETHER));
  1097. Lease4Ptr used(new Lease4(IOAddress("192.0.2.106"), hwaddr2,
  1098. &client_id_->getDuid()[0], client_id_->getDuid().size(),
  1099. temp_valid, temp_t1, temp_t2, temp_timestamp,
  1100. subnet_->getID()));
  1101. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
  1102. // Check that the lease is really in the database
  1103. Lease4Ptr l = LeaseMgrFactory::instance().getLease4(addr);
  1104. ASSERT_TRUE(l);
  1105. // Check that T1, T2, preferred, valid and cltt really set.
  1106. // Constructed lease looks as if it was assigned 10 seconds ago
  1107. // EXPECT_EQ(l->t1_, temp_t1);
  1108. // EXPECT_EQ(l->t2_, temp_t2);
  1109. EXPECT_EQ(l->valid_lft_, temp_valid);
  1110. EXPECT_EQ(l->cltt_, temp_timestamp);
  1111. // Let's create a RENEW
  1112. Pkt4Ptr req = Pkt4Ptr(new Pkt4(DHCPREQUEST, 1234));
  1113. req->setRemoteAddr(IOAddress(addr));
  1114. req->setYiaddr(addr);
  1115. req->setCiaddr(addr); // client's address
  1116. req->setIface("eth0");
  1117. req->setHWAddr(hwaddr2);
  1118. req->addOption(clientid);
  1119. req->addOption(srv_->getServerID());
  1120. // Pass it to the server and hope for a REPLY
  1121. Pkt4Ptr ack = srv_->processRequest(req);
  1122. ASSERT_TRUE(ack);
  1123. // Check that the lease is really in the database
  1124. l = checkLease(ack, clientid, req->getHWAddr(), addr);
  1125. ASSERT_TRUE(l);
  1126. // Check that T1, T2, valid and cltt were NOT updated
  1127. EXPECT_EQ(temp_t1, l->t1_);
  1128. EXPECT_EQ(temp_t2, l->t2_);
  1129. EXPECT_EQ(temp_valid, l->valid_lft_);
  1130. EXPECT_EQ(temp_timestamp, l->cltt_);
  1131. EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease(addr));
  1132. }
  1133. // This test verifies that valid RELEASE triggers lease4_release callouts
  1134. TEST_F(HooksDhcpv4SrvTest, lease4ReleaseSimple) {
  1135. IfaceMgrTestConfig test_config(true);
  1136. IfaceMgr::instance().openSockets4();
  1137. const IOAddress addr("192.0.2.106");
  1138. const uint32_t temp_t1 = 50;
  1139. const uint32_t temp_t2 = 75;
  1140. const uint32_t temp_valid = 100;
  1141. const time_t temp_timestamp = time(NULL) - 10;
  1142. // Install a callout
  1143. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1144. "lease4_release", lease4_release_callout));
  1145. // Generate client-id also duid_
  1146. OptionPtr clientid = generateClientId();
  1147. // Check that the address we are about to use is indeed in pool
  1148. ASSERT_TRUE(subnet_->inPool(Lease::TYPE_V4, addr));
  1149. // Let's create a lease and put it in the LeaseMgr
  1150. uint8_t mac_addr[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
  1151. HWAddrPtr hw(new HWAddr(mac_addr, sizeof(mac_addr), HTYPE_ETHER));
  1152. Lease4Ptr used(new Lease4(addr, hw,
  1153. &client_id_->getDuid()[0], client_id_->getDuid().size(),
  1154. temp_valid, temp_t1, temp_t2, temp_timestamp,
  1155. subnet_->getID()));
  1156. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
  1157. // Check that the lease is really in the database
  1158. Lease4Ptr l = LeaseMgrFactory::instance().getLease4(addr);
  1159. ASSERT_TRUE(l);
  1160. // Let's create a RELEASE
  1161. // Generate client-id also duid_
  1162. Pkt4Ptr rel = Pkt4Ptr(new Pkt4(DHCPRELEASE, 1234));
  1163. rel->setRemoteAddr(addr);
  1164. rel->setCiaddr(addr);
  1165. rel->addOption(clientid);
  1166. rel->addOption(srv_->getServerID());
  1167. rel->setHWAddr(hw);
  1168. // Pass it to the server and hope for a REPLY
  1169. // Note: this is no response to RELEASE in DHCPv4
  1170. EXPECT_NO_THROW(srv_->processRelease(rel));
  1171. // The lease should be gone from LeaseMgr
  1172. l = LeaseMgrFactory::instance().getLease4(addr);
  1173. EXPECT_FALSE(l);
  1174. // Try to get the lease by hardware address
  1175. // @todo: Uncomment this once trac2592 is implemented
  1176. // Lease4Collection leases = LeaseMgrFactory::instance().getLease4(hw->hwaddr_);
  1177. // EXPECT_EQ(leases.size(), 0);
  1178. // Try to get it by hw/subnet_id combination
  1179. l = LeaseMgrFactory::instance().getLease4(hw->hwaddr_, subnet_->getID());
  1180. EXPECT_FALSE(l);
  1181. // Try by client-id
  1182. // @todo: Uncomment this once trac2592 is implemented
  1183. //Lease4Collection leases = LeaseMgrFactory::instance().getLease4(*client_id_);
  1184. //EXPECT_EQ(leases.size(), 0);
  1185. // Try by client-id/subnet-id
  1186. l = LeaseMgrFactory::instance().getLease4(*client_id_, subnet_->getID());
  1187. EXPECT_FALSE(l);
  1188. // Ok, the lease is *really* not there.
  1189. // Check that the callback called is indeed the one we installed
  1190. EXPECT_EQ("lease4_release", callback_name_);
  1191. // Check that pkt4 argument passing was successful and returned proper value
  1192. EXPECT_TRUE(callback_qry_pkt4_.get() == rel.get());
  1193. // Check if all expected parameters were really received
  1194. vector<string> expected_argument_names;
  1195. expected_argument_names.push_back("query4");
  1196. expected_argument_names.push_back("lease4");
  1197. sort(callback_argument_names_.begin(), callback_argument_names_.end());
  1198. sort(expected_argument_names.begin(), expected_argument_names.end());
  1199. EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
  1200. // Pkt passed to a callout must be configured to copy retrieved options.
  1201. EXPECT_TRUE(callback_qry_options_copy_);
  1202. }
  1203. // This test verifies that skip flag returned by a callout installed on the
  1204. // lease4_release hook point will keep the lease
  1205. TEST_F(HooksDhcpv4SrvTest, lease4ReleaseSkip) {
  1206. IfaceMgrTestConfig test_config(true);
  1207. IfaceMgr::instance().openSockets4();
  1208. const IOAddress addr("192.0.2.106");
  1209. const uint32_t temp_t1 = 50;
  1210. const uint32_t temp_t2 = 75;
  1211. const uint32_t temp_valid = 100;
  1212. const time_t temp_timestamp = time(NULL) - 10;
  1213. // Install a callout
  1214. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1215. "lease4_release", skip_callout));
  1216. // Generate client-id also duid_
  1217. OptionPtr clientid = generateClientId();
  1218. // Check that the address we are about to use is indeed in pool
  1219. ASSERT_TRUE(subnet_->inPool(Lease::TYPE_V4, addr));
  1220. // Let's create a lease and put it in the LeaseMgr
  1221. uint8_t mac_addr[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
  1222. HWAddrPtr hw(new HWAddr(mac_addr, sizeof(mac_addr), HTYPE_ETHER));
  1223. Lease4Ptr used(new Lease4(addr, hw,
  1224. &client_id_->getDuid()[0], client_id_->getDuid().size(),
  1225. temp_valid, temp_t1, temp_t2, temp_timestamp,
  1226. subnet_->getID()));
  1227. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
  1228. // Check that the lease is really in the database
  1229. Lease4Ptr l = LeaseMgrFactory::instance().getLease4(addr);
  1230. ASSERT_TRUE(l);
  1231. // Let's create a RELEASE
  1232. // Generate client-id also duid_
  1233. Pkt4Ptr rel = Pkt4Ptr(new Pkt4(DHCPRELEASE, 1234));
  1234. rel->setRemoteAddr(addr);
  1235. rel->setYiaddr(addr);
  1236. rel->addOption(clientid);
  1237. rel->addOption(srv_->getServerID());
  1238. rel->setHWAddr(hw);
  1239. // Pass it to the server and hope for a REPLY
  1240. // Note: this is no response to RELEASE in DHCPv4
  1241. EXPECT_NO_THROW(srv_->processRelease(rel));
  1242. // The lease should be still there
  1243. l = LeaseMgrFactory::instance().getLease4(addr);
  1244. EXPECT_TRUE(l);
  1245. // Try by client-id/subnet-id
  1246. l = LeaseMgrFactory::instance().getLease4(*client_id_, subnet_->getID());
  1247. EXPECT_TRUE(l);
  1248. // Try to get the lease by hardware address, should succeed
  1249. Lease4Collection leases = LeaseMgrFactory::instance().getLease4(*hw);
  1250. EXPECT_EQ(leases.size(), 1);
  1251. // Try by client-id, should be successful as well.
  1252. leases = LeaseMgrFactory::instance().getLease4(*client_id_);
  1253. EXPECT_EQ(leases.size(), 1);
  1254. }
  1255. // Checks that decline4 hooks (lease4_decline) are triggered properly.
  1256. /// @todo: There is a bug in HooksManager that causes the callouts installed
  1257. /// using preCalloutsLibraryHandle() to be uninstalled when loadLibrary
  1258. /// is called. This has changed recently (ticket #5031) as it calls the
  1259. /// load/unload every time, regardless if the hooks-libraries clause is in the
  1260. /// config file or not. #5095 has been submitted for this issue. Please
  1261. /// enable this test once #5095 is fixed.
  1262. TEST_F(HooksDhcpv4SrvTest, DISABLED_HooksDecline) {
  1263. IfaceMgrTestConfig test_config(true);
  1264. IfaceMgr::instance().openSockets4();
  1265. // Install a callout
  1266. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1267. "lease4_decline", lease4_decline_callout));
  1268. // Conduct the actual DORA + Decline.
  1269. Dhcp4Client client(Dhcp4Client::SELECTING);
  1270. acquireAndDecline(client, "01:02:03:04:05:06", "12:14",
  1271. "01:02:03:04:05:06", "12:14",
  1272. SHOULD_PASS);
  1273. EXPECT_EQ("lease4_decline", callback_name_);
  1274. // Verifying DHCPDECLINE is a bit tricky, as it is created somewhere in
  1275. // acquireAndDecline. We'll just verify that it's really a DECLINE
  1276. // and that its address is equal to what we have in LeaseMgr.
  1277. ASSERT_TRUE(callback_qry_pkt4_);
  1278. ASSERT_TRUE(callback_lease4_);
  1279. // Check that it's the proper packet that was reported.
  1280. EXPECT_EQ(DHCPDECLINE, callback_qry_pkt4_->getType());
  1281. // Extract the address being declined.
  1282. OptionCustomPtr opt_declined_addr = boost::dynamic_pointer_cast<
  1283. OptionCustom>(callback_qry_pkt4_->getOption(DHO_DHCP_REQUESTED_ADDRESS));
  1284. ASSERT_TRUE(opt_declined_addr);
  1285. IOAddress addr(opt_declined_addr->readAddress());
  1286. // And try to get a matching lease from the lease manager.
  1287. Lease4Ptr from_mgr = LeaseMgrFactory::instance().getLease4(addr);
  1288. ASSERT_TRUE(from_mgr);
  1289. EXPECT_EQ(Lease::STATE_DECLINED, from_mgr->state_);
  1290. // Let's now check that those 3 things (packet, lease returned and lease from
  1291. // the lease manager) all match.
  1292. EXPECT_EQ(addr, from_mgr->addr_);
  1293. EXPECT_EQ(addr, callback_lease4_->addr_);
  1294. // Pkt passed to a callout must be configured to copy retrieved options.
  1295. EXPECT_TRUE(callback_qry_options_copy_);
  1296. }
  1297. // Checks that decline4 hook is able to drop the packet.
  1298. /// @todo See HooksDhcpv4SrvTest.HooksDecline description for details.
  1299. /// Please reenable this once #5095 is fixed.
  1300. TEST_F(HooksDhcpv4SrvTest, DISABLED_HooksDeclineDrop) {
  1301. IfaceMgrTestConfig test_config(true);
  1302. IfaceMgr::instance().openSockets4();
  1303. // Install a callout
  1304. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1305. "lease4_decline", lease4_decline_drop_callout));
  1306. // Conduct the actual DORA + Decline. The DECLINE should fail, as the
  1307. // hook will set the status to DROP.
  1308. Dhcp4Client client(Dhcp4Client::SELECTING);
  1309. acquireAndDecline(client, "01:02:03:04:05:06", "12:14",
  1310. "01:02:03:04:05:06", "12:14",
  1311. SHOULD_FAIL);
  1312. EXPECT_EQ("lease4_decline", callback_name_);
  1313. // Verifying DHCPDECLINE is a bit tricky, as it is created somewhere in
  1314. // acquireAndDecline. We'll just verify that it's really a DECLINE
  1315. // and that its address is equal to what we have in LeaseMgr.
  1316. ASSERT_TRUE(callback_qry_pkt4_);
  1317. ASSERT_TRUE(callback_lease4_);
  1318. // Check that it's the proper packet that was reported.
  1319. EXPECT_EQ(DHCPDECLINE, callback_qry_pkt4_->getType());
  1320. // Extract the address being declined.
  1321. OptionCustomPtr opt_declined_addr = boost::dynamic_pointer_cast<
  1322. OptionCustom>(callback_qry_pkt4_->getOption(DHO_DHCP_REQUESTED_ADDRESS));
  1323. ASSERT_TRUE(opt_declined_addr);
  1324. IOAddress addr(opt_declined_addr->readAddress());
  1325. // And try to get a matching lease from the lease manager. The lease should
  1326. // still be there in default state, not in declined state.
  1327. Lease4Ptr from_mgr = LeaseMgrFactory::instance().getLease4(addr);
  1328. ASSERT_TRUE(from_mgr);
  1329. EXPECT_EQ(Lease::STATE_DEFAULT, from_mgr->state_);
  1330. // As a final sanity check, let's now check that those 3 things (packet,
  1331. // lease returned and lease from the lease manager) all match.
  1332. EXPECT_EQ(addr, from_mgr->addr_);
  1333. EXPECT_EQ(addr, callback_lease4_->addr_);
  1334. }
  1335. // Verifies that libraries are unloaded by server destruction
  1336. // The callout libraries write their library index number to a marker
  1337. // file upon load and unload, making it simple to test whether or not
  1338. // the load and unload callouts have been invoked.
  1339. TEST_F(LoadUnloadDhcpv4SrvTest, unloadLibaries) {
  1340. ASSERT_NO_THROW(server_.reset(new NakedDhcpv4Srv()));
  1341. // Ensure no marker files to start with.
  1342. ASSERT_FALSE(checkMarkerFileExists(LOAD_MARKER_FILE));
  1343. ASSERT_FALSE(checkMarkerFileExists(UNLOAD_MARKER_FILE));
  1344. // Load the test libraries
  1345. HookLibsCollection libraries;
  1346. libraries.push_back(make_pair(std::string(CALLOUT_LIBRARY_1),
  1347. ConstElementPtr()));
  1348. libraries.push_back(make_pair(std::string(CALLOUT_LIBRARY_2),
  1349. ConstElementPtr()));
  1350. ASSERT_TRUE(HooksManager::loadLibraries(libraries));
  1351. // Verify that they load functions created the LOAD_MARKER_FILE
  1352. // and that it's contents are correct: "12" - the first library
  1353. // appends "1" to the file, the second appends "2"). Also
  1354. // check that the unload marker file does not yet exist.
  1355. EXPECT_TRUE(checkMarkerFile(LOAD_MARKER_FILE, "12"));
  1356. EXPECT_FALSE(checkMarkerFileExists(UNLOAD_MARKER_FILE));
  1357. // Destroy the server, instance which should unload the libraries.
  1358. server_.reset();
  1359. // Check that the libraries were unloaded. The libraries are
  1360. // unloaded in the reverse order to which they are loaded, and
  1361. // this should be reflected in the unload file.
  1362. EXPECT_TRUE(checkMarkerFile(UNLOAD_MARKER_FILE, "21"));
  1363. EXPECT_TRUE(checkMarkerFile(LOAD_MARKER_FILE, "12"));
  1364. }