dhcp4_srv_unittest.cc 109 KB

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