dhcp4_srv_unittest.cc 85 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348
  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. subnet_ = Subnet4Ptr(new Subnet4(IOAddress("192.0.2.0"), 24, 1000,
  171. 2000, 3000));
  172. pool_ = Pool4Ptr(new Pool4(IOAddress("192.0.2.100"), IOAddress("192.0.2.110")));
  173. subnet_->addPool(pool_);
  174. CfgMgr::instance().deleteSubnets4();
  175. CfgMgr::instance().addSubnet4(subnet_);
  176. // Add Router option.
  177. Option4AddrLstPtr opt_routers(new Option4AddrLst(DHO_ROUTERS));
  178. opt_routers->setAddress(IOAddress("192.0.2.2"));
  179. subnet_->addOption(opt_routers, false, "dhcp4");
  180. // it's ok if that fails. There should not be such a file anyway
  181. unlink(SRVID_FILE);
  182. const IfaceMgr::IfaceCollection& ifaces = IfaceMgr::instance().getIfaces();
  183. // There must be some interface detected
  184. if (ifaces.empty()) {
  185. // We can't use ASSERT in constructor
  186. ADD_FAILURE() << "No interfaces detected.";
  187. }
  188. valid_iface_ = ifaces.begin()->getName();
  189. }
  190. virtual ~Dhcpv4SrvTest() {
  191. }
  192. /// @brief Add 'Parameter Request List' option to the packet.
  193. ///
  194. /// This function PRL option comprising the following option codes:
  195. /// - 5 - Name Server
  196. /// - 15 - Domain Name
  197. /// - 7 - Log Server
  198. /// - 8 - Quotes Server
  199. /// - 9 - LPR Server
  200. ///
  201. /// @param pkt packet to add PRL option to.
  202. void addPrlOption(Pkt4Ptr& pkt) {
  203. OptionUint8ArrayPtr option_prl =
  204. OptionUint8ArrayPtr(new OptionUint8Array(Option::V4,
  205. DHO_DHCP_PARAMETER_REQUEST_LIST));
  206. // Let's request options that have been configured for the subnet.
  207. option_prl->addValue(DHO_DOMAIN_NAME_SERVERS);
  208. option_prl->addValue(DHO_DOMAIN_NAME);
  209. option_prl->addValue(DHO_LOG_SERVERS);
  210. option_prl->addValue(DHO_COOKIE_SERVERS);
  211. // Let's also request the option that hasn't been configured. In such
  212. // case server should ignore request for this particular option.
  213. option_prl->addValue(DHO_LPR_SERVERS);
  214. // And add 'Parameter Request List' option into the DISCOVER packet.
  215. pkt->addOption(option_prl);
  216. }
  217. /// @brief Configures options being requested in the PRL option.
  218. ///
  219. /// The lpr-servers option is NOT configured here although it is
  220. /// added to the 'Parameter Request List' option in the
  221. /// \ref addPrlOption. When requested option is not configured
  222. /// the server should not return it in its response. The goal
  223. /// of not configuring the requested option is to verify that
  224. /// the server will not return it.
  225. void configureRequestedOptions() {
  226. // dns-servers
  227. Option4AddrLstPtr
  228. option_dns_servers(new Option4AddrLst(DHO_DOMAIN_NAME_SERVERS));
  229. option_dns_servers->addAddress(IOAddress("192.0.2.1"));
  230. option_dns_servers->addAddress(IOAddress("192.0.2.100"));
  231. ASSERT_NO_THROW(subnet_->addOption(option_dns_servers, false, "dhcp4"));
  232. // domain-name
  233. OptionDefinition def("domain-name", DHO_DOMAIN_NAME, OPT_FQDN_TYPE);
  234. OptionCustomPtr option_domain_name(new OptionCustom(def, Option::V4));
  235. option_domain_name->writeFqdn("example.com");
  236. subnet_->addOption(option_domain_name, false, "dhcp4");
  237. // log-servers
  238. Option4AddrLstPtr option_log_servers(new Option4AddrLst(DHO_LOG_SERVERS));
  239. option_log_servers->addAddress(IOAddress("192.0.2.2"));
  240. option_log_servers->addAddress(IOAddress("192.0.2.10"));
  241. ASSERT_NO_THROW(subnet_->addOption(option_log_servers, false, "dhcp4"));
  242. // cookie-servers
  243. Option4AddrLstPtr option_cookie_servers(new Option4AddrLst(DHO_COOKIE_SERVERS));
  244. option_cookie_servers->addAddress(IOAddress("192.0.2.1"));
  245. ASSERT_NO_THROW(subnet_->addOption(option_cookie_servers, false, "dhcp4"));
  246. }
  247. /// @brief checks that the response matches request
  248. /// @param q query (client's message)
  249. /// @param a answer (server's message)
  250. void messageCheck(const Pkt4Ptr& q, const Pkt4Ptr& a) {
  251. ASSERT_TRUE(q);
  252. ASSERT_TRUE(a);
  253. EXPECT_EQ(q->getHops(), a->getHops());
  254. EXPECT_EQ(q->getIface(), a->getIface());
  255. EXPECT_EQ(q->getIndex(), a->getIndex());
  256. EXPECT_EQ(q->getGiaddr(), a->getGiaddr());
  257. // When processing an incoming packet the remote address
  258. // is copied as a src address, and the source address is
  259. // copied as a remote address to the response.
  260. EXPECT_TRUE(q->getLocalHWAddr() == a->getLocalHWAddr());
  261. EXPECT_TRUE(q->getRemoteHWAddr() == a->getRemoteHWAddr());
  262. // Check that bare minimum of required options are there.
  263. // We don't check options requested by a client. Those
  264. // are checked elsewhere.
  265. EXPECT_TRUE(a->getOption(DHO_SUBNET_MASK));
  266. EXPECT_TRUE(a->getOption(DHO_ROUTERS));
  267. EXPECT_TRUE(a->getOption(DHO_DHCP_SERVER_IDENTIFIER));
  268. EXPECT_TRUE(a->getOption(DHO_DHCP_LEASE_TIME));
  269. EXPECT_TRUE(a->getOption(DHO_SUBNET_MASK));
  270. EXPECT_TRUE(a->getOption(DHO_DOMAIN_NAME));
  271. EXPECT_TRUE(a->getOption(DHO_DOMAIN_NAME_SERVERS));
  272. // Check that something is offered
  273. EXPECT_TRUE(a->getYiaddr().toText() != "0.0.0.0");
  274. }
  275. /// @brief Check that requested options are present.
  276. ///
  277. /// @param pkt packet to be checked.
  278. void optionsCheck(const Pkt4Ptr& pkt) {
  279. // Check that the requested and configured options are returned
  280. // in the ACK message.
  281. EXPECT_TRUE(pkt->getOption(DHO_DOMAIN_NAME))
  282. << "domain-name not present in the response";
  283. EXPECT_TRUE(pkt->getOption(DHO_DOMAIN_NAME_SERVERS))
  284. << "dns-servers not present in the response";
  285. EXPECT_TRUE(pkt->getOption(DHO_LOG_SERVERS))
  286. << "log-servers not present in the response";
  287. EXPECT_TRUE(pkt->getOption(DHO_COOKIE_SERVERS))
  288. << "cookie-servers not present in the response";
  289. // Check that the requested but not configured options are not
  290. // returned in the ACK message.
  291. EXPECT_FALSE(pkt->getOption(DHO_LPR_SERVERS))
  292. << "domain-name present in the response but it is"
  293. << " expected not to be present";
  294. }
  295. /// @brief generates client-id option
  296. ///
  297. /// Generate client-id option of specified length
  298. /// Ids with different lengths are sufficent to generate
  299. /// unique ids. If more fine grained control is required,
  300. /// tests generate client-ids on their own.
  301. /// Sets client_id_ field.
  302. /// @param size size of the client-id to be generated
  303. OptionPtr generateClientId(size_t size = 4) {
  304. OptionBuffer clnt_id(size);
  305. for (int i = 0; i < size; i++) {
  306. clnt_id[i] = 100 + i;
  307. }
  308. client_id_ = ClientIdPtr(new ClientId(clnt_id));
  309. return (OptionPtr(new Option(Option::V4, DHO_DHCP_CLIENT_IDENTIFIER,
  310. clnt_id.begin(),
  311. clnt_id.begin() + size)));
  312. }
  313. /// @brief generate hardware address
  314. ///
  315. /// @param size size of the generated MAC address
  316. /// @param pointer to Hardware Address object
  317. HWAddrPtr generateHWAddr(size_t size = 6) {
  318. const uint8_t hw_type = 123; // Just a fake number (typically 6=HTYPE_ETHER, see dhcp4.h)
  319. OptionBuffer mac(size);
  320. for (int i = 0; i < size; ++i) {
  321. mac[i] = 50 + i;
  322. }
  323. return (HWAddrPtr(new HWAddr(mac, hw_type)));
  324. }
  325. /// Check that address was returned from proper range, that its lease
  326. /// lifetime is correct, that T1 and T2 are returned properly
  327. /// @param rsp response to be checked
  328. /// @param subnet subnet that should be used to verify assigned address
  329. /// and options
  330. /// @param t1_mandatory is T1 mandatory?
  331. /// @param t2_mandatory is T2 mandatory?
  332. void checkAddressParams(const Pkt4Ptr& rsp, const SubnetPtr subnet,
  333. bool t1_mandatory = false,
  334. bool t2_mandatory = false) {
  335. // Technically inPool implies inRange, but let's be on the safe
  336. // side and check both.
  337. EXPECT_TRUE(subnet->inRange(rsp->getYiaddr()));
  338. EXPECT_TRUE(subnet->inPool(rsp->getYiaddr()));
  339. // Check lease time
  340. OptionPtr opt = rsp->getOption(DHO_DHCP_LEASE_TIME);
  341. if (!opt) {
  342. ADD_FAILURE() << "Lease time option missing in response";
  343. } else {
  344. EXPECT_EQ(opt->getUint32(), subnet->getValid());
  345. }
  346. // Check T1 timer
  347. opt = rsp->getOption(DHO_DHCP_RENEWAL_TIME);
  348. if (opt) {
  349. EXPECT_EQ(opt->getUint32(), subnet->getT1());
  350. } else {
  351. if (t1_mandatory) {
  352. ADD_FAILURE() << "Required T1 option missing";
  353. }
  354. }
  355. // Check T2 timer
  356. opt = rsp->getOption(DHO_DHCP_REBINDING_TIME);
  357. if (opt) {
  358. EXPECT_EQ(opt->getUint32(), subnet->getT2());
  359. } else {
  360. if (t2_mandatory) {
  361. ADD_FAILURE() << "Required T2 option missing";
  362. }
  363. }
  364. }
  365. /// @brief Basic checks for generated response (message type and trans-id).
  366. ///
  367. /// @param rsp response packet to be validated
  368. /// @param expected_message_type expected message type
  369. /// @param expected_transid expected transaction-id
  370. void checkResponse(const Pkt4Ptr& rsp, uint8_t expected_message_type,
  371. uint32_t expected_transid) {
  372. ASSERT_TRUE(rsp);
  373. EXPECT_EQ(expected_message_type, rsp->getType());
  374. EXPECT_EQ(expected_transid, rsp->getTransid());
  375. }
  376. /// @brief Checks if the lease sent to client is present in the database
  377. ///
  378. /// @param rsp response packet to be validated
  379. /// @param client_id expected client-identifier (or NULL)
  380. /// @param HWAddr expected hardware address (not used now)
  381. /// @param expected_addr expected address
  382. Lease4Ptr checkLease(const Pkt4Ptr& rsp, const OptionPtr& client_id,
  383. const HWAddrPtr&, const IOAddress& expected_addr) {
  384. ClientIdPtr id;
  385. if (client_id) {
  386. OptionBuffer data = client_id->getData();
  387. id.reset(new ClientId(data));
  388. }
  389. Lease4Ptr lease = LeaseMgrFactory::instance().getLease4(expected_addr);
  390. if (!lease) {
  391. cout << "Lease for " << expected_addr.toText()
  392. << " not found in the database backend.";
  393. return (Lease4Ptr());
  394. }
  395. EXPECT_EQ(rsp->getYiaddr().toText(), expected_addr.toText());
  396. EXPECT_EQ(expected_addr.toText(), lease->addr_.toText());
  397. if (client_id) {
  398. EXPECT_TRUE(*lease->client_id_ == *id);
  399. }
  400. EXPECT_EQ(subnet_->getID(), lease->subnet_id_);
  401. return (lease);
  402. }
  403. /// @brief Checks if server response (OFFER, ACK, NAK) includes proper server-id
  404. /// @param rsp response packet to be validated
  405. /// @param expected_srvid expected value of server-id
  406. void checkServerId(const Pkt4Ptr& rsp, const OptionPtr& expected_srvid) {
  407. // Check that server included its server-id
  408. OptionPtr opt = rsp->getOption(DHO_DHCP_SERVER_IDENTIFIER);
  409. ASSERT_TRUE(opt);
  410. EXPECT_EQ(opt->getType(), expected_srvid->getType() );
  411. EXPECT_EQ(opt->len(), expected_srvid->len() );
  412. EXPECT_TRUE(opt->getData() == expected_srvid->getData());
  413. }
  414. /// @brief Checks if server response (OFFER, ACK, NAK) includes proper client-id
  415. /// @param rsp response packet to be validated
  416. /// @param expected_clientid expected value of client-id
  417. void checkClientId(const Pkt4Ptr& rsp, const OptionPtr& expected_clientid) {
  418. // check that server included our own client-id
  419. OptionPtr opt = rsp->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
  420. ASSERT_TRUE(opt);
  421. EXPECT_EQ(expected_clientid->getType(), opt->getType());
  422. EXPECT_EQ(expected_clientid->len(), opt->len());
  423. EXPECT_TRUE(expected_clientid->getData() == opt->getData());
  424. }
  425. /// @brief Tests if Discover or Request message is processed correctly
  426. ///
  427. /// @param msg_type DHCPDISCOVER or DHCPREQUEST
  428. void testDiscoverRequest(const uint8_t msg_type) {
  429. // Create an instance of the tested class.
  430. boost::scoped_ptr<NakedDhcpv4Srv> srv(new NakedDhcpv4Srv(0));
  431. // Initialize the source HW address.
  432. vector<uint8_t> mac(6);
  433. for (int i = 0; i < 6; ++i) {
  434. mac[i] = i * 10;
  435. }
  436. // Initialized the destination HW address.
  437. vector<uint8_t> dst_mac(6);
  438. for (int i = 0; i < 6; ++i) {
  439. dst_mac[i] = i * 20;
  440. }
  441. // Create a DHCP message. It will be used to simulate the
  442. // incoming message.
  443. boost::shared_ptr<Pkt4> req(new Pkt4(msg_type, 1234));
  444. // Create a response message. It will hold a reponse packet.
  445. // Initially, set it to NULL.
  446. boost::shared_ptr<Pkt4> rsp;
  447. // Set the name of the interface on which packet is received.
  448. req->setIface("eth0");
  449. // Set the interface index. It is just a dummy value and will
  450. // not be interpreted.
  451. req->setIndex(17);
  452. // Set the target HW address. This value is normally used to
  453. // construct the data link layer header.
  454. req->setRemoteHWAddr(1, 6, dst_mac);
  455. // Set the HW address. This value is set on DHCP level (in chaddr).
  456. req->setHWAddr(1, 6, mac);
  457. // Set local HW address. It is used to construct the data link layer
  458. // header.
  459. req->setLocalHWAddr(1, 6, mac);
  460. // Set target IP address.
  461. req->setRemoteAddr(IOAddress("192.0.2.55"));
  462. // Set relay address.
  463. req->setGiaddr(IOAddress("192.0.2.10"));
  464. // We are going to test that certain options are returned
  465. // in the response message when requested using 'Parameter
  466. // Request List' option. Let's configure those options that
  467. // are returned when requested.
  468. configureRequestedOptions();
  469. if (msg_type == DHCPDISCOVER) {
  470. ASSERT_NO_THROW(
  471. rsp = srv->processDiscover(req);
  472. );
  473. // Should return OFFER
  474. ASSERT_TRUE(rsp);
  475. EXPECT_EQ(DHCPOFFER, rsp->getType());
  476. } else {
  477. ASSERT_NO_THROW(
  478. rsp = srv->processRequest(req);
  479. );
  480. // Should return ACK
  481. ASSERT_TRUE(rsp);
  482. EXPECT_EQ(DHCPACK, rsp->getType());
  483. }
  484. messageCheck(req, rsp);
  485. // We did not request any options so these should not be present
  486. // in the RSP.
  487. EXPECT_FALSE(rsp->getOption(DHO_LOG_SERVERS));
  488. EXPECT_FALSE(rsp->getOption(DHO_COOKIE_SERVERS));
  489. EXPECT_FALSE(rsp->getOption(DHO_LPR_SERVERS));
  490. // Repeat the test but request some options.
  491. // Add 'Parameter Request List' option.
  492. addPrlOption(req);
  493. if (msg_type == DHCPDISCOVER) {
  494. ASSERT_NO_THROW(
  495. rsp = srv->processDiscover(req);
  496. );
  497. // Should return non-NULL packet.
  498. ASSERT_TRUE(rsp);
  499. EXPECT_EQ(DHCPOFFER, rsp->getType());
  500. } else {
  501. ASSERT_NO_THROW(
  502. rsp = srv->processRequest(req);
  503. );
  504. // Should return non-NULL packet.
  505. ASSERT_TRUE(rsp);
  506. EXPECT_EQ(DHCPACK, rsp->getType());
  507. }
  508. // Check that the requested options are returned.
  509. optionsCheck(rsp);
  510. }
  511. /// @brief This function cleans up after the test.
  512. virtual void TearDown() {
  513. CfgMgr::instance().deleteSubnets4();
  514. // Let's clean up if there is such a file.
  515. unlink(SRVID_FILE);
  516. // Close all open sockets.
  517. IfaceMgr::instance().closeSockets();
  518. // Some unit tests override the default packet filtering class, used
  519. // by the IfaceMgr. The dummy class, called PktFilterTest, reports the
  520. // capability to directly respond to the clients without IP address
  521. // assigned. This capability is not supported by the default packet
  522. // filtering class: PktFilterInet. Therefore setting the dummy class
  523. // allows to test scenarios, when server responds to the broadcast address
  524. // on client's request, despite having support for direct response.
  525. // The following call restores the use of original packet filtering class
  526. // after the test.
  527. try {
  528. IfaceMgr::instance().setPacketFilter(PktFilterPtr(new PktFilterInet()));
  529. } catch (const Exception& ex) {
  530. FAIL() << "Failed to restore the default (PktFilterInet) packet filtering"
  531. << " class after the test. Exception has been caught: "
  532. << ex.what();
  533. }
  534. }
  535. /// @brief A subnet used in most tests
  536. Subnet4Ptr subnet_;
  537. /// @brief A pool used in most tests
  538. Pool4Ptr pool_;
  539. /// @brief A client-id used in most tests
  540. ClientIdPtr client_id_;
  541. int rcode_;
  542. ConstElementPtr comment_;
  543. // Name of a valid network interface
  544. string valid_iface_;
  545. };
  546. // Sanity check. Verifies that both Dhcpv4Srv and its derived
  547. // class NakedDhcpv4Srv can be instantiated and destroyed.
  548. TEST_F(Dhcpv4SrvTest, basic) {
  549. // Check that the base class can be instantiated
  550. boost::scoped_ptr<Dhcpv4Srv> srv;
  551. ASSERT_NO_THROW(srv.reset(new Dhcpv4Srv(DHCP4_SERVER_PORT + 10000, "type=memfile",
  552. false, false)));
  553. srv.reset();
  554. // We have to close open sockets because further in this test we will
  555. // call the Dhcpv4Srv constructor again. This constructor will try to
  556. // set the appropriate packet filter class for IfaceMgr. This requires
  557. // that all sockets are closed.
  558. IfaceMgr::instance().closeSockets();
  559. // Check that the derived class can be instantiated
  560. boost::scoped_ptr<NakedDhcpv4Srv> naked_srv;
  561. ASSERT_NO_THROW(
  562. naked_srv.reset(new NakedDhcpv4Srv(DHCP4_SERVER_PORT + 10000)));
  563. EXPECT_TRUE(naked_srv->getServerID());
  564. // Close sockets again for the next test.
  565. IfaceMgr::instance().closeSockets();
  566. ASSERT_NO_THROW(naked_srv.reset(new NakedDhcpv4Srv(0)));
  567. EXPECT_TRUE(naked_srv->getServerID());
  568. }
  569. // This test verifies that the destination address of the response
  570. // message is set to giaddr, when giaddr is set to non-zero address
  571. // in the received message.
  572. TEST_F(Dhcpv4SrvTest, adjustRemoteAddressRelay) {
  573. boost::scoped_ptr<NakedDhcpv4Srv> srv(new NakedDhcpv4Srv(0));
  574. // Create the instance of the incoming packet.
  575. boost::shared_ptr<Pkt4> req(new Pkt4(DHCPDISCOVER, 1234));
  576. // Set the giaddr to non-zero address as if it was relayed.
  577. req->setGiaddr(IOAddress("192.0.2.1"));
  578. // Set ciaddr to zero. This simulates the client which applies
  579. // for the new lease.
  580. req->setCiaddr(IOAddress("0.0.0.0"));
  581. // Clear broadcast flag.
  582. req->setFlags(0x0000);
  583. // Create a response packet. Assume that the new lease have
  584. // been created and new address allocated. This address is
  585. // stored in yiaddr field.
  586. boost::shared_ptr<Pkt4> resp(new Pkt4(DHCPOFFER, 1234));
  587. resp->setYiaddr(IOAddress("192.0.2.100"));
  588. // Clear the remote address.
  589. resp->setRemoteAddr(IOAddress("0.0.0.0"));
  590. // This function never throws.
  591. ASSERT_NO_THROW(srv->adjustRemoteAddr(req, resp));
  592. // Now the destination address should be relay's address.
  593. EXPECT_EQ("192.0.2.1", resp->getRemoteAddr().toText());
  594. // Let's do another test and set other fields: ciaddr and
  595. // flags. By doing it, we want to make sure that the relay
  596. // address will take precedence.
  597. req->setGiaddr(IOAddress("192.0.2.50"));
  598. req->setCiaddr(IOAddress("192.0.2.11"));
  599. req->setFlags(Pkt4::FLAG_BROADCAST_MASK);
  600. resp->setYiaddr(IOAddress("192.0.2.100"));
  601. // Clear remote address.
  602. resp->setRemoteAddr(IOAddress("0.0.0.0"));
  603. ASSERT_NO_THROW(srv->adjustRemoteAddr(req, resp));
  604. // Response should be sent back to the relay address.
  605. EXPECT_EQ("192.0.2.50", resp->getRemoteAddr().toText());
  606. }
  607. // This test verifies that the destination address of the response message
  608. // is set to ciaddr when giaddr is set to zero and the ciaddr is set to
  609. // non-zero address in the received message. This is the case when the
  610. // client is in Renew or Rebind state.
  611. TEST_F(Dhcpv4SrvTest, adjustRemoteAddressRenewRebind) {
  612. boost::scoped_ptr<NakedDhcpv4Srv> srv(new NakedDhcpv4Srv(0));
  613. // Create instance of the incoming packet.
  614. boost::shared_ptr<Pkt4> req(new Pkt4(DHCPDISCOVER, 1234));
  615. // Clear giaddr to simulate direct packet.
  616. req->setGiaddr(IOAddress("0.0.0.0"));
  617. // Set ciaddr to non-zero address. The response should be sent to this
  618. // address as the client is in renewing or rebinding state (it is fully
  619. // configured).
  620. req->setCiaddr(IOAddress("192.0.2.15"));
  621. // Let's configure broadcast flag. It should be ignored because
  622. // we are responding directly to the client having an address
  623. // and trying to extend his lease. Broadcast flag is only used
  624. // when new lease is acquired and server must make a decision
  625. // whether to unicast the response to the acquired address or
  626. // broadcast it.
  627. req->setFlags(Pkt4::FLAG_BROADCAST_MASK);
  628. // Create a response.
  629. boost::shared_ptr<Pkt4> resp(new Pkt4(DHCPOFFER, 1234));
  630. // Let's extend the lease for the client in such a way that
  631. // it will actually get different address. The response
  632. // should not be sent to this address but rather to ciaddr
  633. // as client still have ciaddr configured.
  634. resp->setYiaddr(IOAddress("192.0.2.13"));
  635. // Clear the remote address.
  636. resp->setRemoteAddr(IOAddress("0.0.0.0"));
  637. ASSERT_NO_THROW(srv->adjustRemoteAddr(req, resp));
  638. // Check that server responds to ciaddr
  639. EXPECT_EQ("192.0.2.15", resp->getRemoteAddr().toText());
  640. }
  641. // This test verifies that the destination address of the response message
  642. // is set correctly when giaddr and ciaddr is zeroed in the received message
  643. // and the new lease is acquired. The lease address is carried in the
  644. // response message in the yiaddr field. In this case destination address
  645. // of the response should be set to yiaddr if server supports direct responses
  646. // to the client which doesn't have an address yet or broadcast if the server
  647. // doesn't support direct responses.
  648. TEST_F(Dhcpv4SrvTest, adjustRemoteAddressSelect) {
  649. boost::scoped_ptr<NakedDhcpv4Srv> srv(new NakedDhcpv4Srv(0));
  650. // Create instance of the incoming packet.
  651. boost::shared_ptr<Pkt4> req(new Pkt4(DHCPDISCOVER, 1234));
  652. // Clear giaddr to simulate direct packet.
  653. req->setGiaddr(IOAddress("0.0.0.0"));
  654. // Clear client address as it hasn't got any address configured yet.
  655. req->setCiaddr(IOAddress("0.0.0.0"));
  656. // Let's clear the broadcast flag.
  657. req->setFlags(0);
  658. // Create a response.
  659. boost::shared_ptr<Pkt4> resp(new Pkt4(DHCPOFFER, 1234));
  660. // Assign some new address for this client.
  661. resp->setYiaddr(IOAddress("192.0.2.13"));
  662. // Clear the remote address.
  663. resp->setRemoteAddr(IOAddress("0.0.0.0"));
  664. // When running unit tests, the IfaceMgr is using the default Packet
  665. // Filtering class, PktFilterInet. This class does not support direct
  666. // responses to clients without address assigned. When giaddr and ciaddr
  667. // are zero and client has just got new lease, the assigned address is
  668. // carried in yiaddr. In order to send this address to the client,
  669. // server must broadcast its response.
  670. ASSERT_NO_THROW(srv->adjustRemoteAddr(req, resp));
  671. // Check that the response is sent to broadcast address as the
  672. // server doesn't have capability to respond directly.
  673. EXPECT_EQ("255.255.255.255", resp->getRemoteAddr().toText());
  674. // We also want to test the case when the server has capability to
  675. // respond directly to the client which is not configured. Server
  676. // makes decision whether it responds directly or broadcast its
  677. // response based on the capability reported by IfaceMgr. In order
  678. // to set this capability we have to provide a dummy Packet Filter
  679. // class which would report the support for direct responses.
  680. // This class is called PktFilterTest.
  681. IfaceMgr::instance().setPacketFilter(PktFilterPtr(new PktFilterTest()));
  682. // Now we expect that the server will send its response to the
  683. // address assigned for the client.
  684. ASSERT_NO_THROW(srv->adjustRemoteAddr(req, resp));
  685. EXPECT_EQ("192.0.2.13", resp->getRemoteAddr().toText());
  686. }
  687. // This test verifies that the destination address of the response message
  688. // is set to broadcast address when client set broadcast flag in its
  689. // query. Client sets this flag to indicate that it can't receive direct
  690. // responses from the server when it doesn't have its interface configured.
  691. // Server must respect broadcast flag.
  692. TEST_F(Dhcpv4SrvTest, adjustRemoteAddressBroadcast) {
  693. boost::scoped_ptr<NakedDhcpv4Srv> srv(new NakedDhcpv4Srv(0));
  694. // Create instance of the incoming packet.
  695. boost::shared_ptr<Pkt4> req(new Pkt4(DHCPDISCOVER, 1234));
  696. // Clear giaddr to simulate direct packet.
  697. req->setGiaddr(IOAddress("0.0.0.0"));
  698. // Clear client address as it hasn't got any address configured yet.
  699. req->setCiaddr(IOAddress("0.0.0.0"));
  700. // Let's set the broadcast flag.
  701. req->setFlags(Pkt4::FLAG_BROADCAST_MASK);
  702. // Create a response.
  703. boost::shared_ptr<Pkt4> resp(new Pkt4(DHCPOFFER, 1234));
  704. // Assign some new address for this client.
  705. resp->setYiaddr(IOAddress("192.0.2.13"));
  706. // Clear the remote address.
  707. resp->setRemoteAddr(IOAddress("0.0.0.0"));
  708. // When running unit tests, the IfaceMgr is using the default Packet
  709. // Filtering class, PktFilterInet. This class does not support direct
  710. // responses to the clients without address assigned. If giaddr and
  711. // ciaddr are zero and client has just got the new lease, the assigned
  712. // address is carried in yiaddr. In order to send this address to the
  713. // client, server must send the response to the broadcast address when
  714. // direct response is not supported. This conflicts with the purpose
  715. // of this test which is supposed to verify that responses are sent
  716. // to broadcast address only, when broadcast flag is set. Therefore,
  717. // in order to simulate that direct responses are supported we have
  718. // to replace the default packet filtering class with a dummy class
  719. // which reports direct response capability.
  720. IfaceMgr::instance().setPacketFilter(PktFilterPtr(new PktFilterTest()));
  721. ASSERT_NO_THROW(srv->adjustRemoteAddr(req, resp));
  722. // Server must repond to broadcast address when client desired that
  723. // by setting the broadcast flag in its request.
  724. EXPECT_EQ("255.255.255.255", resp->getRemoteAddr().toText());
  725. }
  726. // Verifies that DISCOVER message can be processed correctly,
  727. // that the OFFER message generated in response is valid and
  728. // contains necessary options.
  729. //
  730. // Note: this test focuses on the packet correctness. There
  731. // are other tests that verify correctness of the allocation
  732. // engine. See DiscoverBasic, DiscoverHint, DiscoverNoClientId
  733. // and DiscoverInvalidHint.
  734. TEST_F(Dhcpv4SrvTest, processDiscover) {
  735. testDiscoverRequest(DHCPDISCOVER);
  736. }
  737. // Verifies that REQUEST message can be processed correctly,
  738. // that the OFFER message generated in response is valid and
  739. // contains necessary options.
  740. //
  741. // Note: this test focuses on the packet correctness. There
  742. // are other tests that verify correctness of the allocation
  743. // engine. See DiscoverBasic, DiscoverHint, DiscoverNoClientId
  744. // and DiscoverInvalidHint.
  745. TEST_F(Dhcpv4SrvTest, processRequest) {
  746. testDiscoverRequest(DHCPREQUEST);
  747. }
  748. TEST_F(Dhcpv4SrvTest, processRelease) {
  749. NakedDhcpv4Srv srv;
  750. Pkt4Ptr pkt(new Pkt4(DHCPRELEASE, 1234));
  751. // Should not throw
  752. EXPECT_NO_THROW(srv.processRelease(pkt));
  753. }
  754. TEST_F(Dhcpv4SrvTest, processDecline) {
  755. NakedDhcpv4Srv srv;
  756. Pkt4Ptr pkt(new Pkt4(DHCPDECLINE, 1234));
  757. // Should not throw
  758. EXPECT_NO_THROW(srv.processDecline(pkt));
  759. }
  760. TEST_F(Dhcpv4SrvTest, processInform) {
  761. NakedDhcpv4Srv srv;
  762. Pkt4Ptr pkt(new Pkt4(DHCPINFORM, 1234));
  763. // Should not throw
  764. EXPECT_NO_THROW(srv.processInform(pkt));
  765. // Should return something
  766. EXPECT_TRUE(srv.processInform(pkt));
  767. // @todo Implement more reasonable tests before starting
  768. // work on processSomething() method.
  769. }
  770. TEST_F(Dhcpv4SrvTest, serverReceivedPacketName) {
  771. // Check all possible packet types
  772. for (int itype = 0; itype < 256; ++itype) {
  773. uint8_t type = itype;
  774. switch (type) {
  775. case DHCPDECLINE:
  776. EXPECT_STREQ("DECLINE", Dhcpv4Srv::serverReceivedPacketName(type));
  777. break;
  778. case DHCPDISCOVER:
  779. EXPECT_STREQ("DISCOVER", Dhcpv4Srv::serverReceivedPacketName(type));
  780. break;
  781. case DHCPINFORM:
  782. EXPECT_STREQ("INFORM", Dhcpv4Srv::serverReceivedPacketName(type));
  783. break;
  784. case DHCPRELEASE:
  785. EXPECT_STREQ("RELEASE", Dhcpv4Srv::serverReceivedPacketName(type));
  786. break;
  787. case DHCPREQUEST:
  788. EXPECT_STREQ("REQUEST", Dhcpv4Srv::serverReceivedPacketName(type));
  789. break;
  790. default:
  791. EXPECT_STREQ("UNKNOWN", Dhcpv4Srv::serverReceivedPacketName(type));
  792. }
  793. }
  794. }
  795. // This test verifies that incoming DISCOVER can be handled properly, that an
  796. // OFFER is generated, that the response has an address and that address
  797. // really belongs to the configured pool.
  798. //
  799. // constructed very simple DISCOVER message with:
  800. // - client-id option
  801. //
  802. // expected returned OFFER message:
  803. // - copy of client-id
  804. // - server-id
  805. // - offered address
  806. TEST_F(Dhcpv4SrvTest, DiscoverBasic) {
  807. boost::scoped_ptr<NakedDhcpv4Srv> srv;
  808. ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
  809. Pkt4Ptr dis = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
  810. dis->setRemoteAddr(IOAddress("192.0.2.1"));
  811. OptionPtr clientid = generateClientId();
  812. dis->addOption(clientid);
  813. // Pass it to the server and get an offer
  814. Pkt4Ptr offer = srv->processDiscover(dis);
  815. // Check if we get response at all
  816. checkResponse(offer, DHCPOFFER, 1234);
  817. // Check that address was returned from proper range, that its lease
  818. // lifetime is correct, that T1 and T2 are returned properly
  819. checkAddressParams(offer, subnet_);
  820. // Check identifiers
  821. checkServerId(offer, srv->getServerID());
  822. checkClientId(offer, clientid);
  823. }
  824. // This test verifies that incoming DISCOVER can be handled properly, that an
  825. // OFFER is generated, that the response has an address and that address
  826. // really belongs to the configured pool.
  827. //
  828. // constructed very simple DISCOVER message with:
  829. // - client-id option
  830. // - address set to specific value as hint
  831. //
  832. // expected returned OFFER message:
  833. // - copy of client-id
  834. // - server-id
  835. // - offered address
  836. TEST_F(Dhcpv4SrvTest, DiscoverHint) {
  837. boost::scoped_ptr<NakedDhcpv4Srv> srv;
  838. ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
  839. IOAddress hint("192.0.2.107");
  840. Pkt4Ptr dis = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
  841. dis->setRemoteAddr(IOAddress("192.0.2.1"));
  842. OptionPtr clientid = generateClientId();
  843. dis->addOption(clientid);
  844. dis->setYiaddr(hint);
  845. // Pass it to the server and get an offer
  846. Pkt4Ptr offer = srv->processDiscover(dis);
  847. // Check if we get response at all
  848. checkResponse(offer, DHCPOFFER, 1234);
  849. // Check that address was returned from proper range, that its lease
  850. // lifetime is correct, that T1 and T2 are returned properly
  851. checkAddressParams(offer, subnet_);
  852. EXPECT_EQ(offer->getYiaddr().toText(), hint.toText());
  853. // Check identifiers
  854. checkServerId(offer, srv->getServerID());
  855. checkClientId(offer, clientid);
  856. }
  857. // This test verifies that incoming DISCOVER can be handled properly, that an
  858. // OFFER is generated, that the response has an address and that address
  859. // really belongs to the configured pool.
  860. //
  861. // constructed very simple DISCOVER message with:
  862. // - address set to specific value as hint
  863. //
  864. // expected returned OFFER message:
  865. // - copy of client-id
  866. // - server-id
  867. // - offered address
  868. TEST_F(Dhcpv4SrvTest, DiscoverNoClientId) {
  869. boost::scoped_ptr<NakedDhcpv4Srv> srv;
  870. ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
  871. IOAddress hint("192.0.2.107");
  872. Pkt4Ptr dis = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
  873. dis->setRemoteAddr(IOAddress("192.0.2.1"));
  874. dis->setYiaddr(hint);
  875. dis->setHWAddr(generateHWAddr(6));
  876. // Pass it to the server and get an offer
  877. Pkt4Ptr offer = srv->processDiscover(dis);
  878. // Check if we get response at all
  879. checkResponse(offer, DHCPOFFER, 1234);
  880. // Check that address was returned from proper range, that its lease
  881. // lifetime is correct, that T1 and T2 are returned properly
  882. checkAddressParams(offer, subnet_);
  883. EXPECT_EQ(offer->getYiaddr().toText(), hint.toText());
  884. // Check identifiers
  885. checkServerId(offer, srv->getServerID());
  886. }
  887. // This test verifies that incoming DISCOVER can be handled properly, that an
  888. // OFFER is generated, that the response has an address and that address
  889. // really belongs to the configured pool.
  890. //
  891. // constructed very simple DISCOVER message with:
  892. // - client-id option
  893. // - address set to specific value as hint, but that hint is invalid
  894. //
  895. // expected returned OFFER message:
  896. // - copy of client-id
  897. // - server-id
  898. // - offered address (!= hint)
  899. TEST_F(Dhcpv4SrvTest, DiscoverInvalidHint) {
  900. boost::scoped_ptr<NakedDhcpv4Srv> srv;
  901. ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
  902. IOAddress hint("10.1.2.3");
  903. Pkt4Ptr dis = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
  904. dis->setRemoteAddr(IOAddress("192.0.2.107"));
  905. OptionPtr clientid = generateClientId();
  906. dis->addOption(clientid);
  907. dis->setYiaddr(hint);
  908. // Pass it to the server and get an offer
  909. Pkt4Ptr offer = srv->processDiscover(dis);
  910. // Check if we get response at all
  911. checkResponse(offer, DHCPOFFER, 1234);
  912. // Check that address was returned from proper range, that its lease
  913. // lifetime is correct, that T1 and T2 are returned properly
  914. checkAddressParams(offer, subnet_);
  915. EXPECT_NE(offer->getYiaddr().toText(), hint.toText());
  916. // Check identifiers
  917. checkServerId(offer, srv->getServerID());
  918. checkClientId(offer, clientid);
  919. }
  920. /// @todo: Add a test that client sends hint that is in pool, but currently
  921. /// being used by a different client.
  922. // This test checks that the server is offering different addresses to different
  923. // clients in OFFERs. Please note that OFFER is not a guarantee that such
  924. // an address will be assigned. Had the pool was very small and contained only
  925. // 2 addresses, the third client would get the same offer as the first one
  926. // and this is a correct behavior. It is REQUEST that will fail for the third
  927. // client. OFFER is basically saying "if you send me a request, you will
  928. // probably get an address like this" (there are no guarantees).
  929. TEST_F(Dhcpv4SrvTest, ManyDiscovers) {
  930. boost::scoped_ptr<NakedDhcpv4Srv> srv;
  931. ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
  932. Pkt4Ptr dis1 = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
  933. Pkt4Ptr dis2 = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 2345));
  934. Pkt4Ptr dis3 = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 3456));
  935. dis1->setRemoteAddr(IOAddress("192.0.2.1"));
  936. dis2->setRemoteAddr(IOAddress("192.0.2.2"));
  937. dis3->setRemoteAddr(IOAddress("192.0.2.3"));
  938. // Different client-id sizes
  939. OptionPtr clientid1 = generateClientId(4); // length 4
  940. OptionPtr clientid2 = generateClientId(5); // length 5
  941. OptionPtr clientid3 = generateClientId(6); // length 6
  942. dis1->addOption(clientid1);
  943. dis2->addOption(clientid2);
  944. dis3->addOption(clientid3);
  945. // Pass it to the server and get an offer
  946. Pkt4Ptr offer1 = srv->processDiscover(dis1);
  947. Pkt4Ptr offer2 = srv->processDiscover(dis2);
  948. Pkt4Ptr offer3 = srv->processDiscover(dis3);
  949. // Check if we get response at all
  950. checkResponse(offer1, DHCPOFFER, 1234);
  951. checkResponse(offer2, DHCPOFFER, 2345);
  952. checkResponse(offer3, DHCPOFFER, 3456);
  953. IOAddress addr1 = offer1->getYiaddr();
  954. IOAddress addr2 = offer2->getYiaddr();
  955. IOAddress addr3 = offer3->getYiaddr();
  956. // Check that the assigned address is indeed from the configured pool
  957. checkAddressParams(offer1, subnet_);
  958. checkAddressParams(offer2, subnet_);
  959. checkAddressParams(offer3, subnet_);
  960. // Check server-ids
  961. checkServerId(offer1, srv->getServerID());
  962. checkServerId(offer2, srv->getServerID());
  963. checkServerId(offer3, srv->getServerID());
  964. checkClientId(offer1, clientid1);
  965. checkClientId(offer2, clientid2);
  966. checkClientId(offer3, clientid3);
  967. // Finally check that the addresses offered are different
  968. EXPECT_NE(addr1.toText(), addr2.toText());
  969. EXPECT_NE(addr2.toText(), addr3.toText());
  970. EXPECT_NE(addr3.toText(), addr1.toText());
  971. cout << "Offered address to client1=" << addr1.toText() << endl;
  972. cout << "Offered address to client2=" << addr2.toText() << endl;
  973. cout << "Offered address to client3=" << addr3.toText() << endl;
  974. }
  975. // This test verifies that incoming REQUEST can be handled properly, that an
  976. // ACK is generated, that the response has an address and that address
  977. // really belongs to the configured pool.
  978. //
  979. // constructed a single REQUEST message with:
  980. // - client-id option
  981. // - hwaddr information
  982. // - requested address (that the client received in DISCOVER/OFFER exchange)
  983. //
  984. // expected returned ACK message:
  985. // - copy of client-id
  986. // - server-id
  987. // - assigned address
  988. //
  989. // Test verifies that the lease is actually in the database.
  990. TEST_F(Dhcpv4SrvTest, RequestBasic) {
  991. boost::scoped_ptr<NakedDhcpv4Srv> srv;
  992. ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
  993. IOAddress hint("192.0.2.107");
  994. Pkt4Ptr req = Pkt4Ptr(new Pkt4(DHCPREQUEST, 1234));
  995. req->setRemoteAddr(IOAddress("192.0.2.1"));
  996. OptionPtr clientid = generateClientId();
  997. req->addOption(clientid);
  998. req->setYiaddr(hint);
  999. // Pass it to the server and get an advertise
  1000. Pkt4Ptr ack = srv->processRequest(req);
  1001. // Check if we get response at all
  1002. checkResponse(ack, DHCPACK, 1234);
  1003. EXPECT_EQ(hint.toText(), ack->getYiaddr().toText());
  1004. // Check that address was returned from proper range, that its lease
  1005. // lifetime is correct, that T1 and T2 are returned properly
  1006. checkAddressParams(ack, subnet_);
  1007. // Check identifiers
  1008. checkServerId(ack, srv->getServerID());
  1009. checkClientId(ack, clientid);
  1010. // Check that the lease is really in the database
  1011. Lease4Ptr l = checkLease(ack, clientid, req->getHWAddr(), hint);
  1012. ASSERT_TRUE(l);
  1013. LeaseMgrFactory::instance().deleteLease(l->addr_);
  1014. }
  1015. // This test verifies that incoming REQUEST can be handled properly, that an
  1016. // ACK is generated, that the response has an address and that address
  1017. // really belongs to the configured pool.
  1018. //
  1019. // constructed 3 REQUEST messages with:
  1020. // - client-id option (differs between messages)
  1021. // - hwaddr information (differs between messages)
  1022. //
  1023. // expected returned ACK message:
  1024. // - copy of client-id
  1025. // - server-id
  1026. // - assigned address (different for each client)
  1027. TEST_F(Dhcpv4SrvTest, ManyRequests) {
  1028. boost::scoped_ptr<NakedDhcpv4Srv> srv;
  1029. ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
  1030. const IOAddress req_addr1("192.0.2.105");
  1031. const IOAddress req_addr2("192.0.2.101");
  1032. const IOAddress req_addr3("192.0.2.109");
  1033. const IOAddress relay("192.0.2.1");
  1034. Pkt4Ptr req1 = Pkt4Ptr(new Pkt4(DHCPOFFER, 1234));
  1035. Pkt4Ptr req2 = Pkt4Ptr(new Pkt4(DHCPOFFER, 2345));
  1036. Pkt4Ptr req3 = Pkt4Ptr(new Pkt4(DHCPOFFER, 3456));
  1037. req1->setRemoteAddr(relay);
  1038. req2->setRemoteAddr(relay);
  1039. req3->setRemoteAddr(relay);
  1040. req1->setYiaddr(req_addr1);
  1041. req2->setYiaddr(req_addr2);
  1042. req3->setYiaddr(req_addr3);
  1043. req1->setHWAddr(generateHWAddr(6));
  1044. req2->setHWAddr(generateHWAddr(7));
  1045. req3->setHWAddr(generateHWAddr(8));
  1046. // Different client-id sizes
  1047. OptionPtr clientid1 = generateClientId(4); // length 4
  1048. OptionPtr clientid2 = generateClientId(5); // length 5
  1049. OptionPtr clientid3 = generateClientId(6); // length 6
  1050. req1->addOption(clientid1);
  1051. req2->addOption(clientid2);
  1052. req3->addOption(clientid3);
  1053. // Pass it to the server and get an advertise
  1054. Pkt4Ptr ack1 = srv->processRequest(req1);
  1055. Pkt4Ptr ack2 = srv->processRequest(req2);
  1056. Pkt4Ptr ack3 = srv->processRequest(req3);
  1057. // Check if we get response at all
  1058. checkResponse(ack1, DHCPACK, 1234);
  1059. checkResponse(ack2, DHCPACK, 2345);
  1060. checkResponse(ack3, DHCPACK, 3456);
  1061. IOAddress addr1 = ack1->getYiaddr();
  1062. IOAddress addr2 = ack2->getYiaddr();
  1063. IOAddress addr3 = ack3->getYiaddr();
  1064. // Check that every client received the address it requested
  1065. EXPECT_EQ(req_addr1.toText(), addr1.toText());
  1066. EXPECT_EQ(req_addr2.toText(), addr2.toText());
  1067. EXPECT_EQ(req_addr3.toText(), addr3.toText());
  1068. // Check that the assigned address is indeed from the configured pool
  1069. checkAddressParams(ack1, subnet_);
  1070. checkAddressParams(ack2, subnet_);
  1071. checkAddressParams(ack3, subnet_);
  1072. // Check DUIDs
  1073. checkServerId(ack1, srv->getServerID());
  1074. checkServerId(ack2, srv->getServerID());
  1075. checkServerId(ack3, srv->getServerID());
  1076. checkClientId(ack1, clientid1);
  1077. checkClientId(ack2, clientid2);
  1078. checkClientId(ack3, clientid3);
  1079. // Check that leases are in the database
  1080. Lease4Ptr l = checkLease(ack1, clientid1, req1->getHWAddr(), addr1);
  1081. EXPECT_TRUE(l);
  1082. l = checkLease(ack2, clientid2, req2->getHWAddr(), addr2);
  1083. l = checkLease(ack3, clientid3, req3->getHWAddr(), addr3);
  1084. // Finally check that the addresses offered are different
  1085. EXPECT_NE(addr1.toText(), addr2.toText());
  1086. EXPECT_NE(addr2.toText(), addr3.toText());
  1087. EXPECT_NE(addr3.toText(), addr1.toText());
  1088. cout << "Offered address to client1=" << addr1.toText() << endl;
  1089. cout << "Offered address to client2=" << addr2.toText() << endl;
  1090. cout << "Offered address to client3=" << addr3.toText() << endl;
  1091. }
  1092. // This test verifies that incoming (positive) REQUEST/Renewing can be handled properly, that a
  1093. // REPLY is generated, that the response has an address and that address
  1094. // really belongs to the configured pool and that lease is actually renewed.
  1095. //
  1096. // expected:
  1097. // - returned REPLY message has copy of client-id
  1098. // - returned REPLY message has server-id
  1099. // - returned REPLY message has IA that includes IAADDR
  1100. // - lease is actually renewed in LeaseMgr
  1101. TEST_F(Dhcpv4SrvTest, RenewBasic) {
  1102. boost::scoped_ptr<NakedDhcpv4Srv> srv;
  1103. ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
  1104. const IOAddress addr("192.0.2.106");
  1105. const uint32_t temp_t1 = 50;
  1106. const uint32_t temp_t2 = 75;
  1107. const uint32_t temp_valid = 100;
  1108. const time_t temp_timestamp = time(NULL) - 10;
  1109. // Generate client-id also sets client_id_ member
  1110. OptionPtr clientid = generateClientId();
  1111. // Check that the address we are about to use is indeed in pool
  1112. ASSERT_TRUE(subnet_->inPool(addr));
  1113. // let's create a lease and put it in the LeaseMgr
  1114. uint8_t hwaddr2[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
  1115. Lease4Ptr used(new Lease4(IOAddress("192.0.2.106"), hwaddr2, sizeof(hwaddr2),
  1116. &client_id_->getDuid()[0], client_id_->getDuid().size(),
  1117. temp_valid, temp_t1, temp_t2, temp_timestamp,
  1118. subnet_->getID()));
  1119. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
  1120. // Check that the lease is really in the database
  1121. Lease4Ptr l = LeaseMgrFactory::instance().getLease4(addr);
  1122. ASSERT_TRUE(l);
  1123. // Check that T1, T2, preferred, valid and cltt really set.
  1124. // Constructed lease looks as if it was assigned 10 seconds ago
  1125. // EXPECT_EQ(l->t1_, temp_t1);
  1126. // EXPECT_EQ(l->t2_, temp_t2);
  1127. EXPECT_EQ(l->valid_lft_, temp_valid);
  1128. EXPECT_EQ(l->cltt_, temp_timestamp);
  1129. // Let's create a RENEW
  1130. Pkt4Ptr req = Pkt4Ptr(new Pkt4(DHCPREQUEST, 1234));
  1131. req->setRemoteAddr(IOAddress(addr));
  1132. req->setYiaddr(addr);
  1133. req->setCiaddr(addr); // client's address
  1134. req->addOption(clientid);
  1135. req->addOption(srv->getServerID());
  1136. // Pass it to the server and hope for a REPLY
  1137. Pkt4Ptr ack = srv->processRequest(req);
  1138. // Check if we get response at all
  1139. checkResponse(ack, DHCPACK, 1234);
  1140. EXPECT_EQ(addr.toText(), ack->getYiaddr().toText());
  1141. // Check that address was returned from proper range, that its lease
  1142. // lifetime is correct, that T1 and T2 are returned properly
  1143. checkAddressParams(ack, subnet_);
  1144. // Check identifiers
  1145. checkServerId(ack, srv->getServerID());
  1146. checkClientId(ack, clientid);
  1147. // Check that the lease is really in the database
  1148. l = checkLease(ack, clientid, req->getHWAddr(), addr);
  1149. ASSERT_TRUE(l);
  1150. // Check that T1, T2, preferred, valid and cltt were really updated
  1151. EXPECT_EQ(l->t1_, subnet_->getT1());
  1152. EXPECT_EQ(l->t2_, subnet_->getT2());
  1153. EXPECT_EQ(l->valid_lft_, subnet_->getValid());
  1154. // Checking for CLTT is a bit tricky if we want to avoid off by 1 errors
  1155. int32_t cltt = static_cast<int32_t>(l->cltt_);
  1156. int32_t expected = static_cast<int32_t>(time(NULL));
  1157. // Equality or difference by 1 between cltt and expected is ok.
  1158. EXPECT_GE(1, abs(cltt - expected));
  1159. EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease(addr));
  1160. }
  1161. // @todo: Implement tests for rejecting renewals
  1162. // This test verifies if the sanityCheck() really checks options presence.
  1163. TEST_F(Dhcpv4SrvTest, sanityCheck) {
  1164. boost::scoped_ptr<NakedDhcpv4Srv> srv;
  1165. ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
  1166. Pkt4Ptr pkt = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
  1167. pkt->setHWAddr(generateHWAddr(6));
  1168. // Server-id is optional for information-request, so
  1169. EXPECT_NO_THROW(srv->sanityCheck(pkt, Dhcpv4Srv::OPTIONAL));
  1170. // Empty packet, no server-id
  1171. EXPECT_THROW(srv->sanityCheck(pkt, Dhcpv4Srv::MANDATORY), RFCViolation);
  1172. pkt->addOption(srv->getServerID());
  1173. // Server-id is mandatory and present = no exception
  1174. EXPECT_NO_THROW(srv->sanityCheck(pkt, Dhcpv4Srv::MANDATORY));
  1175. // Server-id is forbidden, but present => exception
  1176. EXPECT_THROW(srv->sanityCheck(pkt, Dhcpv4Srv::FORBIDDEN),
  1177. RFCViolation);
  1178. // There's no client-id and no HWADDR. Server needs something to
  1179. // identify the client
  1180. pkt->setHWAddr(generateHWAddr(0));
  1181. EXPECT_THROW(srv->sanityCheck(pkt, Dhcpv4Srv::MANDATORY), RFCViolation);
  1182. }
  1183. // This test verifies that incoming (positive) RELEASE can be handled properly.
  1184. // As there is no REPLY in DHCPv4, the only thing to verify here is that
  1185. // the lease is indeed removed from the database.
  1186. TEST_F(Dhcpv4SrvTest, ReleaseBasic) {
  1187. boost::scoped_ptr<NakedDhcpv4Srv> srv;
  1188. ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
  1189. const IOAddress addr("192.0.2.106");
  1190. const uint32_t temp_t1 = 50;
  1191. const uint32_t temp_t2 = 75;
  1192. const uint32_t temp_valid = 100;
  1193. const time_t temp_timestamp = time(NULL) - 10;
  1194. // Generate client-id also duid_
  1195. OptionPtr clientid = generateClientId();
  1196. // Check that the address we are about to use is indeed in pool
  1197. ASSERT_TRUE(subnet_->inPool(addr));
  1198. // Let's create a lease and put it in the LeaseMgr
  1199. uint8_t mac_addr[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
  1200. HWAddrPtr hw(new HWAddr(mac_addr, sizeof(mac_addr), HTYPE_ETHER));
  1201. Lease4Ptr used(new Lease4(addr, mac_addr, sizeof(mac_addr),
  1202. &client_id_->getDuid()[0], client_id_->getDuid().size(),
  1203. temp_valid, temp_t1, temp_t2, temp_timestamp,
  1204. subnet_->getID()));
  1205. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
  1206. // Check that the lease is really in the database
  1207. Lease4Ptr l = LeaseMgrFactory::instance().getLease4(addr);
  1208. ASSERT_TRUE(l);
  1209. // Let's create a RELEASE
  1210. // Generate client-id also duid_
  1211. Pkt4Ptr rel = Pkt4Ptr(new Pkt4(DHCPRELEASE, 1234));
  1212. rel->setRemoteAddr(addr);
  1213. rel->setYiaddr(addr);
  1214. rel->addOption(clientid);
  1215. rel->addOption(srv->getServerID());
  1216. rel->setHWAddr(hw);
  1217. // Pass it to the server and hope for a REPLY
  1218. // Note: this is no response to RELEASE in DHCPv4
  1219. EXPECT_NO_THROW(srv->processRelease(rel));
  1220. // The lease should be gone from LeaseMgr
  1221. l = LeaseMgrFactory::instance().getLease4(addr);
  1222. EXPECT_FALSE(l);
  1223. // Try to get the lease by hardware address
  1224. // @todo: Uncomment this once trac2592 is implemented
  1225. // Lease4Collection leases = LeaseMgrFactory::instance().getLease4(hw->hwaddr_);
  1226. // EXPECT_EQ(leases.size(), 0);
  1227. // Try to get it by hw/subnet_id combination
  1228. l = LeaseMgrFactory::instance().getLease4(hw->hwaddr_, subnet_->getID());
  1229. EXPECT_FALSE(l);
  1230. // Try by client-id
  1231. // @todo: Uncomment this once trac2592 is implemented
  1232. //Lease4Collection leases = LeaseMgrFactory::instance().getLease4(*client_id_);
  1233. //EXPECT_EQ(leases.size(), 0);
  1234. // Try by client-id/subnet-id
  1235. l = LeaseMgrFactory::instance().getLease4(*client_id_, subnet_->getID());
  1236. EXPECT_FALSE(l);
  1237. // Ok, the lease is *really* not there.
  1238. }
  1239. // This test verifies that incoming (invalid) RELEASE can be handled properly.
  1240. //
  1241. // This test checks 3 scenarios:
  1242. // 1. there is no such lease at all
  1243. // 2. there is such a lease, but it is assigned to a different IAID
  1244. // 3. there is such a lease, but it belongs to a different client
  1245. TEST_F(Dhcpv4SrvTest, ReleaseReject) {
  1246. boost::scoped_ptr<NakedDhcpv4Srv> srv;
  1247. ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
  1248. const IOAddress addr("192.0.2.106");
  1249. const uint32_t t1 = 50;
  1250. const uint32_t t2 = 75;
  1251. const uint32_t valid = 100;
  1252. const time_t timestamp = time(NULL) - 10;
  1253. // Let's create a lease and put it in the LeaseMgr
  1254. uint8_t bogus_mac_addr[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
  1255. HWAddrPtr bogus_hw(new HWAddr(bogus_mac_addr, sizeof(bogus_mac_addr), HTYPE_ETHER));
  1256. OptionPtr bogus_clientid = generateClientId(7); // different length
  1257. // Generate client-id also duid_
  1258. OptionPtr clientid = generateClientId();
  1259. // Check that the address we are about to use is indeed in pool
  1260. ASSERT_TRUE(subnet_->inPool(addr));
  1261. // Let's create a RELEASE
  1262. // Generate client-id also duid_
  1263. Pkt4Ptr rel = Pkt4Ptr(new Pkt4(DHCPRELEASE, 1234));
  1264. rel->setRemoteAddr(addr);
  1265. rel->setYiaddr(addr);
  1266. rel->addOption(clientid);
  1267. rel->addOption(srv->getServerID());
  1268. rel->setHWAddr(bogus_hw);
  1269. // Case 1: No lease known to server
  1270. SCOPED_TRACE("CASE 1: Lease is not known to the server");
  1271. // There is nothing to check here. The lease is not there and server does
  1272. // not send anything back. This case is enumerated here just for keeping
  1273. // parity with similar test in DHCPv6.
  1274. EXPECT_NO_THROW(srv->processRelease(rel));
  1275. // CASE 2: Lease is known and belongs to this client, but to a different hardware
  1276. SCOPED_TRACE("CASE 2: Lease is known and belongs to this client, but uses different HW addr");
  1277. // Let's create a lease and put it in the LeaseMgr
  1278. uint8_t mac_addr[] = { 0, 0x1, 0x2, 0x3, 0x4, 0x5};
  1279. HWAddrPtr hw(new HWAddr(mac_addr, sizeof(mac_addr), HTYPE_ETHER));
  1280. Lease4Ptr used(new Lease4(addr, mac_addr, sizeof(mac_addr),
  1281. &client_id_->getDuid()[0], client_id_->getDuid().size(),
  1282. valid, t1, t2, timestamp, subnet_->getID()));
  1283. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
  1284. // Check that the lease is really in the database
  1285. Lease4Ptr l = LeaseMgrFactory::instance().getLease4(addr);
  1286. ASSERT_TRUE(l);
  1287. rel->setHWAddr(bogus_hw);
  1288. EXPECT_NO_THROW(srv->processRelease(rel));
  1289. // Check that the lease was not removed (due to hardware address mis-match)
  1290. l = LeaseMgrFactory::instance().getLease4(addr);
  1291. ASSERT_TRUE(l);
  1292. // CASE 3: Lease belongs to a client with different client-id
  1293. SCOPED_TRACE("CASE 3: Lease belongs to a client with different client-id");
  1294. rel->setHWAddr(hw); // proper HW address this time
  1295. rel->delOption(DHO_DHCP_CLIENT_IDENTIFIER);
  1296. rel->addOption(bogus_clientid); // but invalid client-id
  1297. OptionPtr x = rel->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
  1298. EXPECT_NO_THROW(srv->processRelease(rel));
  1299. // Check that the lease is still there
  1300. l = LeaseMgrFactory::instance().getLease4(addr);
  1301. ASSERT_TRUE(l);
  1302. // Final sanity check. Verify that with valid hw and client-id release is successful
  1303. rel->delOption(DHO_DHCP_CLIENT_IDENTIFIER);
  1304. rel->addOption(clientid);
  1305. // It should work this time
  1306. EXPECT_NO_THROW(srv->processRelease(rel));
  1307. // Check that the lease is not there
  1308. l = LeaseMgrFactory::instance().getLease4(addr);
  1309. EXPECT_FALSE(l);
  1310. }
  1311. // This test verifies if the server-id disk operations (read, write) are
  1312. // working properly.
  1313. TEST_F(Dhcpv4SrvTest, ServerID) {
  1314. NakedDhcpv4Srv srv(0);
  1315. string srvid_text = "192.0.2.100";
  1316. IOAddress srvid(srvid_text);
  1317. fstream file1(SRVID_FILE, ios::out | ios::trunc);
  1318. file1 << srvid_text;
  1319. file1.close();
  1320. // Test reading from a file
  1321. EXPECT_TRUE(srv.loadServerID(SRVID_FILE));
  1322. ASSERT_TRUE(srv.getServerID());
  1323. EXPECT_EQ(srvid_text, srv.srvidToString(srv.getServerID()));
  1324. // Now test writing to a file
  1325. EXPECT_EQ(0, unlink(SRVID_FILE));
  1326. EXPECT_NO_THROW(srv.writeServerID(SRVID_FILE));
  1327. fstream file2(SRVID_FILE, ios::in);
  1328. ASSERT_TRUE(file2.good());
  1329. string text;
  1330. file2 >> text;
  1331. file2.close();
  1332. EXPECT_EQ(srvid_text, text);
  1333. }
  1334. /// @todo Implement tests for subnetSelect See tests in dhcp6_srv_unittest.cc:
  1335. /// selectSubnetAddr, selectSubnetIface, selectSubnetRelayLinkaddr,
  1336. /// selectSubnetRelayInterfaceId. Note that the concept of interface-id is not
  1337. /// present in the DHCPv4, so not everything is applicable directly.
  1338. /// See ticket #3057
  1339. // Checks if hooks are registered properly.
  1340. TEST_F(Dhcpv4SrvTest, Hooks) {
  1341. NakedDhcpv4Srv srv(0);
  1342. // check if appropriate hooks are registered
  1343. int hook_index_pkt4_received = -1;
  1344. int hook_index_select_subnet = -1;
  1345. int hook_index_pkt4_send = -1;
  1346. // check if appropriate indexes are set
  1347. EXPECT_NO_THROW(hook_index_pkt4_received = ServerHooks::getServerHooks()
  1348. .getIndex("pkt4_receive"));
  1349. EXPECT_NO_THROW(hook_index_select_subnet = ServerHooks::getServerHooks()
  1350. .getIndex("subnet4_select"));
  1351. EXPECT_NO_THROW(hook_index_pkt4_send = ServerHooks::getServerHooks()
  1352. .getIndex("pkt4_send"));
  1353. EXPECT_TRUE(hook_index_pkt4_received > 0);
  1354. EXPECT_TRUE(hook_index_select_subnet > 0);
  1355. EXPECT_TRUE(hook_index_pkt4_send > 0);
  1356. }
  1357. // a dummy MAC address
  1358. const uint8_t dummyMacAddr[] = {0, 1, 2, 3, 4, 5};
  1359. // A dummy MAC address, padded with 0s
  1360. const uint8_t dummyChaddr[16] = {0, 1, 2, 3, 4, 5, 0, 0,
  1361. 0, 0, 0, 0, 0, 0, 0, 0 };
  1362. // Let's use some creative test content here (128 chars + \0)
  1363. const uint8_t dummyFile[] = "Lorem ipsum dolor sit amet, consectetur "
  1364. "adipiscing elit. Proin mollis placerat metus, at "
  1365. "lacinia orci ornare vitae. Mauris amet.";
  1366. // Yet another type of test content (64 chars + \0)
  1367. const uint8_t dummySname[] = "Lorem ipsum dolor sit amet, consectetur "
  1368. "adipiscing elit posuere.";
  1369. /// @brief a class dedicated to Hooks testing in DHCPv4 server
  1370. ///
  1371. /// This class has a number of static members, because each non-static
  1372. /// method has implicit 'this' parameter, so it does not match callout
  1373. /// signature and couldn't be registered. Furthermore, static methods
  1374. /// can't modify non-static members (for obvious reasons), so many
  1375. /// fields are declared static. It is still better to keep them as
  1376. /// one class rather than unrelated collection of global objects.
  1377. class HooksDhcpv4SrvTest : public Dhcpv4SrvTest {
  1378. public:
  1379. /// @brief creates Dhcpv4Srv and prepares buffers for callouts
  1380. HooksDhcpv4SrvTest() {
  1381. // Allocate new DHCPv6 Server
  1382. srv_ = new NakedDhcpv4Srv(0);
  1383. // clear static buffers
  1384. resetCalloutBuffers();
  1385. }
  1386. /// @brief destructor (deletes Dhcpv4Srv)
  1387. virtual ~HooksDhcpv4SrvTest() {
  1388. HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("pkt4_receive");
  1389. HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("pkt4_send");
  1390. HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("subnet4_select");
  1391. delete srv_;
  1392. }
  1393. /// @brief creates an option with specified option code
  1394. ///
  1395. /// This method is static, because it is used from callouts
  1396. /// that do not have a pointer to HooksDhcpv4SSrvTest object
  1397. ///
  1398. /// @param option_code code of option to be created
  1399. ///
  1400. /// @return pointer to create option object
  1401. static OptionPtr createOption(uint16_t option_code) {
  1402. char payload[] = {
  1403. 0xa, 0xb, 0xc, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14
  1404. };
  1405. OptionBuffer tmp(payload, payload + sizeof(payload));
  1406. return OptionPtr(new Option(Option::V4, option_code, tmp));
  1407. }
  1408. /// @brief Generates test packet.
  1409. ///
  1410. /// Allocates and generates on-wire buffer that represents test packet, with all
  1411. /// fixed fields set to non-zero values. Content is not always reasonable.
  1412. ///
  1413. /// See generateTestPacket1() function that returns exactly the same packet as
  1414. /// Pkt4 object.
  1415. ///
  1416. /// @return pointer to allocated Pkt4 object
  1417. // Returns a vector containing a DHCPv4 packet header.
  1418. Pkt4Ptr
  1419. generateSimpleDiscover() {
  1420. // That is only part of the header. It contains all "short" fields,
  1421. // larger fields are constructed separately.
  1422. uint8_t hdr[] = {
  1423. 1, 6, 6, 13, // op, htype, hlen, hops,
  1424. 0x12, 0x34, 0x56, 0x78, // transaction-id
  1425. 0, 42, 0x80, 0x00, // 42 secs, BROADCAST flags
  1426. 192, 0, 2, 1, // ciaddr
  1427. 1, 2, 3, 4, // yiaddr
  1428. 192, 0, 2, 255, // siaddr
  1429. 255, 255, 255, 255, // giaddr
  1430. };
  1431. // Initialize the vector with the header fields defined above.
  1432. vector<uint8_t> buf(hdr, hdr + sizeof(hdr));
  1433. // Append the large header fields.
  1434. copy(dummyChaddr, dummyChaddr + Pkt4::MAX_CHADDR_LEN, back_inserter(buf));
  1435. copy(dummySname, dummySname + Pkt4::MAX_SNAME_LEN, back_inserter(buf));
  1436. copy(dummyFile, dummyFile + Pkt4::MAX_FILE_LEN, back_inserter(buf));
  1437. // Should now have all the header, so check. The "static_cast" is used
  1438. // to get round an odd bug whereby the linker appears not to find the
  1439. // definition of DHCPV4_PKT_HDR_LEN if it appears within an EXPECT_EQ().
  1440. EXPECT_EQ(static_cast<size_t>(Pkt4::DHCPV4_PKT_HDR_LEN), buf.size());
  1441. // Add magic cookie
  1442. buf.push_back(0x63);
  1443. buf.push_back(0x82);
  1444. buf.push_back(0x53);
  1445. buf.push_back(0x63);
  1446. // Add message type DISCOVER
  1447. buf.push_back(static_cast<uint8_t>(DHO_DHCP_MESSAGE_TYPE));
  1448. buf.push_back(1); // length (just one byte)
  1449. buf.push_back(static_cast<uint8_t>(DHCPDISCOVER));
  1450. return (Pkt4Ptr(new Pkt4(&buf[0], buf.size())));
  1451. }
  1452. /// test callback that stores received callout name and pkt4 value
  1453. /// @param callout_handle handle passed by the hooks framework
  1454. /// @return always 0
  1455. static int
  1456. pkt4_receive_callout(CalloutHandle& callout_handle) {
  1457. callback_name_ = string("pkt4_receive");
  1458. callout_handle.getArgument("query4", callback_pkt4_);
  1459. callback_argument_names_ = callout_handle.getArgumentNames();
  1460. return (0);
  1461. }
  1462. /// test callback that changes client-id value
  1463. /// @param callout_handle handle passed by the hooks framework
  1464. /// @return always 0
  1465. static int
  1466. pkt4_receive_change_clientid(CalloutHandle& callout_handle) {
  1467. Pkt4Ptr pkt;
  1468. callout_handle.getArgument("query4", pkt);
  1469. // get rid of the old client-id
  1470. pkt->delOption(DHO_DHCP_CLIENT_IDENTIFIER);
  1471. // add a new option
  1472. pkt->addOption(createOption(DHO_DHCP_CLIENT_IDENTIFIER));
  1473. // carry on as usual
  1474. return pkt4_receive_callout(callout_handle);
  1475. }
  1476. /// test callback that deletes client-id
  1477. /// @param callout_handle handle passed by the hooks framework
  1478. /// @return always 0
  1479. static int
  1480. pkt4_receive_delete_clientid(CalloutHandle& callout_handle) {
  1481. Pkt4Ptr pkt;
  1482. callout_handle.getArgument("query4", pkt);
  1483. // get rid of the old client-id (and no HWADDR)
  1484. vector<uint8_t> mac;
  1485. pkt->delOption(DHO_DHCP_CLIENT_IDENTIFIER);
  1486. pkt->setHWAddr(1, 0, mac); // HWtype 1, hwardware len = 0
  1487. // carry on as usual
  1488. return pkt4_receive_callout(callout_handle);
  1489. }
  1490. /// test callback that sets skip flag
  1491. /// @param callout_handle handle passed by the hooks framework
  1492. /// @return always 0
  1493. static int
  1494. pkt4_receive_skip(CalloutHandle& callout_handle) {
  1495. Pkt4Ptr pkt;
  1496. callout_handle.getArgument("query4", pkt);
  1497. callout_handle.setSkip(true);
  1498. // carry on as usual
  1499. return pkt4_receive_callout(callout_handle);
  1500. }
  1501. /// Test callback that stores received callout name and pkt4 value
  1502. /// @param callout_handle handle passed by the hooks framework
  1503. /// @return always 0
  1504. static int
  1505. pkt4_send_callout(CalloutHandle& callout_handle) {
  1506. callback_name_ = string("pkt4_send");
  1507. callout_handle.getArgument("response4", callback_pkt4_);
  1508. callback_argument_names_ = callout_handle.getArgumentNames();
  1509. return (0);
  1510. }
  1511. // Test callback that changes server-id
  1512. /// @param callout_handle handle passed by the hooks framework
  1513. /// @return always 0
  1514. static int
  1515. pkt4_send_change_serverid(CalloutHandle& callout_handle) {
  1516. Pkt4Ptr pkt;
  1517. callout_handle.getArgument("response4", pkt);
  1518. // get rid of the old server-id
  1519. pkt->delOption(DHO_DHCP_SERVER_IDENTIFIER);
  1520. // add a new option
  1521. pkt->addOption(createOption(DHO_DHCP_SERVER_IDENTIFIER));
  1522. // carry on as usual
  1523. return pkt4_send_callout(callout_handle);
  1524. }
  1525. /// test callback that deletes server-id
  1526. /// @param callout_handle handle passed by the hooks framework
  1527. /// @return always 0
  1528. static int
  1529. pkt4_send_delete_serverid(CalloutHandle& callout_handle) {
  1530. Pkt4Ptr pkt;
  1531. callout_handle.getArgument("response4", pkt);
  1532. // get rid of the old client-id
  1533. pkt->delOption(DHO_DHCP_SERVER_IDENTIFIER);
  1534. // carry on as usual
  1535. return pkt4_send_callout(callout_handle);
  1536. }
  1537. /// Test callback that sets skip flag
  1538. /// @param callout_handle handle passed by the hooks framework
  1539. /// @return always 0
  1540. static int
  1541. pkt4_send_skip(CalloutHandle& callout_handle) {
  1542. Pkt4Ptr pkt;
  1543. callout_handle.getArgument("response4", pkt);
  1544. callout_handle.setSkip(true);
  1545. // carry on as usual
  1546. return pkt4_send_callout(callout_handle);
  1547. }
  1548. /// Test callback that stores received callout name and subnet4 values
  1549. /// @param callout_handle handle passed by the hooks framework
  1550. /// @return always 0
  1551. static int
  1552. subnet4_select_callout(CalloutHandle& callout_handle) {
  1553. callback_name_ = string("subnet4_select");
  1554. callout_handle.getArgument("query4", callback_pkt4_);
  1555. callout_handle.getArgument("subnet4", callback_subnet4_);
  1556. callout_handle.getArgument("subnet4collection", callback_subnet4collection_);
  1557. callback_argument_names_ = callout_handle.getArgumentNames();
  1558. return (0);
  1559. }
  1560. /// Test callback that picks the other subnet if possible.
  1561. /// @param callout_handle handle passed by the hooks framework
  1562. /// @return always 0
  1563. static int
  1564. subnet4_select_different_subnet_callout(CalloutHandle& callout_handle) {
  1565. // Call the basic calllout to record all passed values
  1566. subnet4_select_callout(callout_handle);
  1567. const Subnet4Collection* subnets;
  1568. Subnet4Ptr subnet;
  1569. callout_handle.getArgument("subnet4", subnet);
  1570. callout_handle.getArgument("subnet4collection", subnets);
  1571. // Let's change to a different subnet
  1572. if (subnets->size() > 1) {
  1573. subnet = (*subnets)[1]; // Let's pick the other subnet
  1574. callout_handle.setArgument("subnet4", subnet);
  1575. }
  1576. return (0);
  1577. }
  1578. /// resets buffers used to store data received by callouts
  1579. void resetCalloutBuffers() {
  1580. callback_name_ = string("");
  1581. callback_pkt4_.reset();
  1582. callback_subnet4_.reset();
  1583. callback_subnet4collection_ = NULL;
  1584. callback_argument_names_.clear();
  1585. }
  1586. /// pointer to Dhcpv4Srv that is used in tests
  1587. NakedDhcpv4Srv* srv_;
  1588. // The following fields are used in testing pkt4_receive_callout
  1589. /// String name of the received callout
  1590. static string callback_name_;
  1591. /// Pkt4 structure returned in the callout
  1592. static Pkt4Ptr callback_pkt4_;
  1593. /// Pointer to a subnet received by callout
  1594. static Subnet4Ptr callback_subnet4_;
  1595. /// A list of all available subnets (received by callout)
  1596. static const Subnet4Collection* callback_subnet4collection_;
  1597. /// A list of all received arguments
  1598. static vector<string> callback_argument_names_;
  1599. };
  1600. // The following fields are used in testing pkt4_receive_callout.
  1601. // See fields description in the class for details
  1602. string HooksDhcpv4SrvTest::callback_name_;
  1603. Pkt4Ptr HooksDhcpv4SrvTest::callback_pkt4_;
  1604. Subnet4Ptr HooksDhcpv4SrvTest::callback_subnet4_;
  1605. const Subnet4Collection* HooksDhcpv4SrvTest::callback_subnet4collection_;
  1606. vector<string> HooksDhcpv4SrvTest::callback_argument_names_;
  1607. // Checks if callouts installed on pkt4_received are indeed called and the
  1608. // all necessary parameters are passed.
  1609. //
  1610. // Note that the test name does not follow test naming convention,
  1611. // but the proper hook name is "pkt4_receive".
  1612. TEST_F(HooksDhcpv4SrvTest, simple_pkt4_receive) {
  1613. // Install pkt4_receive_callout
  1614. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1615. "pkt4_receive", pkt4_receive_callout));
  1616. // Let's create a simple DISCOVER
  1617. Pkt4Ptr sol = Pkt4Ptr(generateSimpleDiscover());
  1618. // Simulate that we have received that traffic
  1619. srv_->fakeReceive(sol);
  1620. // Server will now process to run its normal loop, but instead of calling
  1621. // IfaceMgr::receive4(), it will read all packets from the list set by
  1622. // fakeReceive()
  1623. // In particular, it should call registered pkt4_receive callback.
  1624. srv_->run();
  1625. // check that the callback called is indeed the one we installed
  1626. EXPECT_EQ("pkt4_receive", callback_name_);
  1627. // check that pkt4 argument passing was successful and returned proper value
  1628. EXPECT_TRUE(callback_pkt4_.get() == sol.get());
  1629. // Check that all expected parameters are there
  1630. vector<string> expected_argument_names;
  1631. expected_argument_names.push_back(string("query4"));
  1632. EXPECT_TRUE(expected_argument_names == callback_argument_names_);
  1633. }
  1634. // Checks if callouts installed on pkt4_received is able to change
  1635. // the values and the parameters are indeed used by the server.
  1636. TEST_F(HooksDhcpv4SrvTest, valueChange_pkt4_receive) {
  1637. // Install pkt4_receive_callout
  1638. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1639. "pkt4_receive", pkt4_receive_change_clientid));
  1640. // Let's create a simple DISCOVER
  1641. Pkt4Ptr sol = Pkt4Ptr(generateSimpleDiscover());
  1642. // Simulate that we have received that traffic
  1643. srv_->fakeReceive(sol);
  1644. // Server will now process to run its normal loop, but instead of calling
  1645. // IfaceMgr::receive4(), it will read all packets from the list set by
  1646. // fakeReceive()
  1647. // In particular, it should call registered pkt4_receive callback.
  1648. srv_->run();
  1649. // check that the server did send a reposonce
  1650. ASSERT_EQ(1, srv_->fake_sent_.size());
  1651. // Make sure that we received a response
  1652. Pkt4Ptr adv = srv_->fake_sent_.front();
  1653. ASSERT_TRUE(adv);
  1654. // Get client-id...
  1655. OptionPtr clientid = adv->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
  1656. // ... and check if it is the modified value
  1657. OptionPtr expected = createOption(DHO_DHCP_CLIENT_IDENTIFIER);
  1658. EXPECT_TRUE(clientid->equal(expected));
  1659. }
  1660. // Checks if callouts installed on pkt4_received is able to delete
  1661. // existing options and that change impacts server processing (mandatory
  1662. // client-id option is deleted, so the packet is expected to be dropped)
  1663. TEST_F(HooksDhcpv4SrvTest, deleteClientId_pkt4_receive) {
  1664. // Install pkt4_receive_callout
  1665. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1666. "pkt4_receive", pkt4_receive_delete_clientid));
  1667. // Let's create a simple DISCOVER
  1668. Pkt4Ptr sol = Pkt4Ptr(generateSimpleDiscover());
  1669. // Simulate that we have received that traffic
  1670. srv_->fakeReceive(sol);
  1671. // Server will now process to run its normal loop, but instead of calling
  1672. // IfaceMgr::receive4(), it will read all packets from the list set by
  1673. // fakeReceive()
  1674. // In particular, it should call registered pkt4_receive callback.
  1675. srv_->run();
  1676. // Check that the server dropped the packet and did not send a response
  1677. ASSERT_EQ(0, srv_->fake_sent_.size());
  1678. }
  1679. // Checks if callouts installed on pkt4_received is able to set skip flag that
  1680. // will cause the server to not process the packet (drop), even though it is valid.
  1681. TEST_F(HooksDhcpv4SrvTest, skip_pkt4_receive) {
  1682. // Install pkt4_receive_callout
  1683. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1684. "pkt4_receive", pkt4_receive_skip));
  1685. // Let's create a simple DISCOVER
  1686. Pkt4Ptr sol = Pkt4Ptr(generateSimpleDiscover());
  1687. // Simulate that we have received that traffic
  1688. srv_->fakeReceive(sol);
  1689. // Server will now process to run its normal loop, but instead of calling
  1690. // IfaceMgr::receive4(), it will read all packets from the list set by
  1691. // fakeReceive()
  1692. // In particular, it should call registered pkt4_receive callback.
  1693. srv_->run();
  1694. // check that the server dropped the packet and did not produce any response
  1695. ASSERT_EQ(0, srv_->fake_sent_.size());
  1696. }
  1697. // Checks if callouts installed on pkt4_send are indeed called and the
  1698. // all necessary parameters are passed.
  1699. TEST_F(HooksDhcpv4SrvTest, simple_pkt4_send) {
  1700. // Install pkt4_receive_callout
  1701. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1702. "pkt4_send", pkt4_send_callout));
  1703. // Let's create a simple DISCOVER
  1704. Pkt4Ptr sol = Pkt4Ptr(generateSimpleDiscover());
  1705. // Simulate that we have received that traffic
  1706. srv_->fakeReceive(sol);
  1707. // Server will now process to run its normal loop, but instead of calling
  1708. // IfaceMgr::receive4(), it will read all packets from the list set by
  1709. // fakeReceive()
  1710. // In particular, it should call registered pkt4_receive callback.
  1711. srv_->run();
  1712. // Check that the callback called is indeed the one we installed
  1713. EXPECT_EQ("pkt4_send", callback_name_);
  1714. // Check that there is one packet sent
  1715. ASSERT_EQ(1, srv_->fake_sent_.size());
  1716. Pkt4Ptr adv = srv_->fake_sent_.front();
  1717. // Check that pkt4 argument passing was successful and returned proper value
  1718. EXPECT_TRUE(callback_pkt4_.get() == adv.get());
  1719. // Check that all expected parameters are there
  1720. vector<string> expected_argument_names;
  1721. expected_argument_names.push_back(string("response4"));
  1722. EXPECT_TRUE(expected_argument_names == callback_argument_names_);
  1723. }
  1724. // Checks if callouts installed on pkt4_send is able to change
  1725. // the values and the packet sent contains those changes
  1726. TEST_F(HooksDhcpv4SrvTest, valueChange_pkt4_send) {
  1727. // Install pkt4_receive_callout
  1728. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1729. "pkt4_send", pkt4_send_change_serverid));
  1730. // Let's create a simple DISCOVER
  1731. Pkt4Ptr sol = Pkt4Ptr(generateSimpleDiscover());
  1732. // Simulate that we have received that traffic
  1733. srv_->fakeReceive(sol);
  1734. // Server will now process to run its normal loop, but instead of calling
  1735. // IfaceMgr::receive4(), it will read all packets from the list set by
  1736. // fakeReceive()
  1737. // In particular, it should call registered pkt4_receive callback.
  1738. srv_->run();
  1739. // check that the server did send a reposonce
  1740. ASSERT_EQ(1, srv_->fake_sent_.size());
  1741. // Make sure that we received a response
  1742. Pkt4Ptr adv = srv_->fake_sent_.front();
  1743. ASSERT_TRUE(adv);
  1744. // Get client-id...
  1745. OptionPtr clientid = adv->getOption(DHO_DHCP_SERVER_IDENTIFIER);
  1746. // ... and check if it is the modified value
  1747. OptionPtr expected = createOption(DHO_DHCP_SERVER_IDENTIFIER);
  1748. EXPECT_TRUE(clientid->equal(expected));
  1749. }
  1750. // Checks if callouts installed on pkt4_send is able to delete
  1751. // existing options and that server applies those changes. In particular,
  1752. // we are trying to send a packet without server-id. The packet should
  1753. // be sent
  1754. TEST_F(HooksDhcpv4SrvTest, deleteServerId_pkt4_send) {
  1755. // Install pkt4_receive_callout
  1756. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1757. "pkt4_send", pkt4_send_delete_serverid));
  1758. // Let's create a simple DISCOVER
  1759. Pkt4Ptr sol = Pkt4Ptr(generateSimpleDiscover());
  1760. // Simulate that we have received that traffic
  1761. srv_->fakeReceive(sol);
  1762. // Server will now process to run its normal loop, but instead of calling
  1763. // IfaceMgr::receive4(), it will read all packets from the list set by
  1764. // fakeReceive()
  1765. // In particular, it should call registered pkt4_receive callback.
  1766. srv_->run();
  1767. // Check that the server indeed sent a malformed ADVERTISE
  1768. ASSERT_EQ(1, srv_->fake_sent_.size());
  1769. // Get that ADVERTISE
  1770. Pkt4Ptr adv = srv_->fake_sent_.front();
  1771. ASSERT_TRUE(adv);
  1772. // Make sure that it does not have server-id
  1773. EXPECT_FALSE(adv->getOption(DHO_DHCP_SERVER_IDENTIFIER));
  1774. }
  1775. // Checks if callouts installed on pkt4_skip is able to set skip flag that
  1776. // will cause the server to not process the packet (drop), even though it is valid.
  1777. TEST_F(HooksDhcpv4SrvTest, skip_pkt4_send) {
  1778. // Install pkt4_receive_callout
  1779. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1780. "pkt4_send", pkt4_send_skip));
  1781. // Let's create a simple REQUEST
  1782. Pkt4Ptr sol = Pkt4Ptr(generateSimpleDiscover());
  1783. // Simulate that we have received that traffic
  1784. srv_->fakeReceive(sol);
  1785. // Server will now process to run its normal loop, but instead of calling
  1786. // IfaceMgr::receive4(), it will read all packets from the list set by
  1787. // fakeReceive()
  1788. // In particular, it should call registered pkt4_receive callback.
  1789. srv_->run();
  1790. // check that the server dropped the packet and did not produce any response
  1791. ASSERT_EQ(0, srv_->fake_sent_.size());
  1792. }
  1793. // This test checks if subnet4_select callout is triggered and reports
  1794. // valid parameters
  1795. TEST_F(HooksDhcpv4SrvTest, subnet4_select) {
  1796. // Install pkt4_receive_callout
  1797. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1798. "subnet4_select", subnet4_select_callout));
  1799. // Configure 2 subnets, both directly reachable over local interface
  1800. // (let's not complicate the matter with relays)
  1801. string config = "{ \"interfaces\": [ \"*\" ],"
  1802. "\"rebind-timer\": 2000, "
  1803. "\"renew-timer\": 1000, "
  1804. "\"subnet4\": [ { "
  1805. " \"pool\": [ \"192.0.2.0/25\" ],"
  1806. " \"subnet\": \"192.0.2.0/24\", "
  1807. " \"interface\": \"" + valid_iface_ + "\" "
  1808. " }, {"
  1809. " \"pool\": [ \"192.0.3.0/25\" ],"
  1810. " \"subnet\": \"192.0.3.0/24\" "
  1811. " } ],"
  1812. "\"valid-lifetime\": 4000 }";
  1813. ElementPtr json = Element::fromJSON(config);
  1814. ConstElementPtr status;
  1815. // Configure the server and make sure the config is accepted
  1816. EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
  1817. ASSERT_TRUE(status);
  1818. comment_ = config::parseAnswer(rcode_, status);
  1819. ASSERT_EQ(0, rcode_);
  1820. // Prepare discover packet. Server should select first subnet for it
  1821. Pkt4Ptr sol = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
  1822. sol->setRemoteAddr(IOAddress("192.0.2.1"));
  1823. sol->setIface(valid_iface_);
  1824. OptionPtr clientid = generateClientId();
  1825. sol->addOption(clientid);
  1826. // Pass it to the server and get an advertise
  1827. Pkt4Ptr adv = srv_->processDiscover(sol);
  1828. // check if we get response at all
  1829. ASSERT_TRUE(adv);
  1830. // Check that the callback called is indeed the one we installed
  1831. EXPECT_EQ("subnet4_select", callback_name_);
  1832. // Check that pkt4 argument passing was successful and returned proper value
  1833. EXPECT_TRUE(callback_pkt4_.get() == sol.get());
  1834. const Subnet4Collection* exp_subnets = CfgMgr::instance().getSubnets4();
  1835. // The server is supposed to pick the first subnet, because of matching
  1836. // interface. Check that the value is reported properly.
  1837. ASSERT_TRUE(callback_subnet4_);
  1838. EXPECT_EQ(exp_subnets->front().get(), callback_subnet4_.get());
  1839. // Server is supposed to report two subnets
  1840. ASSERT_EQ(exp_subnets->size(), callback_subnet4collection_->size());
  1841. // Compare that the available subnets are reported as expected
  1842. EXPECT_TRUE((*exp_subnets)[0].get() == (*callback_subnet4collection_)[0].get());
  1843. EXPECT_TRUE((*exp_subnets)[1].get() == (*callback_subnet4collection_)[1].get());
  1844. }
  1845. // This test checks if callout installed on subnet4_select hook point can pick
  1846. // a different subnet.
  1847. TEST_F(HooksDhcpv4SrvTest, subnet_select_change) {
  1848. // Install pkt4_receive_callout
  1849. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1850. "subnet4_select", subnet4_select_different_subnet_callout));
  1851. // Configure 2 subnets, both directly reachable over local interface
  1852. // (let's not complicate the matter with relays)
  1853. string config = "{ \"interfaces\": [ \"*\" ],"
  1854. "\"rebind-timer\": 2000, "
  1855. "\"renew-timer\": 1000, "
  1856. "\"subnet4\": [ { "
  1857. " \"pool\": [ \"192.0.2.0/25\" ],"
  1858. " \"subnet\": \"192.0.2.0/24\", "
  1859. " \"interface\": \"" + valid_iface_ + "\" "
  1860. " }, {"
  1861. " \"pool\": [ \"192.0.3.0/25\" ],"
  1862. " \"subnet\": \"192.0.3.0/24\" "
  1863. " } ],"
  1864. "\"valid-lifetime\": 4000 }";
  1865. ElementPtr json = Element::fromJSON(config);
  1866. ConstElementPtr status;
  1867. // Configure the server and make sure the config is accepted
  1868. EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
  1869. ASSERT_TRUE(status);
  1870. comment_ = config::parseAnswer(rcode_, status);
  1871. ASSERT_EQ(0, rcode_);
  1872. // Prepare discover packet. Server should select first subnet for it
  1873. Pkt4Ptr sol = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
  1874. sol->setRemoteAddr(IOAddress("192.0.2.1"));
  1875. sol->setIface(valid_iface_);
  1876. OptionPtr clientid = generateClientId();
  1877. sol->addOption(clientid);
  1878. // Pass it to the server and get an advertise
  1879. Pkt4Ptr adv = srv_->processDiscover(sol);
  1880. // check if we get response at all
  1881. ASSERT_TRUE(adv);
  1882. // The response should have an address from second pool, so let's check it
  1883. IOAddress addr = adv->getYiaddr();
  1884. EXPECT_NE("0.0.0.0", addr.toText());
  1885. // Get all subnets and use second subnet for verification
  1886. const Subnet4Collection* subnets = CfgMgr::instance().getSubnets4();
  1887. ASSERT_EQ(2, subnets->size());
  1888. // Advertised address must belong to the second pool (in subnet's range,
  1889. // in dynamic pool)
  1890. EXPECT_TRUE((*subnets)[1]->inRange(addr));
  1891. EXPECT_TRUE((*subnets)[1]->inPool(addr));
  1892. }
  1893. } // end of anonymous namespace