hooks_unittest.cc 64 KB

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