From 1c5e0902b11fc70b363c4b84d1fc5c47c43fbe7d Mon Sep 17 00:00:00 2001 From: Tomek Mrugalski Date: Thu, 8 Oct 2015 23:20:37 +0200 Subject: [PATCH] [3987] lease6_decline implemented. --- src/bin/dhcp4/tests/dhcp4_srv_unittest.cc | 1 - src/bin/dhcp4/tests/dhcp4_test_utils.cc | 2 +- src/bin/dhcp6/dhcp6_hooks.dox | 20 +++ src/bin/dhcp6/dhcp6_messages.mes | 14 ++ src/bin/dhcp6/dhcp6_srv.cc | 72 ++++++++- src/bin/dhcp6/dhcp6_srv.h | 14 +- src/bin/dhcp6/tests/confirm_unittest.cc | 1 - src/bin/dhcp6/tests/decline_unittest.cc | 89 +++++------ src/bin/dhcp6/tests/dhcp6_client.cc | 1 - src/bin/dhcp6/tests/dhcp6_client.h | 6 +- src/bin/dhcp6/tests/dhcp6_message_test.h | 4 +- src/bin/dhcp6/tests/dhcp6_srv_unittest.cc | 1 - src/bin/dhcp6/tests/dhcp6_test_utils.cc | 5 +- src/bin/dhcp6/tests/dhcp6_test_utils.h | 43 +++++- src/bin/dhcp6/tests/fqdn_unittest.cc | 2 +- src/bin/dhcp6/tests/hooks_unittest.cc | 166 ++++++++++++++++++++- src/bin/dhcp6/tests/host_unittest.cc | 1 - src/bin/dhcp6/tests/infrequest_unittest.cc | 1 - src/bin/dhcp6/tests/rebind_unittest.cc | 1 - src/bin/dhcp6/tests/renew_unittest.cc | 1 - src/bin/dhcp6/tests/sarr_unittest.cc | 1 - src/lib/dhcp/tests/pkt6_unittest.cc | 5 +- src/lib/dhcp/tests/pkt_captures.h | 11 +- src/lib/dhcp/tests/pkt_captures4.cc | 4 +- src/lib/dhcp/tests/pkt_captures6.cc | 13 +- 25 files changed, 381 insertions(+), 98 deletions(-) diff --git a/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc b/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc index 3b9ef28eef..2f4f1ce767 100644 --- a/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc +++ b/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc @@ -59,7 +59,6 @@ using namespace isc::asiolink; using namespace isc::hooks; using namespace isc::config; using namespace isc::dhcp::test; -using namespace isc::test; namespace { diff --git a/src/bin/dhcp4/tests/dhcp4_test_utils.cc b/src/bin/dhcp4/tests/dhcp4_test_utils.cc index 8fa1b63a81..46ff7b5b4d 100644 --- a/src/bin/dhcp4/tests/dhcp4_test_utils.cc +++ b/src/bin/dhcp4/tests/dhcp4_test_utils.cc @@ -617,7 +617,7 @@ Dhcpv4SrvTest::pretendReceivingPkt(NakedDhcpv4Srv& srv, const std::string& confi configure(config); // Let's just use one of the actual captured packets that we have. - Pkt4Ptr pkt = isc::test::PktCaptures::captureRelayedDiscover(); + Pkt4Ptr pkt = PktCaptures::captureRelayedDiscover(); // We just need to tweak it a it, to pretend that it's type is as desired. // Note that when receiving a packet, its on-wire form is stored in data_ diff --git a/src/bin/dhcp6/dhcp6_hooks.dox b/src/bin/dhcp6/dhcp6_hooks.dox index a76bd3e46e..63ae2b6c38 100644 --- a/src/bin/dhcp6/dhcp6_hooks.dox +++ b/src/bin/dhcp6/dhcp6_hooks.dox @@ -174,6 +174,26 @@ packet processing. Hook points that are not specific to packet processing this fact; otherwise the client will think the lease was renewed and continue to operate under this assumption. +@subsection dhcpv6HooksLease6Decline lease6_decline + + - @b Arguments: + - name: @b query6, type: isc::dhcp::PktPtr, direction: in + - name: @b lease6, type: isc::dhcp::Lease6Ptr, direction: in/out + + - @b Description: This callout is executed when the server engine is + about to decline an existing lease. The client's request is provided as + the "query6" argument and the existing lease with the appropriate fields + already modified is given in the "lease6" argument. The lease contains + the lease before it is being declined. + + - Next step status: If any callout installed on "lease6_decline" + sets the status to SKIP, the server will not decline the lease, but will + continue processing the packet as if it did. It will send the response + that the lease was declined, but the actual database will not be + updated. If any callout installed sets the status to DROP, the packet + processing will be aborted, the lease will not be declined and the + server will not send a response. + @subsection dhcpv6HooksLease6Release lease6_release - @b Arguments: diff --git a/src/bin/dhcp6/dhcp6_messages.mes b/src/bin/dhcp6/dhcp6_messages.mes index ef0ea349ef..1ac0073e45 100644 --- a/src/bin/dhcp6/dhcp6_messages.mes +++ b/src/bin/dhcp6/dhcp6_messages.mes @@ -292,6 +292,20 @@ or released leases), but the response will not be send to the client. The argument includes the client and transaction identification information. +% DHCP6_HOOK_DECLINE_SKIP During Decline processing (client=%1, interface=%2, addr=%3) hook callout set status to DROP, ignoring packet. +This message indicates that the server received DECLINE message, it was verified +to be correct and matching server's lease information. The server called hooks +for the lease6_decline hook point and one of the callouts set next step status to SKIP. +The server will skip the operation of moving the lease to the declined state and +will continue processing. + +% DHCP6_HOOK_DECLINE_DROP During Decline processing (client=%1, interface=%2, addr=%3) hook callout set status to DROP, dropping packet. +This message indicates that the server received DECLINE message, it was verified +to be correct and matching server's lease information. The server called hooks +for the lease6_decline hook point and one of the callouts set next step status to DROP. +The server will now abort processing of the packet as if it was never +received. The lease will continue to be assigned to this client. + % DHCP6_HOOK_LEASE6_RELEASE_NA_SKIP %1: DHCPv6 address lease was not released because a callout set the skip flag This debug message is printed when a callout installed on the lease6_release hook point set the skip flag. For this particular hook diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc index 239311f8f6..89023a154a 100644 --- a/src/bin/dhcp6/dhcp6_srv.cc +++ b/src/bin/dhcp6/dhcp6_srv.cc @@ -96,6 +96,7 @@ struct Dhcp6Hooks { int hook_index_lease6_release_; ///< index for "lease6_release" hook point int hook_index_pkt6_send_; ///< index for "pkt6_send" hook point int hook_index_buffer6_send_; ///< index for "buffer6_send" hook point + int hook_index_lease6_decline_; ///< index for "lease6_decline" hook point /// Constructor that registers hook points for DHCPv6 engine Dhcp6Hooks() { @@ -105,6 +106,7 @@ struct Dhcp6Hooks { hook_index_lease6_release_ = HooksManager::registerHook("lease6_release"); hook_index_pkt6_send_ = HooksManager::registerHook("pkt6_send"); hook_index_buffer6_send_ = HooksManager::registerHook("buffer6_send"); + hook_index_lease6_decline_ = HooksManager::registerHook("lease6_decline"); } }; @@ -2593,12 +2595,17 @@ Dhcpv6Srv::processDecline(const Pkt6Ptr& decline) { // Include server-id appendDefaultOptions(decline, reply); - declineLeases(decline, reply, ctx); + if (declineLeases(decline, reply, ctx)) { + return (reply); + } else { - return (reply); + // declineLeases returns false only if the hooks set the next step + // status to DROP. We'll just doing as requested. + return (Pkt6Ptr()); + } } -void +bool Dhcpv6Srv::declineLeases(const Pkt6Ptr& decline, Pkt6Ptr& reply, AllocEngine::ClientContext6& ctx) { @@ -2619,7 +2626,15 @@ Dhcpv6Srv::declineLeases(const Pkt6Ptr& decline, Pkt6Ptr& reply, OptionPtr answer_opt = declineIA(decline, ctx.duid_, general_status, boost::dynamic_pointer_cast(opt->second)); if (answer_opt) { + + // We have an answer, let's use it. reply->addOption(answer_opt); + } else { + + // The only case when declineIA could return NULL is if one of the + // hook callouts set next step status to DROP. We just need to drop + // this packet. + return (false); } break; } @@ -2628,6 +2643,8 @@ Dhcpv6Srv::declineLeases(const Pkt6Ptr& decline, Pkt6Ptr& reply, ; } } + + return (true); } OptionPtr @@ -2734,7 +2751,11 @@ Dhcpv6Srv::declineIA(const Pkt6Ptr& decline, const DuidPtr& duid, } // Ok, all is good. Decline this lease. - declineLease(decline, lease, ia_rsp); + if (!declineLease(decline, lease, ia_rsp)) { + // declineLease returns false only when hook callouts set the next + // step status to drop. We just propagate the bad news here. + return (OptionPtr()); + } } if (total_addrs == 0) { @@ -2755,10 +2776,47 @@ Dhcpv6Srv::setStatusCode(boost::shared_ptr& container, container->addOption(status); } -void +bool Dhcpv6Srv::declineLease(const Pkt6Ptr& decline, const Lease6Ptr lease, boost::shared_ptr ia_rsp) { + // Let's call lease6_decline hooks if necessary. + if (HooksManager::calloutsPresent(Hooks.hook_index_lease6_decline_)) { + CalloutHandlePtr callout_handle = getCalloutHandle(decline); + + // Delete previously set arguments + callout_handle->deleteAllArguments(); + + // Pass incoming packet as argument + callout_handle->setArgument("query6", decline); + callout_handle->setArgument("lease6", lease); + + // Call callouts + HooksManager::callCallouts(Hooks.hook_index_lease6_decline_, + *callout_handle); + + // Callouts decided to SKIP the next processing step. The next + // processing step would to actually decline the lease, so we'll + // keep the lease as is. + if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) { + LOG_DEBUG(hooks_logger, DBG_DHCP6_DETAIL, DHCP6_HOOK_DECLINE_SKIP) + .arg(decline->getLabel()) + .arg(decline->getIface()) + .arg(lease->addr_.toText()); + return (true); + } + + // Callouts decided to DROP the packet. Let's simply log it and + // return false, so upper layers will act accordingly. + if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP) { + LOG_DEBUG(hooks_logger, DBG_DHCP6_DETAIL, DHCP6_HOOK_DECLINE_DROP) + .arg(decline->getLabel()) + .arg(decline->getIface()) + .arg(lease->addr_.toText()); + return (false); + } + } + // Check if a lease has flags indicating that the FQDN update has // been performed. If so, create NameChangeRequest which removes // the entries. This method does all necessary checks. @@ -2772,8 +2830,6 @@ Dhcpv6Srv::declineLease(const Pkt6Ptr& decline, const Lease6Ptr lease, // Global declined addresses counter. StatsMgr::instance().addValue("declined-addresses", static_cast(1)); - // @todo: Call hooks. - // We need to disassociate the lease from the client. Once we move a lease // to declined state, it is no longer associated with the client in any // way. @@ -2785,6 +2841,8 @@ Dhcpv6Srv::declineLease(const Pkt6Ptr& decline, const Lease6Ptr lease, ia_rsp->addOption(createStatusCode(*decline, *ia_rsp, STATUS_Success, "Lease declined. Hopefully the next one will be better.")); + + return (true); } Pkt6Ptr diff --git a/src/bin/dhcp6/dhcp6_srv.h b/src/bin/dhcp6/dhcp6_srv.h index 9d2ff2d510..38a091f730 100644 --- a/src/bin/dhcp6/dhcp6_srv.h +++ b/src/bin/dhcp6/dhcp6_srv.h @@ -709,9 +709,10 @@ protected: /// @param decline Decline messege sent by a client /// @param reply Server's response (IA_NA with status will be added here) /// @param client context - void - declineLeases(const Pkt6Ptr& decline, Pkt6Ptr& reply, - AllocEngine::ClientContext6& ctx); + /// @return true when expected to continue, false when hooks told us to drop + /// the packet + bool declineLeases(const Pkt6Ptr& decline, Pkt6Ptr& reply, + AllocEngine::ClientContext6& ctx); /// @brief Declines leases in a single IA_NA option /// @@ -743,9 +744,10 @@ protected: /// @param decline used for generating removal Name Change Request. /// @param lease lease to be declined /// @param ia_rsp response IA_NA. - void - declineLease(const Pkt6Ptr& decline, const Lease6Ptr lease, - boost::shared_ptr ia_rsp); + /// @return true when expected to continue, false when hooks told us to drop + /// the packet + bool declineLease(const Pkt6Ptr& decline, const Lease6Ptr lease, + boost::shared_ptr ia_rsp); /// @brief A simple utility method that sets the status code /// diff --git a/src/bin/dhcp6/tests/confirm_unittest.cc b/src/bin/dhcp6/tests/confirm_unittest.cc index ab8cbdfe22..5e2f7ef5df 100644 --- a/src/bin/dhcp6/tests/confirm_unittest.cc +++ b/src/bin/dhcp6/tests/confirm_unittest.cc @@ -25,7 +25,6 @@ using namespace isc::asiolink; using namespace isc::data; using namespace isc::dhcp; using namespace isc::dhcp::test; -using namespace isc::test; namespace { diff --git a/src/bin/dhcp6/tests/decline_unittest.cc b/src/bin/dhcp6/tests/decline_unittest.cc index 41d39d7ffd..d20d11c8f9 100644 --- a/src/bin/dhcp6/tests/decline_unittest.cc +++ b/src/bin/dhcp6/tests/decline_unittest.cc @@ -18,6 +18,7 @@ #include #include #include +#include #include using namespace isc; @@ -25,7 +26,6 @@ using namespace isc::asiolink; using namespace isc::data; using namespace isc::dhcp; using namespace isc::dhcp::test; -using namespace isc::test; using namespace isc::stats; namespace { @@ -56,38 +56,6 @@ const char* DECLINE_CONFIGS[] = { class DeclineTest : public Dhcpv6MessageTest { public: - /// @brief Specifies expected outcome - enum ExpectedResult { - SHOULD_PASS, // pass = accept decline, move lease to declined state. - SHOULD_FAIL // fail = reject the decline - }; - - /// @brief Specifies what address should the client include in its Decline - enum AddressInclusion { - VALID_ADDR, // Client will include its own, valid address - BOGUS_ADDR, // Client will include an address it doesn't own - NO_ADDR, // Client will send empty IA_NA (without address) - NO_IA // Client will not send IA_NA at all - }; - - /// @brief Tests if the acquired lease is or is not declined. - /// - /// @param duid1 DUID used during lease acquisition - /// @param iaid1 IAID used during lease acquisition - /// @param duid2 DUID used during Decline exchange - /// @param iaid2 IAID used during Decline exchange - /// @param addr_type specify what sort of address the client should - /// include (its own, a bogus one or no address at all) - /// @param expected_result SHOULD_PASS if the lease is expected to - /// be successfully declined, or SHOULD_FAIL if the lease is expected - /// to not be declined. - void acquireAndDecline(const std::string& duid1, - const uint32_t iaid1, - const std::string& duid2, - const uint32_t iaid2, - AddressInclusion addr_type, - ExpectedResult expected_result); - /// @brief Constructor. /// /// Sets up fake interfaces. @@ -100,17 +68,23 @@ public: }; +}; + +namespace isc { +namespace dhcp { +namespace test { + void -DeclineTest::acquireAndDecline(const std::string& duid1, - const uint32_t iaid1, - const std::string& duid2, - const uint32_t iaid2, - AddressInclusion addr_type, - ExpectedResult expected_result) { +Dhcpv6SrvTest::acquireAndDecline(Dhcp6Client& client, + const std::string& duid1, + const uint32_t iaid1, + const std::string& duid2, + const uint32_t iaid2, + AddressInclusion addr_type, + ExpectedResult expected_result) { // Set this global statistic explicitly to zero. StatsMgr::instance().setValue("declined-addresses", static_cast(0)); - Dhcp6Client client; client.setDUID(duid1); client.useNA(iaid1); @@ -135,7 +109,7 @@ DeclineTest::acquireAndDecline(const std::string& duid1, // Make sure that the client has acquired NA lease. std::vector leases_client_na = client.getLeasesByType(Lease::TYPE_NA); ASSERT_EQ(1, leases_client_na.size()); - EXPECT_EQ(STATUS_Success, client.getStatusCode(na_iaid_)); + EXPECT_EQ(STATUS_Success, client.getStatusCode(iaid1)); // Remember the acquired address. IOAddress acquired_address = leases_client_na[0].addr_; @@ -214,19 +188,25 @@ DeclineTest::acquireAndDecline(const std::string& duid1, // This test checks that the client can acquire and decline the lease. TEST_F(DeclineTest, basic) { - acquireAndDecline("01:02:03:04:05:06", 1234, - "01:02:03:04:05:06", 1234, - VALID_ADDR, SHOULD_PASS); + Dhcp6Client client; + acquireAndDecline(client, "01:02:03:04:05:06", 1234, "01:02:03:04:05:06", + 1234, VALID_ADDR, SHOULD_PASS); } +}; +}; +}; + +namespace { + // This test verifies the decline is rejected in the following case: // - Client acquires new lease using duid, iaid // - Client sends the DECLINE with duid, iaid, but uses wrong address. // - The server rejects Decline due to address mismatch TEST_F(DeclineTest, addressMismatch) { - acquireAndDecline("01:02:03:04:05:06", 1234, - "01:02:03:04:05:06", 1234, - BOGUS_ADDR, SHOULD_FAIL); + Dhcp6Client client; + acquireAndDecline(client, "01:02:03:04:05:06", 1234, "01:02:03:04:05:06", + 1234, BOGUS_ADDR, SHOULD_FAIL); } // This test verifies the decline is rejected in the following case: @@ -234,9 +214,9 @@ TEST_F(DeclineTest, addressMismatch) { // - Client sends the DECLINE with duid, iaid2 // - The server rejects Decline due to IAID mismatch TEST_F(DeclineTest, iaidMismatch) { - acquireAndDecline("01:02:03:04:05:06", 1234, - "01:02:03:04:05:06", 1235, - VALID_ADDR, SHOULD_FAIL); + Dhcp6Client client; + acquireAndDecline(client, "01:02:03:04:05:06", 1234, "01:02:03:04:05:06", + 1235, VALID_ADDR, SHOULD_FAIL); } // This test verifies the decline correctness in the following case: @@ -244,7 +224,8 @@ TEST_F(DeclineTest, iaidMismatch) { // - Client sends the DECLINE using duid2, iaid // - The server rejects the Decline due to DUID mismatch TEST_F(DeclineTest, duidMismatch) { - acquireAndDecline("01:02:03:04:05:06", 1234, + Dhcp6Client client; + acquireAndDecline(client, "01:02:03:04:05:06", 1234, "01:02:03:04:05:07", 1234, VALID_ADDR, SHOULD_FAIL); } @@ -255,7 +236,8 @@ TEST_F(DeclineTest, duidMismatch) { // include the address in it // - The server rejects the Decline due to missing address TEST_F(DeclineTest, noAddrsSent) { - acquireAndDecline("01:02:03:04:05:06", 1234, + Dhcp6Client client; + acquireAndDecline(client, "01:02:03:04:05:06", 1234, "01:02:03:04:05:06", 1234, NO_ADDR, SHOULD_FAIL); } @@ -266,7 +248,8 @@ TEST_F(DeclineTest, noAddrsSent) { // include IA_NA at all // - The server rejects the Decline due to missing IA_NA TEST_F(DeclineTest, noIAs) { - acquireAndDecline("01:02:03:04:05:06", 1234, + Dhcp6Client client; + acquireAndDecline(client, "01:02:03:04:05:06", 1234, "01:02:03:04:05:06", 1234, NO_IA, SHOULD_FAIL); } diff --git a/src/bin/dhcp6/tests/dhcp6_client.cc b/src/bin/dhcp6/tests/dhcp6_client.cc index 9ca6282216..da67b6a2bd 100644 --- a/src/bin/dhcp6/tests/dhcp6_client.cc +++ b/src/bin/dhcp6/tests/dhcp6_client.cc @@ -30,7 +30,6 @@ using namespace isc::dhcp; using namespace isc::dhcp::test; -using namespace isc::test; namespace { diff --git a/src/bin/dhcp6/tests/dhcp6_client.h b/src/bin/dhcp6/tests/dhcp6_client.h index c4c0750462..afdae26d24 100644 --- a/src/bin/dhcp6/tests/dhcp6_client.h +++ b/src/bin/dhcp6/tests/dhcp6_client.h @@ -178,7 +178,7 @@ public: /// - not relayed /// /// @param srv Object representing server under test. - Dhcp6Client(boost::shared_ptr& srv); + Dhcp6Client(boost::shared_ptr& srv); /// @brief Create lease for the client. /// @@ -365,7 +365,7 @@ public: } /// @brief Returns the server that the client is communicating with. - boost::shared_ptr getServer() const { + boost::shared_ptr getServer() const { return (srv_); } @@ -727,7 +727,7 @@ private: std::string iface_name_; /// @brief Pointer to the server that the client is communicating with. - boost::shared_ptr srv_; + boost::shared_ptr srv_; bool use_na_; ///< Enable address assignment. bool use_pd_; ///< Enable prefix delegation. diff --git a/src/bin/dhcp6/tests/dhcp6_message_test.h b/src/bin/dhcp6/tests/dhcp6_message_test.h index c885bc27b4..832fc79f90 100644 --- a/src/bin/dhcp6/tests/dhcp6_message_test.h +++ b/src/bin/dhcp6/tests/dhcp6_message_test.h @@ -1,4 +1,4 @@ -// Copyright (C) 2014, 2015 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2014-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 @@ -26,7 +26,7 @@ namespace test { /// @brief Base class for test fixure classes used to validate the DHCPv6 /// message processing by the server. -class Dhcpv6MessageTest : public isc::test::Dhcpv6SrvTest { +class Dhcpv6MessageTest : public isc::dhcp::test::Dhcpv6SrvTest { public: /// @brief Constructor. /// diff --git a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc index 4fa269b0bc..dfa145c7a3 100644 --- a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc +++ b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc @@ -53,7 +53,6 @@ using namespace isc; using namespace isc::data; -using namespace isc::test; using namespace isc::asiolink; using namespace isc::dhcp; using namespace isc::dhcp::test; diff --git a/src/bin/dhcp6/tests/dhcp6_test_utils.cc b/src/bin/dhcp6/tests/dhcp6_test_utils.cc index 9c7c7063ef..2f9f2c128d 100644 --- a/src/bin/dhcp6/tests/dhcp6_test_utils.cc +++ b/src/bin/dhcp6/tests/dhcp6_test_utils.cc @@ -29,6 +29,7 @@ using namespace isc::asiolink; using namespace isc::stats; namespace isc { +namespace dhcp { namespace test { const char* NakedDhcpv6SrvTest::DUID_FILE = "server-id-test.txt"; @@ -827,6 +828,6 @@ NakedDhcpv6SrvTest::checkIA_NAStatusCode( } } - -}; // end of isc::test namespace +}; // end of isc::dhcp::test namespace +}; // end of isc::dhcp namespace }; // end of isc namespace diff --git a/src/bin/dhcp6/tests/dhcp6_test_utils.h b/src/bin/dhcp6/tests/dhcp6_test_utils.h index c6fcfad75d..c94efea0ab 100644 --- a/src/bin/dhcp6/tests/dhcp6_test_utils.h +++ b/src/bin/dhcp6/tests/dhcp6_test_utils.h @@ -39,6 +39,7 @@ #include namespace isc { +namespace dhcp { namespace test { /// @brief "naked" Dhcpv6Srv class that exposes internal members @@ -290,11 +291,28 @@ public: std::string valid_iface_; }; +// We need to pass one reference to the Dhcp6Client, which is defined in +// dhcp6_client.h. That header includes this file. To avoid circular +// dependencies, we use forward declaration here. +class Dhcp6Client; + // Provides suport for tests against a preconfigured subnet6 // extends upon NakedDhcp6SrvTest class Dhcpv6SrvTest : public NakedDhcpv6SrvTest { public: - /// Name of the server-id file (used in server-id tests) + /// @brief Specifies expected outcome + enum ExpectedResult { + SHOULD_PASS, // pass = accept decline, move lease to declined state. + SHOULD_FAIL // fail = reject the decline + }; + + /// @brief Specifies what address should the client include in its Decline + enum AddressInclusion { + VALID_ADDR, // Client will include its own, valid address + BOGUS_ADDR, // Client will include an address it doesn't own + NO_ADDR, // Client will send empty IA_NA (without address) + NO_IA // Client will not send IA_NA at all + }; /// @brief Constructor that initializes a simple default configuration /// @@ -437,6 +455,26 @@ public: bool compareOptions(const isc::dhcp::OptionPtr& option1, const isc::dhcp::OptionPtr& option2); + /// @brief Tests if the acquired lease is or is not declined. + /// + /// @param client Dhcp6Client instance + /// @param duid1 DUID used during lease acquisition + /// @param iaid1 IAID used during lease acquisition + /// @param duid2 DUID used during Decline exchange + /// @param iaid2 IAID used during Decline exchange + /// @param addr_type specify what sort of address the client should + /// include (its own, a bogus one or no address at all) + /// @param expected_result SHOULD_PASS if the lease is expected to + /// be successfully declined, or SHOULD_FAIL if the lease is expected + /// to not be declined. + void acquireAndDecline(Dhcp6Client& client, + const std::string& duid1, + const uint32_t iaid1, + const std::string& duid2, + const uint32_t iaid2, + AddressInclusion addr_type, + ExpectedResult expected_result); + /// @brief Performs basic (positive) RENEW test /// /// See renewBasic and pdRenewBasic tests for detailed explanation. @@ -520,7 +558,8 @@ public: NakedDhcpv6Srv srv_; }; -}; // end of isc::test namespace +}; // end of isc::dhcp::test namespace +}; // end of isc::dhcp namespace }; // end of isc namespace #endif // DHCP6_TEST_UTILS_H diff --git a/src/bin/dhcp6/tests/fqdn_unittest.cc b/src/bin/dhcp6/tests/fqdn_unittest.cc index 63885496d5..ee1a25adb4 100644 --- a/src/bin/dhcp6/tests/fqdn_unittest.cc +++ b/src/bin/dhcp6/tests/fqdn_unittest.cc @@ -32,7 +32,7 @@ #include using namespace isc; -using namespace isc::test; +using namespace isc::dhcp::test; using namespace isc::asiolink; using namespace isc::dhcp; using namespace isc::dhcp_ddns; diff --git a/src/bin/dhcp6/tests/hooks_unittest.cc b/src/bin/dhcp6/tests/hooks_unittest.cc index fc14668ee8..6bc491eaf5 100644 --- a/src/bin/dhcp6/tests/hooks_unittest.cc +++ b/src/bin/dhcp6/tests/hooks_unittest.cc @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -39,7 +40,7 @@ using namespace isc; using namespace isc::data; -using namespace isc::test; +using namespace isc::dhcp::test; using namespace isc::asiolink; using namespace isc::dhcp; using namespace isc::util; @@ -457,6 +458,43 @@ public: 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(""); @@ -1452,4 +1490,130 @@ TEST_F(HooksDhcpv6SrvTest, skip_lease6_release) { ASSERT_TRUE(l); } +// This test checks that the basic decline hook (lease6_decline) is +// triggered properly. +TEST_F(HooksDhcpv6SrvTest, declineBasic) { + + // 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 addr_opt = + boost::dynamic_pointer_cast(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, declineSkip) { + // 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 addr_opt = + boost::dynamic_pointer_cast(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, declineDrop) { + // 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 addr_opt = + boost::dynamic_pointer_cast(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 diff --git a/src/bin/dhcp6/tests/host_unittest.cc b/src/bin/dhcp6/tests/host_unittest.cc index e7541b7006..1c90bdc953 100644 --- a/src/bin/dhcp6/tests/host_unittest.cc +++ b/src/bin/dhcp6/tests/host_unittest.cc @@ -20,7 +20,6 @@ using namespace isc; using namespace isc::dhcp; using namespace isc::dhcp::test; -using namespace isc::test; namespace { diff --git a/src/bin/dhcp6/tests/infrequest_unittest.cc b/src/bin/dhcp6/tests/infrequest_unittest.cc index 8b15f7fb6e..87011dc9f3 100644 --- a/src/bin/dhcp6/tests/infrequest_unittest.cc +++ b/src/bin/dhcp6/tests/infrequest_unittest.cc @@ -23,7 +23,6 @@ using namespace isc; using namespace isc::dhcp; using namespace isc::dhcp::test; -using namespace isc::test; namespace { diff --git a/src/bin/dhcp6/tests/rebind_unittest.cc b/src/bin/dhcp6/tests/rebind_unittest.cc index faff77a4d6..96d7868c2b 100644 --- a/src/bin/dhcp6/tests/rebind_unittest.cc +++ b/src/bin/dhcp6/tests/rebind_unittest.cc @@ -25,7 +25,6 @@ using namespace isc::asiolink; using namespace isc::data; using namespace isc::dhcp; using namespace isc::dhcp::test; -using namespace isc::test; namespace { diff --git a/src/bin/dhcp6/tests/renew_unittest.cc b/src/bin/dhcp6/tests/renew_unittest.cc index dc2fd53791..ba08d725d8 100644 --- a/src/bin/dhcp6/tests/renew_unittest.cc +++ b/src/bin/dhcp6/tests/renew_unittest.cc @@ -24,7 +24,6 @@ using namespace isc::asiolink; using namespace isc::data; using namespace isc::dhcp; using namespace isc::dhcp::test; -using namespace isc::test; namespace { diff --git a/src/bin/dhcp6/tests/sarr_unittest.cc b/src/bin/dhcp6/tests/sarr_unittest.cc index 71eb3e96d1..884e10a5da 100644 --- a/src/bin/dhcp6/tests/sarr_unittest.cc +++ b/src/bin/dhcp6/tests/sarr_unittest.cc @@ -25,7 +25,6 @@ using namespace isc; using namespace isc::dhcp; using namespace isc::dhcp::test; -using namespace isc::test; namespace { diff --git a/src/lib/dhcp/tests/pkt6_unittest.cc b/src/lib/dhcp/tests/pkt6_unittest.cc index 12e80e10bd..59bd4d2b85 100644 --- a/src/lib/dhcp/tests/pkt6_unittest.cc +++ b/src/lib/dhcp/tests/pkt6_unittest.cc @@ -44,6 +44,7 @@ using namespace std; using namespace isc; using namespace isc::asiolink; using namespace isc::dhcp; +using namespace isc::dhcp::test; using boost::scoped_ptr; namespace { @@ -1284,7 +1285,7 @@ TEST_F(Pkt6Test, getMAC_DOCSIS_Modem) { // Let's use a captured traffic. The one we have comes from a // modem with MAC address 10:0d:7f:00:07:88. - Pkt6Ptr pkt = isc::test::PktCaptures::captureDocsisRelayedSolicit(); + Pkt6Ptr pkt = PktCaptures::captureDocsisRelayedSolicit(); ASSERT_NO_THROW(pkt->unpack()); // The method should return MAC based on the vendor-specific info, @@ -1312,7 +1313,7 @@ TEST_F(Pkt6Test, getMAC_DOCSIS_CMTS) { // Let's use a captured traffic. The one we have comes from a // modem with MAC address 20:e5:2a:b8:15:14. - Pkt6Ptr pkt = isc::test::PktCaptures::captureeRouterRelayedSolicit(); + Pkt6Ptr pkt = PktCaptures::captureeRouterRelayedSolicit(); ASSERT_NO_THROW(pkt->unpack()); // The method should return MAC based on the vendor-specific info, diff --git a/src/lib/dhcp/tests/pkt_captures.h b/src/lib/dhcp/tests/pkt_captures.h index 8f38971a56..232db6876e 100644 --- a/src/lib/dhcp/tests/pkt_captures.h +++ b/src/lib/dhcp/tests/pkt_captures.h @@ -12,10 +12,14 @@ // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. +#ifndef PKT_CAPTURES_H +#define PKT_CAPTURES_H + #include #include namespace isc { +namespace dhcp { namespace test { class PktCaptures { @@ -69,5 +73,8 @@ protected: static void captureSetDefaultFields(const isc::dhcp::Pkt4Ptr& pkt); }; -}; -}; +}; // end of namespace isc::dhcp::test +}; // end of namespace isc::dhcp +}; // end of namespace isc + +#endif diff --git a/src/lib/dhcp/tests/pkt_captures4.cc b/src/lib/dhcp/tests/pkt_captures4.cc index 3ee87ad766..6177f34751 100644 --- a/src/lib/dhcp/tests/pkt_captures4.cc +++ b/src/lib/dhcp/tests/pkt_captures4.cc @@ -45,6 +45,7 @@ using namespace isc::dhcp; using namespace isc::asiolink; namespace isc { +namespace dhcp { namespace test { Pkt4Ptr PktCaptures::packetFromCapture(const std::string& hex_string) { @@ -185,5 +186,6 @@ Bootstrap Protocol return (packetFromCapture(hex_string)); } -}; // end of isc::test namespace +}; // end of isc::dhcp::test namespace +}; // end of isc::dhcp namespace }; // end of isc namespace diff --git a/src/lib/dhcp/tests/pkt_captures6.cc b/src/lib/dhcp/tests/pkt_captures6.cc index b360fe10c8..12367823eb 100644 --- a/src/lib/dhcp/tests/pkt_captures6.cc +++ b/src/lib/dhcp/tests/pkt_captures6.cc @@ -45,6 +45,7 @@ using namespace isc::asiolink; using namespace std; namespace isc { +namespace dhcp { namespace test { void PktCaptures::captureSetDefaultFields(const Pkt6Ptr& pkt) { @@ -107,7 +108,7 @@ Pkt6Ptr PktCaptures::captureRelayedSolicit() { } /// returns a buffer with relayed SOLICIT (from DOCSIS3.0 cable modem) -Pkt6Ptr isc::test::PktCaptures::captureDocsisRelayedSolicit() { +Pkt6Ptr PktCaptures::captureDocsisRelayedSolicit() { // This is an actual DOCSIS packet // RELAY-FORW (12) @@ -169,7 +170,7 @@ Pkt6Ptr isc::test::PktCaptures::captureDocsisRelayedSolicit() { } /// returns a buffer with relayed SOLICIT (from DOCSIS3.0 eRouter) -Pkt6Ptr isc::test::PktCaptures::captureeRouterRelayedSolicit() { +Pkt6Ptr PktCaptures::captureeRouterRelayedSolicit() { /* Packet description exported from wireshark: DHCPv6 @@ -304,7 +305,7 @@ DHCPv6 return (pkt); } -Pkt6Ptr isc::test::PktCaptures::captureCableLabsShortVendorClass() { +Pkt6Ptr PktCaptures::captureCableLabsShortVendorClass() { // This is a simple non-relayed Solicit: // - client-identifier // - IA_NA @@ -364,7 +365,7 @@ Pkt6Ptr isc::test::PktCaptures::captureCableLabsShortVendorClass() { /// The original capture was posted to dibbler users mailing list. /// /// @return created double relayed SOLICIT message -isc::dhcp::Pkt6Ptr isc::test::PktCaptures::captureRelayed2xRSOO() { +isc::dhcp::Pkt6Ptr PktCaptures::captureRelayed2xRSOO() { // string exported from Wireshark string hex_string = @@ -399,6 +400,6 @@ isc::dhcp::Pkt6Ptr isc::test::PktCaptures::captureRelayed2xRSOO() { return (pkt); } - -}; // end of isc::test namespace +}; // end of isc::dhcp::test namespace +}; // end of isc::dhcp namespace }; // end of isc namespace -- 2.47.2