12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625 |
- // Copyright (C) 2013-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 <asiolink/io_address.h>
- #include <dhcp/dhcp6.h>
- #include <dhcp/duid.h>
- #include <dhcp6/json_config_parser.h>
- #include <dhcp/dhcp6.h>
- #include <dhcpsrv/cfgmgr.h>
- #include <dhcpsrv/lease_mgr.h>
- #include <dhcpsrv/lease_mgr_factory.h>
- #include <dhcpsrv/utils.h>
- #include <util/buffer.h>
- #include <util/range_utilities.h>
- #include <hooks/server_hooks.h>
- #include <dhcp6/tests/dhcp6_test_utils.h>
- #include <dhcp6/tests/dhcp6_client.h>
- #include <dhcp/tests/iface_mgr_test_config.h>
- #include <dhcp/tests/pkt_captures.h>
- #include <cc/command_interpreter.h>
- #include <boost/scoped_ptr.hpp>
- #include <gtest/gtest.h>
- #include <unistd.h>
- #include <fstream>
- #include <iostream>
- #include <sstream>
- using namespace isc;
- using namespace isc::data;
- using namespace isc::dhcp::test;
- using namespace isc::asiolink;
- using namespace isc::dhcp;
- using namespace isc::util;
- using namespace isc::hooks;
- using namespace std;
- // namespace has to be named, because friends are defined in Dhcpv6Srv class
- // Maybe it should be isc::test?
- namespace {
- // Checks if hooks are implemented properly.
- TEST_F(Dhcpv6SrvTest, Hooks) {
- NakedDhcpv6Srv srv(0);
- // check if appropriate hooks are registered
- int hook_index_buffer6_receive = -1;
- int hook_index_buffer6_send = -1;
- int hook_index_lease6_renew = -1;
- int hook_index_lease6_release = -1;
- int hook_index_pkt6_received = -1;
- int hook_index_select_subnet = -1;
- int hook_index_pkt6_send = -1;
- // check if appropriate indexes are set
- EXPECT_NO_THROW(hook_index_buffer6_receive = ServerHooks::getServerHooks()
- .getIndex("buffer6_receive"));
- EXPECT_NO_THROW(hook_index_buffer6_send = ServerHooks::getServerHooks()
- .getIndex("buffer6_send"));
- EXPECT_NO_THROW(hook_index_lease6_renew = ServerHooks::getServerHooks()
- .getIndex("lease6_renew"));
- EXPECT_NO_THROW(hook_index_lease6_release = ServerHooks::getServerHooks()
- .getIndex("lease6_release"));
- EXPECT_NO_THROW(hook_index_pkt6_received = ServerHooks::getServerHooks()
- .getIndex("pkt6_receive"));
- EXPECT_NO_THROW(hook_index_select_subnet = ServerHooks::getServerHooks()
- .getIndex("subnet6_select"));
- EXPECT_NO_THROW(hook_index_pkt6_send = ServerHooks::getServerHooks()
- .getIndex("pkt6_send"));
- EXPECT_TRUE(hook_index_pkt6_received > 0);
- EXPECT_TRUE(hook_index_select_subnet > 0);
- EXPECT_TRUE(hook_index_pkt6_send > 0);
- EXPECT_TRUE(hook_index_buffer6_receive > 0);
- EXPECT_TRUE(hook_index_buffer6_send > 0);
- EXPECT_TRUE(hook_index_lease6_renew > 0);
- EXPECT_TRUE(hook_index_lease6_release > 0);
- }
- /// @brief a class dedicated to Hooks testing in DHCPv6 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 HooksDhcpv6SrvTest : public Dhcpv6SrvTest {
- public:
- /// @brief creates Dhcpv6Srv and prepares buffers for callouts
- HooksDhcpv6SrvTest() {
- // Allocate new DHCPv6 Server
- srv_.reset(new NakedDhcpv6Srv(0));
- // Clear static buffers
- resetCalloutBuffers();
- }
- /// @brief destructor (deletes Dhcpv6Srv)
- ~HooksDhcpv6SrvTest() {
- }
- /// @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 HooksDhcpv6SSrvTest object
- ///
- /// @param option_code code of option to be created
- ///
- /// @return pointer to create option object
- static OptionPtr createOption(uint16_t option_code) {
- uint8_t payload[] = {
- 0xa, 0xb, 0xc, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14
- };
- OptionBuffer tmp(payload, payload + sizeof(payload));
- return OptionPtr(new Option(Option::V6, option_code, tmp));
- }
- /// test callback that stores received callout name and pkt6 value
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- pkt6_receive_callout(CalloutHandle& callout_handle) {
- callback_name_ = string("pkt6_receive");
- callout_handle.getArgument("query6", callback_pkt6_);
- 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
- pkt6_receive_change_clientid(CalloutHandle& callout_handle) {
- Pkt6Ptr pkt;
- callout_handle.getArgument("query6", pkt);
- // Get rid of the old client-id
- pkt->delOption(D6O_CLIENTID);
- // Add a new option
- pkt->addOption(createOption(D6O_CLIENTID));
- // Carry on as usual
- return pkt6_receive_callout(callout_handle);
- }
- /// Test callback that deletes client-id
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- pkt6_receive_delete_clientid(CalloutHandle& callout_handle) {
- Pkt6Ptr pkt;
- callout_handle.getArgument("query6", pkt);
- // Get rid of the old client-id
- pkt->delOption(D6O_CLIENTID);
- // Carry on as usual
- return pkt6_receive_callout(callout_handle);
- }
- /// Test callback that sets skip flag
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- pkt6_receive_skip(CalloutHandle& callout_handle) {
- Pkt6Ptr pkt;
- callout_handle.getArgument("query6", pkt);
- callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
- // Carry on as usual
- return pkt6_receive_callout(callout_handle);
- }
- /// Test callback that stores received callout name and pkt6 value
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- buffer6_receive_callout(CalloutHandle& callout_handle) {
- callback_name_ = string("buffer6_receive");
- callout_handle.getArgument("query6", callback_pkt6_);
- callback_argument_names_ = callout_handle.getArgumentNames();
- return (0);
- }
- /// Test callback that changes first byte of client-id value
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- buffer6_receive_change_clientid(CalloutHandle& callout_handle) {
- Pkt6Ptr pkt;
- callout_handle.getArgument("query6", pkt);
- // If there is at least one option with data
- if (pkt->data_.size() > Pkt6::DHCPV6_PKT_HDR_LEN + Option::OPTION6_HDR_LEN) {
- // Offset of the first byte of the first option. Let's set this byte
- // to some new value that we could later check
- pkt->data_[Pkt6::DHCPV6_PKT_HDR_LEN + Option::OPTION6_HDR_LEN] = 0xff;
- }
- // Carry on as usual
- return buffer6_receive_callout(callout_handle);
- }
- /// Test callback that deletes client-id
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- buffer6_receive_delete_clientid(CalloutHandle& callout_handle) {
- Pkt6Ptr pkt;
- callout_handle.getArgument("query6", pkt);
- // this is modified SOLICIT (with missing mandatory client-id)
- uint8_t data[] = {
- 1, // type 1 = SOLICIT
- 0xca, 0xfe, 0x01, // trans-id = 0xcafe01
- 0, 3, // option type 3 (IA_NA)
- 0, 12, // option length 12
- 0, 0, 0, 1, // iaid = 1
- 0, 0, 0, 0, // T1 = 0
- 0, 0, 0, 0 // T2 = 0
- };
- OptionBuffer modifiedMsg(data, data + sizeof(data));
- pkt->data_ = modifiedMsg;
- // carry on as usual
- return buffer6_receive_callout(callout_handle);
- }
- /// Test callback that sets skip flag
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- buffer6_receive_skip(CalloutHandle& callout_handle) {
- callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
- // Carry on as usual
- return buffer6_receive_callout(callout_handle);
- }
- /// Test callback that stores received callout name and pkt6 value
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- pkt6_send_callout(CalloutHandle& callout_handle) {
- callback_name_ = string("pkt6_send");
- callout_handle.getArgument("response6", callback_pkt6_);
- 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
- pkt6_send_change_serverid(CalloutHandle& callout_handle) {
- Pkt6Ptr pkt;
- callout_handle.getArgument("response6", pkt);
- // Get rid of the old server-id
- pkt->delOption(D6O_SERVERID);
- // Add a new option
- pkt->addOption(createOption(D6O_SERVERID));
- // Carry on as usual
- return pkt6_send_callout(callout_handle);
- }
- /// Test callback that deletes server-id
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- pkt6_send_delete_serverid(CalloutHandle& callout_handle) {
- Pkt6Ptr pkt;
- callout_handle.getArgument("response6", pkt);
- // Get rid of the old client-id
- pkt->delOption(D6O_SERVERID);
- // Carry on as usual
- return pkt6_send_callout(callout_handle);
- }
- /// Test callback that sets skip flag
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- pkt6_send_skip(CalloutHandle& callout_handle) {
- Pkt6Ptr pkt;
- callout_handle.getArgument("response6", pkt);
- callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
- // carry on as usual
- return pkt6_send_callout(callout_handle);
- }
- /// Test callback that stores received callout name and subnet6 values
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- subnet6_select_callout(CalloutHandle& callout_handle) {
- callback_name_ = string("subnet6_select");
- callout_handle.getArgument("query6", callback_pkt6_);
- callout_handle.getArgument("subnet6", callback_subnet6_);
- callout_handle.getArgument("subnet6collection", callback_subnet6collection_);
- 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
- subnet6_select_different_subnet_callout(CalloutHandle& callout_handle) {
- // Call the basic callout to record all passed values
- subnet6_select_callout(callout_handle);
- const Subnet6Collection* subnets;
- Subnet6Ptr subnet;
- callout_handle.getArgument("subnet6", subnet);
- callout_handle.getArgument("subnet6collection", subnets);
- // Let's change to a different subnet
- if (subnets->size() > 1) {
- subnet = (*subnets)[1]; // Let's pick the other subnet
- callout_handle.setArgument("subnet6", subnet);
- }
- return (0);
- }
- /// Test callback that stores received callout name and pkt6 value
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- lease6_renew_callout(CalloutHandle& callout_handle) {
- callback_name_ = string("lease6_renew");
- callout_handle.getArgument("query6", callback_pkt6_);
- callout_handle.getArgument("lease6", callback_lease6_);
- callout_handle.getArgument("ia_na", callback_ia_na_);
- callback_argument_names_ = callout_handle.getArgumentNames();
- return (0);
- }
- /// The following values are used by the callout to override
- /// renewed lease parameters
- static const uint32_t override_iaid_;
- static const uint32_t override_t1_;
- static const uint32_t override_t2_;
- static const uint32_t override_preferred_;
- static const uint32_t override_valid_;
- /// Test callback that overrides received lease. It updates
- /// T1, T2, preferred and valid lifetimes
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- lease6_renew_update_callout(CalloutHandle& callout_handle) {
- callback_name_ = string("lease6_renew");
- callout_handle.getArgument("query6", callback_pkt6_);
- callout_handle.getArgument("lease6", callback_lease6_);
- callout_handle.getArgument("ia_na", callback_ia_na_);
- // Let's override some values in the lease
- callback_lease6_->iaid_ = override_iaid_;
- callback_lease6_->t1_ = override_t1_;
- callback_lease6_->t2_ = override_t2_;
- callback_lease6_->preferred_lft_ = override_preferred_;
- callback_lease6_->valid_lft_ = override_valid_;
- // Override the values to be sent to the client as well
- callback_ia_na_->setIAID(override_iaid_);
- callback_ia_na_->setT1(override_t1_);
- callback_ia_na_->setT2(override_t2_);
- callback_argument_names_ = callout_handle.getArgumentNames();
- return (0);
- }
- /// Test callback that sets the skip flag
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- lease6_renew_skip_callout(CalloutHandle& callout_handle) {
- callback_name_ = string("lease6_renew");
- callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
- 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
- lease6_release_callout(CalloutHandle& callout_handle) {
- callback_name_ = string("lease6_release");
- callout_handle.getArgument("query6", callback_pkt6_);
- callout_handle.getArgument("lease6", callback_lease6_);
- callback_argument_names_ = callout_handle.getArgumentNames();
- return (0);
- }
- /// Test callback that sets the skip flag
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- lease6_release_skip_callout(CalloutHandle& callout_handle) {
- callback_name_ = string("lease6_release");
- callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
- return (0);
- }
- /// Lease6_decline test callback
- ///
- /// Stores all parameters in callback_* fields.
- ///
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- lease6_decline_callout(CalloutHandle& callout_handle) {
- callback_name_ = string("lease6_decline");
- callout_handle.getArgument("query6", callback_pkt6_);
- callout_handle.getArgument("lease6", callback_lease6_);
- return (0);
- }
- /// Lease6_decline callout that sets status to SKIP
- ///
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- lease6_decline_skip_callout(CalloutHandle& callout_handle) {
- callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
- return (lease6_decline_callout(callout_handle));
- }
- /// Lease6_decline callout that sets status to DROP
- ///
- /// @param callout_handle handle passed by the hooks framework
- /// @return always 0
- static int
- lease6_decline_drop_callout(CalloutHandle& callout_handle) {
- callout_handle.setStatus(CalloutHandle::NEXT_STEP_DROP);
- return (lease6_decline_callout(callout_handle));
- }
- /// Resets buffers used to store data received by callouts
- void resetCalloutBuffers() {
- callback_name_ = string("");
- callback_pkt6_.reset();
- callback_subnet6_.reset();
- callback_lease6_.reset();
- callback_ia_na_.reset();
- callback_subnet6collection_ = NULL;
- callback_argument_names_.clear();
- }
- /// Pointer to Dhcpv6Srv that is used in tests
- boost::scoped_ptr<NakedDhcpv6Srv> srv_;
- // The following fields are used in testing pkt6_receive_callout
- /// String name of the received callout
- static string callback_name_;
- /// Pkt6 structure returned in the callout
- static Pkt6Ptr callback_pkt6_;
- /// Pointer to lease6
- static Lease6Ptr callback_lease6_;
- /// Pointer to IA_NA option being renewed
- static boost::shared_ptr<Option6IA> callback_ia_na_;
- /// Pointer to a subnet received by callout
- static Subnet6Ptr callback_subnet6_;
- /// A list of all available subnets (received by callout)
- static const Subnet6Collection* callback_subnet6collection_;
- /// A list of all received arguments
- static vector<string> callback_argument_names_;
- };
- // The following parameters are used by callouts to override
- // renewed lease parameters
- const uint32_t HooksDhcpv6SrvTest::override_iaid_ = 1000;
- const uint32_t HooksDhcpv6SrvTest::override_t1_ = 1001;
- const uint32_t HooksDhcpv6SrvTest::override_t2_ = 1002;
- const uint32_t HooksDhcpv6SrvTest::override_preferred_ = 1003;
- const uint32_t HooksDhcpv6SrvTest::override_valid_ = 1004;
- // The following fields are used in testing pkt6_receive_callout.
- // See fields description in the class for details
- string HooksDhcpv6SrvTest::callback_name_;
- Pkt6Ptr HooksDhcpv6SrvTest::callback_pkt6_;
- Subnet6Ptr HooksDhcpv6SrvTest::callback_subnet6_;
- const Subnet6Collection* HooksDhcpv6SrvTest::callback_subnet6collection_;
- vector<string> HooksDhcpv6SrvTest::callback_argument_names_;
- Lease6Ptr HooksDhcpv6SrvTest::callback_lease6_;
- boost::shared_ptr<Option6IA> HooksDhcpv6SrvTest::callback_ia_na_;
- // Checks if callouts installed on pkt6_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 "buffer6_receive".
- TEST_F(HooksDhcpv6SrvTest, simpleBuffer6Receive) {
- // Install pkt6_receive_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "buffer6_receive", buffer6_receive_callout));
- // Let's create a simple SOLICIT
- Pkt6Ptr sol = Pkt6Ptr(PktCaptures::captureSimpleSolicit());
- // Simulate that we have received that traffic
- srv_->fakeReceive(sol);
- // 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 buffer6_receive callback.
- srv_->run();
- // Check that the callback called is indeed the one we installed
- EXPECT_EQ("buffer6_receive", callback_name_);
- // Check that pkt6 argument passing was successful and returned proper value
- EXPECT_TRUE(callback_pkt6_.get() == sol.get());
- // Check that all expected parameters are there
- vector<string> expected_argument_names;
- expected_argument_names.push_back(string("query6"));
- EXPECT_TRUE(expected_argument_names == callback_argument_names_);
- }
- // Checks if callouts installed on buffer6_receive is able to change
- // the values and the parameters are indeed used by the server.
- TEST_F(HooksDhcpv6SrvTest, valueChangeBuffer6Receive) {
- // Install pkt6_receive_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "buffer6_receive", buffer6_receive_change_clientid));
- // Let's create a simple SOLICIT
- Pkt6Ptr sol = Pkt6Ptr(PktCaptures::captureSimpleSolicit());
- // Simulate that we have received that traffic
- srv_->fakeReceive(sol);
- // 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 pkt6_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
- Pkt6Ptr adv = srv_->fake_sent_.front();
- ASSERT_TRUE(adv);
- // Get client-id...
- OptionPtr clientid = adv->getOption(D6O_CLIENTID);
- ASSERT_TRUE(clientid);
- // ... and check if it is the modified value
- EXPECT_EQ(0xff, clientid->getData()[0]);
- }
- // Checks if callouts installed on buffer6_receive 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(HooksDhcpv6SrvTest, deleteClientIdBuffer6Receive) {
- // Install pkt6_receive_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "buffer6_receive", buffer6_receive_delete_clientid));
- // Let's create a simple SOLICIT
- Pkt6Ptr sol = Pkt6Ptr(PktCaptures::captureSimpleSolicit());
- // Simulate that we have received that traffic
- srv_->fakeReceive(sol);
- // 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 pkt6_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 buffer6_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(HooksDhcpv6SrvTest, skipBuffer6Receive) {
- // Install pkt6_receive_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "buffer6_receive", buffer6_receive_skip));
- // Let's create a simple SOLICIT
- Pkt6Ptr sol = Pkt6Ptr(PktCaptures::captureSimpleSolicit());
- // Simulate that we have received that traffic
- srv_->fakeReceive(sol);
- // 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 pkt6_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 pkt6_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 "pkt6_receive".
- TEST_F(HooksDhcpv6SrvTest, simplePkt6Receive) {
- // Install pkt6_receive_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "pkt6_receive", pkt6_receive_callout));
- // Let's create a simple SOLICIT
- Pkt6Ptr sol = Pkt6Ptr(PktCaptures::captureSimpleSolicit());
- // Simulate that we have received that traffic
- srv_->fakeReceive(sol);
- // 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 pkt6_receive callback.
- srv_->run();
- // Check that the callback called is indeed the one we installed
- EXPECT_EQ("pkt6_receive", callback_name_);
- // Check that pkt6 argument passing was successful and returned proper value
- EXPECT_TRUE(callback_pkt6_.get() == sol.get());
- // Check that all expected parameters are there
- vector<string> expected_argument_names;
- expected_argument_names.push_back(string("query6"));
- EXPECT_TRUE(expected_argument_names == callback_argument_names_);
- }
- // Checks if callouts installed on pkt6_received is able to change
- // the values and the parameters are indeed used by the server.
- TEST_F(HooksDhcpv6SrvTest, valueChangePkt6Receive) {
- // Install pkt6_receive_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "pkt6_receive", pkt6_receive_change_clientid));
- // Let's create a simple SOLICIT
- Pkt6Ptr sol = Pkt6Ptr(PktCaptures::captureSimpleSolicit());
- // Simulate that we have received that traffic
- srv_->fakeReceive(sol);
- // 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 pkt6_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
- Pkt6Ptr adv = srv_->fake_sent_.front();
- ASSERT_TRUE(adv);
- // Get client-id...
- OptionPtr clientid = adv->getOption(D6O_CLIENTID);
- // ... and check if it is the modified value
- OptionPtr expected = createOption(D6O_CLIENTID);
- EXPECT_TRUE(clientid->equals(expected));
- }
- // Checks if callouts installed on pkt6_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(HooksDhcpv6SrvTest, deleteClientIdPkt6Receive) {
- // Install pkt6_receive_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "pkt6_receive", pkt6_receive_delete_clientid));
- // Let's create a simple SOLICIT
- Pkt6Ptr sol = Pkt6Ptr(PktCaptures::captureSimpleSolicit());
- // Simulate that we have received that traffic
- srv_->fakeReceive(sol);
- // 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 pkt6_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 pkt6_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(HooksDhcpv6SrvTest, skipPkt6Receive) {
- // Install pkt6_receive_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "pkt6_receive", pkt6_receive_skip));
- // Let's create a simple SOLICIT
- Pkt6Ptr sol = Pkt6Ptr(PktCaptures::captureSimpleSolicit());
- // Simulate that we have received that traffic
- srv_->fakeReceive(sol);
- // 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 pkt6_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 pkt6_send are indeed called and the
- // all necessary parameters are passed.
- TEST_F(HooksDhcpv6SrvTest, simplePkt6Send) {
- // Install pkt6_receive_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "pkt6_send", pkt6_send_callout));
- // Let's create a simple SOLICIT
- Pkt6Ptr sol = Pkt6Ptr(PktCaptures::captureSimpleSolicit());
- // Simulate that we have received that traffic
- srv_->fakeReceive(sol);
- // 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 pkt6_receive callback.
- srv_->run();
- // Check that the callback called is indeed the one we installed
- EXPECT_EQ("pkt6_send", callback_name_);
- // Check that there is one packet sent
- ASSERT_EQ(1, srv_->fake_sent_.size());
- Pkt6Ptr adv = srv_->fake_sent_.front();
- // Check that pkt6 argument passing was successful and returned proper value
- EXPECT_TRUE(callback_pkt6_.get() == adv.get());
- // Check that all expected parameters are there
- vector<string> expected_argument_names;
- expected_argument_names.push_back(string("response6"));
- EXPECT_TRUE(expected_argument_names == callback_argument_names_);
- }
- // Checks if callouts installed on pkt6_send is able to change
- // the values and the packet sent contains those changes
- TEST_F(HooksDhcpv6SrvTest, valueChangePkt6Send) {
- // Install pkt6_receive_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "pkt6_send", pkt6_send_change_serverid));
- // Let's create a simple SOLICIT
- Pkt6Ptr sol = Pkt6Ptr(PktCaptures::captureSimpleSolicit());
- // Simulate that we have received that traffic
- srv_->fakeReceive(sol);
- // 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 pkt6_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
- Pkt6Ptr adv = srv_->fake_sent_.front();
- ASSERT_TRUE(adv);
- // Get client-id...
- OptionPtr clientid = adv->getOption(D6O_SERVERID);
- // ... and check if it is the modified value
- OptionPtr expected = createOption(D6O_SERVERID);
- EXPECT_TRUE(clientid->equals(expected));
- }
- // Checks if callouts installed on pkt6_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(HooksDhcpv6SrvTest, deleteServerIdPkt6Send) {
- // Install pkt6_receive_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "pkt6_send", pkt6_send_delete_serverid));
- // Let's create a simple SOLICIT
- Pkt6Ptr sol = Pkt6Ptr(PktCaptures::captureSimpleSolicit());
- // Simulate that we have received that traffic
- srv_->fakeReceive(sol);
- // 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 pkt6_receive callback.
- srv_->run();
- // Check that the server indeed sent a malformed ADVERTISE
- ASSERT_EQ(1, srv_->fake_sent_.size());
- // Get that ADVERTISE
- Pkt6Ptr adv = srv_->fake_sent_.front();
- ASSERT_TRUE(adv);
- // Make sure that it does not have server-id
- EXPECT_FALSE(adv->getOption(D6O_SERVERID));
- }
- // Checks if callouts installed on pkt6_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(HooksDhcpv6SrvTest, skipPkt6Send) {
- // Install pkt6_receive_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "pkt6_send", pkt6_send_skip));
- // Let's create a simple REQUEST
- Pkt6Ptr sol = Pkt6Ptr(PktCaptures::captureSimpleSolicit());
- // Simulate that we have received that traffic
- srv_->fakeReceive(sol);
- // 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 pkt6_receive callback.
- srv_->run();
- // Check that the server send the packet
- ASSERT_EQ(1, srv_->fake_sent_.size());
- // But the sent packet should have 0 length (we told the server to
- // skip pack(), but did not do packing outselves)
- Pkt6Ptr sent = srv_->fake_sent_.front();
- // The actual size of sent packet should be 0
- EXPECT_EQ(0, sent->getBuffer().getLength());
- }
- // This test checks if subnet6_select callout is triggered and reports
- // valid parameters
- TEST_F(HooksDhcpv6SrvTest, subnet6Select) {
- // Install pkt6_receive_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "subnet6_select", subnet6_select_callout));
- // Configure 2 subnets, both directly reachable over local interface
- // (let's not complicate the matter with relays)
- string config = "{ \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- "},"
- "\"preferred-lifetime\": 3000,"
- "\"rebind-timer\": 2000, "
- "\"renew-timer\": 1000, "
- "\"subnet6\": [ { "
- " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
- " \"subnet\": \"2001:db8:1::/48\", "
- " \"interface\": \"" + valid_iface_ + "\" "
- " }, {"
- " \"pools\": [ { \"pool\": \"2001:db8:2::/64\" } ],"
- " \"subnet\": \"2001:db8:2::/48\" "
- " } ],"
- "\"valid-lifetime\": 4000 }";
- ElementPtr json = Element::fromJSON(config);
- ConstElementPtr status;
- // Configure the server and make sure the config is accepted
- EXPECT_NO_THROW(status = configureDhcp6Server(*srv_, json));
- ASSERT_TRUE(status);
- comment_ = isc::config::parseAnswer(rcode_, status);
- ASSERT_EQ(0, rcode_);
- CfgMgr::instance().commit();
- // Prepare solicit packet. Server should select first subnet for it
- Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
- sol->setRemoteAddr(IOAddress("fe80::abcd"));
- sol->setIface(valid_iface_);
- sol->addOption(generateIA(D6O_IA_NA, 234, 1500, 3000));
- OptionPtr clientid = generateClientId();
- sol->addOption(clientid);
- // Pass it to the server and get an advertise
- Pkt6Ptr adv = srv_->processSolicit(sol);
- // Check if we get response at all
- ASSERT_TRUE(adv);
- // Check that the callback called is indeed the one we installed
- EXPECT_EQ("subnet6_select", callback_name_);
- // Check that pkt6 argument passing was successful and returned proper value
- EXPECT_TRUE(callback_pkt6_.get() == sol.get());
- const Subnet6Collection* exp_subnets =
- CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
- // The server is supposed to pick the first subnet, because of matching
- // interface. Check that the value is reported properly.
- ASSERT_TRUE(callback_subnet6_);
- EXPECT_EQ(callback_subnet6_.get(), exp_subnets->front().get());
- // Server is supposed to report two subnets
- ASSERT_EQ(exp_subnets->size(), callback_subnet6collection_->size());
- // Compare that the available subnets are reported as expected
- EXPECT_TRUE((*exp_subnets)[0].get() == (*callback_subnet6collection_)[0].get());
- EXPECT_TRUE((*exp_subnets)[1].get() == (*callback_subnet6collection_)[1].get());
- }
- // This test checks if callout installed on subnet6_select hook point can pick
- // a different subnet.
- TEST_F(HooksDhcpv6SrvTest, subnet6SselectChange) {
- // Install pkt6_receive_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "subnet6_select", subnet6_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\": [ \"*\" ]"
- "},"
- "\"preferred-lifetime\": 3000,"
- "\"rebind-timer\": 2000, "
- "\"renew-timer\": 1000, "
- "\"subnet6\": [ { "
- " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
- " \"subnet\": \"2001:db8:1::/48\", "
- " \"interface\": \"" + valid_iface_ + "\" "
- " }, {"
- " \"pools\": [ { \"pool\": \"2001:db8:2::/64\" } ],"
- " \"subnet\": \"2001:db8:2::/48\" "
- " } ],"
- "\"valid-lifetime\": 4000 }";
- ElementPtr json = Element::fromJSON(config);
- ConstElementPtr status;
- // Configure the server and make sure the config is accepted
- EXPECT_NO_THROW(status = configureDhcp6Server(*srv_, json));
- ASSERT_TRUE(status);
- comment_ = isc::config::parseAnswer(rcode_, status);
- ASSERT_EQ(0, rcode_);
- CfgMgr::instance().commit();
- // Prepare solicit packet. Server should select first subnet for it
- Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
- sol->setRemoteAddr(IOAddress("fe80::abcd"));
- sol->setIface(valid_iface_);
- sol->addOption(generateIA(D6O_IA_NA, 234, 1500, 3000));
- OptionPtr clientid = generateClientId();
- sol->addOption(clientid);
- // Pass it to the server and get an advertise
- Pkt6Ptr adv = srv_->processSolicit(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
- OptionPtr tmp = adv->getOption(D6O_IA_NA);
- ASSERT_TRUE(tmp);
- boost::shared_ptr<Option6IA> ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
- ASSERT_TRUE(ia);
- tmp = ia->getOption(D6O_IAADDR);
- ASSERT_TRUE(tmp);
- boost::shared_ptr<Option6IAAddr> addr_opt =
- boost::dynamic_pointer_cast<Option6IAAddr>(tmp);
- ASSERT_TRUE(addr_opt);
- // Get all subnets and use second subnet for verification
- const Subnet6Collection* subnets =
- CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->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_opt->getAddress()));
- EXPECT_TRUE((*subnets)[1]->inPool(Lease::TYPE_NA, addr_opt->getAddress()));
- }
- // This test verifies that incoming (positive) RENEW can be handled properly,
- // and the lease6_renew callouts are triggered.
- TEST_F(HooksDhcpv6SrvTest, basicLease6Renew) {
- NakedDhcpv6Srv srv(0);
- // Install pkt6_receive_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "lease6_renew", lease6_renew_callout));
- const IOAddress addr("2001:db8:1:1::cafe:babe");
- const uint32_t iaid = 234;
- // 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_NA, addr));
- // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
- // value on purpose. They should be updated during RENEW.
- Lease6Ptr lease(new Lease6(Lease::TYPE_NA, addr, duid_, iaid,
- 501, 502, 503, 504, subnet_->getID(),
- HWAddrPtr(), 0));
- lease->cltt_ = 1234;
- ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
- // Check that the lease is really in the database
- Lease6Ptr l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
- addr);
- ASSERT_TRUE(l);
- // Check that T1, T2, preferred, valid and cltt really set and not using
- // previous (500, 501, etc.) values
- EXPECT_NE(l->t1_, subnet_->getT1());
- EXPECT_NE(l->t2_, subnet_->getT2());
- EXPECT_NE(l->preferred_lft_, subnet_->getPreferred());
- EXPECT_NE(l->valid_lft_, subnet_->getValid());
- EXPECT_NE(l->cltt_, time(NULL));
- // Let's create a RENEW
- Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RENEW, 1234));
- req->setRemoteAddr(IOAddress("fe80::abcd"));
- req->setIface("eth0");
- boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
- OptionPtr renewed_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
- ia->addOption(renewed_addr_opt);
- req->addOption(ia);
- req->addOption(clientid);
- // Server-id is mandatory in RENEW
- req->addOption(srv.getServerID());
- // Pass it to the server and hope for a REPLY
- Pkt6Ptr reply = srv.processRenew(req);
- ASSERT_TRUE(reply);
- // Check that the callback called is indeed the one we installed
- EXPECT_EQ("lease6_renew", callback_name_);
- // Check that appropriate parameters are passed to the callouts
- EXPECT_TRUE(callback_pkt6_);
- EXPECT_TRUE(callback_lease6_);
- EXPECT_TRUE(callback_ia_na_);
- // Check if all expected parameters were really received
- vector<string> expected_argument_names;
- expected_argument_names.push_back("query6");
- expected_argument_names.push_back("lease6");
- expected_argument_names.push_back("ia_na");
- 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);
- // Check if we get response at all
- checkResponse(reply, DHCPV6_REPLY, 1234);
- OptionPtr tmp = reply->getOption(D6O_IA_NA);
- ASSERT_TRUE(tmp);
- // Check that IA_NA was returned and that there's an address included
- boost::shared_ptr<Option6IAAddr> addr_opt = checkIA_NA(reply, 234, subnet_->getT1(),
- subnet_->getT2());
- ASSERT_TRUE(addr_opt);
- // Check that the lease is really in the database
- l = checkLease(duid_, reply->getOption(D6O_IA_NA), addr_opt);
- ASSERT_TRUE(l);
- // Check that the lease has been returned
- ASSERT_TRUE(callback_lease6_);
- // Check that the returned lease6 in callout is the same as the one in the
- // database
- EXPECT_TRUE(*callback_lease6_ == *l);
- }
- // This test verifies that incoming (positive) RENEW can be handled properly,
- // and the lease6_renew callouts are able to change the lease being updated.
- TEST_F(HooksDhcpv6SrvTest, leaseUpdateLease6Renew) {
- NakedDhcpv6Srv srv(0);
- // Install pkt6_receive_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "lease6_renew", lease6_renew_update_callout));
- const IOAddress addr("2001:db8:1:1::cafe:babe");
- const uint32_t iaid = 234;
- // 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_NA, addr));
- // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
- // value on purpose. They should be updated during RENEW.
- Lease6Ptr lease(new Lease6(Lease::TYPE_NA, addr, duid_, iaid,
- 501, 502, 503, 504, subnet_->getID(),
- HWAddrPtr(), 0));
- lease->cltt_ = 1234;
- ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
- // Check that the lease is really in the database
- Lease6Ptr l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
- addr);
- ASSERT_TRUE(l);
- // Check that T1, T2, preferred, valid and cltt really set and not using
- // previous (500, 501, etc.) values
- EXPECT_NE(l->t1_, subnet_->getT1());
- EXPECT_NE(l->t2_, subnet_->getT2());
- EXPECT_NE(l->preferred_lft_, subnet_->getPreferred());
- EXPECT_NE(l->valid_lft_, subnet_->getValid());
- EXPECT_NE(l->cltt_, time(NULL));
- // Let's create a RENEW
- Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RENEW, 1234));
- req->setRemoteAddr(IOAddress("fe80::abcd"));
- req->setIface("eth0");
- boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
- OptionPtr renewed_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
- ia->addOption(renewed_addr_opt);
- req->addOption(ia);
- req->addOption(clientid);
- // Server-id is mandatory in RENEW
- req->addOption(srv.getServerID());
- // Pass it to the server and hope for a REPLY
- Pkt6Ptr reply = srv.processRenew(req);
- ASSERT_TRUE(reply);
- // Check if we get response at all
- checkResponse(reply, DHCPV6_REPLY, 1234);
- OptionPtr tmp = reply->getOption(D6O_IA_NA);
- ASSERT_TRUE(tmp);
- // Check that IA_NA was returned and that there's an address included
- boost::shared_ptr<Option6IAAddr> addr_opt = checkIA_NA(reply, 1000, 1001, 1002);
- ASSERT_TRUE(addr_opt);
- // Check that the lease is really in the database
- l = checkLease(duid_, reply->getOption(D6O_IA_NA), addr_opt);
- ASSERT_TRUE(l);
- // Check that we chose the distinct override values
- ASSERT_NE(override_t1_, subnet_->getT1());
- ASSERT_NE(override_t2_, subnet_->getT2());
- ASSERT_NE(override_preferred_, subnet_->getPreferred());
- EXPECT_NE(override_valid_, subnet_->getValid());
- // Check that T1, T2, preferred, valid were overridden the the callout
- EXPECT_EQ(override_t1_, l->t1_);
- EXPECT_EQ(override_t2_, l->t2_);
- EXPECT_EQ(override_preferred_, l->preferred_lft_);
- EXPECT_EQ(override_valid_, l->valid_lft_);
- // Checking for CLTT is a bit tricky if we want to avoid off by 1 errors
- int32_t cltt = static_cast<int32_t>(l->cltt_);
- int32_t expected = static_cast<int32_t>(time(NULL));
- // Equality or difference by 1 between cltt and expected is ok.
- EXPECT_GE(1, abs(cltt - expected));
- EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease(addr_opt->getAddress()));
- }
- // This test verifies that incoming (positive) RENEW can be handled properly,
- // and the lease6_renew callouts are able to set the skip flag that will
- // reject the renewal
- TEST_F(HooksDhcpv6SrvTest, skipLease6Renew) {
- NakedDhcpv6Srv srv(0);
- // Install pkt6_receive_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "lease6_renew", lease6_renew_skip_callout));
- const IOAddress addr("2001:db8:1:1::cafe:babe");
- const uint32_t iaid = 234;
- // 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_NA, addr));
- // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
- // value on purpose. They should be updated during RENEW.
- Lease6Ptr lease(new Lease6(Lease::TYPE_NA, addr, duid_, iaid,
- 501, 502, 503, 504, subnet_->getID(),
- HWAddrPtr(), 0));
- lease->cltt_ = 1234;
- ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
- // Check that the lease is really in the database
- Lease6Ptr l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
- addr);
- ASSERT_TRUE(l);
- // Check that T1, T2, preferred, valid and cltt really set and not using
- // previous (500, 501, etc.) values
- EXPECT_NE(l->t1_, subnet_->getT1());
- EXPECT_NE(l->t2_, subnet_->getT2());
- EXPECT_NE(l->preferred_lft_, subnet_->getPreferred());
- EXPECT_NE(l->valid_lft_, subnet_->getValid());
- EXPECT_NE(l->cltt_, time(NULL));
- // Let's create a RENEW
- Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RENEW, 1234));
- req->setRemoteAddr(IOAddress("fe80::abcd"));
- req->setIface("eth0");
- boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
- OptionPtr renewed_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
- ia->addOption(renewed_addr_opt);
- req->addOption(ia);
- req->addOption(clientid);
- // Server-id is mandatory in RENEW
- req->addOption(srv.getServerID());
- // Pass it to the server and hope for a REPLY
- Pkt6Ptr reply = srv.processRenew(req);
- ASSERT_TRUE(reply);
- // Check that our callback was called
- EXPECT_EQ("lease6_renew", callback_name_);
- l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA, addr);
- // Check that the old values are still there and they were not
- // updated by the renewal
- EXPECT_NE(l->t1_, subnet_->getT1());
- EXPECT_NE(l->t2_, subnet_->getT2());
- EXPECT_NE(l->preferred_lft_, subnet_->getPreferred());
- EXPECT_NE(l->valid_lft_, subnet_->getValid());
- EXPECT_NE(l->cltt_, time(NULL));
- }
- // This test verifies that incoming (positive) RELEASE can be handled properly,
- // that a REPLY is generated, that the response has status code and that the
- // lease is indeed removed from the database.
- //
- // expected:
- // - returned REPLY message has copy of client-id
- // - returned REPLY message has server-id
- // - returned REPLY message has IA that does not include an IAADDR
- // - lease is actually removed from LeaseMgr
- TEST_F(HooksDhcpv6SrvTest, basicLease6Release) {
- NakedDhcpv6Srv srv(0);
- // Install pkt6_receive_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "lease6_release", lease6_release_callout));
- const IOAddress addr("2001:db8:1:1::cafe:babe");
- const uint32_t iaid = 234;
- // 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_NA, addr));
- // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
- // value on purpose. They should be updated during RENEW.
- Lease6Ptr lease(new Lease6(Lease::TYPE_NA, addr, duid_, iaid,
- 501, 502, 503, 504, subnet_->getID(),
- HWAddrPtr(), 0));
- lease->cltt_ = 1234;
- ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
- // Check that the lease is really in the database
- Lease6Ptr l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
- addr);
- ASSERT_TRUE(l);
- // Let's create a RELEASE
- Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RELEASE, 1234));
- req->setRemoteAddr(IOAddress("fe80::abcd"));
- boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
- OptionPtr released_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
- ia->addOption(released_addr_opt);
- req->addOption(ia);
- req->addOption(clientid);
- // Server-id is mandatory in RELEASE
- req->addOption(srv.getServerID());
- // Pass it to the server and hope for a REPLY
- Pkt6Ptr reply = srv.processRelease(req);
- ASSERT_TRUE(reply);
- // Check that the callback called is indeed the one we installed
- EXPECT_EQ("lease6_release", callback_name_);
- // Check that appropriate parameters are passed to the callouts
- EXPECT_TRUE(callback_pkt6_);
- EXPECT_TRUE(callback_lease6_);
- // Check if all expected parameters were really received
- vector<string> expected_argument_names;
- expected_argument_names.push_back("query6");
- expected_argument_names.push_back("lease6");
- 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);
- // Check that the lease is really gone in the database
- // get lease by address
- l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA, addr);
- ASSERT_FALSE(l);
- // Get lease by subnetid/duid/iaid combination
- l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA, *duid_, iaid,
- subnet_->getID());
- ASSERT_FALSE(l);
- }
- // This test verifies that incoming (positive) RELEASE can be handled properly,
- // that a REPLY is generated, that the response has status code and that the
- // lease is indeed removed from the database.
- //
- // expected:
- // - returned REPLY message has copy of client-id
- // - returned REPLY message has server-id
- // - returned REPLY message has IA that does not include an IAADDR
- // - lease is actually removed from LeaseMgr
- TEST_F(HooksDhcpv6SrvTest, skipLease6Release) {
- NakedDhcpv6Srv srv(0);
- // Install pkt6_receive_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "lease6_release", lease6_release_skip_callout));
- const IOAddress addr("2001:db8:1:1::cafe:babe");
- const uint32_t iaid = 234;
- // 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_NA, addr));
- // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
- // value on purpose. They should be updated during RENEW.
- Lease6Ptr lease(new Lease6(Lease::TYPE_NA, addr, duid_, iaid,
- 501, 502, 503, 504, subnet_->getID(),
- HWAddrPtr(), 0));
- lease->cltt_ = 1234;
- ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
- // Check that the lease is really in the database
- Lease6Ptr l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
- addr);
- ASSERT_TRUE(l);
- // Let's create a RELEASE
- Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RELEASE, 1234));
- req->setRemoteAddr(IOAddress("fe80::abcd"));
- boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
- OptionPtr released_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
- ia->addOption(released_addr_opt);
- req->addOption(ia);
- req->addOption(clientid);
- // Server-id is mandatory in RELEASE
- req->addOption(srv.getServerID());
- // Pass it to the server and hope for a REPLY
- Pkt6Ptr reply = srv.processRelease(req);
- ASSERT_TRUE(reply);
- // Check that the callback called is indeed the one we installed
- EXPECT_EQ("lease6_release", callback_name_);
- // Check that the lease is still there
- // get lease by address
- l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
- addr);
- ASSERT_TRUE(l);
- // Get lease by subnetid/duid/iaid combination
- l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA, *duid_, iaid,
- subnet_->getID());
- ASSERT_TRUE(l);
- }
- // This test checks that the basic decline hook (lease6_decline) is
- // triggered properly.
- TEST_F(HooksDhcpv6SrvTest, basicLease6Decline) {
- IfaceMgrTestConfig test_config(true);
- // Install lease6_decline callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "lease6_decline", lease6_decline_callout));
- // Get an address and decline it. DUIDs, IAID match and we send valid
- // address, so the decline procedure should be successful.
- Dhcp6Client client;
- acquireAndDecline(client, "01:02:03:04:05:06", 1234, "01:02:03:04:05:06",
- 1234, VALID_ADDR, SHOULD_PASS);
- // Check that the proper callback was called.
- EXPECT_EQ("lease6_decline", callback_name_);
- // And valid parameters were passed.
- ASSERT_TRUE(callback_pkt6_);
- ASSERT_TRUE(callback_lease6_);
- // Test sanity check - it was a decline, right?
- EXPECT_EQ(DHCPV6_DECLINE, callback_pkt6_->getType());
- // Get the address from this decline.
- OptionPtr ia = callback_pkt6_->getOption(D6O_IA_NA);
- ASSERT_TRUE(ia);
- boost::shared_ptr<Option6IAAddr> addr_opt =
- boost::dynamic_pointer_cast<Option6IAAddr>(ia->getOption(D6O_IAADDR));
- ASSERT_TRUE(addr_opt);
- IOAddress addr(addr_opt->getAddress());
- // Now get a lease from the database.
- Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
- addr);
- ASSERT_TRUE(from_mgr);
- // Now check that it's indeed declined.
- EXPECT_EQ(Lease::STATE_DECLINED, from_mgr->state_);
- // And that the parameters passed to callout are consistent with the database
- EXPECT_EQ(addr, from_mgr->addr_);
- EXPECT_EQ(addr, callback_lease6_->addr_);
- }
- // Test that the lease6_decline hook point can handle SKIP status.
- TEST_F(HooksDhcpv6SrvTest, lease6DeclineSkip) {
- IfaceMgrTestConfig test_config(true);
- // Install lease6_decline callout. It will set the status to skip
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "lease6_decline", lease6_decline_skip_callout));
- // Get an address and decline it. DUIDs, IAID match and we send valid
- // address, so the decline procedure should be successful.
- Dhcp6Client client;
- acquireAndDecline(client, "01:02:03:04:05:06", 1234, "01:02:03:04:05:06",
- 1234, VALID_ADDR, SHOULD_FAIL);
- // Check that the proper callback was called.
- EXPECT_EQ("lease6_decline", callback_name_);
- // And valid parameters were passed.
- ASSERT_TRUE(callback_pkt6_);
- ASSERT_TRUE(callback_lease6_);
- // Test sanity check - it was a decline, right?
- EXPECT_EQ(DHCPV6_DECLINE, callback_pkt6_->getType());
- // Get the address from this decline.
- OptionPtr ia = callback_pkt6_->getOption(D6O_IA_NA);
- ASSERT_TRUE(ia);
- boost::shared_ptr<Option6IAAddr> addr_opt =
- boost::dynamic_pointer_cast<Option6IAAddr>(ia->getOption(D6O_IAADDR));
- ASSERT_TRUE(addr_opt);
- IOAddress addr(addr_opt->getAddress());
- // Now get a lease from the database.
- Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
- addr);
- ASSERT_TRUE(from_mgr);
- // Now check that it's NOT declined.
- EXPECT_EQ(Lease::STATE_DEFAULT, from_mgr->state_);
- // And that the parameters passed to callout are consistent with the database
- EXPECT_EQ(addr, from_mgr->addr_);
- EXPECT_EQ(addr, callback_lease6_->addr_);
- }
- // Test that the lease6_decline hook point can handle DROP status.
- TEST_F(HooksDhcpv6SrvTest, lease6DeclineDrop) {
- IfaceMgrTestConfig test_config(true);
- // Install lease6_decline callout. It will set the status to skip
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "lease6_decline", lease6_decline_drop_callout));
- // Get an address and decline it. DUIDs, IAID match and we send valid
- // address, so it would work, but the callout sets status to DROP, so
- // the server should not update the lease and should not send back any
- // packets.
- Dhcp6Client client;
- acquireAndDecline(client, "01:02:03:04:05:06", 1234, "01:02:03:04:05:06",
- 1234, VALID_ADDR, SHOULD_FAIL);
- // Check that the proper callback was called.
- EXPECT_EQ("lease6_decline", callback_name_);
- // And valid parameters were passed.
- ASSERT_TRUE(callback_pkt6_);
- ASSERT_TRUE(callback_lease6_);
- // Test sanity check - it was a decline, right?
- EXPECT_EQ(DHCPV6_DECLINE, callback_pkt6_->getType());
- // Get the address from this decline.
- OptionPtr ia = callback_pkt6_->getOption(D6O_IA_NA);
- ASSERT_TRUE(ia);
- boost::shared_ptr<Option6IAAddr> addr_opt =
- boost::dynamic_pointer_cast<Option6IAAddr>(ia->getOption(D6O_IAADDR));
- ASSERT_TRUE(addr_opt);
- IOAddress addr(addr_opt->getAddress());
- // Now get a lease from the database.
- Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
- addr);
- ASSERT_TRUE(from_mgr);
- // Now check that it's NOT declined.
- EXPECT_EQ(Lease::STATE_DEFAULT, from_mgr->state_);
- }
- } // end of anonymous namespace
|