dhcp4_srv_unittest.cc 92 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521
  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(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(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(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. // @todo: Uncomment this once trac2592 is implemented
  1227. // Lease4Collection leases = LeaseMgrFactory::instance().getLease4(hw->hwaddr_);
  1228. // EXPECT_EQ(leases.size(), 0);
  1229. // Try to get it by hw/subnet_id combination
  1230. l = LeaseMgrFactory::instance().getLease4(hw->hwaddr_, subnet_->getID());
  1231. EXPECT_FALSE(l);
  1232. // Try by client-id
  1233. // @todo: Uncomment this once trac2592 is implemented
  1234. //Lease4Collection leases = LeaseMgrFactory::instance().getLease4(*client_id_);
  1235. //EXPECT_EQ(leases.size(), 0);
  1236. // Try by client-id/subnet-id
  1237. l = LeaseMgrFactory::instance().getLease4(*client_id_, subnet_->getID());
  1238. EXPECT_FALSE(l);
  1239. // Ok, the lease is *really* not there.
  1240. }
  1241. // This test verifies that incoming (invalid) RELEASE can be handled properly.
  1242. //
  1243. // This test checks 3 scenarios:
  1244. // 1. there is no such lease at all
  1245. // 2. there is such a lease, but it is assigned to a different IAID
  1246. // 3. there is such a lease, but it belongs to a different client
  1247. TEST_F(Dhcpv4SrvTest, ReleaseReject) {
  1248. boost::scoped_ptr<NakedDhcpv4Srv> srv;
  1249. ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
  1250. const IOAddress addr("192.0.2.106");
  1251. const uint32_t t1 = 50;
  1252. const uint32_t t2 = 75;
  1253. const uint32_t valid = 100;
  1254. const time_t timestamp = time(NULL) - 10;
  1255. // Let's create a lease and put it in the LeaseMgr
  1256. uint8_t bogus_mac_addr[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
  1257. HWAddrPtr bogus_hw(new HWAddr(bogus_mac_addr, sizeof(bogus_mac_addr), HTYPE_ETHER));
  1258. OptionPtr bogus_clientid = generateClientId(7); // different length
  1259. // Generate client-id also duid_
  1260. OptionPtr clientid = generateClientId();
  1261. // Check that the address we are about to use is indeed in pool
  1262. ASSERT_TRUE(subnet_->inPool(addr));
  1263. // Let's create a RELEASE
  1264. // Generate client-id also duid_
  1265. Pkt4Ptr rel = Pkt4Ptr(new Pkt4(DHCPRELEASE, 1234));
  1266. rel->setRemoteAddr(addr);
  1267. rel->setYiaddr(addr);
  1268. rel->addOption(clientid);
  1269. rel->addOption(srv->getServerID());
  1270. rel->setHWAddr(bogus_hw);
  1271. // Case 1: No lease known to server
  1272. SCOPED_TRACE("CASE 1: Lease is not known to the server");
  1273. // There is nothing to check here. The lease is not there and server does
  1274. // not send anything back. This case is enumerated here just for keeping
  1275. // parity with similar test in DHCPv6.
  1276. EXPECT_NO_THROW(srv->processRelease(rel));
  1277. // CASE 2: Lease is known and belongs to this client, but to a different hardware
  1278. SCOPED_TRACE("CASE 2: Lease is known and belongs to this client, but uses different HW addr");
  1279. // Let's create a lease and put it in the LeaseMgr
  1280. uint8_t mac_addr[] = { 0, 0x1, 0x2, 0x3, 0x4, 0x5};
  1281. HWAddrPtr hw(new HWAddr(mac_addr, sizeof(mac_addr), HTYPE_ETHER));
  1282. Lease4Ptr used(new Lease4(addr, mac_addr, sizeof(mac_addr),
  1283. &client_id_->getDuid()[0], client_id_->getDuid().size(),
  1284. valid, t1, t2, timestamp, subnet_->getID()));
  1285. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
  1286. // Check that the lease is really in the database
  1287. Lease4Ptr l = LeaseMgrFactory::instance().getLease4(addr);
  1288. ASSERT_TRUE(l);
  1289. rel->setHWAddr(bogus_hw);
  1290. EXPECT_NO_THROW(srv->processRelease(rel));
  1291. // Check that the lease was not removed (due to hardware address mis-match)
  1292. l = LeaseMgrFactory::instance().getLease4(addr);
  1293. ASSERT_TRUE(l);
  1294. // CASE 3: Lease belongs to a client with different client-id
  1295. SCOPED_TRACE("CASE 3: Lease belongs to a client with different client-id");
  1296. rel->setHWAddr(hw); // proper HW address this time
  1297. rel->delOption(DHO_DHCP_CLIENT_IDENTIFIER);
  1298. rel->addOption(bogus_clientid); // but invalid client-id
  1299. OptionPtr x = rel->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
  1300. EXPECT_NO_THROW(srv->processRelease(rel));
  1301. // Check that the lease is still there
  1302. l = LeaseMgrFactory::instance().getLease4(addr);
  1303. ASSERT_TRUE(l);
  1304. // Final sanity check. Verify that with valid hw and client-id release is successful
  1305. rel->delOption(DHO_DHCP_CLIENT_IDENTIFIER);
  1306. rel->addOption(clientid);
  1307. // It should work this time
  1308. EXPECT_NO_THROW(srv->processRelease(rel));
  1309. // Check that the lease is not there
  1310. l = LeaseMgrFactory::instance().getLease4(addr);
  1311. EXPECT_FALSE(l);
  1312. }
  1313. // This test verifies if the server-id disk operations (read, write) are
  1314. // working properly.
  1315. TEST_F(Dhcpv4SrvTest, ServerID) {
  1316. NakedDhcpv4Srv srv(0);
  1317. string srvid_text = "192.0.2.100";
  1318. IOAddress srvid(srvid_text);
  1319. fstream file1(SRVID_FILE, ios::out | ios::trunc);
  1320. file1 << srvid_text;
  1321. file1.close();
  1322. // Test reading from a file
  1323. EXPECT_TRUE(srv.loadServerID(SRVID_FILE));
  1324. ASSERT_TRUE(srv.getServerID());
  1325. EXPECT_EQ(srvid_text, srv.srvidToString(srv.getServerID()));
  1326. // Now test writing to a file
  1327. EXPECT_EQ(0, unlink(SRVID_FILE));
  1328. EXPECT_NO_THROW(srv.writeServerID(SRVID_FILE));
  1329. fstream file2(SRVID_FILE, ios::in);
  1330. ASSERT_TRUE(file2.good());
  1331. string text;
  1332. file2 >> text;
  1333. file2.close();
  1334. EXPECT_EQ(srvid_text, text);
  1335. }
  1336. /// @todo Implement tests for subnetSelect See tests in dhcp6_srv_unittest.cc:
  1337. /// selectSubnetAddr, selectSubnetIface, selectSubnetRelayLinkaddr,
  1338. /// selectSubnetRelayInterfaceId. Note that the concept of interface-id is not
  1339. /// present in the DHCPv4, so not everything is applicable directly.
  1340. /// See ticket #3057
  1341. // Checks if hooks are registered properly.
  1342. TEST_F(Dhcpv4SrvTest, Hooks) {
  1343. NakedDhcpv4Srv srv(0);
  1344. // check if appropriate hooks are registered
  1345. int hook_index_buffer4_receive = -1;
  1346. int hook_index_pkt4_receive = -1;
  1347. int hook_index_select_subnet = -1;
  1348. int hook_index_lease4_release = -1;
  1349. int hook_index_pkt4_send = -1;
  1350. int hook_index_buffer4_send = -1;
  1351. // check if appropriate indexes are set
  1352. EXPECT_NO_THROW(hook_index_buffer4_receive = ServerHooks::getServerHooks()
  1353. .getIndex("buffer4_receive"));
  1354. EXPECT_NO_THROW(hook_index_pkt4_receive = ServerHooks::getServerHooks()
  1355. .getIndex("pkt4_receive"));
  1356. EXPECT_NO_THROW(hook_index_select_subnet = ServerHooks::getServerHooks()
  1357. .getIndex("subnet4_select"));
  1358. EXPECT_NO_THROW(hook_index_lease4_release = ServerHooks::getServerHooks()
  1359. .getIndex("lease4_release"));
  1360. EXPECT_NO_THROW(hook_index_pkt4_send = ServerHooks::getServerHooks()
  1361. .getIndex("pkt4_send"));
  1362. EXPECT_NO_THROW(hook_index_buffer4_send = ServerHooks::getServerHooks()
  1363. .getIndex("buffer4_send"));
  1364. EXPECT_TRUE(hook_index_buffer4_receive > 0);
  1365. EXPECT_TRUE(hook_index_pkt4_receive > 0);
  1366. EXPECT_TRUE(hook_index_select_subnet > 0);
  1367. EXPECT_TRUE(hook_index_lease4_release > 0);
  1368. EXPECT_TRUE(hook_index_pkt4_send > 0);
  1369. EXPECT_TRUE(hook_index_buffer4_send > 0);
  1370. }
  1371. // a dummy MAC address
  1372. const uint8_t dummyMacAddr[] = {0, 1, 2, 3, 4, 5};
  1373. // A dummy MAC address, padded with 0s
  1374. const uint8_t dummyChaddr[16] = {0, 1, 2, 3, 4, 5, 0, 0,
  1375. 0, 0, 0, 0, 0, 0, 0, 0 };
  1376. // Let's use some creative test content here (128 chars + \0)
  1377. const uint8_t dummyFile[] = "Lorem ipsum dolor sit amet, consectetur "
  1378. "adipiscing elit. Proin mollis placerat metus, at "
  1379. "lacinia orci ornare vitae. Mauris amet.";
  1380. // Yet another type of test content (64 chars + \0)
  1381. const uint8_t dummySname[] = "Lorem ipsum dolor sit amet, consectetur "
  1382. "adipiscing elit posuere.";
  1383. /// @brief a class dedicated to Hooks testing in DHCPv4 server
  1384. ///
  1385. /// This class has a number of static members, because each non-static
  1386. /// method has implicit 'this' parameter, so it does not match callout
  1387. /// signature and couldn't be registered. Furthermore, static methods
  1388. /// can't modify non-static members (for obvious reasons), so many
  1389. /// fields are declared static. It is still better to keep them as
  1390. /// one class rather than unrelated collection of global objects.
  1391. class HooksDhcpv4SrvTest : public Dhcpv4SrvTest {
  1392. public:
  1393. /// @brief creates Dhcpv4Srv and prepares buffers for callouts
  1394. HooksDhcpv4SrvTest() {
  1395. // Allocate new DHCPv6 Server
  1396. srv_ = new NakedDhcpv4Srv(0);
  1397. // clear static buffers
  1398. resetCalloutBuffers();
  1399. }
  1400. /// @brief destructor (deletes Dhcpv4Srv)
  1401. virtual ~HooksDhcpv4SrvTest() {
  1402. HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("pkt4_receive");
  1403. HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("pkt4_send");
  1404. HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("subnet4_select");
  1405. delete srv_;
  1406. }
  1407. /// @brief creates an option with specified option code
  1408. ///
  1409. /// This method is static, because it is used from callouts
  1410. /// that do not have a pointer to HooksDhcpv4SSrvTest object
  1411. ///
  1412. /// @param option_code code of option to be created
  1413. ///
  1414. /// @return pointer to create option object
  1415. static OptionPtr createOption(uint16_t option_code) {
  1416. char payload[] = {
  1417. 0xa, 0xb, 0xc, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14
  1418. };
  1419. OptionBuffer tmp(payload, payload + sizeof(payload));
  1420. return OptionPtr(new Option(Option::V4, option_code, tmp));
  1421. }
  1422. /// @brief Generates test packet.
  1423. ///
  1424. /// Allocates and generates on-wire buffer that represents test packet, with all
  1425. /// fixed fields set to non-zero values. Content is not always reasonable.
  1426. ///
  1427. /// See generateTestPacket1() function that returns exactly the same packet as
  1428. /// Pkt4 object.
  1429. ///
  1430. /// @return pointer to allocated Pkt4 object
  1431. // Returns a vector containing a DHCPv4 packet header.
  1432. Pkt4Ptr
  1433. generateSimpleDiscover() {
  1434. // That is only part of the header. It contains all "short" fields,
  1435. // larger fields are constructed separately.
  1436. uint8_t hdr[] = {
  1437. 1, 6, 6, 13, // op, htype, hlen, hops,
  1438. 0x12, 0x34, 0x56, 0x78, // transaction-id
  1439. 0, 42, 0x80, 0x00, // 42 secs, BROADCAST flags
  1440. 192, 0, 2, 1, // ciaddr
  1441. 1, 2, 3, 4, // yiaddr
  1442. 192, 0, 2, 255, // siaddr
  1443. 255, 255, 255, 255, // giaddr
  1444. };
  1445. // Initialize the vector with the header fields defined above.
  1446. vector<uint8_t> buf(hdr, hdr + sizeof(hdr));
  1447. // Append the large header fields.
  1448. copy(dummyChaddr, dummyChaddr + Pkt4::MAX_CHADDR_LEN, back_inserter(buf));
  1449. copy(dummySname, dummySname + Pkt4::MAX_SNAME_LEN, back_inserter(buf));
  1450. copy(dummyFile, dummyFile + Pkt4::MAX_FILE_LEN, back_inserter(buf));
  1451. // Should now have all the header, so check. The "static_cast" is used
  1452. // to get round an odd bug whereby the linker appears not to find the
  1453. // definition of DHCPV4_PKT_HDR_LEN if it appears within an EXPECT_EQ().
  1454. EXPECT_EQ(static_cast<size_t>(Pkt4::DHCPV4_PKT_HDR_LEN), buf.size());
  1455. // Add magic cookie
  1456. buf.push_back(0x63);
  1457. buf.push_back(0x82);
  1458. buf.push_back(0x53);
  1459. buf.push_back(0x63);
  1460. // Add message type DISCOVER
  1461. buf.push_back(static_cast<uint8_t>(DHO_DHCP_MESSAGE_TYPE));
  1462. buf.push_back(1); // length (just one byte)
  1463. buf.push_back(static_cast<uint8_t>(DHCPDISCOVER));
  1464. return (Pkt4Ptr(new Pkt4(&buf[0], buf.size())));
  1465. }
  1466. /// Test callback that stores received callout name and pkt4 value
  1467. /// @param callout_handle handle passed by the hooks framework
  1468. /// @return always 0
  1469. static int
  1470. buffer4_receive_callout(CalloutHandle& callout_handle) {
  1471. callback_name_ = string("buffer4_receive");
  1472. callout_handle.getArgument("query4", callback_pkt4_);
  1473. callback_argument_names_ = callout_handle.getArgumentNames();
  1474. return (0);
  1475. }
  1476. /// Test callback that changes hwaddr value
  1477. /// @param callout_handle handle passed by the hooks framework
  1478. /// @return always 0
  1479. static int
  1480. buffer4_receive_change_hwaddr(CalloutHandle& callout_handle) {
  1481. Pkt4Ptr pkt;
  1482. callout_handle.getArgument("query4", pkt);
  1483. // If there is at least one option with data
  1484. if (pkt->data_.size() >= Pkt4::DHCPV4_PKT_HDR_LEN) {
  1485. // Offset of the first byte of the CHWADDR field. Let's the first
  1486. // byte to some new value that we could later check
  1487. pkt->data_[28] = 0xff;
  1488. }
  1489. // Carry on as usual
  1490. return buffer4_receive_callout(callout_handle);
  1491. }
  1492. /// Test callback that deletes MAC address
  1493. /// @param callout_handle handle passed by the hooks framework
  1494. /// @return always 0
  1495. static int
  1496. buffer4_receive_delete_hwaddr(CalloutHandle& callout_handle) {
  1497. Pkt4Ptr pkt;
  1498. callout_handle.getArgument("query4", pkt);
  1499. pkt->data_[2] = 0; // offset 2 is hlen, let's set it to zero
  1500. memset(&pkt->data_[28], 0, Pkt4::MAX_CHADDR_LEN); // Clear CHADDR content
  1501. // carry on as usual
  1502. return buffer4_receive_callout(callout_handle);
  1503. }
  1504. /// Test callback that sets skip flag
  1505. /// @param callout_handle handle passed by the hooks framework
  1506. /// @return always 0
  1507. static int
  1508. buffer4_receive_skip(CalloutHandle& callout_handle) {
  1509. callout_handle.setSkip(true);
  1510. // Carry on as usual
  1511. return buffer4_receive_callout(callout_handle);
  1512. }
  1513. /// test callback that stores received callout name and pkt4 value
  1514. /// @param callout_handle handle passed by the hooks framework
  1515. /// @return always 0
  1516. static int
  1517. pkt4_receive_callout(CalloutHandle& callout_handle) {
  1518. callback_name_ = string("pkt4_receive");
  1519. callout_handle.getArgument("query4", callback_pkt4_);
  1520. callback_argument_names_ = callout_handle.getArgumentNames();
  1521. return (0);
  1522. }
  1523. /// test callback that changes client-id value
  1524. /// @param callout_handle handle passed by the hooks framework
  1525. /// @return always 0
  1526. static int
  1527. pkt4_receive_change_clientid(CalloutHandle& callout_handle) {
  1528. Pkt4Ptr pkt;
  1529. callout_handle.getArgument("query4", pkt);
  1530. // get rid of the old client-id
  1531. pkt->delOption(DHO_DHCP_CLIENT_IDENTIFIER);
  1532. // add a new option
  1533. pkt->addOption(createOption(DHO_DHCP_CLIENT_IDENTIFIER));
  1534. // carry on as usual
  1535. return pkt4_receive_callout(callout_handle);
  1536. }
  1537. /// test callback that deletes client-id
  1538. /// @param callout_handle handle passed by the hooks framework
  1539. /// @return always 0
  1540. static int
  1541. pkt4_receive_delete_clientid(CalloutHandle& callout_handle) {
  1542. Pkt4Ptr pkt;
  1543. callout_handle.getArgument("query4", pkt);
  1544. // get rid of the old client-id (and no HWADDR)
  1545. vector<uint8_t> mac;
  1546. pkt->delOption(DHO_DHCP_CLIENT_IDENTIFIER);
  1547. pkt->setHWAddr(1, 0, mac); // HWtype 1, hwardware len = 0
  1548. // carry on as usual
  1549. return pkt4_receive_callout(callout_handle);
  1550. }
  1551. /// test callback that sets skip flag
  1552. /// @param callout_handle handle passed by the hooks framework
  1553. /// @return always 0
  1554. static int
  1555. pkt4_receive_skip(CalloutHandle& callout_handle) {
  1556. Pkt4Ptr pkt;
  1557. callout_handle.getArgument("query4", pkt);
  1558. callout_handle.setSkip(true);
  1559. // carry on as usual
  1560. return pkt4_receive_callout(callout_handle);
  1561. }
  1562. /// Test callback that stores received callout name and pkt4 value
  1563. /// @param callout_handle handle passed by the hooks framework
  1564. /// @return always 0
  1565. static int
  1566. pkt4_send_callout(CalloutHandle& callout_handle) {
  1567. callback_name_ = string("pkt4_send");
  1568. callout_handle.getArgument("response4", callback_pkt4_);
  1569. callback_argument_names_ = callout_handle.getArgumentNames();
  1570. return (0);
  1571. }
  1572. // Test callback that changes server-id
  1573. /// @param callout_handle handle passed by the hooks framework
  1574. /// @return always 0
  1575. static int
  1576. pkt4_send_change_serverid(CalloutHandle& callout_handle) {
  1577. Pkt4Ptr pkt;
  1578. callout_handle.getArgument("response4", pkt);
  1579. // get rid of the old server-id
  1580. pkt->delOption(DHO_DHCP_SERVER_IDENTIFIER);
  1581. // add a new option
  1582. pkt->addOption(createOption(DHO_DHCP_SERVER_IDENTIFIER));
  1583. // carry on as usual
  1584. return pkt4_send_callout(callout_handle);
  1585. }
  1586. /// test callback that deletes server-id
  1587. /// @param callout_handle handle passed by the hooks framework
  1588. /// @return always 0
  1589. static int
  1590. pkt4_send_delete_serverid(CalloutHandle& callout_handle) {
  1591. Pkt4Ptr pkt;
  1592. callout_handle.getArgument("response4", pkt);
  1593. // get rid of the old client-id
  1594. pkt->delOption(DHO_DHCP_SERVER_IDENTIFIER);
  1595. // carry on as usual
  1596. return pkt4_send_callout(callout_handle);
  1597. }
  1598. /// Test callback that sets skip flag
  1599. /// @param callout_handle handle passed by the hooks framework
  1600. /// @return always 0
  1601. static int
  1602. pkt4_send_skip(CalloutHandle& callout_handle) {
  1603. Pkt4Ptr pkt;
  1604. callout_handle.getArgument("response4", pkt);
  1605. callout_handle.setSkip(true);
  1606. // carry on as usual
  1607. return pkt4_send_callout(callout_handle);
  1608. }
  1609. /// Test callback that stores received callout name and subnet4 values
  1610. /// @param callout_handle handle passed by the hooks framework
  1611. /// @return always 0
  1612. static int
  1613. subnet4_select_callout(CalloutHandle& callout_handle) {
  1614. callback_name_ = string("subnet4_select");
  1615. callout_handle.getArgument("query4", callback_pkt4_);
  1616. callout_handle.getArgument("subnet4", callback_subnet4_);
  1617. callout_handle.getArgument("subnet4collection", callback_subnet4collection_);
  1618. callback_argument_names_ = callout_handle.getArgumentNames();
  1619. return (0);
  1620. }
  1621. /// Test callback that picks the other subnet if possible.
  1622. /// @param callout_handle handle passed by the hooks framework
  1623. /// @return always 0
  1624. static int
  1625. subnet4_select_different_subnet_callout(CalloutHandle& callout_handle) {
  1626. // Call the basic calllout to record all passed values
  1627. subnet4_select_callout(callout_handle);
  1628. const Subnet4Collection* subnets;
  1629. Subnet4Ptr subnet;
  1630. callout_handle.getArgument("subnet4", subnet);
  1631. callout_handle.getArgument("subnet4collection", subnets);
  1632. // Let's change to a different subnet
  1633. if (subnets->size() > 1) {
  1634. subnet = (*subnets)[1]; // Let's pick the other subnet
  1635. callout_handle.setArgument("subnet4", subnet);
  1636. }
  1637. return (0);
  1638. }
  1639. /// resets buffers used to store data received by callouts
  1640. void resetCalloutBuffers() {
  1641. callback_name_ = string("");
  1642. callback_pkt4_.reset();
  1643. callback_subnet4_.reset();
  1644. callback_subnet4collection_ = NULL;
  1645. callback_argument_names_.clear();
  1646. }
  1647. /// pointer to Dhcpv4Srv that is used in tests
  1648. NakedDhcpv4Srv* srv_;
  1649. // The following fields are used in testing pkt4_receive_callout
  1650. /// String name of the received callout
  1651. static string callback_name_;
  1652. /// Pkt4 structure returned in the callout
  1653. static Pkt4Ptr callback_pkt4_;
  1654. /// Pointer to a subnet received by callout
  1655. static Subnet4Ptr callback_subnet4_;
  1656. /// A list of all available subnets (received by callout)
  1657. static const Subnet4Collection* callback_subnet4collection_;
  1658. /// A list of all received arguments
  1659. static vector<string> callback_argument_names_;
  1660. };
  1661. // The following fields are used in testing pkt4_receive_callout.
  1662. // See fields description in the class for details
  1663. string HooksDhcpv4SrvTest::callback_name_;
  1664. Pkt4Ptr HooksDhcpv4SrvTest::callback_pkt4_;
  1665. Subnet4Ptr HooksDhcpv4SrvTest::callback_subnet4_;
  1666. const Subnet4Collection* HooksDhcpv4SrvTest::callback_subnet4collection_;
  1667. vector<string> HooksDhcpv4SrvTest::callback_argument_names_;
  1668. // Checks if callouts installed on pkt4_receive are indeed called and the
  1669. // all necessary parameters are passed.
  1670. //
  1671. // Note that the test name does not follow test naming convention,
  1672. // but the proper hook name is "buffer4_receive".
  1673. TEST_F(HooksDhcpv4SrvTest, simple_buffer4_receive) {
  1674. // Install pkt6_receive_callout
  1675. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1676. "buffer4_receive", buffer4_receive_callout));
  1677. // Let's create a simple DISCOVER
  1678. Pkt4Ptr dis = generateSimpleDiscover();
  1679. // Simulate that we have received that traffic
  1680. srv_->fakeReceive(dis);
  1681. // Server will now process to run its normal loop, but instead of calling
  1682. // IfaceMgr::receive4(), it will read all packets from the list set by
  1683. // fakeReceive()
  1684. // In particular, it should call registered buffer4_receive callback.
  1685. srv_->run();
  1686. // Check that the callback called is indeed the one we installed
  1687. EXPECT_EQ("buffer4_receive", callback_name_);
  1688. // Check that pkt4 argument passing was successful and returned proper value
  1689. EXPECT_TRUE(callback_pkt4_.get() == dis.get());
  1690. // Check that all expected parameters are there
  1691. vector<string> expected_argument_names;
  1692. expected_argument_names.push_back(string("query4"));
  1693. EXPECT_TRUE(expected_argument_names == callback_argument_names_);
  1694. }
  1695. // Checks if callouts installed on buffer4_receive is able to change
  1696. // the values and the parameters are indeed used by the server.
  1697. TEST_F(HooksDhcpv4SrvTest, valueChange_buffer4_receive) {
  1698. // Install callback that modifies MAC addr of incoming packet
  1699. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1700. "buffer4_receive", buffer4_receive_change_hwaddr));
  1701. // Let's create a simple DISCOVER
  1702. Pkt4Ptr discover = generateSimpleDiscover();
  1703. // Simulate that we have received that traffic
  1704. srv_->fakeReceive(discover);
  1705. // Server will now process to run its normal loop, but instead of calling
  1706. // IfaceMgr::receive6(), it will read all packets from the list set by
  1707. // fakeReceive()
  1708. // In particular, it should call registered buffer4_receive callback.
  1709. srv_->run();
  1710. // Check that the server did send a reposonce
  1711. ASSERT_EQ(1, srv_->fake_sent_.size());
  1712. // Make sure that we received a response
  1713. Pkt4Ptr offer = srv_->fake_sent_.front();
  1714. ASSERT_TRUE(offer);
  1715. // Get client-id...
  1716. HWAddrPtr hwaddr = offer->getHWAddr();
  1717. ASSERT_TRUE(hwaddr); // basic sanity check. HWAddr is always present
  1718. // ... and check if it is the modified value
  1719. ASSERT_FALSE(hwaddr->hwaddr_.empty()); // there must be a MAC address
  1720. EXPECT_EQ(0xff, hwaddr->hwaddr_[0]); // check that its first byte was modified
  1721. }
  1722. // Checks if callouts installed on buffer4_receive is able to set skip flag that
  1723. // will cause the server to not parse the packet. Even though the packet is valid,
  1724. // the server should eventually drop it, because there won't be mandatory options
  1725. // (or rather option objects) in it.
  1726. TEST_F(HooksDhcpv4SrvTest, skip_buffer4_receive) {
  1727. // Install pkt6_receive_callout
  1728. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1729. "buffer4_receive", buffer4_receive_skip));
  1730. // Let's create a simple DISCOVER
  1731. Pkt4Ptr discover = generateSimpleDiscover();
  1732. // Simulate that we have received that traffic
  1733. srv_->fakeReceive(discover);
  1734. // Server will now process to run its normal loop, but instead of calling
  1735. // IfaceMgr::receive6(), it will read all packets from the list set by
  1736. // fakeReceive()
  1737. // In particular, it should call registered pkt6_receive callback.
  1738. srv_->run();
  1739. // Check that the server dropped the packet and did not produce any response
  1740. ASSERT_EQ(0, srv_->fake_sent_.size());
  1741. }
  1742. // Checks if callouts installed on pkt4_receive are indeed called and the
  1743. // all necessary parameters are passed.
  1744. //
  1745. // Note that the test name does not follow test naming convention,
  1746. // but the proper hook name is "pkt4_receive".
  1747. TEST_F(HooksDhcpv4SrvTest, simple_pkt4_receive) {
  1748. // Install pkt4_receive_callout
  1749. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1750. "pkt4_receive", pkt4_receive_callout));
  1751. // Let's create a simple DISCOVER
  1752. Pkt4Ptr sol = generateSimpleDiscover();
  1753. // Simulate that we have received that traffic
  1754. srv_->fakeReceive(sol);
  1755. // Server will now process to run its normal loop, but instead of calling
  1756. // IfaceMgr::receive4(), it will read all packets from the list set by
  1757. // fakeReceive()
  1758. // In particular, it should call registered pkt4_receive callback.
  1759. srv_->run();
  1760. // check that the callback called is indeed the one we installed
  1761. EXPECT_EQ("pkt4_receive", callback_name_);
  1762. // check that pkt4 argument passing was successful and returned proper value
  1763. EXPECT_TRUE(callback_pkt4_.get() == sol.get());
  1764. // Check that all expected parameters are there
  1765. vector<string> expected_argument_names;
  1766. expected_argument_names.push_back(string("query4"));
  1767. EXPECT_TRUE(expected_argument_names == callback_argument_names_);
  1768. }
  1769. // Checks if callouts installed on pkt4_received is able to change
  1770. // the values and the parameters are indeed used by the server.
  1771. TEST_F(HooksDhcpv4SrvTest, valueChange_pkt4_receive) {
  1772. // Install pkt4_receive_callout
  1773. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1774. "pkt4_receive", pkt4_receive_change_clientid));
  1775. // Let's create a simple DISCOVER
  1776. Pkt4Ptr sol = generateSimpleDiscover();
  1777. // Simulate that we have received that traffic
  1778. srv_->fakeReceive(sol);
  1779. // Server will now process to run its normal loop, but instead of calling
  1780. // IfaceMgr::receive4(), it will read all packets from the list set by
  1781. // fakeReceive()
  1782. // In particular, it should call registered pkt4_receive callback.
  1783. srv_->run();
  1784. // check that the server did send a reposonce
  1785. ASSERT_EQ(1, srv_->fake_sent_.size());
  1786. // Make sure that we received a response
  1787. Pkt4Ptr adv = srv_->fake_sent_.front();
  1788. ASSERT_TRUE(adv);
  1789. // Get client-id...
  1790. OptionPtr clientid = adv->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
  1791. // ... and check if it is the modified value
  1792. OptionPtr expected = createOption(DHO_DHCP_CLIENT_IDENTIFIER);
  1793. EXPECT_TRUE(clientid->equal(expected));
  1794. }
  1795. // Checks if callouts installed on pkt4_received is able to delete
  1796. // existing options and that change impacts server processing (mandatory
  1797. // client-id option is deleted, so the packet is expected to be dropped)
  1798. TEST_F(HooksDhcpv4SrvTest, deleteClientId_pkt4_receive) {
  1799. // Install pkt4_receive_callout
  1800. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1801. "pkt4_receive", pkt4_receive_delete_clientid));
  1802. // Let's create a simple DISCOVER
  1803. Pkt4Ptr sol = generateSimpleDiscover();
  1804. // Simulate that we have received that traffic
  1805. srv_->fakeReceive(sol);
  1806. // Server will now process to run its normal loop, but instead of calling
  1807. // IfaceMgr::receive4(), it will read all packets from the list set by
  1808. // fakeReceive()
  1809. // In particular, it should call registered pkt4_receive callback.
  1810. srv_->run();
  1811. // Check that the server dropped the packet and did not send a response
  1812. ASSERT_EQ(0, srv_->fake_sent_.size());
  1813. }
  1814. // Checks if callouts installed on pkt4_received is able to set skip flag that
  1815. // will cause the server to not process the packet (drop), even though it is valid.
  1816. TEST_F(HooksDhcpv4SrvTest, skip_pkt4_receive) {
  1817. // Install pkt4_receive_callout
  1818. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1819. "pkt4_receive", pkt4_receive_skip));
  1820. // Let's create a simple DISCOVER
  1821. Pkt4Ptr sol = generateSimpleDiscover();
  1822. // Simulate that we have received that traffic
  1823. srv_->fakeReceive(sol);
  1824. // Server will now process to run its normal loop, but instead of calling
  1825. // IfaceMgr::receive4(), it will read all packets from the list set by
  1826. // fakeReceive()
  1827. // In particular, it should call registered pkt4_receive callback.
  1828. srv_->run();
  1829. // check that the server dropped the packet and did not produce any response
  1830. ASSERT_EQ(0, srv_->fake_sent_.size());
  1831. }
  1832. // Checks if callouts installed on pkt4_send are indeed called and the
  1833. // all necessary parameters are passed.
  1834. TEST_F(HooksDhcpv4SrvTest, simple_pkt4_send) {
  1835. // Install pkt4_receive_callout
  1836. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1837. "pkt4_send", pkt4_send_callout));
  1838. // Let's create a simple DISCOVER
  1839. Pkt4Ptr sol = generateSimpleDiscover();
  1840. // Simulate that we have received that traffic
  1841. srv_->fakeReceive(sol);
  1842. // Server will now process to run its normal loop, but instead of calling
  1843. // IfaceMgr::receive4(), it will read all packets from the list set by
  1844. // fakeReceive()
  1845. // In particular, it should call registered pkt4_receive callback.
  1846. srv_->run();
  1847. // Check that the callback called is indeed the one we installed
  1848. EXPECT_EQ("pkt4_send", callback_name_);
  1849. // Check that there is one packet sent
  1850. ASSERT_EQ(1, srv_->fake_sent_.size());
  1851. Pkt4Ptr adv = srv_->fake_sent_.front();
  1852. // Check that pkt4 argument passing was successful and returned proper value
  1853. EXPECT_TRUE(callback_pkt4_.get() == adv.get());
  1854. // Check that all expected parameters are there
  1855. vector<string> expected_argument_names;
  1856. expected_argument_names.push_back(string("response4"));
  1857. EXPECT_TRUE(expected_argument_names == callback_argument_names_);
  1858. }
  1859. // Checks if callouts installed on pkt4_send is able to change
  1860. // the values and the packet sent contains those changes
  1861. TEST_F(HooksDhcpv4SrvTest, valueChange_pkt4_send) {
  1862. // Install pkt4_receive_callout
  1863. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1864. "pkt4_send", pkt4_send_change_serverid));
  1865. // Let's create a simple DISCOVER
  1866. Pkt4Ptr sol = generateSimpleDiscover();
  1867. // Simulate that we have received that traffic
  1868. srv_->fakeReceive(sol);
  1869. // Server will now process to run its normal loop, but instead of calling
  1870. // IfaceMgr::receive4(), it will read all packets from the list set by
  1871. // fakeReceive()
  1872. // In particular, it should call registered pkt4_receive callback.
  1873. srv_->run();
  1874. // check that the server did send a reposonce
  1875. ASSERT_EQ(1, srv_->fake_sent_.size());
  1876. // Make sure that we received a response
  1877. Pkt4Ptr adv = srv_->fake_sent_.front();
  1878. ASSERT_TRUE(adv);
  1879. // Get client-id...
  1880. OptionPtr clientid = adv->getOption(DHO_DHCP_SERVER_IDENTIFIER);
  1881. // ... and check if it is the modified value
  1882. OptionPtr expected = createOption(DHO_DHCP_SERVER_IDENTIFIER);
  1883. EXPECT_TRUE(clientid->equal(expected));
  1884. }
  1885. // Checks if callouts installed on pkt4_send is able to delete
  1886. // existing options and that server applies those changes. In particular,
  1887. // we are trying to send a packet without server-id. The packet should
  1888. // be sent
  1889. TEST_F(HooksDhcpv4SrvTest, deleteServerId_pkt4_send) {
  1890. // Install pkt4_receive_callout
  1891. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1892. "pkt4_send", pkt4_send_delete_serverid));
  1893. // Let's create a simple DISCOVER
  1894. Pkt4Ptr sol = generateSimpleDiscover();
  1895. // Simulate that we have received that traffic
  1896. srv_->fakeReceive(sol);
  1897. // Server will now process to run its normal loop, but instead of calling
  1898. // IfaceMgr::receive4(), it will read all packets from the list set by
  1899. // fakeReceive()
  1900. // In particular, it should call registered pkt4_receive callback.
  1901. srv_->run();
  1902. // Check that the server indeed sent a malformed ADVERTISE
  1903. ASSERT_EQ(1, srv_->fake_sent_.size());
  1904. // Get that ADVERTISE
  1905. Pkt4Ptr adv = srv_->fake_sent_.front();
  1906. ASSERT_TRUE(adv);
  1907. // Make sure that it does not have server-id
  1908. EXPECT_FALSE(adv->getOption(DHO_DHCP_SERVER_IDENTIFIER));
  1909. }
  1910. // Checks if callouts installed on pkt4_skip is able to set skip flag that
  1911. // will cause the server to not process the packet (drop), even though it is valid.
  1912. TEST_F(HooksDhcpv4SrvTest, skip_pkt4_send) {
  1913. // Install pkt4_receive_callout
  1914. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1915. "pkt4_send", pkt4_send_skip));
  1916. // Let's create a simple REQUEST
  1917. Pkt4Ptr sol = generateSimpleDiscover();
  1918. // Simulate that we have received that traffic
  1919. srv_->fakeReceive(sol);
  1920. // Server will now process to run its normal loop, but instead of calling
  1921. // IfaceMgr::receive4(), it will read all packets from the list set by
  1922. // fakeReceive()
  1923. // In particular, it should call registered pkt4_receive callback.
  1924. srv_->run();
  1925. // check that the server dropped the packet and did not produce any response
  1926. ASSERT_EQ(0, srv_->fake_sent_.size());
  1927. }
  1928. // This test checks if subnet4_select callout is triggered and reports
  1929. // valid parameters
  1930. TEST_F(HooksDhcpv4SrvTest, subnet4_select) {
  1931. // Install pkt4_receive_callout
  1932. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1933. "subnet4_select", subnet4_select_callout));
  1934. // Configure 2 subnets, both directly reachable over local interface
  1935. // (let's not complicate the matter with relays)
  1936. string config = "{ \"interfaces\": [ \"*\" ],"
  1937. "\"rebind-timer\": 2000, "
  1938. "\"renew-timer\": 1000, "
  1939. "\"subnet4\": [ { "
  1940. " \"pool\": [ \"192.0.2.0/25\" ],"
  1941. " \"subnet\": \"192.0.2.0/24\", "
  1942. " \"interface\": \"" + valid_iface_ + "\" "
  1943. " }, {"
  1944. " \"pool\": [ \"192.0.3.0/25\" ],"
  1945. " \"subnet\": \"192.0.3.0/24\" "
  1946. " } ],"
  1947. "\"valid-lifetime\": 4000 }";
  1948. ElementPtr json = Element::fromJSON(config);
  1949. ConstElementPtr status;
  1950. // Configure the server and make sure the config is accepted
  1951. EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
  1952. ASSERT_TRUE(status);
  1953. comment_ = config::parseAnswer(rcode_, status);
  1954. ASSERT_EQ(0, rcode_);
  1955. // Prepare discover packet. Server should select first subnet for it
  1956. Pkt4Ptr sol = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
  1957. sol->setRemoteAddr(IOAddress("192.0.2.1"));
  1958. sol->setIface(valid_iface_);
  1959. OptionPtr clientid = generateClientId();
  1960. sol->addOption(clientid);
  1961. // Pass it to the server and get an advertise
  1962. Pkt4Ptr adv = srv_->processDiscover(sol);
  1963. // check if we get response at all
  1964. ASSERT_TRUE(adv);
  1965. // Check that the callback called is indeed the one we installed
  1966. EXPECT_EQ("subnet4_select", callback_name_);
  1967. // Check that pkt4 argument passing was successful and returned proper value
  1968. EXPECT_TRUE(callback_pkt4_.get() == sol.get());
  1969. const Subnet4Collection* exp_subnets = CfgMgr::instance().getSubnets4();
  1970. // The server is supposed to pick the first subnet, because of matching
  1971. // interface. Check that the value is reported properly.
  1972. ASSERT_TRUE(callback_subnet4_);
  1973. EXPECT_EQ(exp_subnets->front().get(), callback_subnet4_.get());
  1974. // Server is supposed to report two subnets
  1975. ASSERT_EQ(exp_subnets->size(), callback_subnet4collection_->size());
  1976. // Compare that the available subnets are reported as expected
  1977. EXPECT_TRUE((*exp_subnets)[0].get() == (*callback_subnet4collection_)[0].get());
  1978. EXPECT_TRUE((*exp_subnets)[1].get() == (*callback_subnet4collection_)[1].get());
  1979. }
  1980. // This test checks if callout installed on subnet4_select hook point can pick
  1981. // a different subnet.
  1982. TEST_F(HooksDhcpv4SrvTest, subnet_select_change) {
  1983. // Install pkt4_receive_callout
  1984. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1985. "subnet4_select", subnet4_select_different_subnet_callout));
  1986. // Configure 2 subnets, both directly reachable over local interface
  1987. // (let's not complicate the matter with relays)
  1988. string config = "{ \"interfaces\": [ \"*\" ],"
  1989. "\"rebind-timer\": 2000, "
  1990. "\"renew-timer\": 1000, "
  1991. "\"subnet4\": [ { "
  1992. " \"pool\": [ \"192.0.2.0/25\" ],"
  1993. " \"subnet\": \"192.0.2.0/24\", "
  1994. " \"interface\": \"" + valid_iface_ + "\" "
  1995. " }, {"
  1996. " \"pool\": [ \"192.0.3.0/25\" ],"
  1997. " \"subnet\": \"192.0.3.0/24\" "
  1998. " } ],"
  1999. "\"valid-lifetime\": 4000 }";
  2000. ElementPtr json = Element::fromJSON(config);
  2001. ConstElementPtr status;
  2002. // Configure the server and make sure the config is accepted
  2003. EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
  2004. ASSERT_TRUE(status);
  2005. comment_ = config::parseAnswer(rcode_, status);
  2006. ASSERT_EQ(0, rcode_);
  2007. // Prepare discover packet. Server should select first subnet for it
  2008. Pkt4Ptr sol = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
  2009. sol->setRemoteAddr(IOAddress("192.0.2.1"));
  2010. sol->setIface(valid_iface_);
  2011. OptionPtr clientid = generateClientId();
  2012. sol->addOption(clientid);
  2013. // Pass it to the server and get an advertise
  2014. Pkt4Ptr adv = srv_->processDiscover(sol);
  2015. // check if we get response at all
  2016. ASSERT_TRUE(adv);
  2017. // The response should have an address from second pool, so let's check it
  2018. IOAddress addr = adv->getYiaddr();
  2019. EXPECT_NE("0.0.0.0", addr.toText());
  2020. // Get all subnets and use second subnet for verification
  2021. const Subnet4Collection* subnets = CfgMgr::instance().getSubnets4();
  2022. ASSERT_EQ(2, subnets->size());
  2023. // Advertised address must belong to the second pool (in subnet's range,
  2024. // in dynamic pool)
  2025. EXPECT_TRUE((*subnets)[1]->inRange(addr));
  2026. EXPECT_TRUE((*subnets)[1]->inPool(addr));
  2027. }
  2028. } // end of anonymous namespace