]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[3987] lease6_decline implemented.
authorTomek Mrugalski <tomasz@isc.org>
Thu, 8 Oct 2015 21:20:37 +0000 (23:20 +0200)
committerTomek Mrugalski <tomasz@isc.org>
Thu, 8 Oct 2015 21:20:37 +0000 (23:20 +0200)
25 files changed:
src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
src/bin/dhcp4/tests/dhcp4_test_utils.cc
src/bin/dhcp6/dhcp6_hooks.dox
src/bin/dhcp6/dhcp6_messages.mes
src/bin/dhcp6/dhcp6_srv.cc
src/bin/dhcp6/dhcp6_srv.h
src/bin/dhcp6/tests/confirm_unittest.cc
src/bin/dhcp6/tests/decline_unittest.cc
src/bin/dhcp6/tests/dhcp6_client.cc
src/bin/dhcp6/tests/dhcp6_client.h
src/bin/dhcp6/tests/dhcp6_message_test.h
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
src/bin/dhcp6/tests/dhcp6_test_utils.cc
src/bin/dhcp6/tests/dhcp6_test_utils.h
src/bin/dhcp6/tests/fqdn_unittest.cc
src/bin/dhcp6/tests/hooks_unittest.cc
src/bin/dhcp6/tests/host_unittest.cc
src/bin/dhcp6/tests/infrequest_unittest.cc
src/bin/dhcp6/tests/rebind_unittest.cc
src/bin/dhcp6/tests/renew_unittest.cc
src/bin/dhcp6/tests/sarr_unittest.cc
src/lib/dhcp/tests/pkt6_unittest.cc
src/lib/dhcp/tests/pkt_captures.h
src/lib/dhcp/tests/pkt_captures4.cc
src/lib/dhcp/tests/pkt_captures6.cc

