dhcp4_srv_unittest.cc 102 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818
  1. // Copyright (C) 2011-2013 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <config.h>
  15. #include <sstream>
  16. #include <asiolink/io_address.h>
  17. #include <config/ccsession.h>
  18. #include <dhcp4/tests/dhcp4_test_utils.h>
  19. #include <dhcp/dhcp4.h>
  20. #include <dhcp/iface_mgr.h>
  21. #include <dhcp/option.h>
  22. #include <dhcp/option_int.h>
  23. #include <dhcp/option4_addrlst.h>
  24. #include <dhcp/option_custom.h>
  25. #include <dhcp/option_int_array.h>
  26. #include <dhcp/pkt_filter.h>
  27. #include <dhcp/pkt_filter_inet.h>
  28. #include <dhcp4/dhcp4_srv.h>
  29. #include <dhcp4/dhcp4_log.h>
  30. #include <dhcp4/config_parser.h>
  31. #include <hooks/server_hooks.h>
  32. #include <dhcpsrv/cfgmgr.h>
  33. #include <dhcpsrv/lease_mgr.h>
  34. #include <dhcpsrv/lease_mgr_factory.h>
  35. #include <dhcpsrv/utils.h>
  36. #include <gtest/gtest.h>
  37. #include <hooks/server_hooks.h>
  38. #include <hooks/hooks_manager.h>
  39. #include <boost/scoped_ptr.hpp>
  40. #include <fstream>
  41. #include <iostream>
  42. #include <arpa/inet.h>
  43. using namespace std;
  44. using namespace isc;
  45. using namespace isc::dhcp;
  46. using namespace isc::data;
  47. using namespace isc::asiolink;
  48. using namespace isc::hooks;
  49. #if 0
  50. namespace {
  51. class NakedDhcpv4Srv: public Dhcpv4Srv {
  52. // "Naked" DHCPv4 server, exposes internal fields
  53. public:
  54. /// @brief Constructor.
  55. ///
  56. /// This constructor disables default modes of operation used by the
  57. /// Dhcpv4Srv class:
  58. /// - Send/receive broadcast messages through sockets on interfaces
  59. /// which support broadcast traffic.
  60. /// - Direct DHCPv4 traffic - communication with clients which do not
  61. /// have IP address assigned yet.
  62. ///
  63. /// Enabling these modes requires root privilges so they must be
  64. /// disabled for unit testing.
  65. ///
  66. /// Note, that disabling broadcast options on sockets does not impact
  67. /// the operation of these tests because they use local loopback
  68. /// interface which doesn't have broadcast capability anyway. It rather
  69. /// prevents setting broadcast options on other (broadcast capable)
  70. /// sockets which are opened on other interfaces in Dhcpv4Srv constructor.
  71. ///
  72. /// The Direct DHCPv4 Traffic capability can be disabled here because
  73. /// it is tested with PktFilterLPFTest unittest. The tests which belong
  74. /// to PktFilterLPFTest can be enabled on demand when root privileges can
  75. /// be guaranteed.
  76. ///
  77. /// @param port port number to listen on; the default value 0 indicates
  78. /// that sockets should not be opened.
  79. NakedDhcpv4Srv(uint16_t port = 0)
  80. : Dhcpv4Srv(port, "type=memfile", false, false) {
  81. }
  82. /// @brief fakes packet reception
  83. /// @param timeout ignored
  84. ///
  85. /// The method receives all packets queued in receive queue, one after
  86. /// another. Once the queue is empty, it initiates the shutdown procedure.
  87. ///
  88. /// See fake_received_ field for description
  89. virtual Pkt4Ptr receivePacket(int /*timeout*/) {
  90. // If there is anything prepared as fake incoming traffic, use it
  91. if (!fake_received_.empty()) {
  92. Pkt4Ptr pkt = fake_received_.front();
  93. fake_received_.pop_front();
  94. return (pkt);
  95. }
  96. // If not, just trigger shutdown and return immediately
  97. shutdown();
  98. return (Pkt4Ptr());
  99. }
  100. /// @brief fake packet sending
  101. ///
  102. /// Pretend to send a packet, but instead just store it in fake_send_ list
  103. /// where test can later inspect server's response.
  104. virtual void sendPacket(const Pkt4Ptr& pkt) {
  105. fake_sent_.push_back(pkt);
  106. }
  107. /// @brief adds a packet to fake receive queue
  108. ///
  109. /// See fake_received_ field for description
  110. void fakeReceive(const Pkt4Ptr& pkt) {
  111. fake_received_.push_back(pkt);
  112. }
  113. virtual ~NakedDhcpv4Srv() {
  114. }
  115. /// @brief packets we pretend to receive
  116. ///
  117. /// Instead of setting up sockets on interfaces that change between OSes, it
  118. /// is much easier to fake packet reception. This is a list of packets that
  119. /// we pretend to have received. You can schedule new packets to be received
  120. /// using fakeReceive() and NakedDhcpv4Srv::receivePacket() methods.
  121. list<Pkt4Ptr> fake_received_;
  122. list<Pkt4Ptr> fake_sent_;
  123. using Dhcpv4Srv::adjustRemoteAddr;
  124. using Dhcpv4Srv::processDiscover;
  125. using Dhcpv4Srv::processRequest;
  126. using Dhcpv4Srv::processRelease;
  127. using Dhcpv4Srv::processDecline;
  128. using Dhcpv4Srv::processInform;
  129. using Dhcpv4Srv::getServerID;
  130. using Dhcpv4Srv::loadServerID;
  131. using Dhcpv4Srv::generateServerID;
  132. using Dhcpv4Srv::writeServerID;
  133. using Dhcpv4Srv::sanityCheck;
  134. using Dhcpv4Srv::srvidToString;
  135. using Dhcpv4Srv::unpackOptions;
  136. };
  137. #endif
  138. /// dummy server-id file location
  139. static const char* SRVID_FILE = "server-id-test.txt";
  140. namespace isc {
  141. namespace dhcp {
  142. namespace test {
  143. // Sanity check. Verifies that both Dhcpv4Srv and its derived
  144. // class NakedDhcpv4Srv can be instantiated and destroyed.
  145. TEST_F(Dhcpv4SrvTest, basic) {
  146. // Check that the base class can be instantiated
  147. boost::scoped_ptr<Dhcpv4Srv> srv;
  148. ASSERT_NO_THROW(srv.reset(new Dhcpv4Srv(DHCP4_SERVER_PORT + 10000, "type=memfile",
  149. false, false)));
  150. srv.reset();
  151. // We have to close open sockets because further in this test we will
  152. // call the Dhcpv4Srv constructor again. This constructor will try to
  153. // set the appropriate packet filter class for IfaceMgr. This requires
  154. // that all sockets are closed.
  155. IfaceMgr::instance().closeSockets();
  156. // Check that the derived class can be instantiated
  157. boost::scoped_ptr<NakedDhcpv4Srv> naked_srv;
  158. ASSERT_NO_THROW(
  159. naked_srv.reset(new NakedDhcpv4Srv(DHCP4_SERVER_PORT + 10000)));
  160. EXPECT_TRUE(naked_srv->getServerID());
  161. // Close sockets again for the next test.
  162. IfaceMgr::instance().closeSockets();
  163. ASSERT_NO_THROW(naked_srv.reset(new NakedDhcpv4Srv(0)));
  164. EXPECT_TRUE(naked_srv->getServerID());
  165. }
  166. // This test verifies that the destination address of the response
  167. // message is set to giaddr, when giaddr is set to non-zero address
  168. // in the received message.
  169. TEST_F(Dhcpv4SrvTest, adjustRemoteAddressRelay) {
  170. boost::scoped_ptr<NakedDhcpv4Srv> srv(new NakedDhcpv4Srv(0));
  171. // Create the instance of the incoming packet.
  172. boost::shared_ptr<Pkt4> req(new Pkt4(DHCPDISCOVER, 1234));
  173. // Set the giaddr to non-zero address as if it was relayed.
  174. req->setGiaddr(IOAddress("192.0.2.1"));
  175. // Set ciaddr to zero. This simulates the client which applies
  176. // for the new lease.
  177. req->setCiaddr(IOAddress("0.0.0.0"));
  178. // Clear broadcast flag.
  179. req->setFlags(0x0000);
  180. // Create a response packet. Assume that the new lease have
  181. // been created and new address allocated. This address is
  182. // stored in yiaddr field.
  183. boost::shared_ptr<Pkt4> resp(new Pkt4(DHCPOFFER, 1234));
  184. resp->setYiaddr(IOAddress("192.0.2.100"));
  185. // Clear the remote address.
  186. resp->setRemoteAddr(IOAddress("0.0.0.0"));
  187. // This function never throws.
  188. ASSERT_NO_THROW(srv->adjustRemoteAddr(req, resp));
  189. // Now the destination address should be relay's address.
  190. EXPECT_EQ("192.0.2.1", resp->getRemoteAddr().toText());
  191. // Let's do another test and set other fields: ciaddr and
  192. // flags. By doing it, we want to make sure that the relay
  193. // address will take precedence.
  194. req->setGiaddr(IOAddress("192.0.2.50"));
  195. req->setCiaddr(IOAddress("192.0.2.11"));
  196. req->setFlags(Pkt4::FLAG_BROADCAST_MASK);
  197. resp->setYiaddr(IOAddress("192.0.2.100"));
  198. // Clear remote address.
  199. resp->setRemoteAddr(IOAddress("0.0.0.0"));
  200. ASSERT_NO_THROW(srv->adjustRemoteAddr(req, resp));
  201. // Response should be sent back to the relay address.
  202. EXPECT_EQ("192.0.2.50", resp->getRemoteAddr().toText());
  203. }
  204. // This test verifies that the destination address of the response message
  205. // is set to ciaddr when giaddr is set to zero and the ciaddr is set to
  206. // non-zero address in the received message. This is the case when the
  207. // client is in Renew or Rebind state.
  208. TEST_F(Dhcpv4SrvTest, adjustRemoteAddressRenewRebind) {
  209. boost::scoped_ptr<NakedDhcpv4Srv> srv(new NakedDhcpv4Srv(0));
  210. // Create instance of the incoming packet.
  211. boost::shared_ptr<Pkt4> req(new Pkt4(DHCPDISCOVER, 1234));
  212. // Clear giaddr to simulate direct packet.
  213. req->setGiaddr(IOAddress("0.0.0.0"));
  214. // Set ciaddr to non-zero address. The response should be sent to this
  215. // address as the client is in renewing or rebinding state (it is fully
  216. // configured).
  217. req->setCiaddr(IOAddress("192.0.2.15"));
  218. // Let's configure broadcast flag. It should be ignored because
  219. // we are responding directly to the client having an address
  220. // and trying to extend his lease. Broadcast flag is only used
  221. // when new lease is acquired and server must make a decision
  222. // whether to unicast the response to the acquired address or
  223. // broadcast it.
  224. req->setFlags(Pkt4::FLAG_BROADCAST_MASK);
  225. // Create a response.
  226. boost::shared_ptr<Pkt4> resp(new Pkt4(DHCPOFFER, 1234));
  227. // Let's extend the lease for the client in such a way that
  228. // it will actually get different address. The response
  229. // should not be sent to this address but rather to ciaddr
  230. // as client still have ciaddr configured.
  231. resp->setYiaddr(IOAddress("192.0.2.13"));
  232. // Clear the remote address.
  233. resp->setRemoteAddr(IOAddress("0.0.0.0"));
  234. ASSERT_NO_THROW(srv->adjustRemoteAddr(req, resp));
  235. // Check that server responds to ciaddr
  236. EXPECT_EQ("192.0.2.15", resp->getRemoteAddr().toText());
  237. }
  238. // This test verifies that the destination address of the response message
  239. // is set correctly when giaddr and ciaddr is zeroed in the received message
  240. // and the new lease is acquired. The lease address is carried in the
  241. // response message in the yiaddr field. In this case destination address
  242. // of the response should be set to yiaddr if server supports direct responses
  243. // to the client which doesn't have an address yet or broadcast if the server
  244. // doesn't support direct responses.
  245. TEST_F(Dhcpv4SrvTest, adjustRemoteAddressSelect) {
  246. boost::scoped_ptr<NakedDhcpv4Srv> srv(new NakedDhcpv4Srv(0));
  247. // Create instance of the incoming packet.
  248. boost::shared_ptr<Pkt4> req(new Pkt4(DHCPDISCOVER, 1234));
  249. // Clear giaddr to simulate direct packet.
  250. req->setGiaddr(IOAddress("0.0.0.0"));
  251. // Clear client address as it hasn't got any address configured yet.
  252. req->setCiaddr(IOAddress("0.0.0.0"));
  253. // Let's clear the broadcast flag.
  254. req->setFlags(0);
  255. // Create a response.
  256. boost::shared_ptr<Pkt4> resp(new Pkt4(DHCPOFFER, 1234));
  257. // Assign some new address for this client.
  258. resp->setYiaddr(IOAddress("192.0.2.13"));
  259. // Clear the remote address.
  260. resp->setRemoteAddr(IOAddress("0.0.0.0"));
  261. // When running unit tests, the IfaceMgr is using the default Packet
  262. // Filtering class, PktFilterInet. This class does not support direct
  263. // responses to clients without address assigned. When giaddr and ciaddr
  264. // are zero and client has just got new lease, the assigned address is
  265. // carried in yiaddr. In order to send this address to the client,
  266. // server must broadcast its response.
  267. ASSERT_NO_THROW(srv->adjustRemoteAddr(req, resp));
  268. // Check that the response is sent to broadcast address as the
  269. // server doesn't have capability to respond directly.
  270. EXPECT_EQ("255.255.255.255", resp->getRemoteAddr().toText());
  271. // We also want to test the case when the server has capability to
  272. // respond directly to the client which is not configured. Server
  273. // makes decision whether it responds directly or broadcast its
  274. // response based on the capability reported by IfaceMgr. In order
  275. // to set this capability we have to provide a dummy Packet Filter
  276. // class which would report the support for direct responses.
  277. // This class is called PktFilterTest.
  278. IfaceMgr::instance().setPacketFilter(PktFilterPtr(new PktFilterTest()));
  279. // Now we expect that the server will send its response to the
  280. // address assigned for the client.
  281. ASSERT_NO_THROW(srv->adjustRemoteAddr(req, resp));
  282. EXPECT_EQ("192.0.2.13", resp->getRemoteAddr().toText());
  283. }
  284. // This test verifies that the destination address of the response message
  285. // is set to broadcast address when client set broadcast flag in its
  286. // query. Client sets this flag to indicate that it can't receive direct
  287. // responses from the server when it doesn't have its interface configured.
  288. // Server must respect broadcast flag.
  289. TEST_F(Dhcpv4SrvTest, adjustRemoteAddressBroadcast) {
  290. boost::scoped_ptr<NakedDhcpv4Srv> srv(new NakedDhcpv4Srv(0));
  291. // Create instance of the incoming packet.
  292. boost::shared_ptr<Pkt4> req(new Pkt4(DHCPDISCOVER, 1234));
  293. // Clear giaddr to simulate direct packet.
  294. req->setGiaddr(IOAddress("0.0.0.0"));
  295. // Clear client address as it hasn't got any address configured yet.
  296. req->setCiaddr(IOAddress("0.0.0.0"));
  297. // Let's set the broadcast flag.
  298. req->setFlags(Pkt4::FLAG_BROADCAST_MASK);
  299. // Create a response.
  300. boost::shared_ptr<Pkt4> resp(new Pkt4(DHCPOFFER, 1234));
  301. // Assign some new address for this client.
  302. resp->setYiaddr(IOAddress("192.0.2.13"));
  303. // Clear the remote address.
  304. resp->setRemoteAddr(IOAddress("0.0.0.0"));
  305. // When running unit tests, the IfaceMgr is using the default Packet
  306. // Filtering class, PktFilterInet. This class does not support direct
  307. // responses to the clients without address assigned. If giaddr and
  308. // ciaddr are zero and client has just got the new lease, the assigned
  309. // address is carried in yiaddr. In order to send this address to the
  310. // client, server must send the response to the broadcast address when
  311. // direct response is not supported. This conflicts with the purpose
  312. // of this test which is supposed to verify that responses are sent
  313. // to broadcast address only, when broadcast flag is set. Therefore,
  314. // in order to simulate that direct responses are supported we have
  315. // to replace the default packet filtering class with a dummy class
  316. // which reports direct response capability.
  317. IfaceMgr::instance().setPacketFilter(PktFilterPtr(new PktFilterTest()));
  318. ASSERT_NO_THROW(srv->adjustRemoteAddr(req, resp));
  319. // Server must repond to broadcast address when client desired that
  320. // by setting the broadcast flag in its request.
  321. EXPECT_EQ("255.255.255.255", resp->getRemoteAddr().toText());
  322. }
  323. // Verifies that DISCOVER message can be processed correctly,
  324. // that the OFFER message generated in response is valid and
  325. // contains necessary options.
  326. //
  327. // Note: this test focuses on the packet correctness. There
  328. // are other tests that verify correctness of the allocation
  329. // engine. See DiscoverBasic, DiscoverHint, DiscoverNoClientId
  330. // and DiscoverInvalidHint.
  331. TEST_F(Dhcpv4SrvTest, processDiscover) {
  332. testDiscoverRequest(DHCPDISCOVER);
  333. }
  334. // Verifies that REQUEST message can be processed correctly,
  335. // that the OFFER message generated in response is valid and
  336. // contains necessary options.
  337. //
  338. // Note: this test focuses on the packet correctness. There
  339. // are other tests that verify correctness of the allocation
  340. // engine. See DiscoverBasic, DiscoverHint, DiscoverNoClientId
  341. // and DiscoverInvalidHint.
  342. TEST_F(Dhcpv4SrvTest, processRequest) {
  343. testDiscoverRequest(DHCPREQUEST);
  344. }
  345. TEST_F(Dhcpv4SrvTest, processRelease) {
  346. NakedDhcpv4Srv srv;
  347. Pkt4Ptr pkt(new Pkt4(DHCPRELEASE, 1234));
  348. // Should not throw
  349. EXPECT_NO_THROW(srv.processRelease(pkt));
  350. }
  351. TEST_F(Dhcpv4SrvTest, processDecline) {
  352. NakedDhcpv4Srv srv;
  353. Pkt4Ptr pkt(new Pkt4(DHCPDECLINE, 1234));
  354. // Should not throw
  355. EXPECT_NO_THROW(srv.processDecline(pkt));
  356. }
  357. TEST_F(Dhcpv4SrvTest, processInform) {
  358. NakedDhcpv4Srv srv;
  359. Pkt4Ptr pkt(new Pkt4(DHCPINFORM, 1234));
  360. // Should not throw
  361. EXPECT_NO_THROW(srv.processInform(pkt));
  362. // Should return something
  363. EXPECT_TRUE(srv.processInform(pkt));
  364. // @todo Implement more reasonable tests before starting
  365. // work on processSomething() method.
  366. }
  367. TEST_F(Dhcpv4SrvTest, serverReceivedPacketName) {
  368. // Check all possible packet types
  369. for (int itype = 0; itype < 256; ++itype) {
  370. uint8_t type = itype;
  371. switch (type) {
  372. case DHCPDECLINE:
  373. EXPECT_STREQ("DECLINE", Dhcpv4Srv::serverReceivedPacketName(type));
  374. break;
  375. case DHCPDISCOVER:
  376. EXPECT_STREQ("DISCOVER", Dhcpv4Srv::serverReceivedPacketName(type));
  377. break;
  378. case DHCPINFORM:
  379. EXPECT_STREQ("INFORM", Dhcpv4Srv::serverReceivedPacketName(type));
  380. break;
  381. case DHCPRELEASE:
  382. EXPECT_STREQ("RELEASE", Dhcpv4Srv::serverReceivedPacketName(type));
  383. break;
  384. case DHCPREQUEST:
  385. EXPECT_STREQ("REQUEST", Dhcpv4Srv::serverReceivedPacketName(type));
  386. break;
  387. default:
  388. EXPECT_STREQ("UNKNOWN", Dhcpv4Srv::serverReceivedPacketName(type));
  389. }
  390. }
  391. }
  392. // This test verifies that incoming DISCOVER can be handled properly, that an
  393. // OFFER is generated, that the response has an address and that address
  394. // really belongs to the configured pool.
  395. //
  396. // constructed very simple DISCOVER message with:
  397. // - client-id option
  398. //
  399. // expected returned OFFER message:
  400. // - copy of client-id
  401. // - server-id
  402. // - offered address
  403. TEST_F(Dhcpv4SrvTest, DiscoverBasic) {
  404. boost::scoped_ptr<NakedDhcpv4Srv> srv;
  405. ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
  406. Pkt4Ptr dis = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
  407. dis->setRemoteAddr(IOAddress("192.0.2.1"));
  408. OptionPtr clientid = generateClientId();
  409. dis->addOption(clientid);
  410. // Pass it to the server and get an offer
  411. Pkt4Ptr offer = srv->processDiscover(dis);
  412. // Check if we get response at all
  413. checkResponse(offer, DHCPOFFER, 1234);
  414. // Check that address was returned from proper range, that its lease
  415. // lifetime is correct, that T1 and T2 are returned properly
  416. checkAddressParams(offer, subnet_);
  417. // Check identifiers
  418. checkServerId(offer, srv->getServerID());
  419. checkClientId(offer, clientid);
  420. }
  421. // This test verifies that incoming DISCOVER can be handled properly, that an
  422. // OFFER is generated, that the response has an address and that address
  423. // really belongs to the configured pool.
  424. //
  425. // constructed very simple DISCOVER message with:
  426. // - client-id option
  427. // - address set to specific value as hint
  428. //
  429. // expected returned OFFER message:
  430. // - copy of client-id
  431. // - server-id
  432. // - offered address
  433. TEST_F(Dhcpv4SrvTest, DiscoverHint) {
  434. boost::scoped_ptr<NakedDhcpv4Srv> srv;
  435. ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
  436. IOAddress hint("192.0.2.107");
  437. Pkt4Ptr dis = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
  438. dis->setRemoteAddr(IOAddress("192.0.2.1"));
  439. OptionPtr clientid = generateClientId();
  440. dis->addOption(clientid);
  441. dis->setYiaddr(hint);
  442. // Pass it to the server and get an offer
  443. Pkt4Ptr offer = srv->processDiscover(dis);
  444. // Check if we get response at all
  445. checkResponse(offer, DHCPOFFER, 1234);
  446. // Check that address was returned from proper range, that its lease
  447. // lifetime is correct, that T1 and T2 are returned properly
  448. checkAddressParams(offer, subnet_);
  449. EXPECT_EQ(offer->getYiaddr().toText(), hint.toText());
  450. // Check identifiers
  451. checkServerId(offer, srv->getServerID());
  452. checkClientId(offer, clientid);
  453. }
  454. // This test verifies that incoming DISCOVER can be handled properly, that an
  455. // OFFER is generated, that the response has an address and that address
  456. // really belongs to the configured pool.
  457. //
  458. // constructed very simple DISCOVER message with:
  459. // - address set to specific value as hint
  460. //
  461. // expected returned OFFER message:
  462. // - copy of client-id
  463. // - server-id
  464. // - offered address
  465. TEST_F(Dhcpv4SrvTest, DiscoverNoClientId) {
  466. boost::scoped_ptr<NakedDhcpv4Srv> srv;
  467. ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
  468. IOAddress hint("192.0.2.107");
  469. Pkt4Ptr dis = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
  470. dis->setRemoteAddr(IOAddress("192.0.2.1"));
  471. dis->setYiaddr(hint);
  472. dis->setHWAddr(generateHWAddr(6));
  473. // Pass it to the server and get an offer
  474. Pkt4Ptr offer = srv->processDiscover(dis);
  475. // Check if we get response at all
  476. checkResponse(offer, DHCPOFFER, 1234);
  477. // Check that address was returned from proper range, that its lease
  478. // lifetime is correct, that T1 and T2 are returned properly
  479. checkAddressParams(offer, subnet_);
  480. EXPECT_EQ(offer->getYiaddr().toText(), hint.toText());
  481. // Check identifiers
  482. checkServerId(offer, srv->getServerID());
  483. }
  484. // This test verifies that incoming DISCOVER can be handled properly, that an
  485. // OFFER is generated, that the response has an address and that address
  486. // really belongs to the configured pool.
  487. //
  488. // constructed very simple DISCOVER message with:
  489. // - client-id option
  490. // - address set to specific value as hint, but that hint is invalid
  491. //
  492. // expected returned OFFER message:
  493. // - copy of client-id
  494. // - server-id
  495. // - offered address (!= hint)
  496. TEST_F(Dhcpv4SrvTest, DiscoverInvalidHint) {
  497. boost::scoped_ptr<NakedDhcpv4Srv> srv;
  498. ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
  499. IOAddress hint("10.1.2.3");
  500. Pkt4Ptr dis = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
  501. dis->setRemoteAddr(IOAddress("192.0.2.107"));
  502. OptionPtr clientid = generateClientId();
  503. dis->addOption(clientid);
  504. dis->setYiaddr(hint);
  505. // Pass it to the server and get an offer
  506. Pkt4Ptr offer = srv->processDiscover(dis);
  507. // Check if we get response at all
  508. checkResponse(offer, DHCPOFFER, 1234);
  509. // Check that address was returned from proper range, that its lease
  510. // lifetime is correct, that T1 and T2 are returned properly
  511. checkAddressParams(offer, subnet_);
  512. EXPECT_NE(offer->getYiaddr().toText(), hint.toText());
  513. // Check identifiers
  514. checkServerId(offer, srv->getServerID());
  515. checkClientId(offer, clientid);
  516. }
  517. /// @todo: Add a test that client sends hint that is in pool, but currently
  518. /// being used by a different client.
  519. // This test checks that the server is offering different addresses to different
  520. // clients in OFFERs. Please note that OFFER is not a guarantee that such
  521. // an address will be assigned. Had the pool was very small and contained only
  522. // 2 addresses, the third client would get the same offer as the first one
  523. // and this is a correct behavior. It is REQUEST that will fail for the third
  524. // client. OFFER is basically saying "if you send me a request, you will
  525. // probably get an address like this" (there are no guarantees).
  526. TEST_F(Dhcpv4SrvTest, ManyDiscovers) {
  527. boost::scoped_ptr<NakedDhcpv4Srv> srv;
  528. ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
  529. Pkt4Ptr dis1 = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
  530. Pkt4Ptr dis2 = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 2345));
  531. Pkt4Ptr dis3 = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 3456));
  532. dis1->setRemoteAddr(IOAddress("192.0.2.1"));
  533. dis2->setRemoteAddr(IOAddress("192.0.2.2"));
  534. dis3->setRemoteAddr(IOAddress("192.0.2.3"));
  535. // Different client-id sizes
  536. OptionPtr clientid1 = generateClientId(4); // length 4
  537. OptionPtr clientid2 = generateClientId(5); // length 5
  538. OptionPtr clientid3 = generateClientId(6); // length 6
  539. dis1->addOption(clientid1);
  540. dis2->addOption(clientid2);
  541. dis3->addOption(clientid3);
  542. // Pass it to the server and get an offer
  543. Pkt4Ptr offer1 = srv->processDiscover(dis1);
  544. Pkt4Ptr offer2 = srv->processDiscover(dis2);
  545. Pkt4Ptr offer3 = srv->processDiscover(dis3);
  546. // Check if we get response at all
  547. checkResponse(offer1, DHCPOFFER, 1234);
  548. checkResponse(offer2, DHCPOFFER, 2345);
  549. checkResponse(offer3, DHCPOFFER, 3456);
  550. IOAddress addr1 = offer1->getYiaddr();
  551. IOAddress addr2 = offer2->getYiaddr();
  552. IOAddress addr3 = offer3->getYiaddr();
  553. // Check that the assigned address is indeed from the configured pool
  554. checkAddressParams(offer1, subnet_);
  555. checkAddressParams(offer2, subnet_);
  556. checkAddressParams(offer3, subnet_);
  557. // Check server-ids
  558. checkServerId(offer1, srv->getServerID());
  559. checkServerId(offer2, srv->getServerID());
  560. checkServerId(offer3, srv->getServerID());
  561. checkClientId(offer1, clientid1);
  562. checkClientId(offer2, clientid2);
  563. checkClientId(offer3, clientid3);
  564. // Finally check that the addresses offered are different
  565. EXPECT_NE(addr1.toText(), addr2.toText());
  566. EXPECT_NE(addr2.toText(), addr3.toText());
  567. EXPECT_NE(addr3.toText(), addr1.toText());
  568. cout << "Offered address to client1=" << addr1.toText() << endl;
  569. cout << "Offered address to client2=" << addr2.toText() << endl;
  570. cout << "Offered address to client3=" << addr3.toText() << endl;
  571. }
  572. // Checks whether echoing back client-id is controllable, i.e.
  573. // whether the server obeys echo-client-id and sends (or not)
  574. // client-id
  575. TEST_F(Dhcpv4SrvTest, discoverEchoClientId) {
  576. NakedDhcpv4Srv srv(0);
  577. Pkt4Ptr dis = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
  578. dis->setRemoteAddr(IOAddress("192.0.2.1"));
  579. OptionPtr clientid = generateClientId();
  580. dis->addOption(clientid);
  581. // Pass it to the server and get an offer
  582. Pkt4Ptr offer = srv.processDiscover(dis);
  583. // Check if we get response at all
  584. checkResponse(offer, DHCPOFFER, 1234);
  585. checkClientId(offer, clientid);
  586. CfgMgr::instance().echoClientId(false);
  587. offer = srv.processDiscover(dis);
  588. // Check if we get response at all
  589. checkResponse(offer, DHCPOFFER, 1234);
  590. checkClientId(offer, clientid);
  591. }
  592. // This test verifies that incoming REQUEST can be handled properly, that an
  593. // ACK is generated, that the response has an address and that address
  594. // really belongs to the configured pool.
  595. //
  596. // constructed a single REQUEST message with:
  597. // - client-id option
  598. // - hwaddr information
  599. // - requested address (that the client received in DISCOVER/OFFER exchange)
  600. //
  601. // expected returned ACK message:
  602. // - copy of client-id
  603. // - server-id
  604. // - assigned address
  605. //
  606. // Test verifies that the lease is actually in the database.
  607. TEST_F(Dhcpv4SrvTest, RequestBasic) {
  608. boost::scoped_ptr<NakedDhcpv4Srv> srv;
  609. ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
  610. IOAddress hint("192.0.2.107");
  611. Pkt4Ptr req = Pkt4Ptr(new Pkt4(DHCPREQUEST, 1234));
  612. req->setRemoteAddr(IOAddress("192.0.2.1"));
  613. OptionPtr clientid = generateClientId();
  614. req->addOption(clientid);
  615. req->setYiaddr(hint);
  616. // Pass it to the server and get an advertise
  617. Pkt4Ptr ack = srv->processRequest(req);
  618. // Check if we get response at all
  619. checkResponse(ack, DHCPACK, 1234);
  620. EXPECT_EQ(hint.toText(), ack->getYiaddr().toText());
  621. // Check that address was returned from proper range, that its lease
  622. // lifetime is correct, that T1 and T2 are returned properly
  623. checkAddressParams(ack, subnet_);
  624. // Check identifiers
  625. checkServerId(ack, srv->getServerID());
  626. checkClientId(ack, clientid);
  627. // Check that the lease is really in the database
  628. Lease4Ptr l = checkLease(ack, clientid, req->getHWAddr(), hint);
  629. ASSERT_TRUE(l);
  630. LeaseMgrFactory::instance().deleteLease(l->addr_);
  631. }
  632. // This test verifies that incoming REQUEST can be handled properly, that an
  633. // ACK is generated, that the response has an address and that address
  634. // really belongs to the configured pool.
  635. //
  636. // constructed 3 REQUEST messages with:
  637. // - client-id option (differs between messages)
  638. // - hwaddr information (differs between messages)
  639. //
  640. // expected returned ACK message:
  641. // - copy of client-id
  642. // - server-id
  643. // - assigned address (different for each client)
  644. TEST_F(Dhcpv4SrvTest, ManyRequests) {
  645. boost::scoped_ptr<NakedDhcpv4Srv> srv;
  646. ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
  647. const IOAddress req_addr1("192.0.2.105");
  648. const IOAddress req_addr2("192.0.2.101");
  649. const IOAddress req_addr3("192.0.2.109");
  650. const IOAddress relay("192.0.2.1");
  651. Pkt4Ptr req1 = Pkt4Ptr(new Pkt4(DHCPOFFER, 1234));
  652. Pkt4Ptr req2 = Pkt4Ptr(new Pkt4(DHCPOFFER, 2345));
  653. Pkt4Ptr req3 = Pkt4Ptr(new Pkt4(DHCPOFFER, 3456));
  654. req1->setRemoteAddr(relay);
  655. req2->setRemoteAddr(relay);
  656. req3->setRemoteAddr(relay);
  657. req1->setYiaddr(req_addr1);
  658. req2->setYiaddr(req_addr2);
  659. req3->setYiaddr(req_addr3);
  660. req1->setHWAddr(generateHWAddr(6));
  661. req2->setHWAddr(generateHWAddr(7));
  662. req3->setHWAddr(generateHWAddr(8));
  663. // Different client-id sizes
  664. OptionPtr clientid1 = generateClientId(4); // length 4
  665. OptionPtr clientid2 = generateClientId(5); // length 5
  666. OptionPtr clientid3 = generateClientId(6); // length 6
  667. req1->addOption(clientid1);
  668. req2->addOption(clientid2);
  669. req3->addOption(clientid3);
  670. // Pass it to the server and get an advertise
  671. Pkt4Ptr ack1 = srv->processRequest(req1);
  672. Pkt4Ptr ack2 = srv->processRequest(req2);
  673. Pkt4Ptr ack3 = srv->processRequest(req3);
  674. // Check if we get response at all
  675. checkResponse(ack1, DHCPACK, 1234);
  676. checkResponse(ack2, DHCPACK, 2345);
  677. checkResponse(ack3, DHCPACK, 3456);
  678. IOAddress addr1 = ack1->getYiaddr();
  679. IOAddress addr2 = ack2->getYiaddr();
  680. IOAddress addr3 = ack3->getYiaddr();
  681. // Check that every client received the address it requested
  682. EXPECT_EQ(req_addr1.toText(), addr1.toText());
  683. EXPECT_EQ(req_addr2.toText(), addr2.toText());
  684. EXPECT_EQ(req_addr3.toText(), addr3.toText());
  685. // Check that the assigned address is indeed from the configured pool
  686. checkAddressParams(ack1, subnet_);
  687. checkAddressParams(ack2, subnet_);
  688. checkAddressParams(ack3, subnet_);
  689. // Check DUIDs
  690. checkServerId(ack1, srv->getServerID());
  691. checkServerId(ack2, srv->getServerID());
  692. checkServerId(ack3, srv->getServerID());
  693. checkClientId(ack1, clientid1);
  694. checkClientId(ack2, clientid2);
  695. checkClientId(ack3, clientid3);
  696. // Check that leases are in the database
  697. Lease4Ptr l = checkLease(ack1, clientid1, req1->getHWAddr(), addr1);
  698. EXPECT_TRUE(l);
  699. l = checkLease(ack2, clientid2, req2->getHWAddr(), addr2);
  700. l = checkLease(ack3, clientid3, req3->getHWAddr(), addr3);
  701. // Finally check that the addresses offered are different
  702. EXPECT_NE(addr1.toText(), addr2.toText());
  703. EXPECT_NE(addr2.toText(), addr3.toText());
  704. EXPECT_NE(addr3.toText(), addr1.toText());
  705. cout << "Offered address to client1=" << addr1.toText() << endl;
  706. cout << "Offered address to client2=" << addr2.toText() << endl;
  707. cout << "Offered address to client3=" << addr3.toText() << endl;
  708. }
  709. // Checks whether echoing back client-id is controllable
  710. TEST_F(Dhcpv4SrvTest, requestEchoClientId) {
  711. NakedDhcpv4Srv srv(0);
  712. Pkt4Ptr dis = Pkt4Ptr(new Pkt4(DHCPREQUEST, 1234));
  713. dis->setRemoteAddr(IOAddress("192.0.2.1"));
  714. OptionPtr clientid = generateClientId();
  715. dis->addOption(clientid);
  716. // Pass it to the server and get ACK
  717. Pkt4Ptr ack = srv.processRequest(dis);
  718. // Check if we get response at all
  719. checkResponse(ack, DHCPACK, 1234);
  720. checkClientId(ack, clientid);
  721. CfgMgr::instance().echoClientId(false);
  722. ack = srv.processDiscover(dis);
  723. // Check if we get response at all
  724. checkResponse(ack, DHCPOFFER, 1234);
  725. checkClientId(ack, clientid);
  726. }
  727. // This test verifies that incoming (positive) REQUEST/Renewing can be handled properly, that a
  728. // REPLY is generated, that the response has an address and that address
  729. // really belongs to the configured pool and that lease is actually renewed.
  730. //
  731. // expected:
  732. // - returned REPLY message has copy of client-id
  733. // - returned REPLY message has server-id
  734. // - returned REPLY message has IA that includes IAADDR
  735. // - lease is actually renewed in LeaseMgr
  736. TEST_F(Dhcpv4SrvTest, RenewBasic) {
  737. boost::scoped_ptr<NakedDhcpv4Srv> srv;
  738. ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
  739. const IOAddress addr("192.0.2.106");
  740. const uint32_t temp_t1 = 50;
  741. const uint32_t temp_t2 = 75;
  742. const uint32_t temp_valid = 100;
  743. const time_t temp_timestamp = time(NULL) - 10;
  744. // Generate client-id also sets client_id_ member
  745. OptionPtr clientid = generateClientId();
  746. // Check that the address we are about to use is indeed in pool
  747. ASSERT_TRUE(subnet_->inPool(Lease::TYPE_V4, addr));
  748. // let's create a lease and put it in the LeaseMgr
  749. uint8_t hwaddr2[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
  750. Lease4Ptr used(new Lease4(IOAddress("192.0.2.106"), hwaddr2, sizeof(hwaddr2),
  751. &client_id_->getDuid()[0], client_id_->getDuid().size(),
  752. temp_valid, temp_t1, temp_t2, temp_timestamp,
  753. subnet_->getID()));
  754. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
  755. // Check that the lease is really in the database
  756. Lease4Ptr l = LeaseMgrFactory::instance().getLease4(addr);
  757. ASSERT_TRUE(l);
  758. // Check that T1, T2, preferred, valid and cltt really set.
  759. // Constructed lease looks as if it was assigned 10 seconds ago
  760. // EXPECT_EQ(l->t1_, temp_t1);
  761. // EXPECT_EQ(l->t2_, temp_t2);
  762. EXPECT_EQ(l->valid_lft_, temp_valid);
  763. EXPECT_EQ(l->cltt_, temp_timestamp);
  764. // Let's create a RENEW
  765. Pkt4Ptr req = Pkt4Ptr(new Pkt4(DHCPREQUEST, 1234));
  766. req->setRemoteAddr(IOAddress(addr));
  767. req->setYiaddr(addr);
  768. req->setCiaddr(addr); // client's address
  769. req->addOption(clientid);
  770. req->addOption(srv->getServerID());
  771. // Pass it to the server and hope for a REPLY
  772. Pkt4Ptr ack = srv->processRequest(req);
  773. // Check if we get response at all
  774. checkResponse(ack, DHCPACK, 1234);
  775. EXPECT_EQ(addr.toText(), ack->getYiaddr().toText());
  776. // Check that address was returned from proper range, that its lease
  777. // lifetime is correct, that T1 and T2 are returned properly
  778. checkAddressParams(ack, subnet_);
  779. // Check identifiers
  780. checkServerId(ack, srv->getServerID());
  781. checkClientId(ack, clientid);
  782. // Check that the lease is really in the database
  783. l = checkLease(ack, clientid, req->getHWAddr(), addr);
  784. ASSERT_TRUE(l);
  785. // Check that T1, T2, preferred, valid and cltt were really updated
  786. EXPECT_EQ(l->t1_, subnet_->getT1());
  787. EXPECT_EQ(l->t2_, subnet_->getT2());
  788. EXPECT_EQ(l->valid_lft_, subnet_->getValid());
  789. // Checking for CLTT is a bit tricky if we want to avoid off by 1 errors
  790. int32_t cltt = static_cast<int32_t>(l->cltt_);
  791. int32_t expected = static_cast<int32_t>(time(NULL));
  792. // Equality or difference by 1 between cltt and expected is ok.
  793. EXPECT_GE(1, abs(cltt - expected));
  794. EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease(addr));
  795. }
  796. // @todo: Implement tests for rejecting renewals
  797. // This test verifies if the sanityCheck() really checks options presence.
  798. TEST_F(Dhcpv4SrvTest, sanityCheck) {
  799. boost::scoped_ptr<NakedDhcpv4Srv> srv;
  800. ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
  801. Pkt4Ptr pkt = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
  802. pkt->setHWAddr(generateHWAddr(6));
  803. // Server-id is optional for information-request, so
  804. EXPECT_NO_THROW(srv->sanityCheck(pkt, Dhcpv4Srv::OPTIONAL));
  805. // Empty packet, no server-id
  806. EXPECT_THROW(srv->sanityCheck(pkt, Dhcpv4Srv::MANDATORY), RFCViolation);
  807. pkt->addOption(srv->getServerID());
  808. // Server-id is mandatory and present = no exception
  809. EXPECT_NO_THROW(srv->sanityCheck(pkt, Dhcpv4Srv::MANDATORY));
  810. // Server-id is forbidden, but present => exception
  811. EXPECT_THROW(srv->sanityCheck(pkt, Dhcpv4Srv::FORBIDDEN),
  812. RFCViolation);
  813. // There's no client-id and no HWADDR. Server needs something to
  814. // identify the client
  815. pkt->setHWAddr(generateHWAddr(0));
  816. EXPECT_THROW(srv->sanityCheck(pkt, Dhcpv4Srv::MANDATORY), RFCViolation);
  817. }
  818. // This test verifies that incoming (positive) RELEASE can be handled properly.
  819. // As there is no REPLY in DHCPv4, the only thing to verify here is that
  820. // the lease is indeed removed from the database.
  821. TEST_F(Dhcpv4SrvTest, ReleaseBasic) {
  822. boost::scoped_ptr<NakedDhcpv4Srv> srv;
  823. ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
  824. const IOAddress addr("192.0.2.106");
  825. const uint32_t temp_t1 = 50;
  826. const uint32_t temp_t2 = 75;
  827. const uint32_t temp_valid = 100;
  828. const time_t temp_timestamp = time(NULL) - 10;
  829. // Generate client-id also duid_
  830. OptionPtr clientid = generateClientId();
  831. // Check that the address we are about to use is indeed in pool
  832. ASSERT_TRUE(subnet_->inPool(Lease::TYPE_V4, addr));
  833. // Let's create a lease and put it in the LeaseMgr
  834. uint8_t mac_addr[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
  835. HWAddrPtr hw(new HWAddr(mac_addr, sizeof(mac_addr), HTYPE_ETHER));
  836. Lease4Ptr used(new Lease4(addr, mac_addr, sizeof(mac_addr),
  837. &client_id_->getDuid()[0], client_id_->getDuid().size(),
  838. temp_valid, temp_t1, temp_t2, temp_timestamp,
  839. subnet_->getID()));
  840. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
  841. // Check that the lease is really in the database
  842. Lease4Ptr l = LeaseMgrFactory::instance().getLease4(addr);
  843. ASSERT_TRUE(l);
  844. // Let's create a RELEASE
  845. // Generate client-id also duid_
  846. Pkt4Ptr rel = Pkt4Ptr(new Pkt4(DHCPRELEASE, 1234));
  847. rel->setRemoteAddr(addr);
  848. rel->setYiaddr(addr);
  849. rel->addOption(clientid);
  850. rel->addOption(srv->getServerID());
  851. rel->setHWAddr(hw);
  852. // Pass it to the server and hope for a REPLY
  853. // Note: this is no response to RELEASE in DHCPv4
  854. EXPECT_NO_THROW(srv->processRelease(rel));
  855. // The lease should be gone from LeaseMgr
  856. l = LeaseMgrFactory::instance().getLease4(addr);
  857. EXPECT_FALSE(l);
  858. // Try to get the lease by hardware address
  859. Lease4Collection leases = LeaseMgrFactory::instance().getLease4(hw->hwaddr_);
  860. EXPECT_EQ(leases.size(), 0);
  861. // Try to get it by hw/subnet_id combination
  862. l = LeaseMgrFactory::instance().getLease4(hw->hwaddr_, subnet_->getID());
  863. EXPECT_FALSE(l);
  864. // Try by client-id
  865. leases = LeaseMgrFactory::instance().getLease4(*client_id_);
  866. EXPECT_EQ(leases.size(), 0);
  867. // Try by client-id/subnet-id
  868. l = LeaseMgrFactory::instance().getLease4(*client_id_, subnet_->getID());
  869. EXPECT_FALSE(l);
  870. // Ok, the lease is *really* not there.
  871. }
  872. // This test verifies that incoming (invalid) RELEASE can be handled properly.
  873. //
  874. // This test checks 3 scenarios:
  875. // 1. there is no such lease at all
  876. // 2. there is such a lease, but it is assigned to a different IAID
  877. // 3. there is such a lease, but it belongs to a different client
  878. TEST_F(Dhcpv4SrvTest, ReleaseReject) {
  879. boost::scoped_ptr<NakedDhcpv4Srv> srv;
  880. ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
  881. const IOAddress addr("192.0.2.106");
  882. const uint32_t t1 = 50;
  883. const uint32_t t2 = 75;
  884. const uint32_t valid = 100;
  885. const time_t timestamp = time(NULL) - 10;
  886. // Let's create a lease and put it in the LeaseMgr
  887. uint8_t bogus_mac_addr[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
  888. HWAddrPtr bogus_hw(new HWAddr(bogus_mac_addr, sizeof(bogus_mac_addr), HTYPE_ETHER));
  889. OptionPtr bogus_clientid = generateClientId(7); // different length
  890. // Generate client-id also duid_
  891. OptionPtr clientid = generateClientId();
  892. // Check that the address we are about to use is indeed in pool
  893. ASSERT_TRUE(subnet_->inPool(Lease::TYPE_V4, addr));
  894. // Let's create a RELEASE
  895. // Generate client-id also duid_
  896. Pkt4Ptr rel = Pkt4Ptr(new Pkt4(DHCPRELEASE, 1234));
  897. rel->setRemoteAddr(addr);
  898. rel->setYiaddr(addr);
  899. rel->addOption(clientid);
  900. rel->addOption(srv->getServerID());
  901. rel->setHWAddr(bogus_hw);
  902. // Case 1: No lease known to server
  903. SCOPED_TRACE("CASE 1: Lease is not known to the server");
  904. // There is nothing to check here. The lease is not there and server does
  905. // not send anything back. This case is enumerated here just for keeping
  906. // parity with similar test in DHCPv6.
  907. EXPECT_NO_THROW(srv->processRelease(rel));
  908. // CASE 2: Lease is known and belongs to this client, but to a different hardware
  909. SCOPED_TRACE("CASE 2: Lease is known and belongs to this client, but uses different HW addr");
  910. // Let's create a lease and put it in the LeaseMgr
  911. uint8_t mac_addr[] = { 0, 0x1, 0x2, 0x3, 0x4, 0x5};
  912. HWAddrPtr hw(new HWAddr(mac_addr, sizeof(mac_addr), HTYPE_ETHER));
  913. Lease4Ptr used(new Lease4(addr, mac_addr, sizeof(mac_addr),
  914. &client_id_->getDuid()[0], client_id_->getDuid().size(),
  915. valid, t1, t2, timestamp, subnet_->getID()));
  916. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
  917. // Check that the lease is really in the database
  918. Lease4Ptr l = LeaseMgrFactory::instance().getLease4(addr);
  919. ASSERT_TRUE(l);
  920. rel->setHWAddr(bogus_hw);
  921. EXPECT_NO_THROW(srv->processRelease(rel));
  922. // Check that the lease was not removed (due to hardware address mis-match)
  923. l = LeaseMgrFactory::instance().getLease4(addr);
  924. ASSERT_TRUE(l);
  925. // CASE 3: Lease belongs to a client with different client-id
  926. SCOPED_TRACE("CASE 3: Lease belongs to a client with different client-id");
  927. rel->setHWAddr(hw); // proper HW address this time
  928. rel->delOption(DHO_DHCP_CLIENT_IDENTIFIER);
  929. rel->addOption(bogus_clientid); // but invalid client-id
  930. OptionPtr x = rel->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
  931. EXPECT_NO_THROW(srv->processRelease(rel));
  932. // Check that the lease is still there
  933. l = LeaseMgrFactory::instance().getLease4(addr);
  934. ASSERT_TRUE(l);
  935. // Final sanity check. Verify that with valid hw and client-id release is successful
  936. rel->delOption(DHO_DHCP_CLIENT_IDENTIFIER);
  937. rel->addOption(clientid);
  938. // It should work this time
  939. EXPECT_NO_THROW(srv->processRelease(rel));
  940. // Check that the lease is not there
  941. l = LeaseMgrFactory::instance().getLease4(addr);
  942. EXPECT_FALSE(l);
  943. }
  944. // This test verifies if the server-id disk operations (read, write) are
  945. // working properly.
  946. TEST_F(Dhcpv4SrvTest, ServerID) {
  947. NakedDhcpv4Srv srv(0);
  948. string srvid_text = "192.0.2.100";
  949. IOAddress srvid(srvid_text);
  950. fstream file1(SRVID_FILE, ios::out | ios::trunc);
  951. file1 << srvid_text;
  952. file1.close();
  953. // Test reading from a file
  954. EXPECT_TRUE(srv.loadServerID(SRVID_FILE));
  955. ASSERT_TRUE(srv.getServerID());
  956. EXPECT_EQ(srvid_text, srv.srvidToString(srv.getServerID()));
  957. // Now test writing to a file
  958. EXPECT_EQ(0, unlink(SRVID_FILE));
  959. EXPECT_NO_THROW(srv.writeServerID(SRVID_FILE));
  960. fstream file2(SRVID_FILE, ios::in);
  961. ASSERT_TRUE(file2.good());
  962. string text;
  963. file2 >> text;
  964. file2.close();
  965. EXPECT_EQ(srvid_text, text);
  966. }
  967. // Checks if callouts installed on pkt4_receive are indeed called and the
  968. // all necessary parameters are passed.
  969. //
  970. // Note that the test name does not follow test naming convention,
  971. // but the proper hook name is "buffer4_receive".
  972. TEST_F(Dhcpv4SrvTest, relayAgentInfoEcho) {
  973. NakedDhcpv4Srv srv(0);
  974. // Let's create a relayed DISCOVER. This particular relayed DISCOVER has
  975. // added option 82 (relay agent info) with 3 suboptions. The server
  976. // is supposed to echo it back in its response.
  977. Pkt4Ptr dis;
  978. ASSERT_NO_THROW(dis = captureRelayedDiscover());
  979. // Simulate that we have received that traffic
  980. srv.fakeReceive(dis);
  981. // Server will now process to run its normal loop, but instead of calling
  982. // IfaceMgr::receive4(), it will read all packets from the list set by
  983. // fakeReceive()
  984. // In particular, it should call registered buffer4_receive callback.
  985. srv.run();
  986. // Check that the server did send a reposonse
  987. ASSERT_EQ(1, srv.fake_sent_.size());
  988. // Make sure that we received a response
  989. Pkt4Ptr offer = srv.fake_sent_.front();
  990. ASSERT_TRUE(offer);
  991. // Get Relay Agent Info from query...
  992. OptionPtr rai_query = dis->getOption(DHO_DHCP_AGENT_OPTIONS);
  993. ASSERT_TRUE(rai_query);
  994. // Get Relay Agent Info from response...
  995. OptionPtr rai_response = offer->getOption(DHO_DHCP_AGENT_OPTIONS);
  996. ASSERT_TRUE(rai_response);
  997. EXPECT_TRUE(rai_response->equal(rai_query));
  998. }
  999. /// @todo Implement tests for subnetSelect See tests in dhcp6_srv_unittest.cc:
  1000. /// selectSubnetAddr, selectSubnetIface, selectSubnetRelayLinkaddr,
  1001. /// selectSubnetRelayInterfaceId. Note that the concept of interface-id is not
  1002. /// present in the DHCPv4, so not everything is applicable directly.
  1003. /// See ticket #3057
  1004. // Checks if hooks are registered properly.
  1005. TEST_F(Dhcpv4SrvTest, Hooks) {
  1006. NakedDhcpv4Srv srv(0);
  1007. // check if appropriate hooks are registered
  1008. int hook_index_buffer4_receive = -1;
  1009. int hook_index_pkt4_receive = -1;
  1010. int hook_index_select_subnet = -1;
  1011. int hook_index_lease4_release = -1;
  1012. int hook_index_pkt4_send = -1;
  1013. int hook_index_buffer4_send = -1;
  1014. // check if appropriate indexes are set
  1015. EXPECT_NO_THROW(hook_index_buffer4_receive = ServerHooks::getServerHooks()
  1016. .getIndex("buffer4_receive"));
  1017. EXPECT_NO_THROW(hook_index_pkt4_receive = ServerHooks::getServerHooks()
  1018. .getIndex("pkt4_receive"));
  1019. EXPECT_NO_THROW(hook_index_select_subnet = ServerHooks::getServerHooks()
  1020. .getIndex("subnet4_select"));
  1021. EXPECT_NO_THROW(hook_index_lease4_release = ServerHooks::getServerHooks()
  1022. .getIndex("lease4_release"));
  1023. EXPECT_NO_THROW(hook_index_pkt4_send = ServerHooks::getServerHooks()
  1024. .getIndex("pkt4_send"));
  1025. EXPECT_NO_THROW(hook_index_buffer4_send = ServerHooks::getServerHooks()
  1026. .getIndex("buffer4_send"));
  1027. EXPECT_TRUE(hook_index_buffer4_receive > 0);
  1028. EXPECT_TRUE(hook_index_pkt4_receive > 0);
  1029. EXPECT_TRUE(hook_index_select_subnet > 0);
  1030. EXPECT_TRUE(hook_index_lease4_release > 0);
  1031. EXPECT_TRUE(hook_index_pkt4_send > 0);
  1032. EXPECT_TRUE(hook_index_buffer4_send > 0);
  1033. }
  1034. // This test verifies that the following option structure can be parsed:
  1035. // - option (option space 'foobar')
  1036. // - sub option (option space 'foo')
  1037. // - sub option (option space 'bar')
  1038. // @todo Add more thorough unit tests for unpackOptions.
  1039. TEST_F(Dhcpv4SrvTest, unpackOptions) {
  1040. // Create option definition for each level of encapsulation. Each option
  1041. // definition is for the option code 1. Options may have the same
  1042. // option code because they belong to different option spaces.
  1043. // Top level option encapsulates options which belong to 'space-foo'.
  1044. OptionDefinitionPtr opt_def(new OptionDefinition("option-foobar", 1, "uint32",
  1045. "space-foo"));\
  1046. // Middle option encapsulates options which belong to 'space-bar'
  1047. OptionDefinitionPtr opt_def2(new OptionDefinition("option-foo", 1, "uint16",
  1048. "space-bar"));
  1049. // Low level option doesn't encapsulate any option space.
  1050. OptionDefinitionPtr opt_def3(new OptionDefinition("option-bar", 1,
  1051. "uint8"));
  1052. // Add option definitions to the Configuration Manager. Each goes under
  1053. // different option space.
  1054. CfgMgr& cfgmgr = CfgMgr::instance();
  1055. ASSERT_NO_THROW(cfgmgr.addOptionDef(opt_def, "space-foobar"));
  1056. ASSERT_NO_THROW(cfgmgr.addOptionDef(opt_def2, "space-foo"));
  1057. ASSERT_NO_THROW(cfgmgr.addOptionDef(opt_def3, "space-bar"));
  1058. // Create the buffer holding the structure of options.
  1059. const char raw_data[] = {
  1060. // First option starts here.
  1061. 0x01, // option code = 1
  1062. 0x0B, // option length = 11
  1063. 0x00, 0x01, 0x02, 0x03, // This option carries uint32 value
  1064. // Sub option starts here.
  1065. 0x01, // option code = 1
  1066. 0x05, // option length = 5
  1067. 0x01, 0x02, // this option carries uint16 value
  1068. // Last option starts here.
  1069. 0x01, // option code = 1
  1070. 0x01, // option length = 1
  1071. 0x00 // This option carries a single uint8
  1072. // value and has no sub options.
  1073. };
  1074. OptionBuffer buf(raw_data, raw_data + sizeof(raw_data));
  1075. // Parse options.
  1076. NakedDhcpv4Srv srv(0);
  1077. OptionCollection options;
  1078. ASSERT_NO_THROW(srv.unpackOptions(buf, "space-foobar", options));
  1079. // There should be one top level option.
  1080. ASSERT_EQ(1, options.size());
  1081. boost::shared_ptr<OptionInt<uint32_t> > option_foobar =
  1082. boost::dynamic_pointer_cast<OptionInt<uint32_t> >(options.begin()->
  1083. second);
  1084. ASSERT_TRUE(option_foobar);
  1085. EXPECT_EQ(1, option_foobar->getType());
  1086. EXPECT_EQ(0x00010203, option_foobar->getValue());
  1087. // There should be a middle level option held in option_foobar.
  1088. boost::shared_ptr<OptionInt<uint16_t> > option_foo =
  1089. boost::dynamic_pointer_cast<OptionInt<uint16_t> >(option_foobar->
  1090. getOption(1));
  1091. ASSERT_TRUE(option_foo);
  1092. EXPECT_EQ(1, option_foo->getType());
  1093. EXPECT_EQ(0x0102, option_foo->getValue());
  1094. // Finally, there should be a low level option under option_foo.
  1095. boost::shared_ptr<OptionInt<uint8_t> > option_bar =
  1096. boost::dynamic_pointer_cast<OptionInt<uint8_t> >(option_foo->getOption(1));
  1097. ASSERT_TRUE(option_bar);
  1098. EXPECT_EQ(1, option_bar->getType());
  1099. EXPECT_EQ(0x0, option_bar->getValue());
  1100. }
  1101. // Checks whether the server uses default (0.0.0.0) siaddr value, unless
  1102. // explicitly specified
  1103. TEST_F(Dhcpv4SrvTest, siaddrDefault) {
  1104. boost::scoped_ptr<NakedDhcpv4Srv> srv;
  1105. ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
  1106. IOAddress hint("192.0.2.107");
  1107. Pkt4Ptr dis = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
  1108. dis->setRemoteAddr(IOAddress("192.0.2.1"));
  1109. OptionPtr clientid = generateClientId();
  1110. dis->addOption(clientid);
  1111. dis->setYiaddr(hint);
  1112. // Pass it to the server and get an offer
  1113. Pkt4Ptr offer = srv->processDiscover(dis);
  1114. ASSERT_TRUE(offer);
  1115. // Check if we get response at all
  1116. checkResponse(offer, DHCPOFFER, 1234);
  1117. // Verify that it is 0.0.0.0
  1118. EXPECT_EQ("0.0.0.0", offer->getSiaddr().toText());
  1119. }
  1120. // Checks whether the server uses specified siaddr value
  1121. TEST_F(Dhcpv4SrvTest, siaddr) {
  1122. boost::scoped_ptr<NakedDhcpv4Srv> srv;
  1123. ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
  1124. subnet_->setSiaddr(IOAddress("192.0.2.123"));
  1125. Pkt4Ptr dis = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
  1126. dis->setRemoteAddr(IOAddress("192.0.2.1"));
  1127. OptionPtr clientid = generateClientId();
  1128. dis->addOption(clientid);
  1129. // Pass it to the server and get an offer
  1130. Pkt4Ptr offer = srv->processDiscover(dis);
  1131. ASSERT_TRUE(offer);
  1132. // Check if we get response at all
  1133. checkResponse(offer, DHCPOFFER, 1234);
  1134. // Verify that its value is proper
  1135. EXPECT_EQ("192.0.2.123", offer->getSiaddr().toText());
  1136. }
  1137. // Checks if the next-server defined as global value is overridden by subnet
  1138. // specific value and returned in server messages. There's also similar test for
  1139. // checking parser only configuration, see Dhcp4ParserTest.nextServerOverride in
  1140. // config_parser_unittest.cc.
  1141. TEST_F(Dhcpv4SrvTest, nextServerOverride) {
  1142. NakedDhcpv4Srv srv(0);
  1143. ConstElementPtr status;
  1144. string config = "{ \"interfaces\": [ \"*\" ],"
  1145. "\"rebind-timer\": 2000, "
  1146. "\"renew-timer\": 1000, "
  1147. "\"next-server\": \"192.0.0.1\", "
  1148. "\"subnet4\": [ { "
  1149. " \"pool\": [ \"192.0.2.1 - 192.0.2.100\" ],"
  1150. " \"next-server\": \"1.2.3.4\", "
  1151. " \"subnet\": \"192.0.2.0/24\" } ],"
  1152. "\"valid-lifetime\": 4000 }";
  1153. ElementPtr json = Element::fromJSON(config);
  1154. EXPECT_NO_THROW(status = configureDhcp4Server(srv, json));
  1155. // check if returned status is OK
  1156. ASSERT_TRUE(status);
  1157. comment_ = config::parseAnswer(rcode_, status);
  1158. ASSERT_EQ(0, rcode_);
  1159. Pkt4Ptr dis = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
  1160. dis->setRemoteAddr(IOAddress("192.0.2.1"));
  1161. OptionPtr clientid = generateClientId();
  1162. dis->addOption(clientid);
  1163. // Pass it to the server and get an offer
  1164. Pkt4Ptr offer = srv.processDiscover(dis);
  1165. ASSERT_TRUE(offer);
  1166. EXPECT_EQ(DHCPOFFER, offer->getType());
  1167. EXPECT_EQ("1.2.3.4", offer->getSiaddr().toText());
  1168. }
  1169. // Checks if the next-server defined as global value is used in responses
  1170. // when there is no specific value defined in subnet and returned to the client
  1171. // properly. There's also similar test for checking parser only configuration,
  1172. // see Dhcp4ParserTest.nextServerGlobal in config_parser_unittest.cc.
  1173. TEST_F(Dhcpv4SrvTest, nextServerGlobal) {
  1174. NakedDhcpv4Srv srv(0);
  1175. ConstElementPtr status;
  1176. string config = "{ \"interfaces\": [ \"*\" ],"
  1177. "\"rebind-timer\": 2000, "
  1178. "\"renew-timer\": 1000, "
  1179. "\"next-server\": \"192.0.0.1\", "
  1180. "\"subnet4\": [ { "
  1181. " \"pool\": [ \"192.0.2.1 - 192.0.2.100\" ],"
  1182. " \"subnet\": \"192.0.2.0/24\" } ],"
  1183. "\"valid-lifetime\": 4000 }";
  1184. ElementPtr json = Element::fromJSON(config);
  1185. EXPECT_NO_THROW(status = configureDhcp4Server(srv, json));
  1186. // check if returned status is OK
  1187. ASSERT_TRUE(status);
  1188. comment_ = config::parseAnswer(rcode_, status);
  1189. ASSERT_EQ(0, rcode_);
  1190. Pkt4Ptr dis = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
  1191. dis->setRemoteAddr(IOAddress("192.0.2.1"));
  1192. OptionPtr clientid = generateClientId();
  1193. dis->addOption(clientid);
  1194. // Pass it to the server and get an offer
  1195. Pkt4Ptr offer = srv.processDiscover(dis);
  1196. ASSERT_TRUE(offer);
  1197. EXPECT_EQ(DHCPOFFER, offer->getType());
  1198. EXPECT_EQ("192.0.0.1", offer->getSiaddr().toText());
  1199. }
  1200. // a dummy MAC address
  1201. const uint8_t dummyMacAddr[] = {0, 1, 2, 3, 4, 5};
  1202. // A dummy MAC address, padded with 0s
  1203. const uint8_t dummyChaddr[16] = {0, 1, 2, 3, 4, 5, 0, 0,
  1204. 0, 0, 0, 0, 0, 0, 0, 0 };
  1205. // Let's use some creative test content here (128 chars + \0)
  1206. const uint8_t dummyFile[] = "Lorem ipsum dolor sit amet, consectetur "
  1207. "adipiscing elit. Proin mollis placerat metus, at "
  1208. "lacinia orci ornare vitae. Mauris amet.";
  1209. // Yet another type of test content (64 chars + \0)
  1210. const uint8_t dummySname[] = "Lorem ipsum dolor sit amet, consectetur "
  1211. "adipiscing elit posuere.";
  1212. /// @brief a class dedicated to Hooks testing in DHCPv4 server
  1213. ///
  1214. /// This class has a number of static members, because each non-static
  1215. /// method has implicit 'this' parameter, so it does not match callout
  1216. /// signature and couldn't be registered. Furthermore, static methods
  1217. /// can't modify non-static members (for obvious reasons), so many
  1218. /// fields are declared static. It is still better to keep them as
  1219. /// one class rather than unrelated collection of global objects.
  1220. class HooksDhcpv4SrvTest : public Dhcpv4SrvTest {
  1221. public:
  1222. /// @brief creates Dhcpv4Srv and prepares buffers for callouts
  1223. HooksDhcpv4SrvTest() {
  1224. // Allocate new DHCPv6 Server
  1225. srv_ = new NakedDhcpv4Srv(0);
  1226. // clear static buffers
  1227. resetCalloutBuffers();
  1228. }
  1229. /// @brief destructor (deletes Dhcpv4Srv)
  1230. virtual ~HooksDhcpv4SrvTest() {
  1231. HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("buffer4_receive");
  1232. HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("buffer4_send");
  1233. HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("pkt4_receive");
  1234. HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("pkt4_send");
  1235. HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("subnet4_select");
  1236. HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("lease4_renew");
  1237. HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("lease4_release");
  1238. delete srv_;
  1239. }
  1240. /// @brief creates an option with specified option code
  1241. ///
  1242. /// This method is static, because it is used from callouts
  1243. /// that do not have a pointer to HooksDhcpv4SSrvTest object
  1244. ///
  1245. /// @param option_code code of option to be created
  1246. ///
  1247. /// @return pointer to create option object
  1248. static OptionPtr createOption(uint16_t option_code) {
  1249. char payload[] = {
  1250. 0xa, 0xb, 0xc, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14
  1251. };
  1252. OptionBuffer tmp(payload, payload + sizeof(payload));
  1253. return OptionPtr(new Option(Option::V4, option_code, tmp));
  1254. }
  1255. /// @brief Generates test packet.
  1256. ///
  1257. /// Allocates and generates on-wire buffer that represents test packet, with all
  1258. /// fixed fields set to non-zero values. Content is not always reasonable.
  1259. ///
  1260. /// See generateTestPacket1() function that returns exactly the same packet as
  1261. /// Pkt4 object.
  1262. ///
  1263. /// @return pointer to allocated Pkt4 object
  1264. // Returns a vector containing a DHCPv4 packet header.
  1265. Pkt4Ptr
  1266. generateSimpleDiscover() {
  1267. // That is only part of the header. It contains all "short" fields,
  1268. // larger fields are constructed separately.
  1269. uint8_t hdr[] = {
  1270. 1, 6, 6, 13, // op, htype, hlen, hops,
  1271. 0x12, 0x34, 0x56, 0x78, // transaction-id
  1272. 0, 42, 0x80, 0x00, // 42 secs, BROADCAST flags
  1273. 192, 0, 2, 1, // ciaddr
  1274. 1, 2, 3, 4, // yiaddr
  1275. 192, 0, 2, 255, // siaddr
  1276. 255, 255, 255, 255, // giaddr
  1277. };
  1278. // Initialize the vector with the header fields defined above.
  1279. vector<uint8_t> buf(hdr, hdr + sizeof(hdr));
  1280. // Append the large header fields.
  1281. copy(dummyChaddr, dummyChaddr + Pkt4::MAX_CHADDR_LEN, back_inserter(buf));
  1282. copy(dummySname, dummySname + Pkt4::MAX_SNAME_LEN, back_inserter(buf));
  1283. copy(dummyFile, dummyFile + Pkt4::MAX_FILE_LEN, back_inserter(buf));
  1284. // Should now have all the header, so check. The "static_cast" is used
  1285. // to get round an odd bug whereby the linker appears not to find the
  1286. // definition of DHCPV4_PKT_HDR_LEN if it appears within an EXPECT_EQ().
  1287. EXPECT_EQ(static_cast<size_t>(Pkt4::DHCPV4_PKT_HDR_LEN), buf.size());
  1288. // Add magic cookie
  1289. buf.push_back(0x63);
  1290. buf.push_back(0x82);
  1291. buf.push_back(0x53);
  1292. buf.push_back(0x63);
  1293. // Add message type DISCOVER
  1294. buf.push_back(static_cast<uint8_t>(DHO_DHCP_MESSAGE_TYPE));
  1295. buf.push_back(1); // length (just one byte)
  1296. buf.push_back(static_cast<uint8_t>(DHCPDISCOVER));
  1297. return (Pkt4Ptr(new Pkt4(&buf[0], buf.size())));
  1298. }
  1299. /// Test callback that stores received callout name and pkt4 value
  1300. /// @param callout_handle handle passed by the hooks framework
  1301. /// @return always 0
  1302. static int
  1303. buffer4_receive_callout(CalloutHandle& callout_handle) {
  1304. callback_name_ = string("buffer4_receive");
  1305. callout_handle.getArgument("query4", callback_pkt4_);
  1306. callback_argument_names_ = callout_handle.getArgumentNames();
  1307. return (0);
  1308. }
  1309. /// Test callback that changes hwaddr value
  1310. /// @param callout_handle handle passed by the hooks framework
  1311. /// @return always 0
  1312. static int
  1313. buffer4_receive_change_hwaddr(CalloutHandle& callout_handle) {
  1314. Pkt4Ptr pkt;
  1315. callout_handle.getArgument("query4", pkt);
  1316. // If there is at least one option with data
  1317. if (pkt->data_.size() >= Pkt4::DHCPV4_PKT_HDR_LEN) {
  1318. // Offset of the first byte of the CHWADDR field. Let's the first
  1319. // byte to some new value that we could later check
  1320. pkt->data_[28] = 0xff;
  1321. }
  1322. // Carry on as usual
  1323. return buffer4_receive_callout(callout_handle);
  1324. }
  1325. /// Test callback that deletes MAC address
  1326. /// @param callout_handle handle passed by the hooks framework
  1327. /// @return always 0
  1328. static int
  1329. buffer4_receive_delete_hwaddr(CalloutHandle& callout_handle) {
  1330. Pkt4Ptr pkt;
  1331. callout_handle.getArgument("query4", pkt);
  1332. pkt->data_[2] = 0; // offset 2 is hlen, let's set it to zero
  1333. memset(&pkt->data_[28], 0, Pkt4::MAX_CHADDR_LEN); // Clear CHADDR content
  1334. // carry on as usual
  1335. return buffer4_receive_callout(callout_handle);
  1336. }
  1337. /// Test callback that sets skip flag
  1338. /// @param callout_handle handle passed by the hooks framework
  1339. /// @return always 0
  1340. static int
  1341. buffer4_receive_skip(CalloutHandle& callout_handle) {
  1342. callout_handle.setSkip(true);
  1343. // Carry on as usual
  1344. return buffer4_receive_callout(callout_handle);
  1345. }
  1346. /// test callback that stores received callout name and pkt4 value
  1347. /// @param callout_handle handle passed by the hooks framework
  1348. /// @return always 0
  1349. static int
  1350. pkt4_receive_callout(CalloutHandle& callout_handle) {
  1351. callback_name_ = string("pkt4_receive");
  1352. callout_handle.getArgument("query4", callback_pkt4_);
  1353. callback_argument_names_ = callout_handle.getArgumentNames();
  1354. return (0);
  1355. }
  1356. /// test callback that changes client-id value
  1357. /// @param callout_handle handle passed by the hooks framework
  1358. /// @return always 0
  1359. static int
  1360. pkt4_receive_change_clientid(CalloutHandle& callout_handle) {
  1361. Pkt4Ptr pkt;
  1362. callout_handle.getArgument("query4", pkt);
  1363. // get rid of the old client-id
  1364. pkt->delOption(DHO_DHCP_CLIENT_IDENTIFIER);
  1365. // add a new option
  1366. pkt->addOption(createOption(DHO_DHCP_CLIENT_IDENTIFIER));
  1367. // carry on as usual
  1368. return pkt4_receive_callout(callout_handle);
  1369. }
  1370. /// test callback that deletes client-id
  1371. /// @param callout_handle handle passed by the hooks framework
  1372. /// @return always 0
  1373. static int
  1374. pkt4_receive_delete_clientid(CalloutHandle& callout_handle) {
  1375. Pkt4Ptr pkt;
  1376. callout_handle.getArgument("query4", pkt);
  1377. // get rid of the old client-id (and no HWADDR)
  1378. vector<uint8_t> mac;
  1379. pkt->delOption(DHO_DHCP_CLIENT_IDENTIFIER);
  1380. pkt->setHWAddr(1, 0, mac); // HWtype 1, hwardware len = 0
  1381. // carry on as usual
  1382. return pkt4_receive_callout(callout_handle);
  1383. }
  1384. /// test callback that sets skip flag
  1385. /// @param callout_handle handle passed by the hooks framework
  1386. /// @return always 0
  1387. static int
  1388. pkt4_receive_skip(CalloutHandle& callout_handle) {
  1389. Pkt4Ptr pkt;
  1390. callout_handle.getArgument("query4", pkt);
  1391. callout_handle.setSkip(true);
  1392. // carry on as usual
  1393. return pkt4_receive_callout(callout_handle);
  1394. }
  1395. /// Test callback that stores received callout name and pkt4 value
  1396. /// @param callout_handle handle passed by the hooks framework
  1397. /// @return always 0
  1398. static int
  1399. pkt4_send_callout(CalloutHandle& callout_handle) {
  1400. callback_name_ = string("pkt4_send");
  1401. callout_handle.getArgument("response4", callback_pkt4_);
  1402. callback_argument_names_ = callout_handle.getArgumentNames();
  1403. return (0);
  1404. }
  1405. // Test callback that changes server-id
  1406. /// @param callout_handle handle passed by the hooks framework
  1407. /// @return always 0
  1408. static int
  1409. pkt4_send_change_serverid(CalloutHandle& callout_handle) {
  1410. Pkt4Ptr pkt;
  1411. callout_handle.getArgument("response4", pkt);
  1412. // get rid of the old server-id
  1413. pkt->delOption(DHO_DHCP_SERVER_IDENTIFIER);
  1414. // add a new option
  1415. pkt->addOption(createOption(DHO_DHCP_SERVER_IDENTIFIER));
  1416. // carry on as usual
  1417. return pkt4_send_callout(callout_handle);
  1418. }
  1419. /// test callback that deletes server-id
  1420. /// @param callout_handle handle passed by the hooks framework
  1421. /// @return always 0
  1422. static int
  1423. pkt4_send_delete_serverid(CalloutHandle& callout_handle) {
  1424. Pkt4Ptr pkt;
  1425. callout_handle.getArgument("response4", pkt);
  1426. // get rid of the old client-id
  1427. pkt->delOption(DHO_DHCP_SERVER_IDENTIFIER);
  1428. // carry on as usual
  1429. return pkt4_send_callout(callout_handle);
  1430. }
  1431. /// Test callback that sets skip flag
  1432. /// @param callout_handle handle passed by the hooks framework
  1433. /// @return always 0
  1434. static int
  1435. pkt4_send_skip(CalloutHandle& callout_handle) {
  1436. Pkt4Ptr pkt;
  1437. callout_handle.getArgument("response4", pkt);
  1438. callout_handle.setSkip(true);
  1439. // carry on as usual
  1440. return pkt4_send_callout(callout_handle);
  1441. }
  1442. /// Test callback that stores received callout name and pkt4 value
  1443. /// @param callout_handle handle passed by the hooks framework
  1444. /// @return always 0
  1445. static int
  1446. buffer4_send_callout(CalloutHandle& callout_handle) {
  1447. callback_name_ = string("buffer4_send");
  1448. callout_handle.getArgument("response4", callback_pkt4_);
  1449. callback_argument_names_ = callout_handle.getArgumentNames();
  1450. return (0);
  1451. }
  1452. /// Test callback changes the output buffer to a hardcoded value
  1453. /// @param callout_handle handle passed by the hooks framework
  1454. /// @return always 0
  1455. static int
  1456. buffer4_send_change_callout(CalloutHandle& callout_handle) {
  1457. Pkt4Ptr pkt;
  1458. callout_handle.getArgument("response4", pkt);
  1459. // modify buffer to set a diffferent payload
  1460. pkt->getBuffer().clear();
  1461. pkt->getBuffer().writeData(dummyFile, sizeof(dummyFile));
  1462. return (0);
  1463. }
  1464. /// Test callback that stores received callout name and pkt4 value
  1465. /// @param callout_handle handle passed by the hooks framework
  1466. /// @return always 0
  1467. static int
  1468. skip_callout(CalloutHandle& callout_handle) {
  1469. callout_handle.setSkip(true);
  1470. return (0);
  1471. }
  1472. /// Test callback that stores received callout name and subnet4 values
  1473. /// @param callout_handle handle passed by the hooks framework
  1474. /// @return always 0
  1475. static int
  1476. subnet4_select_callout(CalloutHandle& callout_handle) {
  1477. callback_name_ = string("subnet4_select");
  1478. callout_handle.getArgument("query4", callback_pkt4_);
  1479. callout_handle.getArgument("subnet4", callback_subnet4_);
  1480. callout_handle.getArgument("subnet4collection", callback_subnet4collection_);
  1481. callback_argument_names_ = callout_handle.getArgumentNames();
  1482. return (0);
  1483. }
  1484. /// Test callback that picks the other subnet if possible.
  1485. /// @param callout_handle handle passed by the hooks framework
  1486. /// @return always 0
  1487. static int
  1488. subnet4_select_different_subnet_callout(CalloutHandle& callout_handle) {
  1489. // Call the basic calllout to record all passed values
  1490. subnet4_select_callout(callout_handle);
  1491. const Subnet4Collection* subnets;
  1492. Subnet4Ptr subnet;
  1493. callout_handle.getArgument("subnet4", subnet);
  1494. callout_handle.getArgument("subnet4collection", subnets);
  1495. // Let's change to a different subnet
  1496. if (subnets->size() > 1) {
  1497. subnet = (*subnets)[1]; // Let's pick the other subnet
  1498. callout_handle.setArgument("subnet4", subnet);
  1499. }
  1500. return (0);
  1501. }
  1502. /// Test callback that stores received callout name passed parameters
  1503. /// @param callout_handle handle passed by the hooks framework
  1504. /// @return always 0
  1505. static int
  1506. lease4_release_callout(CalloutHandle& callout_handle) {
  1507. callback_name_ = string("lease4_release");
  1508. callout_handle.getArgument("query4", callback_pkt4_);
  1509. callout_handle.getArgument("lease4", callback_lease4_);
  1510. callback_argument_names_ = callout_handle.getArgumentNames();
  1511. return (0);
  1512. }
  1513. /// Test callback that stores received callout name and subnet4 values
  1514. /// @param callout_handle handle passed by the hooks framework
  1515. /// @return always 0
  1516. static int
  1517. lease4_renew_callout(CalloutHandle& callout_handle) {
  1518. callback_name_ = string("lease4_renew");
  1519. callout_handle.getArgument("subnet4", callback_subnet4_);
  1520. callout_handle.getArgument("lease4", callback_lease4_);
  1521. callout_handle.getArgument("hwaddr", callback_hwaddr_);
  1522. callout_handle.getArgument("clientid", callback_clientid_);
  1523. callback_argument_names_ = callout_handle.getArgumentNames();
  1524. return (0);
  1525. }
  1526. /// resets buffers used to store data received by callouts
  1527. void resetCalloutBuffers() {
  1528. callback_name_ = string("");
  1529. callback_pkt4_.reset();
  1530. callback_lease4_.reset();
  1531. callback_hwaddr_.reset();
  1532. callback_clientid_.reset();
  1533. callback_subnet4_.reset();
  1534. callback_subnet4collection_ = NULL;
  1535. callback_argument_names_.clear();
  1536. }
  1537. /// pointer to Dhcpv4Srv that is used in tests
  1538. NakedDhcpv4Srv* srv_;
  1539. // The following fields are used in testing pkt4_receive_callout
  1540. /// String name of the received callout
  1541. static string callback_name_;
  1542. /// Pkt4 structure returned in the callout
  1543. static Pkt4Ptr callback_pkt4_;
  1544. /// Lease4 structure returned in the callout
  1545. static Lease4Ptr callback_lease4_;
  1546. /// Hardware address returned in the callout
  1547. static HWAddrPtr callback_hwaddr_;
  1548. /// Client-id returned in the callout
  1549. static ClientIdPtr callback_clientid_;
  1550. /// Pointer to a subnet received by callout
  1551. static Subnet4Ptr callback_subnet4_;
  1552. /// A list of all available subnets (received by callout)
  1553. static const Subnet4Collection* callback_subnet4collection_;
  1554. /// A list of all received arguments
  1555. static vector<string> callback_argument_names_;
  1556. };
  1557. // The following fields are used in testing pkt4_receive_callout.
  1558. // See fields description in the class for details
  1559. string HooksDhcpv4SrvTest::callback_name_;
  1560. Pkt4Ptr HooksDhcpv4SrvTest::callback_pkt4_;
  1561. Subnet4Ptr HooksDhcpv4SrvTest::callback_subnet4_;
  1562. HWAddrPtr HooksDhcpv4SrvTest::callback_hwaddr_;
  1563. ClientIdPtr HooksDhcpv4SrvTest::callback_clientid_;
  1564. Lease4Ptr HooksDhcpv4SrvTest::callback_lease4_;
  1565. const Subnet4Collection* HooksDhcpv4SrvTest::callback_subnet4collection_;
  1566. vector<string> HooksDhcpv4SrvTest::callback_argument_names_;
  1567. // Checks if callouts installed on pkt4_receive are indeed called and the
  1568. // all necessary parameters are passed.
  1569. //
  1570. // Note that the test name does not follow test naming convention,
  1571. // but the proper hook name is "buffer4_receive".
  1572. TEST_F(HooksDhcpv4SrvTest, Buffer4ReceiveSimple) {
  1573. // Install pkt4_receive_callout
  1574. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1575. "buffer4_receive", buffer4_receive_callout));
  1576. // Let's create a simple DISCOVER
  1577. Pkt4Ptr dis = generateSimpleDiscover();
  1578. // Simulate that we have received that traffic
  1579. srv_->fakeReceive(dis);
  1580. // Server will now process to run its normal loop, but instead of calling
  1581. // IfaceMgr::receive4(), it will read all packets from the list set by
  1582. // fakeReceive()
  1583. // In particular, it should call registered buffer4_receive callback.
  1584. srv_->run();
  1585. // Check that the callback called is indeed the one we installed
  1586. EXPECT_EQ("buffer4_receive", callback_name_);
  1587. // Check that pkt4 argument passing was successful and returned proper value
  1588. EXPECT_TRUE(callback_pkt4_.get() == dis.get());
  1589. // Check that all expected parameters are there
  1590. vector<string> expected_argument_names;
  1591. expected_argument_names.push_back(string("query4"));
  1592. EXPECT_TRUE(expected_argument_names == callback_argument_names_);
  1593. }
  1594. // Checks if callouts installed on buffer4_receive is able to change
  1595. // the values and the parameters are indeed used by the server.
  1596. TEST_F(HooksDhcpv4SrvTest, buffer4RreceiveValueChange) {
  1597. // Install callback that modifies MAC addr of incoming packet
  1598. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1599. "buffer4_receive", buffer4_receive_change_hwaddr));
  1600. // Let's create a simple DISCOVER
  1601. Pkt4Ptr discover = generateSimpleDiscover();
  1602. // Simulate that we have received that traffic
  1603. srv_->fakeReceive(discover);
  1604. // Server will now process to run its normal loop, but instead of calling
  1605. // IfaceMgr::receive6(), it will read all packets from the list set by
  1606. // fakeReceive()
  1607. // In particular, it should call registered buffer4_receive callback.
  1608. srv_->run();
  1609. // Check that the server did send a reposonse
  1610. ASSERT_EQ(1, srv_->fake_sent_.size());
  1611. // Make sure that we received a response
  1612. Pkt4Ptr offer = srv_->fake_sent_.front();
  1613. ASSERT_TRUE(offer);
  1614. // Get client-id...
  1615. HWAddrPtr hwaddr = offer->getHWAddr();
  1616. ASSERT_TRUE(hwaddr); // basic sanity check. HWAddr is always present
  1617. // ... and check if it is the modified value
  1618. ASSERT_FALSE(hwaddr->hwaddr_.empty()); // there must be a MAC address
  1619. EXPECT_EQ(0xff, hwaddr->hwaddr_[0]); // check that its first byte was modified
  1620. }
  1621. // Checks if callouts installed on buffer4_receive is able to set skip flag that
  1622. // will cause the server to not parse the packet. Even though the packet is valid,
  1623. // the server should eventually drop it, because there won't be mandatory options
  1624. // (or rather option objects) in it.
  1625. TEST_F(HooksDhcpv4SrvTest, buffer4ReceiveSkip) {
  1626. // Install pkt4_receive_callout
  1627. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1628. "buffer4_receive", buffer4_receive_skip));
  1629. // Let's create a simple DISCOVER
  1630. Pkt4Ptr discover = generateSimpleDiscover();
  1631. // Simulate that we have received that traffic
  1632. srv_->fakeReceive(discover);
  1633. // Server will now process to run its normal loop, but instead of calling
  1634. // IfaceMgr::receive6(), it will read all packets from the list set by
  1635. // fakeReceive()
  1636. // In particular, it should call registered pkt4_receive callback.
  1637. srv_->run();
  1638. // Check that the server dropped the packet and did not produce any response
  1639. ASSERT_EQ(0, srv_->fake_sent_.size());
  1640. }
  1641. // Checks if callouts installed on pkt4_receive are indeed called and the
  1642. // all necessary parameters are passed.
  1643. //
  1644. // Note that the test name does not follow test naming convention,
  1645. // but the proper hook name is "pkt4_receive".
  1646. TEST_F(HooksDhcpv4SrvTest, pkt4ReceiveSimple) {
  1647. // Install pkt4_receive_callout
  1648. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1649. "pkt4_receive", pkt4_receive_callout));
  1650. // Let's create a simple DISCOVER
  1651. Pkt4Ptr sol = generateSimpleDiscover();
  1652. // Simulate that we have received that traffic
  1653. srv_->fakeReceive(sol);
  1654. // Server will now process to run its normal loop, but instead of calling
  1655. // IfaceMgr::receive4(), it will read all packets from the list set by
  1656. // fakeReceive()
  1657. // In particular, it should call registered pkt4_receive callback.
  1658. srv_->run();
  1659. // check that the callback called is indeed the one we installed
  1660. EXPECT_EQ("pkt4_receive", callback_name_);
  1661. // check that pkt4 argument passing was successful and returned proper value
  1662. EXPECT_TRUE(callback_pkt4_.get() == sol.get());
  1663. // Check that all expected parameters are there
  1664. vector<string> expected_argument_names;
  1665. expected_argument_names.push_back(string("query4"));
  1666. EXPECT_TRUE(expected_argument_names == callback_argument_names_);
  1667. }
  1668. // Checks if callouts installed on pkt4_received is able to change
  1669. // the values and the parameters are indeed used by the server.
  1670. TEST_F(HooksDhcpv4SrvTest, valueChange_pkt4_receive) {
  1671. // Install pkt4_receive_callout
  1672. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1673. "pkt4_receive", pkt4_receive_change_clientid));
  1674. // Let's create a simple DISCOVER
  1675. Pkt4Ptr sol = generateSimpleDiscover();
  1676. // Simulate that we have received that traffic
  1677. srv_->fakeReceive(sol);
  1678. // Server will now process to run its normal loop, but instead of calling
  1679. // IfaceMgr::receive4(), it will read all packets from the list set by
  1680. // fakeReceive()
  1681. // In particular, it should call registered pkt4_receive callback.
  1682. srv_->run();
  1683. // check that the server did send a reposonce
  1684. ASSERT_EQ(1, srv_->fake_sent_.size());
  1685. // Make sure that we received a response
  1686. Pkt4Ptr adv = srv_->fake_sent_.front();
  1687. ASSERT_TRUE(adv);
  1688. // Get client-id...
  1689. OptionPtr clientid = adv->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
  1690. // ... and check if it is the modified value
  1691. OptionPtr expected = createOption(DHO_DHCP_CLIENT_IDENTIFIER);
  1692. EXPECT_TRUE(clientid->equal(expected));
  1693. }
  1694. // Checks if callouts installed on pkt4_received is able to delete
  1695. // existing options and that change impacts server processing (mandatory
  1696. // client-id option is deleted, so the packet is expected to be dropped)
  1697. TEST_F(HooksDhcpv4SrvTest, pkt4ReceiveDeleteClientId) {
  1698. // Install pkt4_receive_callout
  1699. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1700. "pkt4_receive", pkt4_receive_delete_clientid));
  1701. // Let's create a simple DISCOVER
  1702. Pkt4Ptr sol = generateSimpleDiscover();
  1703. // Simulate that we have received that traffic
  1704. srv_->fakeReceive(sol);
  1705. // Server will now process to run its normal loop, but instead of calling
  1706. // IfaceMgr::receive4(), it will read all packets from the list set by
  1707. // fakeReceive()
  1708. // In particular, it should call registered pkt4_receive callback.
  1709. srv_->run();
  1710. // Check that the server dropped the packet and did not send a response
  1711. ASSERT_EQ(0, srv_->fake_sent_.size());
  1712. }
  1713. // Checks if callouts installed on pkt4_received is able to set skip flag that
  1714. // will cause the server to not process the packet (drop), even though it is valid.
  1715. TEST_F(HooksDhcpv4SrvTest, pkt4ReceiveSkip) {
  1716. // Install pkt4_receive_callout
  1717. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1718. "pkt4_receive", pkt4_receive_skip));
  1719. // Let's create a simple DISCOVER
  1720. Pkt4Ptr sol = generateSimpleDiscover();
  1721. // Simulate that we have received that traffic
  1722. srv_->fakeReceive(sol);
  1723. // Server will now process to run its normal loop, but instead of calling
  1724. // IfaceMgr::receive4(), it will read all packets from the list set by
  1725. // fakeReceive()
  1726. // In particular, it should call registered pkt4_receive callback.
  1727. srv_->run();
  1728. // check that the server dropped the packet and did not produce any response
  1729. ASSERT_EQ(0, srv_->fake_sent_.size());
  1730. }
  1731. // Checks if callouts installed on pkt4_send are indeed called and the
  1732. // all necessary parameters are passed.
  1733. TEST_F(HooksDhcpv4SrvTest, pkt4SendSimple) {
  1734. // Install pkt4_receive_callout
  1735. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1736. "pkt4_send", pkt4_send_callout));
  1737. // Let's create a simple DISCOVER
  1738. Pkt4Ptr sol = generateSimpleDiscover();
  1739. // Simulate that we have received that traffic
  1740. srv_->fakeReceive(sol);
  1741. // Server will now process to run its normal loop, but instead of calling
  1742. // IfaceMgr::receive4(), it will read all packets from the list set by
  1743. // fakeReceive()
  1744. // In particular, it should call registered pkt4_receive callback.
  1745. srv_->run();
  1746. // Check that the callback called is indeed the one we installed
  1747. EXPECT_EQ("pkt4_send", callback_name_);
  1748. // Check that there is one packet sent
  1749. ASSERT_EQ(1, srv_->fake_sent_.size());
  1750. Pkt4Ptr adv = srv_->fake_sent_.front();
  1751. // Check that pkt4 argument passing was successful and returned proper value
  1752. EXPECT_TRUE(callback_pkt4_.get() == adv.get());
  1753. // Check that all expected parameters are there
  1754. vector<string> expected_argument_names;
  1755. expected_argument_names.push_back(string("response4"));
  1756. EXPECT_TRUE(expected_argument_names == callback_argument_names_);
  1757. }
  1758. // Checks if callouts installed on pkt4_send is able to change
  1759. // the values and the packet sent contains those changes
  1760. TEST_F(HooksDhcpv4SrvTest, pkt4SendValueChange) {
  1761. // Install pkt4_receive_callout
  1762. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1763. "pkt4_send", pkt4_send_change_serverid));
  1764. // Let's create a simple DISCOVER
  1765. Pkt4Ptr sol = generateSimpleDiscover();
  1766. // Simulate that we have received that traffic
  1767. srv_->fakeReceive(sol);
  1768. // Server will now process to run its normal loop, but instead of calling
  1769. // IfaceMgr::receive4(), it will read all packets from the list set by
  1770. // fakeReceive()
  1771. // In particular, it should call registered pkt4_receive callback.
  1772. srv_->run();
  1773. // check that the server did send a reposonce
  1774. ASSERT_EQ(1, srv_->fake_sent_.size());
  1775. // Make sure that we received a response
  1776. Pkt4Ptr adv = srv_->fake_sent_.front();
  1777. ASSERT_TRUE(adv);
  1778. // Get client-id...
  1779. OptionPtr clientid = adv->getOption(DHO_DHCP_SERVER_IDENTIFIER);
  1780. // ... and check if it is the modified value
  1781. OptionPtr expected = createOption(DHO_DHCP_SERVER_IDENTIFIER);
  1782. EXPECT_TRUE(clientid->equal(expected));
  1783. }
  1784. // Checks if callouts installed on pkt4_send is able to delete
  1785. // existing options and that server applies those changes. In particular,
  1786. // we are trying to send a packet without server-id. The packet should
  1787. // be sent
  1788. TEST_F(HooksDhcpv4SrvTest, pkt4SendDeleteServerId) {
  1789. // Install pkt4_receive_callout
  1790. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1791. "pkt4_send", pkt4_send_delete_serverid));
  1792. // Let's create a simple DISCOVER
  1793. Pkt4Ptr sol = generateSimpleDiscover();
  1794. // Simulate that we have received that traffic
  1795. srv_->fakeReceive(sol);
  1796. // Server will now process to run its normal loop, but instead of calling
  1797. // IfaceMgr::receive4(), it will read all packets from the list set by
  1798. // fakeReceive()
  1799. // In particular, it should call registered pkt4_receive callback.
  1800. srv_->run();
  1801. // Check that the server indeed sent a malformed ADVERTISE
  1802. ASSERT_EQ(1, srv_->fake_sent_.size());
  1803. // Get that ADVERTISE
  1804. Pkt4Ptr adv = srv_->fake_sent_.front();
  1805. ASSERT_TRUE(adv);
  1806. // Make sure that it does not have server-id
  1807. EXPECT_FALSE(adv->getOption(DHO_DHCP_SERVER_IDENTIFIER));
  1808. }
  1809. // Checks if callouts installed on pkt4_skip is able to set skip flag that
  1810. // will cause the server to not process the packet (drop), even though it is valid.
  1811. TEST_F(HooksDhcpv4SrvTest, skip_pkt4_send) {
  1812. // Install pkt4_receive_callout
  1813. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1814. "pkt4_send", pkt4_send_skip));
  1815. // Let's create a simple REQUEST
  1816. Pkt4Ptr sol = generateSimpleDiscover();
  1817. // Simulate that we have received that traffic
  1818. srv_->fakeReceive(sol);
  1819. // Server will now process to run its normal loop, but instead of calling
  1820. // IfaceMgr::receive4(), it will read all packets from the list set by
  1821. // fakeReceive()
  1822. // In particular, it should call registered pkt4_send callback.
  1823. srv_->run();
  1824. // Check that the server sent the message
  1825. ASSERT_EQ(1, srv_->fake_sent_.size());
  1826. // Get the first packet and check that it has zero length (i.e. the server
  1827. // did not do packing on its own)
  1828. Pkt4Ptr sent = srv_->fake_sent_.front();
  1829. EXPECT_EQ(0, sent->getBuffer().getLength());
  1830. }
  1831. // Checks if callouts installed on buffer4_send are indeed called and the
  1832. // all necessary parameters are passed.
  1833. TEST_F(HooksDhcpv4SrvTest, buffer4SendSimple) {
  1834. // Install pkt4_receive_callout
  1835. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1836. "buffer4_send", buffer4_send_callout));
  1837. // Let's create a simple DISCOVER
  1838. Pkt4Ptr discover = generateSimpleDiscover();
  1839. // Simulate that we have received that traffic
  1840. srv_->fakeReceive(discover);
  1841. // Server will now process to run its normal loop, but instead of calling
  1842. // IfaceMgr::receive4(), it will read all packets from the list set by
  1843. // fakeReceive()
  1844. // In particular, it should call registered pkt4_receive callback.
  1845. srv_->run();
  1846. // Check that the callback called is indeed the one we installed
  1847. EXPECT_EQ("buffer4_send", callback_name_);
  1848. // Check that there is one packet sent
  1849. ASSERT_EQ(1, srv_->fake_sent_.size());
  1850. Pkt4Ptr adv = srv_->fake_sent_.front();
  1851. // Check that pkt4 argument passing was successful and returned proper value
  1852. EXPECT_TRUE(callback_pkt4_.get() == adv.get());
  1853. // Check that all expected parameters are there
  1854. vector<string> expected_argument_names;
  1855. expected_argument_names.push_back(string("response4"));
  1856. EXPECT_TRUE(expected_argument_names == callback_argument_names_);
  1857. }
  1858. // Checks if callouts installed on buffer4_send are indeed called and that
  1859. // the output buffer can be changed.
  1860. TEST_F(HooksDhcpv4SrvTest, buffer4Send) {
  1861. // Install pkt4_receive_callout
  1862. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1863. "buffer4_send", buffer4_send_change_callout));
  1864. // Let's create a simple DISCOVER
  1865. Pkt4Ptr discover = generateSimpleDiscover();
  1866. // Simulate that we have received that traffic
  1867. srv_->fakeReceive(discover);
  1868. // Server will now process to run its normal loop, but instead of calling
  1869. // IfaceMgr::receive4(), it will read all packets from the list set by
  1870. // fakeReceive()
  1871. // In particular, it should call registered pkt4_receive callback.
  1872. srv_->run();
  1873. // Check that there is one packet sent
  1874. ASSERT_EQ(1, srv_->fake_sent_.size());
  1875. Pkt4Ptr adv = srv_->fake_sent_.front();
  1876. // The callout is supposed to fill the output buffer with dummyFile content
  1877. ASSERT_EQ(sizeof(dummyFile), adv->getBuffer().getLength());
  1878. EXPECT_EQ(0, memcmp(adv->getBuffer().getData(), dummyFile, sizeof(dummyFile)));
  1879. }
  1880. // Checks if callouts installed on buffer4_send can set skip flag and that flag
  1881. // causes the packet to not be sent
  1882. TEST_F(HooksDhcpv4SrvTest, buffer4SendSkip) {
  1883. // Install pkt4_receive_callout
  1884. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1885. "buffer4_send", skip_callout));
  1886. // Let's create a simple DISCOVER
  1887. Pkt4Ptr discover = generateSimpleDiscover();
  1888. // Simulate that we have received that traffic
  1889. srv_->fakeReceive(discover);
  1890. // Server will now process to run its normal loop, but instead of calling
  1891. // IfaceMgr::receive4(), it will read all packets from the list set by
  1892. // fakeReceive()
  1893. // In particular, it should call registered pkt4_receive callback.
  1894. srv_->run();
  1895. // Check that there is no packet sent.
  1896. ASSERT_EQ(0, srv_->fake_sent_.size());
  1897. }
  1898. // This test checks if subnet4_select callout is triggered and reports
  1899. // valid parameters
  1900. TEST_F(HooksDhcpv4SrvTest, subnet4SelectSimple) {
  1901. // Install pkt4_receive_callout
  1902. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1903. "subnet4_select", subnet4_select_callout));
  1904. // Configure 2 subnets, both directly reachable over local interface
  1905. // (let's not complicate the matter with relays)
  1906. string config = "{ \"interfaces\": [ \"*\" ],"
  1907. "\"rebind-timer\": 2000, "
  1908. "\"renew-timer\": 1000, "
  1909. "\"subnet4\": [ { "
  1910. " \"pool\": [ \"192.0.2.0/25\" ],"
  1911. " \"subnet\": \"192.0.2.0/24\", "
  1912. " \"interface\": \"" + valid_iface_ + "\" "
  1913. " }, {"
  1914. " \"pool\": [ \"192.0.3.0/25\" ],"
  1915. " \"subnet\": \"192.0.3.0/24\" "
  1916. " } ],"
  1917. "\"valid-lifetime\": 4000 }";
  1918. ElementPtr json = Element::fromJSON(config);
  1919. ConstElementPtr status;
  1920. // Configure the server and make sure the config is accepted
  1921. EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
  1922. ASSERT_TRUE(status);
  1923. comment_ = config::parseAnswer(rcode_, status);
  1924. ASSERT_EQ(0, rcode_);
  1925. // Prepare discover packet. Server should select first subnet for it
  1926. Pkt4Ptr sol = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
  1927. sol->setRemoteAddr(IOAddress("192.0.2.1"));
  1928. sol->setIface(valid_iface_);
  1929. OptionPtr clientid = generateClientId();
  1930. sol->addOption(clientid);
  1931. // Pass it to the server and get an advertise
  1932. Pkt4Ptr adv = srv_->processDiscover(sol);
  1933. // check if we get response at all
  1934. ASSERT_TRUE(adv);
  1935. // Check that the callback called is indeed the one we installed
  1936. EXPECT_EQ("subnet4_select", callback_name_);
  1937. // Check that pkt4 argument passing was successful and returned proper value
  1938. EXPECT_TRUE(callback_pkt4_.get() == sol.get());
  1939. const Subnet4Collection* exp_subnets = CfgMgr::instance().getSubnets4();
  1940. // The server is supposed to pick the first subnet, because of matching
  1941. // interface. Check that the value is reported properly.
  1942. ASSERT_TRUE(callback_subnet4_);
  1943. EXPECT_EQ(exp_subnets->front().get(), callback_subnet4_.get());
  1944. // Server is supposed to report two subnets
  1945. ASSERT_EQ(exp_subnets->size(), callback_subnet4collection_->size());
  1946. // Compare that the available subnets are reported as expected
  1947. EXPECT_TRUE((*exp_subnets)[0].get() == (*callback_subnet4collection_)[0].get());
  1948. EXPECT_TRUE((*exp_subnets)[1].get() == (*callback_subnet4collection_)[1].get());
  1949. }
  1950. // This test checks if callout installed on subnet4_select hook point can pick
  1951. // a different subnet.
  1952. TEST_F(HooksDhcpv4SrvTest, subnet4SelectChange) {
  1953. // Install a callout
  1954. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1955. "subnet4_select", subnet4_select_different_subnet_callout));
  1956. // Configure 2 subnets, both directly reachable over local interface
  1957. // (let's not complicate the matter with relays)
  1958. string config = "{ \"interfaces\": [ \"*\" ],"
  1959. "\"rebind-timer\": 2000, "
  1960. "\"renew-timer\": 1000, "
  1961. "\"subnet4\": [ { "
  1962. " \"pool\": [ \"192.0.2.0/25\" ],"
  1963. " \"subnet\": \"192.0.2.0/24\", "
  1964. " \"interface\": \"" + valid_iface_ + "\" "
  1965. " }, {"
  1966. " \"pool\": [ \"192.0.3.0/25\" ],"
  1967. " \"subnet\": \"192.0.3.0/24\" "
  1968. " } ],"
  1969. "\"valid-lifetime\": 4000 }";
  1970. ElementPtr json = Element::fromJSON(config);
  1971. ConstElementPtr status;
  1972. // Configure the server and make sure the config is accepted
  1973. EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
  1974. ASSERT_TRUE(status);
  1975. comment_ = config::parseAnswer(rcode_, status);
  1976. ASSERT_EQ(0, rcode_);
  1977. // Prepare discover packet. Server should select first subnet for it
  1978. Pkt4Ptr sol = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
  1979. sol->setRemoteAddr(IOAddress("192.0.2.1"));
  1980. sol->setIface(valid_iface_);
  1981. OptionPtr clientid = generateClientId();
  1982. sol->addOption(clientid);
  1983. // Pass it to the server and get an advertise
  1984. Pkt4Ptr adv = srv_->processDiscover(sol);
  1985. // check if we get response at all
  1986. ASSERT_TRUE(adv);
  1987. // The response should have an address from second pool, so let's check it
  1988. IOAddress addr = adv->getYiaddr();
  1989. EXPECT_NE("0.0.0.0", addr.toText());
  1990. // Get all subnets and use second subnet for verification
  1991. const Subnet4Collection* subnets = CfgMgr::instance().getSubnets4();
  1992. ASSERT_EQ(2, subnets->size());
  1993. // Advertised address must belong to the second pool (in subnet's range,
  1994. // in dynamic pool)
  1995. EXPECT_TRUE((*subnets)[1]->inRange(addr));
  1996. EXPECT_TRUE((*subnets)[1]->inPool(Lease::TYPE_V4, addr));
  1997. }
  1998. // This test verifies that incoming (positive) REQUEST/Renewing can be handled
  1999. // properly and that callout installed on lease4_renew is triggered with
  2000. // expected parameters.
  2001. TEST_F(HooksDhcpv4SrvTest, lease4RenewSimple) {
  2002. const IOAddress addr("192.0.2.106");
  2003. const uint32_t temp_t1 = 50;
  2004. const uint32_t temp_t2 = 75;
  2005. const uint32_t temp_valid = 100;
  2006. const time_t temp_timestamp = time(NULL) - 10;
  2007. // Install a callout
  2008. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  2009. "lease4_renew", lease4_renew_callout));
  2010. // Generate client-id also sets client_id_ member
  2011. OptionPtr clientid = generateClientId();
  2012. // Check that the address we are about to use is indeed in pool
  2013. ASSERT_TRUE(subnet_->inPool(Lease::TYPE_V4, addr));
  2014. // let's create a lease and put it in the LeaseMgr
  2015. uint8_t hwaddr2[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
  2016. Lease4Ptr used(new Lease4(IOAddress("192.0.2.106"), hwaddr2, sizeof(hwaddr2),
  2017. &client_id_->getDuid()[0], client_id_->getDuid().size(),
  2018. temp_valid, temp_t1, temp_t2, temp_timestamp,
  2019. subnet_->getID()));
  2020. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
  2021. // Check that the lease is really in the database
  2022. Lease4Ptr l = LeaseMgrFactory::instance().getLease4(addr);
  2023. ASSERT_TRUE(l);
  2024. // Let's create a RENEW
  2025. Pkt4Ptr req = Pkt4Ptr(new Pkt4(DHCPREQUEST, 1234));
  2026. req->setRemoteAddr(IOAddress(addr));
  2027. req->setYiaddr(addr);
  2028. req->setCiaddr(addr); // client's address
  2029. req->addOption(clientid);
  2030. req->addOption(srv_->getServerID());
  2031. // Pass it to the server and hope for a REPLY
  2032. Pkt4Ptr ack = srv_->processRequest(req);
  2033. // Check if we get response at all
  2034. checkResponse(ack, DHCPACK, 1234);
  2035. // Check that the lease is really in the database
  2036. l = checkLease(ack, clientid, req->getHWAddr(), addr);
  2037. ASSERT_TRUE(l);
  2038. // Check that T1, T2, preferred, valid and cltt were really updated
  2039. EXPECT_EQ(l->t1_, subnet_->getT1());
  2040. EXPECT_EQ(l->t2_, subnet_->getT2());
  2041. EXPECT_EQ(l->valid_lft_, subnet_->getValid());
  2042. // Check that the callback called is indeed the one we installed
  2043. EXPECT_EQ("lease4_renew", callback_name_);
  2044. // Check that hwaddr parameter is passed properly
  2045. ASSERT_TRUE(callback_hwaddr_);
  2046. EXPECT_TRUE(*callback_hwaddr_ == *req->getHWAddr());
  2047. // Check that the subnet is passed properly
  2048. ASSERT_TRUE(callback_subnet4_);
  2049. EXPECT_EQ(callback_subnet4_->toText(), subnet_->toText());
  2050. ASSERT_TRUE(callback_clientid_);
  2051. ASSERT_TRUE(client_id_);
  2052. EXPECT_TRUE(*client_id_ == *callback_clientid_);
  2053. // Check if all expected parameters were really received
  2054. vector<string> expected_argument_names;
  2055. expected_argument_names.push_back("subnet4");
  2056. expected_argument_names.push_back("clientid");
  2057. expected_argument_names.push_back("hwaddr");
  2058. expected_argument_names.push_back("lease4");
  2059. sort(callback_argument_names_.begin(), callback_argument_names_.end());
  2060. sort(expected_argument_names.begin(), expected_argument_names.end());
  2061. EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
  2062. EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease(addr));
  2063. }
  2064. // This test verifies that a callout installed on lease4_renew can trigger
  2065. // the server to not renew a lease.
  2066. TEST_F(HooksDhcpv4SrvTest, lease4RenewSkip) {
  2067. const IOAddress addr("192.0.2.106");
  2068. const uint32_t temp_t1 = 50;
  2069. const uint32_t temp_t2 = 75;
  2070. const uint32_t temp_valid = 100;
  2071. const time_t temp_timestamp = time(NULL) - 10;
  2072. // Install a callout
  2073. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  2074. "lease4_renew", skip_callout));
  2075. // Generate client-id also sets client_id_ member
  2076. OptionPtr clientid = generateClientId();
  2077. // Check that the address we are about to use is indeed in pool
  2078. ASSERT_TRUE(subnet_->inPool(Lease::TYPE_V4, addr));
  2079. // let's create a lease and put it in the LeaseMgr
  2080. uint8_t hwaddr2[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
  2081. Lease4Ptr used(new Lease4(IOAddress("192.0.2.106"), hwaddr2, sizeof(hwaddr2),
  2082. &client_id_->getDuid()[0], client_id_->getDuid().size(),
  2083. temp_valid, temp_t1, temp_t2, temp_timestamp,
  2084. subnet_->getID()));
  2085. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
  2086. // Check that the lease is really in the database
  2087. Lease4Ptr l = LeaseMgrFactory::instance().getLease4(addr);
  2088. ASSERT_TRUE(l);
  2089. // Check that T1, T2, preferred, valid and cltt really set.
  2090. // Constructed lease looks as if it was assigned 10 seconds ago
  2091. // EXPECT_EQ(l->t1_, temp_t1);
  2092. // EXPECT_EQ(l->t2_, temp_t2);
  2093. EXPECT_EQ(l->valid_lft_, temp_valid);
  2094. EXPECT_EQ(l->cltt_, temp_timestamp);
  2095. // Let's create a RENEW
  2096. Pkt4Ptr req = Pkt4Ptr(new Pkt4(DHCPREQUEST, 1234));
  2097. req->setRemoteAddr(IOAddress(addr));
  2098. req->setYiaddr(addr);
  2099. req->setCiaddr(addr); // client's address
  2100. req->addOption(clientid);
  2101. req->addOption(srv_->getServerID());
  2102. // Pass it to the server and hope for a REPLY
  2103. Pkt4Ptr ack = srv_->processRequest(req);
  2104. ASSERT_TRUE(ack);
  2105. // Check that the lease is really in the database
  2106. l = checkLease(ack, clientid, req->getHWAddr(), addr);
  2107. ASSERT_TRUE(l);
  2108. // Check that T1, T2, valid and cltt were NOT updated
  2109. EXPECT_EQ(temp_t1, l->t1_);
  2110. EXPECT_EQ(temp_t2, l->t2_);
  2111. EXPECT_EQ(temp_valid, l->valid_lft_);
  2112. EXPECT_EQ(temp_timestamp, l->cltt_);
  2113. EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease(addr));
  2114. }
  2115. // This test verifies that valid RELEASE triggers lease4_release callouts
  2116. TEST_F(HooksDhcpv4SrvTest, lease4ReleaseSimple) {
  2117. const IOAddress addr("192.0.2.106");
  2118. const uint32_t temp_t1 = 50;
  2119. const uint32_t temp_t2 = 75;
  2120. const uint32_t temp_valid = 100;
  2121. const time_t temp_timestamp = time(NULL) - 10;
  2122. // Install a callout
  2123. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  2124. "lease4_release", lease4_release_callout));
  2125. // Generate client-id also duid_
  2126. OptionPtr clientid = generateClientId();
  2127. // Check that the address we are about to use is indeed in pool
  2128. ASSERT_TRUE(subnet_->inPool(Lease::TYPE_V4, addr));
  2129. // Let's create a lease and put it in the LeaseMgr
  2130. uint8_t mac_addr[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
  2131. HWAddrPtr hw(new HWAddr(mac_addr, sizeof(mac_addr), HTYPE_ETHER));
  2132. Lease4Ptr used(new Lease4(addr, mac_addr, sizeof(mac_addr),
  2133. &client_id_->getDuid()[0], client_id_->getDuid().size(),
  2134. temp_valid, temp_t1, temp_t2, temp_timestamp,
  2135. subnet_->getID()));
  2136. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
  2137. // Check that the lease is really in the database
  2138. Lease4Ptr l = LeaseMgrFactory::instance().getLease4(addr);
  2139. ASSERT_TRUE(l);
  2140. // Let's create a RELEASE
  2141. // Generate client-id also duid_
  2142. Pkt4Ptr rel = Pkt4Ptr(new Pkt4(DHCPRELEASE, 1234));
  2143. rel->setRemoteAddr(addr);
  2144. rel->setYiaddr(addr);
  2145. rel->addOption(clientid);
  2146. rel->addOption(srv_->getServerID());
  2147. rel->setHWAddr(hw);
  2148. // Pass it to the server and hope for a REPLY
  2149. // Note: this is no response to RELEASE in DHCPv4
  2150. EXPECT_NO_THROW(srv_->processRelease(rel));
  2151. // The lease should be gone from LeaseMgr
  2152. l = LeaseMgrFactory::instance().getLease4(addr);
  2153. EXPECT_FALSE(l);
  2154. // Try to get the lease by hardware address
  2155. // @todo: Uncomment this once trac2592 is implemented
  2156. // Lease4Collection leases = LeaseMgrFactory::instance().getLease4(hw->hwaddr_);
  2157. // EXPECT_EQ(leases.size(), 0);
  2158. // Try to get it by hw/subnet_id combination
  2159. l = LeaseMgrFactory::instance().getLease4(hw->hwaddr_, subnet_->getID());
  2160. EXPECT_FALSE(l);
  2161. // Try by client-id
  2162. // @todo: Uncomment this once trac2592 is implemented
  2163. //Lease4Collection leases = LeaseMgrFactory::instance().getLease4(*client_id_);
  2164. //EXPECT_EQ(leases.size(), 0);
  2165. // Try by client-id/subnet-id
  2166. l = LeaseMgrFactory::instance().getLease4(*client_id_, subnet_->getID());
  2167. EXPECT_FALSE(l);
  2168. // Ok, the lease is *really* not there.
  2169. // Check that the callback called is indeed the one we installed
  2170. EXPECT_EQ("lease4_release", callback_name_);
  2171. // Check that pkt4 argument passing was successful and returned proper value
  2172. EXPECT_TRUE(callback_pkt4_.get() == rel.get());
  2173. // Check if all expected parameters were really received
  2174. vector<string> expected_argument_names;
  2175. expected_argument_names.push_back("query4");
  2176. expected_argument_names.push_back("lease4");
  2177. sort(callback_argument_names_.begin(), callback_argument_names_.end());
  2178. sort(expected_argument_names.begin(), expected_argument_names.end());
  2179. EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
  2180. }
  2181. // This test verifies that skip flag returned by a callout installed on the
  2182. // lease4_release hook point will keep the lease
  2183. TEST_F(HooksDhcpv4SrvTest, lease4ReleaseSkip) {
  2184. const IOAddress addr("192.0.2.106");
  2185. const uint32_t temp_t1 = 50;
  2186. const uint32_t temp_t2 = 75;
  2187. const uint32_t temp_valid = 100;
  2188. const time_t temp_timestamp = time(NULL) - 10;
  2189. // Install a callout
  2190. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  2191. "lease4_release", skip_callout));
  2192. // Generate client-id also duid_
  2193. OptionPtr clientid = generateClientId();
  2194. // Check that the address we are about to use is indeed in pool
  2195. ASSERT_TRUE(subnet_->inPool(Lease::TYPE_V4, addr));
  2196. // Let's create a lease and put it in the LeaseMgr
  2197. uint8_t mac_addr[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
  2198. HWAddrPtr hw(new HWAddr(mac_addr, sizeof(mac_addr), HTYPE_ETHER));
  2199. Lease4Ptr used(new Lease4(addr, mac_addr, sizeof(mac_addr),
  2200. &client_id_->getDuid()[0], client_id_->getDuid().size(),
  2201. temp_valid, temp_t1, temp_t2, temp_timestamp,
  2202. subnet_->getID()));
  2203. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
  2204. // Check that the lease is really in the database
  2205. Lease4Ptr l = LeaseMgrFactory::instance().getLease4(addr);
  2206. ASSERT_TRUE(l);
  2207. // Let's create a RELEASE
  2208. // Generate client-id also duid_
  2209. Pkt4Ptr rel = Pkt4Ptr(new Pkt4(DHCPRELEASE, 1234));
  2210. rel->setRemoteAddr(addr);
  2211. rel->setYiaddr(addr);
  2212. rel->addOption(clientid);
  2213. rel->addOption(srv_->getServerID());
  2214. rel->setHWAddr(hw);
  2215. // Pass it to the server and hope for a REPLY
  2216. // Note: this is no response to RELEASE in DHCPv4
  2217. EXPECT_NO_THROW(srv_->processRelease(rel));
  2218. // The lease should be still there
  2219. l = LeaseMgrFactory::instance().getLease4(addr);
  2220. EXPECT_TRUE(l);
  2221. // Try by client-id/subnet-id
  2222. l = LeaseMgrFactory::instance().getLease4(*client_id_, subnet_->getID());
  2223. EXPECT_TRUE(l);
  2224. // Try to get the lease by hardware address
  2225. // @todo: Uncomment this once trac2592 is implemented
  2226. // Lease4Collection leases = LeaseMgrFactory::instance().getLease4(hw->hwaddr_);
  2227. // EXPECT_EQ(leases.size(), 1);
  2228. // Try by client-id
  2229. // @todo: Uncomment this once trac2592 is implemented
  2230. //Lease4Collection leases = LeaseMgrFactory::instance().getLease4(*client_id_);
  2231. //EXPECT_EQ(leases.size(), 1);
  2232. }
  2233. }; // end of isc::dhcp::test namespace
  2234. }; // end of isc::dhcp namespace
  2235. }; // end of isc namespace