12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562 |
- // Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
- //
- // Permission to use, copy, modify, and/or distribute this software for any
- // purpose with or without fee is hereby granted, provided that the above
- // copyright notice and this permission notice appear in all copies.
- //
- // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
- // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
- // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- // PERFORMANCE OF THIS SOFTWARE.
- #include <config.h>
- #include <dhcp4/tests/dhcp4_test_utils.h>
- #include <dhcp4/json_config_parser.h>
- #include <cc/command_interpreter.h>
- #include <config/command_mgr.h>
- #include <hooks/server_hooks.h>
- #include <hooks/hooks_manager.h>
- #include <dhcpsrv/cfgmgr.h>
- #include <dhcp/tests/iface_mgr_test_config.h>
- #include <dhcp/option.h>
- #include <asiolink/io_address.h>
- #include <vector>
- using namespace std;
- using namespace isc::asiolink;
- using namespace isc::data;
- using namespace isc::hooks;
- using namespace isc::config;
- using namespace isc::dhcp::test;
- using namespace isc::dhcp;
- // Checks if hooks are registered properly.
- TEST_F(Dhcpv4SrvTest, Hooks) {
- NakedDhcpv4Srv srv(0);
- // check if appropriate hooks are registered
- int hook_index_buffer4_receive = -1;
- int hook_index_pkt4_receive = -1;
- int hook_index_select_subnet = -1;
- int hook_index_lease4_release = -1;
- int hook_index_pkt4_send = -1;
- int hook_index_buffer4_send = -1;
- // check if appropriate indexes are set
- EXPECT_NO_THROW(hook_index_buffer4_receive = ServerHooks::getServerHooks()
- .getIndex("buffer4_receive"));
- EXPECT_NO_THROW(hook_index_pkt4_receive = ServerHooks::getServerHooks()
- .getIndex("pkt4_receive"));
- EXPECT_NO_THROW(hook_index_select_subnet = ServerHooks::getServerHooks()
- .getIndex("subnet4_select"));
- EXPECT_NO_THROW(hook_index_lease4_release = ServerHooks::getServerHooks()
- .getIndex("lease4_release"));
- EXPECT_NO_THROW(hook_index_pkt4_send = ServerHooks::getServerHooks()
- .getIndex("pkt4_send"));
- EXPECT_NO_THROW(hook_index_buffer4_send = ServerHooks::getServerHooks()
- .getIndex("buffer4_send"));
- EXPECT_TRUE(hook_index_buffer4_receive > 0);
- EXPECT_TRUE(hook_index_pkt4_receive > 0);
- EXPECT_TRUE(hook_index_select_subnet > 0);
- EXPECT_TRUE(hook_index_lease4_release > 0);
- EXPECT_TRUE(hook_index_pkt4_send > 0);
- EXPECT_TRUE(hook_index_buffer4_send > 0);
- }
- // A dummy MAC address, padded with 0s
- const uint8_t dummyChaddr[16] = {0, 1, 2, 3, 4, 5, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 };
- // Let's use some creative test content here (128 chars + \0)
- const uint8_t dummyFile[] = "Lorem ipsum dolor sit amet, consectetur "
- "adipiscing elit. Proin mollis placerat metus, at "
- "lacinia orci ornare vitae. Mauris amet.";
- // Yet another type of test content (64 chars + \0)
- const uint8_t dummySname[] = "Lorem ipsum dolor sit amet, consectetur "
- "adipiscing elit posuere.";
- /// @brief a class dedicated to Hooks testing in DHCPv4 server
- ///
- /// This class has a number of static members, because each non-static
- /// method has implicit 'this' parameter, so it does not match callout
- /// signature and couldn't be registered. Furthermore, static methods
- /// can't modify non-static members (for obvious reasons), so many
- /// fields are declared static. It is still better to keep them as
- /// one class rather than unrelated collection of global objects.
- class HooksDhcpv4SrvTest : public Dhcpv4SrvTest {
- public:
- /// @brief creates Dhcpv4Srv and prepares buffers for callouts
- HooksDhcpv4SrvTest() {
- // Allocate new DHCPv6 Server
- srv_ = new NakedDhcpv4Srv(0);
- // clear static buffers
- resetCalloutBuffers();
- }
- /// @brief destructor (deletes Dhcpv4Srv)
- virtual ~HooksDhcpv4SrvTest() {
- HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("buffer4_receive");
- HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("buffer4_send");
- HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("pkt4_receive");
- HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("pkt4_send");
- HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("subnet4_select");
- HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("lease4_renew");
- HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("lease4_release");
- HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("lease4_decline");
- delete srv_;
- }
- /// @brief creates an option with specified option code
- ///
- /// This method is static, because it is used from callouts
- /// that do not have a pointer to HooksDhcpv4SSrvTest object
- ///
- /// @param option_code code of option to be created
- ///
- /// @return pointer to create option object
- static OptionPtr createOption(uint16_t option_code) {
- char payload[] = {
- 0xa, 0xb, 0xc, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14
- };
- OptionBuffer tmp(payload, payload + sizeof(payload));
- return OptionPtr(new Option(Option::V4, option_code, tmp));
- }
- /// @brief Generates test packet.
- ///
- /// Allocates and generates on-wire buffer that represents test packet, with all
- /// fixed fields set to non-zero values. Content is not always reasonable.
- ///
- /// See generateTestPacket1() function that returns exactly the same packet as
- /// Pkt4 object.
- ///
- /// @return pointer to allocated Pkt4 object
- // Returns a vector containing a DHCPv4 packet header.
- Pkt4Ptr
- generateSimpleDiscover() {
- // That is only part of the header. It contains all "short" fields,
- // larger fields are constructed separately.
- uint8_t hdr[] = {
- 1, 6, 6, 13, // op, htype, hlen, hops,
- 0x12, 0x34, 0x56, 0x78, // transaction-id
- 0, 42, 0x80, 0x00, // 42 secs, BROADCAST flags
- 192, 0, 2, 1, // ciaddr
- 1, 2, 3, 4, // yiaddr
- 192, 0, 2, 255, // siaddr
- 192, 0, 2, 50, // giaddr
- };
- // Initialize the vector with the header fields defined above.
- vector<uint8_t> buf(hdr, hdr + sizeof(hdr));
- // Append the large header fields.
- copy(dummyChaddr, dummyChaddr + Pkt4::MAX_CHADDR_LEN, back_inserter(buf));
- copy(dummySname, dummySname + Pkt4::MAX_SNAME_LEN, back_inserter(buf));
- copy(dummyFile, dummyFile + Pkt4::MAX_FILE_LEN, back_inserter(buf));
- // Should now have all the header, so check. The "static_cast" is used
- // to get round an odd bug whereby the linker appears not to find the
- // definition of DHCPV4_PKT_HDR_LEN if it appears within an EXPECT_EQ().
- EXPECT_EQ(static_cast<size_t>(Pkt4::DHCPV4_PKT_HDR_LEN), buf.size());
- // Add magic cookie
- buf.push_back(0x63);
- buf.push_back(0x82);
- buf.push_back(0x53);
- buf.push_back(0x63);
- // Add message type DISCOVER
- buf.push_back(static_cast<uint8_t>(DHO_DHCP_MESSAGE_TYPE));
- buf.push_back(1); // length (just one byte)
- buf.push_back(static_cast<uint8_t>(DHCPDISCOVER));
- Pkt4Ptr dis(new Pkt4(&buf[0], buf.size()));
- // Interface must be selected for a Discover. Server will use the interface
- // name to select a subnet for a client. This test is using fake interfaces
- // and the fake eth0 interface has IPv4 address matching the subnet
- // currently configured for this test.
- dis->setIface("eth1");
- return (dis);
- }
- /// Test callback that stores received callout name and pkt4 value
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- buffer4_receive_callout(CalloutHandle& callout_handle) {
- callback_name_ = string("buffer4_receive");
- callout_handle.getArgument("query4", callback_pkt4_);
- callback_argument_names_ = callout_handle.getArgumentNames();
- return (0);
- }
- /// Test callback that changes hwaddr value
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- buffer4_receive_change_hwaddr(CalloutHandle& callout_handle) {
- Pkt4Ptr pkt;
- callout_handle.getArgument("query4", pkt);
- // If there is at least one option with data
- if (pkt->data_.size() >= Pkt4::DHCPV4_PKT_HDR_LEN) {
- // Offset of the first byte of the CHWADDR field. Let's the first
- // byte to some new value that we could later check
- pkt->data_[28] = 0xff;
- }
- // Carry on as usual
- return buffer4_receive_callout(callout_handle);
- }
- /// Test callback that sets skip flag
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- buffer4_receive_skip(CalloutHandle& callout_handle) {
- callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
- // Carry on as usual
- return buffer4_receive_callout(callout_handle);
- }
- /// test callback that stores received callout name and pkt4 value
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- pkt4_receive_callout(CalloutHandle& callout_handle) {
- callback_name_ = string("pkt4_receive");
- callout_handle.getArgument("query4", callback_pkt4_);
- callback_argument_names_ = callout_handle.getArgumentNames();
- return (0);
- }
- /// test callback that changes client-id value
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- pkt4_receive_change_clientid(CalloutHandle& callout_handle) {
- Pkt4Ptr pkt;
- callout_handle.getArgument("query4", pkt);
- // get rid of the old client-id
- pkt->delOption(DHO_DHCP_CLIENT_IDENTIFIER);
- // add a new option
- pkt->addOption(createOption(DHO_DHCP_CLIENT_IDENTIFIER));
- // carry on as usual
- return pkt4_receive_callout(callout_handle);
- }
- /// test callback that deletes client-id
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- pkt4_receive_delete_clientid(CalloutHandle& callout_handle) {
- Pkt4Ptr pkt;
- callout_handle.getArgument("query4", pkt);
- // get rid of the old client-id (and no HWADDR)
- vector<uint8_t> mac;
- pkt->delOption(DHO_DHCP_CLIENT_IDENTIFIER);
- pkt->setHWAddr(1, 0, mac); // HWtype 1, hardware len = 0
- // carry on as usual
- return pkt4_receive_callout(callout_handle);
- }
- /// test callback that sets skip flag
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- pkt4_receive_skip(CalloutHandle& callout_handle) {
- Pkt4Ptr pkt;
- callout_handle.getArgument("query4", pkt);
- callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
- // carry on as usual
- return pkt4_receive_callout(callout_handle);
- }
- /// Test callback that stores received callout name and pkt4 value
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- pkt4_send_callout(CalloutHandle& callout_handle) {
- callback_name_ = string("pkt4_send");
- callout_handle.getArgument("response4", callback_pkt4_);
- callback_argument_names_ = callout_handle.getArgumentNames();
- return (0);
- }
- // Test callback that changes server-id
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- pkt4_send_change_serverid(CalloutHandle& callout_handle) {
- Pkt4Ptr pkt;
- callout_handle.getArgument("response4", pkt);
- // get rid of the old server-id
- pkt->delOption(DHO_DHCP_SERVER_IDENTIFIER);
- // add a new option
- pkt->addOption(createOption(DHO_DHCP_SERVER_IDENTIFIER));
- // carry on as usual
- return pkt4_send_callout(callout_handle);
- }
- /// test callback that deletes server-id
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- pkt4_send_delete_serverid(CalloutHandle& callout_handle) {
- Pkt4Ptr pkt;
- callout_handle.getArgument("response4", pkt);
- // get rid of the old client-id
- pkt->delOption(DHO_DHCP_SERVER_IDENTIFIER);
- // carry on as usual
- return pkt4_send_callout(callout_handle);
- }
- /// Test callback that sets skip flag
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- pkt4_send_skip(CalloutHandle& callout_handle) {
- Pkt4Ptr pkt;
- callout_handle.getArgument("response4", pkt);
- callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
- // carry on as usual
- return pkt4_send_callout(callout_handle);
- }
- /// Test callback that stores received callout name and pkt4 value
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- buffer4_send_callout(CalloutHandle& callout_handle) {
- callback_name_ = string("buffer4_send");
- callout_handle.getArgument("response4", callback_pkt4_);
- callback_argument_names_ = callout_handle.getArgumentNames();
- return (0);
- }
- /// Test callback changes the output buffer to a hardcoded value
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- buffer4_send_change_callout(CalloutHandle& callout_handle) {
- Pkt4Ptr pkt;
- callout_handle.getArgument("response4", pkt);
- // modify buffer to set a different payload
- pkt->getBuffer().clear();
- pkt->getBuffer().writeData(dummyFile, sizeof(dummyFile));
- return (0);
- }
- /// Test callback that stores received callout name and pkt4 value
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- skip_callout(CalloutHandle& callout_handle) {
- callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
- return (0);
- }
- /// Test callback that stores received callout name and subnet4 values
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- subnet4_select_callout(CalloutHandle& callout_handle) {
- callback_name_ = string("subnet4_select");
- callout_handle.getArgument("query4", callback_pkt4_);
- callout_handle.getArgument("subnet4", callback_subnet4_);
- callout_handle.getArgument("subnet4collection", callback_subnet4collection_);
- callback_argument_names_ = callout_handle.getArgumentNames();
- return (0);
- }
- /// Test callback that picks the other subnet if possible.
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- subnet4_select_different_subnet_callout(CalloutHandle& callout_handle) {
- // Call the basic callout to record all passed values
- subnet4_select_callout(callout_handle);
- const Subnet4Collection* subnets;
- Subnet4Ptr subnet;
- callout_handle.getArgument("subnet4", subnet);
- callout_handle.getArgument("subnet4collection", subnets);
- // Let's change to a different subnet
- if (subnets->size() > 1) {
- subnet = (*subnets)[1]; // Let's pick the other subnet
- callout_handle.setArgument("subnet4", subnet);
- }
- return (0);
- }
- /// Test callback that stores received callout name passed parameters
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- lease4_release_callout(CalloutHandle& callout_handle) {
- callback_name_ = string("lease4_release");
- callout_handle.getArgument("query4", callback_pkt4_);
- callout_handle.getArgument("lease4", callback_lease4_);
- callback_argument_names_ = callout_handle.getArgumentNames();
- return (0);
- }
- /// Test callback that stores received callout name and subnet4 values
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- lease4_renew_callout(CalloutHandle& callout_handle) {
- callback_name_ = string("lease4_renew");
- callout_handle.getArgument("subnet4", callback_subnet4_);
- callout_handle.getArgument("lease4", callback_lease4_);
- callout_handle.getArgument("hwaddr", callback_hwaddr_);
- callout_handle.getArgument("clientid", callback_clientid_);
- callback_argument_names_ = callout_handle.getArgumentNames();
- return (0);
- }
- /// Test lease4_decline callback that stores received parameters.
- ///
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- lease4_decline_callout(CalloutHandle& callout_handle) {
- callback_name_ = string("lease4_decline");
- callout_handle.getArgument("query4", callback_pkt4_);
- callout_handle.getArgument("lease4", callback_lease4_);
- return (0);
- }
- /// Test lease4_decline callback that sets next step to DROP.
- ///
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- lease4_decline_drop_callout(CalloutHandle& callout_handle) {
- callout_handle.setStatus(CalloutHandle::NEXT_STEP_DROP);
- return (lease4_decline_callout(callout_handle));
- }
- /// resets buffers used to store data received by callouts
- void resetCalloutBuffers() {
- callback_name_ = string("");
- callback_pkt4_.reset();
- callback_lease4_.reset();
- callback_hwaddr_.reset();
- callback_clientid_.reset();
- callback_subnet4_.reset();
- callback_subnet4collection_ = NULL;
- callback_argument_names_.clear();
- }
- /// pointer to Dhcpv4Srv that is used in tests
- NakedDhcpv4Srv* srv_;
- // The following fields are used in testing pkt4_receive_callout
- /// String name of the received callout
- static string callback_name_;
- /// Pkt4 structure returned in the callout
- static Pkt4Ptr callback_pkt4_;
- /// Lease4 structure returned in the callout
- static Lease4Ptr callback_lease4_;
- /// Hardware address returned in the callout
- static HWAddrPtr callback_hwaddr_;
- /// Client-id returned in the callout
- static ClientIdPtr callback_clientid_;
- /// Pointer to a subnet received by callout
- static Subnet4Ptr callback_subnet4_;
- /// A list of all available subnets (received by callout)
- static const Subnet4Collection* callback_subnet4collection_;
- /// A list of all received arguments
- static vector<string> callback_argument_names_;
- };
- // The following fields are used in testing pkt4_receive_callout.
- // See fields description in the class for details
- string HooksDhcpv4SrvTest::callback_name_;
- Pkt4Ptr HooksDhcpv4SrvTest::callback_pkt4_;
- Subnet4Ptr HooksDhcpv4SrvTest::callback_subnet4_;
- HWAddrPtr HooksDhcpv4SrvTest::callback_hwaddr_;
- ClientIdPtr HooksDhcpv4SrvTest::callback_clientid_;
- Lease4Ptr HooksDhcpv4SrvTest::callback_lease4_;
- const Subnet4Collection* HooksDhcpv4SrvTest::callback_subnet4collection_;
- vector<string> HooksDhcpv4SrvTest::callback_argument_names_;
- // Checks if callouts installed on pkt4_receive are indeed called and the
- // all necessary parameters are passed.
- //
- // Note that the test name does not follow test naming convention,
- // but the proper hook name is "buffer4_receive".
- TEST_F(HooksDhcpv4SrvTest, Buffer4ReceiveSimple) {
- IfaceMgrTestConfig test_config(true);
- IfaceMgr::instance().openSockets4();
- // Install pkt4_receive_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "buffer4_receive", buffer4_receive_callout));
- // Let's create a simple DISCOVER
- Pkt4Ptr dis = generateSimpleDiscover();
- // Simulate that we have received that traffic
- srv_->fakeReceive(dis);
- // Server will now process to run its normal loop, but instead of calling
- // IfaceMgr::receive4(), it will read all packets from the list set by
- // fakeReceive()
- // In particular, it should call registered buffer4_receive callback.
- srv_->run();
- // Check that the callback called is indeed the one we installed
- EXPECT_EQ("buffer4_receive", callback_name_);
- // Check that pkt4 argument passing was successful and returned proper value
- EXPECT_TRUE(callback_pkt4_.get() == dis.get());
- // Check that all expected parameters are there
- vector<string> expected_argument_names;
- expected_argument_names.push_back(string("query4"));
- EXPECT_TRUE(expected_argument_names == callback_argument_names_);
- }
- // Checks if callouts installed on buffer4_receive is able to change
- // the values and the parameters are indeed used by the server.
- TEST_F(HooksDhcpv4SrvTest, buffer4ReceiveValueChange) {
- IfaceMgrTestConfig test_config(true);
- IfaceMgr::instance().openSockets4();
- // Install callback that modifies MAC addr of incoming packet
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "buffer4_receive", buffer4_receive_change_hwaddr));
- // Let's create a simple DISCOVER
- Pkt4Ptr discover = generateSimpleDiscover();
- // Simulate that we have received that traffic
- srv_->fakeReceive(discover);
- // Server will now process to run its normal loop, but instead of calling
- // IfaceMgr::receive6(), it will read all packets from the list set by
- // fakeReceive()
- // In particular, it should call registered buffer4_receive callback.
- srv_->run();
- // Check that the server did send a response
- ASSERT_EQ(1, srv_->fake_sent_.size());
- // Make sure that we received a response
- Pkt4Ptr offer = srv_->fake_sent_.front();
- ASSERT_TRUE(offer);
- // Get client-id...
- HWAddrPtr hwaddr = offer->getHWAddr();
- ASSERT_TRUE(hwaddr); // basic sanity check. HWAddr is always present
- // ... and check if it is the modified value
- ASSERT_FALSE(hwaddr->hwaddr_.empty()); // there must be a MAC address
- EXPECT_EQ(0xff, hwaddr->hwaddr_[0]); // check that its first byte was modified
- }
- // Checks if callouts installed on buffer4_receive is able to set skip flag that
- // will cause the server to not parse the packet. Even though the packet is valid,
- // the server should eventually drop it, because there won't be mandatory options
- // (or rather option objects) in it.
- TEST_F(HooksDhcpv4SrvTest, buffer4ReceiveSkip) {
- IfaceMgrTestConfig test_config(true);
- IfaceMgr::instance().openSockets4();
- // Install pkt4_receive_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "buffer4_receive", buffer4_receive_skip));
- // Let's create a simple DISCOVER
- Pkt4Ptr discover = generateSimpleDiscover();
- // Simulate that we have received that traffic
- srv_->fakeReceive(discover);
- // Server will now process to run its normal loop, but instead of calling
- // IfaceMgr::receive6(), it will read all packets from the list set by
- // fakeReceive()
- // In particular, it should call registered pkt4_receive callback.
- srv_->run();
- // Check that the server dropped the packet and did not produce any response
- ASSERT_EQ(0, srv_->fake_sent_.size());
- }
- // Checks if callouts installed on pkt4_receive are indeed called and the
- // all necessary parameters are passed.
- //
- // Note that the test name does not follow test naming convention,
- // but the proper hook name is "pkt4_receive".
- TEST_F(HooksDhcpv4SrvTest, pkt4ReceiveSimple) {
- IfaceMgrTestConfig test_config(true);
- IfaceMgr::instance().openSockets4();
- // Install pkt4_receive_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "pkt4_receive", pkt4_receive_callout));
- // Let's create a simple DISCOVER
- Pkt4Ptr sol = generateSimpleDiscover();
- // Simulate that we have received that traffic
- srv_->fakeReceive(sol);
- // Server will now process to run its normal loop, but instead of calling
- // IfaceMgr::receive4(), it will read all packets from the list set by
- // fakeReceive()
- // In particular, it should call registered pkt4_receive callback.
- srv_->run();
- // check that the callback called is indeed the one we installed
- EXPECT_EQ("pkt4_receive", callback_name_);
- // check that pkt4 argument passing was successful and returned proper value
- EXPECT_TRUE(callback_pkt4_.get() == sol.get());
- // Check that all expected parameters are there
- vector<string> expected_argument_names;
- expected_argument_names.push_back(string("query4"));
- EXPECT_TRUE(expected_argument_names == callback_argument_names_);
- }
- // Checks if callouts installed on pkt4_received is able to change
- // the values and the parameters are indeed used by the server.
- TEST_F(HooksDhcpv4SrvTest, valueChange_pkt4_receive) {
- IfaceMgrTestConfig test_config(true);
- IfaceMgr::instance().openSockets4();
- // Install pkt4_receive_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "pkt4_receive", pkt4_receive_change_clientid));
- // Let's create a simple DISCOVER
- Pkt4Ptr sol = generateSimpleDiscover();
- // Simulate that we have received that traffic
- srv_->fakeReceive(sol);
- // Server will now process to run its normal loop, but instead of calling
- // IfaceMgr::receive4(), it will read all packets from the list set by
- // fakeReceive()
- // In particular, it should call registered pkt4_receive callback.
- srv_->run();
- // check that the server did send a response
- ASSERT_EQ(1, srv_->fake_sent_.size());
- // Make sure that we received a response
- Pkt4Ptr adv = srv_->fake_sent_.front();
- ASSERT_TRUE(adv);
- // Get client-id...
- OptionPtr clientid = adv->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
- // ... and check if it is the modified value
- OptionPtr expected = createOption(DHO_DHCP_CLIENT_IDENTIFIER);
- EXPECT_TRUE(clientid->equals(expected));
- }
- // Checks if callouts installed on pkt4_received is able to delete
- // existing options and that change impacts server processing (mandatory
- // client-id option is deleted, so the packet is expected to be dropped)
- TEST_F(HooksDhcpv4SrvTest, pkt4ReceiveDeleteClientId) {
- IfaceMgrTestConfig test_config(true);
- IfaceMgr::instance().openSockets4();
- // Install pkt4_receive_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "pkt4_receive", pkt4_receive_delete_clientid));
- // Let's create a simple DISCOVER
- Pkt4Ptr sol = generateSimpleDiscover();
- // Simulate that we have received that traffic
- srv_->fakeReceive(sol);
- // Server will now process to run its normal loop, but instead of calling
- // IfaceMgr::receive4(), it will read all packets from the list set by
- // fakeReceive()
- // In particular, it should call registered pkt4_receive callback.
- srv_->run();
- // Check that the server dropped the packet and did not send a response
- ASSERT_EQ(0, srv_->fake_sent_.size());
- }
- // Checks if callouts installed on pkt4_received is able to set skip flag that
- // will cause the server to not process the packet (drop), even though it is valid.
- TEST_F(HooksDhcpv4SrvTest, pkt4ReceiveSkip) {
- IfaceMgrTestConfig test_config(true);
- IfaceMgr::instance().openSockets4();
- // Install pkt4_receive_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "pkt4_receive", pkt4_receive_skip));
- // Let's create a simple DISCOVER
- Pkt4Ptr sol = generateSimpleDiscover();
- // Simulate that we have received that traffic
- srv_->fakeReceive(sol);
- // Server will now process to run its normal loop, but instead of calling
- // IfaceMgr::receive4(), it will read all packets from the list set by
- // fakeReceive()
- // In particular, it should call registered pkt4_receive callback.
- srv_->run();
- // check that the server dropped the packet and did not produce any response
- ASSERT_EQ(0, srv_->fake_sent_.size());
- }
- // Checks if callouts installed on pkt4_send are indeed called and the
- // all necessary parameters are passed.
- TEST_F(HooksDhcpv4SrvTest, pkt4SendSimple) {
- IfaceMgrTestConfig test_config(true);
- IfaceMgr::instance().openSockets4();
- // Install pkt4_receive_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "pkt4_send", pkt4_send_callout));
- // Let's create a simple DISCOVER
- Pkt4Ptr sol = generateSimpleDiscover();
- // Simulate that we have received that traffic
- srv_->fakeReceive(sol);
- // Server will now process to run its normal loop, but instead of calling
- // IfaceMgr::receive4(), it will read all packets from the list set by
- // fakeReceive()
- // In particular, it should call registered pkt4_receive callback.
- srv_->run();
- // Check that the callback called is indeed the one we installed
- EXPECT_EQ("pkt4_send", callback_name_);
- // Check that there is one packet sent
- ASSERT_EQ(1, srv_->fake_sent_.size());
- Pkt4Ptr adv = srv_->fake_sent_.front();
- // Check that pkt4 argument passing was successful and returned proper value
- EXPECT_TRUE(callback_pkt4_.get() == adv.get());
- // Check that all expected parameters are there
- vector<string> expected_argument_names;
- expected_argument_names.push_back(string("response4"));
- EXPECT_TRUE(expected_argument_names == callback_argument_names_);
- }
- // Checks if callouts installed on pkt4_send is able to change
- // the values and the packet sent contains those changes
- TEST_F(HooksDhcpv4SrvTest, pkt4SendValueChange) {
- IfaceMgrTestConfig test_config(true);
- IfaceMgr::instance().openSockets4();
- // Install pkt4_receive_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "pkt4_send", pkt4_send_change_serverid));
- // Let's create a simple DISCOVER
- Pkt4Ptr sol = generateSimpleDiscover();
- // Simulate that we have received that traffic
- srv_->fakeReceive(sol);
- // Server will now process to run its normal loop, but instead of calling
- // IfaceMgr::receive4(), it will read all packets from the list set by
- // fakeReceive()
- // In particular, it should call registered pkt4_receive callback.
- srv_->run();
- // check that the server did send a response
- ASSERT_EQ(1, srv_->fake_sent_.size());
- // Make sure that we received a response
- Pkt4Ptr adv = srv_->fake_sent_.front();
- ASSERT_TRUE(adv);
- // Get client-id...
- OptionPtr clientid = adv->getOption(DHO_DHCP_SERVER_IDENTIFIER);
- // ... and check if it is the modified value
- OptionPtr expected = createOption(DHO_DHCP_SERVER_IDENTIFIER);
- EXPECT_TRUE(clientid->equals(expected));
- }
- // Checks if callouts installed on pkt4_send is able to delete
- // existing options and that server applies those changes. In particular,
- // we are trying to send a packet without server-id. The packet should
- // be sent
- TEST_F(HooksDhcpv4SrvTest, pkt4SendDeleteServerId) {
- IfaceMgrTestConfig test_config(true);
- IfaceMgr::instance().openSockets4();
- // Install pkt4_receive_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "pkt4_send", pkt4_send_delete_serverid));
- // Let's create a simple DISCOVER
- Pkt4Ptr sol = generateSimpleDiscover();
- // Simulate that we have received that traffic
- srv_->fakeReceive(sol);
- // Server will now process to run its normal loop, but instead of calling
- // IfaceMgr::receive4(), it will read all packets from the list set by
- // fakeReceive()
- // In particular, it should call registered pkt4_receive callback.
- srv_->run();
- // Check that the server indeed sent a malformed ADVERTISE
- ASSERT_EQ(1, srv_->fake_sent_.size());
- // Get that ADVERTISE
- Pkt4Ptr adv = srv_->fake_sent_.front();
- ASSERT_TRUE(adv);
- // Make sure that it does not have server-id
- EXPECT_FALSE(adv->getOption(DHO_DHCP_SERVER_IDENTIFIER));
- }
- // Checks if callouts installed on pkt4_skip is able to set skip flag that
- // will cause the server to not process the packet (drop), even though it is valid.
- TEST_F(HooksDhcpv4SrvTest, skip_pkt4_send) {
- IfaceMgrTestConfig test_config(true);
- IfaceMgr::instance().openSockets4();
- // Install pkt4_receive_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "pkt4_send", pkt4_send_skip));
- // Let's create a simple REQUEST
- Pkt4Ptr sol = generateSimpleDiscover();
- // Simulate that we have received that traffic
- srv_->fakeReceive(sol);
- // Server will now process to run its normal loop, but instead of calling
- // IfaceMgr::receive4(), it will read all packets from the list set by
- // fakeReceive()
- // In particular, it should call registered pkt4_send callback.
- srv_->run();
- // Check that the server sent the message
- ASSERT_EQ(1, srv_->fake_sent_.size());
- // Get the first packet and check that it has zero length (i.e. the server
- // did not do packing on its own)
- Pkt4Ptr sent = srv_->fake_sent_.front();
- EXPECT_EQ(0, sent->getBuffer().getLength());
- }
- // Checks if callouts installed on buffer4_send are indeed called and the
- // all necessary parameters are passed.
- TEST_F(HooksDhcpv4SrvTest, buffer4SendSimple) {
- IfaceMgrTestConfig test_config(true);
- IfaceMgr::instance().openSockets4();
- // Install pkt4_receive_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "buffer4_send", buffer4_send_callout));
- // Let's create a simple DISCOVER
- Pkt4Ptr discover = generateSimpleDiscover();
- // Simulate that we have received that traffic
- srv_->fakeReceive(discover);
- // Server will now process to run its normal loop, but instead of calling
- // IfaceMgr::receive4(), it will read all packets from the list set by
- // fakeReceive()
- // In particular, it should call registered pkt4_receive callback.
- srv_->run();
- // Check that the callback called is indeed the one we installed
- EXPECT_EQ("buffer4_send", callback_name_);
- // Check that there is one packet sent
- ASSERT_EQ(1, srv_->fake_sent_.size());
- Pkt4Ptr adv = srv_->fake_sent_.front();
- // Check that pkt4 argument passing was successful and returned proper value
- EXPECT_TRUE(callback_pkt4_.get() == adv.get());
- // Check that all expected parameters are there
- vector<string> expected_argument_names;
- expected_argument_names.push_back(string("response4"));
- EXPECT_TRUE(expected_argument_names == callback_argument_names_);
- }
- // Checks if callouts installed on buffer4_send are indeed called and that
- // the output buffer can be changed.
- TEST_F(HooksDhcpv4SrvTest, buffer4Send) {
- IfaceMgrTestConfig test_config(true);
- IfaceMgr::instance().openSockets4();
- // Install pkt4_receive_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "buffer4_send", buffer4_send_change_callout));
- // Let's create a simple DISCOVER
- Pkt4Ptr discover = generateSimpleDiscover();
- // Simulate that we have received that traffic
- srv_->fakeReceive(discover);
- // Server will now process to run its normal loop, but instead of calling
- // IfaceMgr::receive4(), it will read all packets from the list set by
- // fakeReceive()
- // In particular, it should call registered pkt4_receive callback.
- srv_->run();
- // Check that there is one packet sent
- ASSERT_EQ(1, srv_->fake_sent_.size());
- Pkt4Ptr adv = srv_->fake_sent_.front();
- // The callout is supposed to fill the output buffer with dummyFile content
- ASSERT_EQ(sizeof(dummyFile), adv->getBuffer().getLength());
- EXPECT_EQ(0, memcmp(adv->getBuffer().getData(), dummyFile, sizeof(dummyFile)));
- }
- // Checks if callouts installed on buffer4_send can set skip flag and that flag
- // causes the packet to not be sent
- TEST_F(HooksDhcpv4SrvTest, buffer4SendSkip) {
- IfaceMgrTestConfig test_config(true);
- IfaceMgr::instance().openSockets4();
- // Install pkt4_receive_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "buffer4_send", skip_callout));
- // Let's create a simple DISCOVER
- Pkt4Ptr discover = generateSimpleDiscover();
- // Simulate that we have received that traffic
- srv_->fakeReceive(discover);
- // Server will now process to run its normal loop, but instead of calling
- // IfaceMgr::receive4(), it will read all packets from the list set by
- // fakeReceive()
- // In particular, it should call registered pkt4_receive callback.
- srv_->run();
- // Check that there is no packet sent.
- ASSERT_EQ(0, srv_->fake_sent_.size());
- }
- // This test checks if subnet4_select callout is triggered and reports
- // valid parameters
- TEST_F(HooksDhcpv4SrvTest, subnet4SelectSimple) {
- IfaceMgrTestConfig test_config(true);
- IfaceMgr::instance().openSockets4();
- // Install pkt4_receive_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "subnet4_select", subnet4_select_callout));
- // Configure 2 subnets, both directly reachable over local interface
- // (let's not complicate the matter with relays)
- string config = "{ \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- "},"
- "\"rebind-timer\": 2000, "
- "\"renew-timer\": 1000, "
- "\"subnet4\": [ { "
- " \"pools\": [ { \"pool\": \"192.0.2.0/25\" } ],"
- " \"subnet\": \"192.0.2.0/24\", "
- " \"interface\": \"eth0\" "
- " }, {"
- " \"pools\": [ { \"pool\": \"192.0.3.0/25\" } ],"
- " \"subnet\": \"192.0.3.0/24\" "
- " } ],"
- "\"valid-lifetime\": 4000 }";
- ElementPtr json = Element::fromJSON(config);
- ConstElementPtr status;
- // Configure the server and make sure the config is accepted
- EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
- ASSERT_TRUE(status);
- comment_ = parseAnswer(rcode_, status);
- ASSERT_EQ(0, rcode_);
- // Commit the config
- CfgMgr::instance().commit();
- // Prepare discover packet. Server should select first subnet for it
- Pkt4Ptr sol = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
- sol->setRemoteAddr(IOAddress("192.0.2.1"));
- sol->setIface("eth1");
- OptionPtr clientid = generateClientId();
- sol->addOption(clientid);
- // Pass it to the server and get an advertise
- Pkt4Ptr adv = srv_->processDiscover(sol);
- // check if we get response at all
- ASSERT_TRUE(adv);
- // Check that the callback called is indeed the one we installed
- EXPECT_EQ("subnet4_select", callback_name_);
- // Check that pkt4 argument passing was successful and returned proper value
- EXPECT_TRUE(callback_pkt4_.get() == sol.get());
- const Subnet4Collection* exp_subnets =
- CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getAll();
- // The server is supposed to pick the first subnet, because of matching
- // interface. Check that the value is reported properly.
- ASSERT_TRUE(callback_subnet4_);
- EXPECT_EQ(exp_subnets->front().get(), callback_subnet4_.get());
- // Server is supposed to report two subnets
- ASSERT_EQ(exp_subnets->size(), callback_subnet4collection_->size());
- ASSERT_GE(exp_subnets->size(), 2);
- // Compare that the available subnets are reported as expected
- EXPECT_TRUE((*exp_subnets)[0].get() == (*callback_subnet4collection_)[0].get());
- EXPECT_TRUE((*exp_subnets)[1].get() == (*callback_subnet4collection_)[1].get());
- }
- // This test checks if callout installed on subnet4_select hook point can pick
- // a different subnet.
- TEST_F(HooksDhcpv4SrvTest, subnet4SelectChange) {
- IfaceMgrTestConfig test_config(true);
- IfaceMgr::instance().openSockets4();
- // Install a callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "subnet4_select", subnet4_select_different_subnet_callout));
- // Configure 2 subnets, both directly reachable over local interface
- // (let's not complicate the matter with relays)
- string config = "{ \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- "},"
- "\"rebind-timer\": 2000, "
- "\"renew-timer\": 1000, "
- "\"subnet4\": [ { "
- " \"pools\": [ { \"pool\": \"192.0.2.0/25\" } ],"
- " \"subnet\": \"192.0.2.0/24\", "
- " \"interface\": \"eth0\" "
- " }, {"
- " \"pools\": [ { \"pool\": \"192.0.3.0/25\" } ],"
- " \"subnet\": \"192.0.3.0/24\" "
- " } ],"
- "\"valid-lifetime\": 4000 }";
- ElementPtr json = Element::fromJSON(config);
- ConstElementPtr status;
- // Configure the server and make sure the config is accepted
- EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
- ASSERT_TRUE(status);
- comment_ = parseAnswer(rcode_, status);
- ASSERT_EQ(0, rcode_);
- CfgMgr::instance().commit();
- // Prepare discover packet. Server should select first subnet for it
- Pkt4Ptr sol = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
- sol->setRemoteAddr(IOAddress("192.0.2.1"));
- sol->setIface("eth0");
- OptionPtr clientid = generateClientId();
- sol->addOption(clientid);
- // Pass it to the server and get an advertise
- Pkt4Ptr adv = srv_->processDiscover(sol);
- // check if we get response at all
- ASSERT_TRUE(adv);
- // The response should have an address from second pool, so let's check it
- IOAddress addr = adv->getYiaddr();
- EXPECT_NE("0.0.0.0", addr.toText());
- // Get all subnets and use second subnet for verification
- const Subnet4Collection* subnets =
- CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getAll();
- ASSERT_EQ(2, subnets->size());
- // Advertised address must belong to the second pool (in subnet's range,
- // in dynamic pool)
- EXPECT_TRUE((*subnets)[1]->inRange(addr));
- EXPECT_TRUE((*subnets)[1]->inPool(Lease::TYPE_V4, addr));
- }
- // This test verifies that incoming (positive) REQUEST/Renewing can be handled
- // properly and that callout installed on lease4_renew is triggered with
- // expected parameters.
- TEST_F(HooksDhcpv4SrvTest, lease4RenewSimple) {
- IfaceMgrTestConfig test_config(true);
- IfaceMgr::instance().openSockets4();
- const IOAddress addr("192.0.2.106");
- const uint32_t temp_t1 = 50;
- const uint32_t temp_t2 = 75;
- const uint32_t temp_valid = 100;
- const time_t temp_timestamp = time(NULL) - 10;
- // Install a callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "lease4_renew", lease4_renew_callout));
- // Generate client-id also sets client_id_ member
- OptionPtr clientid = generateClientId();
- // Check that the address we are about to use is indeed in pool
- ASSERT_TRUE(subnet_->inPool(Lease::TYPE_V4, addr));
- // let's create a lease and put it in the LeaseMgr
- uint8_t hwaddr2_data[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
- HWAddrPtr hwaddr2(new HWAddr(hwaddr2_data, sizeof(hwaddr2_data), HTYPE_ETHER));
- Lease4Ptr used(new Lease4(IOAddress("192.0.2.106"), hwaddr2,
- &client_id_->getDuid()[0], client_id_->getDuid().size(),
- temp_valid, temp_t1, temp_t2, temp_timestamp,
- subnet_->getID()));
- ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
- // Check that the lease is really in the database
- Lease4Ptr l = LeaseMgrFactory::instance().getLease4(addr);
- ASSERT_TRUE(l);
- // Let's create a RENEW
- Pkt4Ptr req = Pkt4Ptr(new Pkt4(DHCPREQUEST, 1234));
- req->setRemoteAddr(IOAddress(addr));
- req->setYiaddr(addr);
- req->setCiaddr(addr); // client's address
- req->setIface("eth0");
- req->setHWAddr(hwaddr2);
- req->addOption(clientid);
- req->addOption(srv_->getServerID());
- // Pass it to the server and hope for a REPLY
- Pkt4Ptr ack = srv_->processRequest(req);
- // Check if we get response at all
- checkResponse(ack, DHCPACK, 1234);
- // Check that the lease is really in the database
- l = checkLease(ack, clientid, req->getHWAddr(), addr);
- ASSERT_TRUE(l);
- // Check that T1, T2, preferred, valid and cltt were really updated
- EXPECT_EQ(l->t1_, subnet_->getT1());
- EXPECT_EQ(l->t2_, subnet_->getT2());
- EXPECT_EQ(l->valid_lft_, subnet_->getValid());
- // Check that the callback called is indeed the one we installed
- EXPECT_EQ("lease4_renew", callback_name_);
- // Check that hwaddr parameter is passed properly
- ASSERT_TRUE(callback_hwaddr_);
- EXPECT_TRUE(*callback_hwaddr_ == *req->getHWAddr());
- // Check that the subnet is passed properly
- ASSERT_TRUE(callback_subnet4_);
- EXPECT_EQ(callback_subnet4_->toText(), subnet_->toText());
- ASSERT_TRUE(callback_clientid_);
- ASSERT_TRUE(client_id_);
- EXPECT_TRUE(*client_id_ == *callback_clientid_);
- // Check if all expected parameters were really received
- vector<string> expected_argument_names;
- expected_argument_names.push_back("subnet4");
- expected_argument_names.push_back("clientid");
- expected_argument_names.push_back("hwaddr");
- expected_argument_names.push_back("lease4");
- sort(callback_argument_names_.begin(), callback_argument_names_.end());
- sort(expected_argument_names.begin(), expected_argument_names.end());
- EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
- EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease(addr));
- }
- // This test verifies that a callout installed on lease4_renew can trigger
- // the server to not renew a lease.
- TEST_F(HooksDhcpv4SrvTest, lease4RenewSkip) {
- IfaceMgrTestConfig test_config(true);
- IfaceMgr::instance().openSockets4();
- const IOAddress addr("192.0.2.106");
- const uint32_t temp_t1 = 50;
- const uint32_t temp_t2 = 75;
- const uint32_t temp_valid = 100;
- const time_t temp_timestamp = time(NULL) - 10;
- // Install a callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "lease4_renew", skip_callout));
- // Generate client-id also sets client_id_ member
- OptionPtr clientid = generateClientId();
- // Check that the address we are about to use is indeed in pool
- ASSERT_TRUE(subnet_->inPool(Lease::TYPE_V4, addr));
- // let's create a lease and put it in the LeaseMgr
- uint8_t hwaddr2_data[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
- HWAddrPtr hwaddr2(new HWAddr(hwaddr2_data, sizeof(hwaddr2_data), HTYPE_ETHER));
- Lease4Ptr used(new Lease4(IOAddress("192.0.2.106"), hwaddr2,
- &client_id_->getDuid()[0], client_id_->getDuid().size(),
- temp_valid, temp_t1, temp_t2, temp_timestamp,
- subnet_->getID()));
- ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
- // Check that the lease is really in the database
- Lease4Ptr l = LeaseMgrFactory::instance().getLease4(addr);
- ASSERT_TRUE(l);
- // Check that T1, T2, preferred, valid and cltt really set.
- // Constructed lease looks as if it was assigned 10 seconds ago
- // EXPECT_EQ(l->t1_, temp_t1);
- // EXPECT_EQ(l->t2_, temp_t2);
- EXPECT_EQ(l->valid_lft_, temp_valid);
- EXPECT_EQ(l->cltt_, temp_timestamp);
- // Let's create a RENEW
- Pkt4Ptr req = Pkt4Ptr(new Pkt4(DHCPREQUEST, 1234));
- req->setRemoteAddr(IOAddress(addr));
- req->setYiaddr(addr);
- req->setCiaddr(addr); // client's address
- req->setIface("eth0");
- req->setHWAddr(hwaddr2);
- req->addOption(clientid);
- req->addOption(srv_->getServerID());
- // Pass it to the server and hope for a REPLY
- Pkt4Ptr ack = srv_->processRequest(req);
- ASSERT_TRUE(ack);
- // Check that the lease is really in the database
- l = checkLease(ack, clientid, req->getHWAddr(), addr);
- ASSERT_TRUE(l);
- // Check that T1, T2, valid and cltt were NOT updated
- EXPECT_EQ(temp_t1, l->t1_);
- EXPECT_EQ(temp_t2, l->t2_);
- EXPECT_EQ(temp_valid, l->valid_lft_);
- EXPECT_EQ(temp_timestamp, l->cltt_);
- EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease(addr));
- }
- // This test verifies that valid RELEASE triggers lease4_release callouts
- TEST_F(HooksDhcpv4SrvTest, lease4ReleaseSimple) {
- IfaceMgrTestConfig test_config(true);
- IfaceMgr::instance().openSockets4();
- const IOAddress addr("192.0.2.106");
- const uint32_t temp_t1 = 50;
- const uint32_t temp_t2 = 75;
- const uint32_t temp_valid = 100;
- const time_t temp_timestamp = time(NULL) - 10;
- // Install a callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "lease4_release", lease4_release_callout));
- // Generate client-id also duid_
- OptionPtr clientid = generateClientId();
- // Check that the address we are about to use is indeed in pool
- ASSERT_TRUE(subnet_->inPool(Lease::TYPE_V4, addr));
- // Let's create a lease and put it in the LeaseMgr
- uint8_t mac_addr[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
- HWAddrPtr hw(new HWAddr(mac_addr, sizeof(mac_addr), HTYPE_ETHER));
- Lease4Ptr used(new Lease4(addr, hw,
- &client_id_->getDuid()[0], client_id_->getDuid().size(),
- temp_valid, temp_t1, temp_t2, temp_timestamp,
- subnet_->getID()));
- ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
- // Check that the lease is really in the database
- Lease4Ptr l = LeaseMgrFactory::instance().getLease4(addr);
- ASSERT_TRUE(l);
- // Let's create a RELEASE
- // Generate client-id also duid_
- Pkt4Ptr rel = Pkt4Ptr(new Pkt4(DHCPRELEASE, 1234));
- rel->setRemoteAddr(addr);
- rel->setCiaddr(addr);
- rel->addOption(clientid);
- rel->addOption(srv_->getServerID());
- rel->setHWAddr(hw);
- // Pass it to the server and hope for a REPLY
- // Note: this is no response to RELEASE in DHCPv4
- EXPECT_NO_THROW(srv_->processRelease(rel));
- // The lease should be gone from LeaseMgr
- l = LeaseMgrFactory::instance().getLease4(addr);
- EXPECT_FALSE(l);
- // Try to get the lease by hardware address
- // @todo: Uncomment this once trac2592 is implemented
- // Lease4Collection leases = LeaseMgrFactory::instance().getLease4(hw->hwaddr_);
- // EXPECT_EQ(leases.size(), 0);
- // Try to get it by hw/subnet_id combination
- l = LeaseMgrFactory::instance().getLease4(hw->hwaddr_, subnet_->getID());
- EXPECT_FALSE(l);
- // Try by client-id
- // @todo: Uncomment this once trac2592 is implemented
- //Lease4Collection leases = LeaseMgrFactory::instance().getLease4(*client_id_);
- //EXPECT_EQ(leases.size(), 0);
- // Try by client-id/subnet-id
- l = LeaseMgrFactory::instance().getLease4(*client_id_, subnet_->getID());
- EXPECT_FALSE(l);
- // Ok, the lease is *really* not there.
- // Check that the callback called is indeed the one we installed
- EXPECT_EQ("lease4_release", callback_name_);
- // Check that pkt4 argument passing was successful and returned proper value
- EXPECT_TRUE(callback_pkt4_.get() == rel.get());
- // Check if all expected parameters were really received
- vector<string> expected_argument_names;
- expected_argument_names.push_back("query4");
- expected_argument_names.push_back("lease4");
- sort(callback_argument_names_.begin(), callback_argument_names_.end());
- sort(expected_argument_names.begin(), expected_argument_names.end());
- EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
- }
- // This test verifies that skip flag returned by a callout installed on the
- // lease4_release hook point will keep the lease
- TEST_F(HooksDhcpv4SrvTest, lease4ReleaseSkip) {
- IfaceMgrTestConfig test_config(true);
- IfaceMgr::instance().openSockets4();
- const IOAddress addr("192.0.2.106");
- const uint32_t temp_t1 = 50;
- const uint32_t temp_t2 = 75;
- const uint32_t temp_valid = 100;
- const time_t temp_timestamp = time(NULL) - 10;
- // Install a callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "lease4_release", skip_callout));
- // Generate client-id also duid_
- OptionPtr clientid = generateClientId();
- // Check that the address we are about to use is indeed in pool
- ASSERT_TRUE(subnet_->inPool(Lease::TYPE_V4, addr));
- // Let's create a lease and put it in the LeaseMgr
- uint8_t mac_addr[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
- HWAddrPtr hw(new HWAddr(mac_addr, sizeof(mac_addr), HTYPE_ETHER));
- Lease4Ptr used(new Lease4(addr, hw,
- &client_id_->getDuid()[0], client_id_->getDuid().size(),
- temp_valid, temp_t1, temp_t2, temp_timestamp,
- subnet_->getID()));
- ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
- // Check that the lease is really in the database
- Lease4Ptr l = LeaseMgrFactory::instance().getLease4(addr);
- ASSERT_TRUE(l);
- // Let's create a RELEASE
- // Generate client-id also duid_
- Pkt4Ptr rel = Pkt4Ptr(new Pkt4(DHCPRELEASE, 1234));
- rel->setRemoteAddr(addr);
- rel->setYiaddr(addr);
- rel->addOption(clientid);
- rel->addOption(srv_->getServerID());
- rel->setHWAddr(hw);
- // Pass it to the server and hope for a REPLY
- // Note: this is no response to RELEASE in DHCPv4
- EXPECT_NO_THROW(srv_->processRelease(rel));
- // The lease should be still there
- l = LeaseMgrFactory::instance().getLease4(addr);
- EXPECT_TRUE(l);
- // Try by client-id/subnet-id
- l = LeaseMgrFactory::instance().getLease4(*client_id_, subnet_->getID());
- EXPECT_TRUE(l);
- // Try to get the lease by hardware address, should succeed
- Lease4Collection leases = LeaseMgrFactory::instance().getLease4(*hw);
- EXPECT_EQ(leases.size(), 1);
- // Try by client-id, should be successful as well.
- leases = LeaseMgrFactory::instance().getLease4(*client_id_);
- EXPECT_EQ(leases.size(), 1);
- }
- // Checks that decline4 hooks (lease4_decline) are triggered properly.
- TEST_F(HooksDhcpv4SrvTest, HooksDecline) {
- IfaceMgrTestConfig test_config(true);
- IfaceMgr::instance().openSockets4();
- // Install a callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "lease4_decline", lease4_decline_callout));
- // Conduct the actual DORA + Decline.
- acquireAndDecline("01:02:03:04:05:06", "12:14",
- "01:02:03:04:05:06", "12:14",
- SHOULD_PASS);
- EXPECT_EQ("lease4_decline", callback_name_);
- // Verifying DHCPDECLINE is a bit tricky, as it is created somewhere in
- // acquireAndDecline. We'll just verify that it's really a DECLINE
- // and that its address is equal to what we have in LeaseMgr.
- ASSERT_TRUE(callback_pkt4_);
- ASSERT_TRUE(callback_lease4_);
- // Check that it's the proper packet that was reported.
- EXPECT_EQ(DHCPDECLINE, callback_pkt4_->getType());
- // Extract the address being declined.
- OptionCustomPtr opt_declined_addr = boost::dynamic_pointer_cast<
- OptionCustom>(callback_pkt4_->getOption(DHO_DHCP_REQUESTED_ADDRESS));
- ASSERT_TRUE(opt_declined_addr);
- IOAddress addr(opt_declined_addr->readAddress());
- // And try to get a matching lease from the lease manager.
- Lease4Ptr from_mgr = LeaseMgrFactory::instance().getLease4(addr);
- ASSERT_TRUE(from_mgr);
- EXPECT_EQ(Lease::STATE_DECLINED, from_mgr->state_);
- // Let's now check that those 3 things (packet, lease returned and lease from
- // the lease manager) all match.
- EXPECT_EQ(addr, from_mgr->addr_);
- EXPECT_EQ(addr, callback_lease4_->addr_);
- }
- // Checks that decline4 hook is able to drop the packet.
- TEST_F(HooksDhcpv4SrvTest, HooksDeclineDrop) {
- IfaceMgrTestConfig test_config(true);
- IfaceMgr::instance().openSockets4();
- // Install a callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "lease4_decline", lease4_decline_drop_callout));
- // Conduct the actual DORA + Decline. The DECLINE should fail, as the
- // hook will set the status to DROP.
- acquireAndDecline("01:02:03:04:05:06", "12:14",
- "01:02:03:04:05:06", "12:14",
- SHOULD_FAIL);
- EXPECT_EQ("lease4_decline", callback_name_);
- // Verifying DHCPDECLINE is a bit tricky, as it is created somewhere in
- // acquireAndDecline. We'll just verify that it's really a DECLINE
- // and that its address is equal to what we have in LeaseMgr.
- ASSERT_TRUE(callback_pkt4_);
- ASSERT_TRUE(callback_lease4_);
- // Check that it's the proper packet that was reported.
- EXPECT_EQ(DHCPDECLINE, callback_pkt4_->getType());
- // Extract the address being declined.
- OptionCustomPtr opt_declined_addr = boost::dynamic_pointer_cast<
- OptionCustom>(callback_pkt4_->getOption(DHO_DHCP_REQUESTED_ADDRESS));
- ASSERT_TRUE(opt_declined_addr);
- IOAddress addr(opt_declined_addr->readAddress());
- // And try to get a matching lease from the lease manager. The lease should
- // still be there in default state, not in declined state.
- Lease4Ptr from_mgr = LeaseMgrFactory::instance().getLease4(addr);
- ASSERT_TRUE(from_mgr);
- EXPECT_EQ(Lease::STATE_DEFAULT, from_mgr->state_);
- // As a final sanity check, let's now check that those 3 things (packet,
- // lease returned and lease from the lease manager) all match.
- EXPECT_EQ(addr, from_mgr->addr_);
- EXPECT_EQ(addr, callback_lease4_->addr_);
- }
|