index 3b9ef28eef6e02644ce2bb4353d91578d34198fa..2f4f1ce767097ef1a3de7352c5bd39fcf66e4bf7 100644 (file)
@@ -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 {
 
index 8fa1b63a814a21ddfc845d256439925c891590aa..46ff7b5b4da0fbc4ec0914008c2f8c462fcd29bd 100644 (file)
@@ -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_
index a76bd3e46e4517fc47b2fe2f9825fd4b8597a603..63ae2b6c383afa8a1b288feee9fd3559edf9afff 100644 (file)
@@ -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: <b>in</b>
+   - name: @b lease6, type: isc::dhcp::Lease6Ptr, direction: <b>in/out</b>
+
+ - @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.
+
+ - <b>Next step status</b>: 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:
index ef0ea349ef12ccf4aa3b25bf04b2939998428d95..1ac0073e45fc9513bb93758e304dd74778ba1674 100644 (file)
@@ -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
index 239311f8f62b73f6911a3f0777da8fa7fdd0ffef..89023a154a1e155e5d328d8154a9399bfc3aa92d 100644 (file)
@@ -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<Option6IA>(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<isc::dhcp::Option6IA>& container,
     container->addOption(status);
 }
 
-void
+bool
 Dhcpv6Srv::declineLease(const Pkt6Ptr& decline, const Lease6Ptr lease,
                         boost::shared_ptr<Option6IA> 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<int64_t>(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
index 9d2ff2d510e95f848e93bd0e2c458ead7ad9f397..38a091f730c1d4f4c0df26e95db83924e087d0f2 100644 (file)
@@ -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<Option6IA> 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<Option6IA> ia_rsp);
 
     /// @brief A simple utility method that sets the status code
     ///
index ab8cbdfe228f90cbd74afb1f8fea94c0e70eb45b..5e2f7ef5dff3ca9eec6f162c89046978fd0a94f7 100644 (file)
@@ -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 {
 
index 41d39d7ffd19d59fe15fdc39a1c3fbf07bf5180a..d20d11c8f9c9381598f5ff2a53c164aa8cdb2e76 100644 (file)
@@ -18,6 +18,7 @@
 #include <dhcp/tests/iface_mgr_test_config.h>
 #include <dhcp6/json_config_parser.h>
 #include <dhcp6/tests/dhcp6_message_test.h>
+#include <dhcpsrv/lease.h>
 #include <stats/stats_mgr.h>
 
 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<int64_t>(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<Lease6> 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);
 }
index 9ca62822160b9f36ed59fc8e90c67707ac8e52ab..da67b6a2bd8e95e769a99e1a9a333285eadf7d9f 100644 (file)
@@ -30,7 +30,6 @@
 
 using namespace isc::dhcp;
 using namespace isc::dhcp::test;
-using namespace isc::test;
 
 namespace {
 
index c4c075046262cf00187c19f1baa47807ffef813e..afdae26d24ea3d4131f955bfe683d2f502cf0791 100644 (file)
@@ -178,7 +178,7 @@ public:
     /// - not relayed
     ///
     /// @param srv Object representing server under test.
-    Dhcp6Client(boost::shared_ptr<isc::test::NakedDhcpv6Srv>& srv);
+    Dhcp6Client(boost::shared_ptr<isc::dhcp::test::NakedDhcpv6Srv>& 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<isc::test::NakedDhcpv6Srv> getServer() const {
+    boost::shared_ptr<isc::dhcp::test::NakedDhcpv6Srv> 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<isc::test::NakedDhcpv6Srv> srv_;
+    boost::shared_ptr<isc::dhcp::test::NakedDhcpv6Srv> srv_;
 
     bool use_na_;    ///< Enable address assignment.
     bool use_pd_;    ///< Enable prefix delegation.
index c885bc27b47761f2e513f3574fd47d698841f7e0..832fc79f907116370ebe86209a724ad2c51ff7f7 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 20142015  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.
     ///
index 4fa269b0bc6e432d7d31e4a2f70faa1ac1098669..dfa145c7a391551de7bbf045a9d4e9b8c36bb2a7 100644 (file)
@@ -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;
index 9c7c7063ef3070bb1e4099bc2af6d284a4f41638..2f9f2c128db502e1c5affa3fb5278b1d9f19bce5 100644 (file)
@@ -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
index c6fcfad75d0e8f6da4cd5da0ea7e2ba9722daf75..c94efea0ab38df513e526a4705584ae8d924f903 100644 (file)
@@ -39,6 +39,7 @@
 #include <list>
 
 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
index 63885496d516674fbc6530450cb5fbe196010376..ee1a25adb490ac8b4885913cf53e46f3cc478cdd 100644 (file)
@@ -32,7 +32,7 @@
 #include <gtest/gtest.h>
 
 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;
index fc14668ee87418cb086d143c0f4f8d06fc8271db..6bc491eaf53414a63a0d2398792c4281fbe2ece9 100644 (file)
@@ -28,6 +28,7 @@
 #include <hooks/server_hooks.h>
 
 #include <dhcp6/tests/dhcp6_test_utils.h>
+#include <dhcp6/tests/dhcp6_client.h>
 #include <dhcp/tests/pkt_captures.h>
 #include <cc/command_interpreter.h>
 #include <boost/scoped_ptr.hpp>
@@ -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<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, 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<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, 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<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
index e7541b7006ce59b81bfeab1082dbb44e905d77ea..1c90bdc953815745eaf5ac81921d4f8f7d18f87b 100644 (file)
@@ -20,7 +20,6 @@
 using namespace isc;
 using namespace isc::dhcp;
 using namespace isc::dhcp::test;
-using namespace isc::test;
 
 namespace {
 
index 8b15f7fb6e3e8dde94664c04501bf0d442638ceb..87011dc9f324e0f6ef10e3e1c61f78550db66356 100644 (file)
@@ -23,7 +23,6 @@
 using namespace isc;
 using namespace isc::dhcp;
 using namespace isc::dhcp::test;
-using namespace isc::test;
 
 namespace {
 
index faff77a4d65d493166da2061a787624eba9add55..96d7868c2be64fba54e553db0cd5a13ae3992c70 100644 (file)
@@ -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 {
 
index dc2fd537918c1713cafc4947b9dc8357857b0af8..ba08d725d8c0ecab97aaa9557b009ecbda15058a 100644 (file)
@@ -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 {
 
index 71eb3e96d16a0a2298f4fae5e5903f199982af73..884e10a5da43e2d0f503226ae6c914ab8e1d6598 100644 (file)
@@ -25,7 +25,6 @@
 using namespace isc;
 using namespace isc::dhcp;
 using namespace isc::dhcp::test;
-using namespace isc::test;
 
 namespace {
 
index 12e80e10bd2b160d1a85ffdaa7732af3ec84a8a1..59bd4d2b85e6b5916fa01a642390c9bfd94093dd 100644 (file)
@@ -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,
index 8f38971a5650cb5014685538e027617b909cd235..232db6876e44695b7da4a7b1e6d8010483957870 100644 (file)
 // 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 <dhcp/pkt4.h>
 #include <dhcp/pkt6.h>
 
 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
index 3ee87ad766bf8d124eda9abac260ebefeb5787a0..6177f347515e4b11277310d89a356a87f7f3d40f 100644 (file)
@@ -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
index b360fe10c83f297cd2171d4667c421116293721f..12367823eb035b274ead228c89a5488246c6d9eb 100644 (file)
@@ -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