]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#1064] Unpack and set msgtype type in buffer4_received
authorFrancis Dupont <fdupont@isc.org>
Mon, 20 Jan 2020 16:38:34 +0000 (17:38 +0100)
committerTomek Mrugalski <tomasz@isc.org>
Sun, 26 Jan 2020 18:42:44 +0000 (19:42 +0100)
src/hooks/dhcp/bootp/Makefile.am
src/hooks/dhcp/bootp/bootp.dox
src/hooks/dhcp/bootp/bootp_callouts.cc
src/hooks/dhcp/bootp/bootp_messages.cc
src/hooks/dhcp/bootp/bootp_messages.h
src/hooks/dhcp/bootp/bootp_messages.mes
src/hooks/dhcp/bootp/tests/Makefile.am
src/hooks/dhcp/bootp/tests/bootp_unittests.cc

index 6a3be0bb5a5305370144eee5e7855ef36f4b3edc..de796531e446e525d2adfc8ed8d42da33b6a70b5 100644 (file)
@@ -30,6 +30,7 @@ libdhcp_bootp_la_SOURCES  =
 libdhcp_bootp_la_LDFLAGS  = $(AM_LDFLAGS)
 libdhcp_bootp_la_LDFLAGS  += -avoid-version -export-dynamic -module
 libdhcp_bootp_la_LIBADD = libbootp.la
+libdhcp_bootp_la_LIBADD += $(top_builddir)/src/lib/stats/libkea-stats.la
 libdhcp_bootp_la_LIBADD += $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la
 libdhcp_bootp_la_LIBADD += $(top_builddir)/src/lib/hooks/libkea-hooks.la
 libdhcp_bootp_la_LIBADD += $(top_builddir)/src/lib/database/libkea-database.la
index 3d5d1dc828e5e24d7020063fb914281c9f5767ad..c110036bf19e301c3b218052b029d9eb3939dd43 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2019 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2019-2010 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -53,8 +53,8 @@ bootp_callouts.cc. It checks if the necessary parameter is passed and
 decodes the option configurations. @ref unload() free the configuration.
 
 Kea engine checks if the library has functions that match known hook
-point names. This library has two such functions: @ref buffer4_receive
-and @ref pkt4_receive located in bootp_callouts.cc.
+point names. This library has one such function: @ref buffer4_receive
+located in bootp_callouts.cc.
 
 If the receive query has to dhcp-message-type option then it is a BOOTP
 one: the BOOTP client class and a DHCPREQUEST dhcp-message-type option
index 3d2dcb87b7c7eb03cc69b3e201fa73cd3bbc43cc..47026fecc99e3335fe67a9898ed8e267748b61da 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2019 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2019-2020 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the End User License
 // Agreement. See COPYING file in the premium/ directory.
@@ -8,12 +8,14 @@
 #include <bootp_log.h>
 #include <hooks/hooks.h>
 #include <dhcp/pkt4.h>
+#include <stats/stats_mgr.h>
 
 using namespace isc;
 using namespace isc::bootp;
 using namespace isc::dhcp;
 using namespace isc::hooks;
 using namespace isc::log;
+using namespace isc::stats;
 
 // Functions accessed by the hooks framework use C linkage to avoid the name
 // mangling that accompanies use of the C++ compiler as well as to avoid
@@ -23,7 +25,8 @@ extern "C" {
 /// @brief This callout is called at the "buffer4_receive" hook.
 ///
 /// Ignore DHCP and BOOTREPLY messages.
-/// Remaining packets should be BOOTP requests so add the BOOTP client class,
+/// Remaining packets should be BOOTP requests so add the BOOTP client class
+/// and set the message type to DHCPREQUEST.
 ///
 /// @param handle CalloutHandle.
 ///
@@ -34,54 +37,48 @@ int buffer4_receive(CalloutHandle& handle) {
     handle.getArgument("query4", query);
 
     try {
-        // Take a copy and unpack it.
-        Pkt4Ptr copy(new Pkt4(&query->data_[0], query->data_.size()));
-        copy->unpack();
+        // Unpack it (TODO check if it was already unpacked).
+        query->unpack();
 
-        if (copy->getType() != DHCP_NOTYPE) {
-            // DHCP query.
-            return (0);
-        }
-        if (copy->getOp() == BOOTREPLY) {
-            // BOOTP response.
-            return (0);
+        // Not DHCP query nor BOOTP response?
+        if ((query->getType() == DHCP_NOTYPE) &&
+            (query->getOp() == BOOTREQUEST)) {
+
+            query->addClass("BOOTP");
+            query->setType(DHCPREQUEST);
+
+            LOG_DEBUG(bootp_logger, DBGLVL_TRACE_BASIC, BOOTP_BOOTP_QUERY)
+                .arg(query->getLabel());
         }
-        // BOOTP query.
-        query->addClass("BOOTP");
-        LOG_DEBUG(bootp_logger, DBGLVL_TRACE_BASIC, BOOTP_ADDED_CLASS)
-            .arg(query->getLabel());
-    } catch (const std::exception&) {
-        // Got an error. The query shall very likely be dropped later.
-        // Note this covers malformed DHCP packets where the message
-        // type option can't be unpacked, and RFC 951 BOOTP.
-    }
+    } catch (const SkipRemainingOptionsError& ex) {
+        // An option failed to unpack but we are to attempt to process it
+        // anyway.  Log it and let's hope for the best.
+        LOG_DEBUG(bootp_logger, DBGLVL_TRACE_BASIC,
+                  BOOTP_PACKET_OPTIONS_SKIPPED)
+            .arg(ex.what());
+    } catch (const std::exception& ex) {
+        // Failed to parse the packet.
+        LOG_DEBUG(bootp_logger, DBGLVL_TRACE_BASIC,
+                  BOOTP_PACKET_UNPACK_FAILED)
+            .arg(query->getRemoteAddr().toText())
+            .arg(query->getLocalAddr().toText())
+            .arg(query->getIface())
+            .arg(ex.what());
 
-    return (0);
-}
+        // Increase the statistics of parse failures and dropped packets.
+        StatsMgr::instance().addValue("pkt4-parse-failed",
+                                      static_cast<int64_t>(1));
+        StatsMgr::instance().addValue("pkt4-receive-drop",
+                                      static_cast<int64_t>(1));
 
-/// @brief This callout is called at the "pkt4_receive" hook.
-///
-/// If in the BOOTP class add a DHCPREQUEST dhcp-message-type.
-///
-/// @param handle CalloutHandle.
-///
-/// @return 0 upon success, non-zero otherwise.
-int pkt4_receive(CalloutHandle& handle) {
-    // Get the received unpacked message.
-    Pkt4Ptr query;
-    handle.getArgument("query4", query);
+        handle.setStatus(CalloutHandle::NEXT_STEP_DROP);
 
-    try {
-        if (!query->inClass("BOOTP")) {
-            return (0);
-        }
-        query->setType(DHCPREQUEST);
-        LOG_DEBUG(bootp_logger, DBGLVL_TRACE_BASIC, BOOTP_ADDED_MSGTYPE)
-            .arg(query->getLabel());
-    } catch (const std::exception&) {
-        // Got an error (should not happen).
+        return (0);
     }
 
+    // Avoid to unpack it a second time!
+    handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
+
     return (0);
 }
 
index 6724fa7cb2763fccbe6a96ac3b9d886ab6de2ab8..c097ffd0ba274f12657cc14512dec52086190611 100644 (file)
@@ -1,20 +1,22 @@
-// File created from ../../../../src/hooks/dhcp/bootp/bootp_messages.mes on Fri Nov 22 2019 01:05
+// File created from ../../../../src/hooks/dhcp/bootp/bootp_messages.mes on Mon Jan 20 2020 17:15
 
 #include <cstddef>
 #include <log/message_types.h>
 #include <log/message_initializer.h>
 
-extern const isc::log::MessageID BOOTP_ADDED_CLASS = "BOOTP_ADDED_CLASS";
-extern const isc::log::MessageID BOOTP_ADDED_MSGTYPE = "BOOTP_ADDED_MSGTYPE";
+extern const isc::log::MessageID BOOTP_BOOTP_QUERY = "BOOTP_BOOTP_QUERY";
 extern const isc::log::MessageID BOOTP_LOAD = "BOOTP_LOAD";
+extern const isc::log::MessageID BOOTP_PACKET_OPTIONS_SKIPPED = "BOOTP_PACKET_OPTIONS_SKIPPED";
+extern const isc::log::MessageID BOOTP_PACKET_UNPACK_FAILED = "BOOTP_PACKET_UNPACK_FAILED";
 extern const isc::log::MessageID BOOTP_UNLOAD = "BOOTP_UNLOAD";
 
 namespace {
 
 const char* values[] = {
-    "BOOTP_ADDED_CLASS", "added BOOTP class to a BOOTP query: %1",
-    "BOOTP_ADDED_MSGTYPE", "added DHCPREQUEST message type to a BOOTP query: %1",
+    "BOOTP_BOOTP_QUERY", "recognized a BOOTP query: %1",
     "BOOTP_LOAD", "Bootp hooks library has been loaded",
+    "BOOTP_PACKET_OPTIONS_SKIPPED", "an error upacking an option, caused subsequent options to be skipped: %1",
+    "BOOTP_PACKET_UNPACK_FAILED", "failed to parse query from %1 to %2, received over interface %3, reason: %4",
     "BOOTP_UNLOAD", "Bootp hooks library has been unloaded",
     NULL
 };
index 8587dee6c932962c26c36fd7a5983a0f23b43c0e..29bb524a9481b0c04f5802160187174f83a80734 100644 (file)
@@ -1,13 +1,14 @@
-// File created from ../../../../src/hooks/dhcp/bootp/bootp_messages.mes on Fri Nov 22 2019 01:05
+// File created from ../../../../src/hooks/dhcp/bootp/bootp_messages.mes on Mon Jan 20 2020 17:15
 
 #ifndef BOOTP_MESSAGES_H
 #define BOOTP_MESSAGES_H
 
 #include <log/message_types.h>
 
-extern const isc::log::MessageID BOOTP_ADDED_CLASS;
-extern const isc::log::MessageID BOOTP_ADDED_MSGTYPE;
+extern const isc::log::MessageID BOOTP_BOOTP_QUERY;
 extern const isc::log::MessageID BOOTP_LOAD;
+extern const isc::log::MessageID BOOTP_PACKET_OPTIONS_SKIPPED;
+extern const isc::log::MessageID BOOTP_PACKET_UNPACK_FAILED;
 extern const isc::log::MessageID BOOTP_UNLOAD;
 
 #endif // BOOTP_MESSAGES_H
index a78d301ea6685d9e490208d70d4307802cb7eb88..1f6d147bb85f4dae7bae2f10f69e5e1b699bebcc 100644 (file)
@@ -1,17 +1,25 @@
-# Copyright (C) 2019 Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 2019-2020 Internet Systems Consortium, Inc. ("ISC")
 
-% BOOTP_ADDED_CLASS added BOOTP class to a BOOTP query: %1
-This debug message is printed when the BOOTP client class was added to
-a BOOTP query.  The query client and transaction identification are
-displayed.
-
-% BOOTP_ADDED_MSGTYPE added DHCPREQUEST message type to a BOOTP query: %1
-This debug message is printed when the DHCPREQUEST message type was
-added to a BOOTP query.  The query client and transaction
-identification are displayed.
+% BOOTP_BOOTP_QUERY recognized a BOOTP query: %1
+This debug message is printed when the BOOTP query was recognized. The
+BOOTP client class was added and the message type set to DHCPREQUEST.
+The query client and transaction identification are displayed.
 
 % BOOTP_LOAD Bootp hooks library has been loaded
 This info message indicates that the Bootp hooks library has been loaded.
 
+% BOOTP_PACKET_OPTIONS_SKIPPED an error upacking an option, caused subsequent options to be skipped: %1
+A debug message issued when an option failed to unpack correctly, making it
+impossible to unpack the remaining options in the DHCPv4 query. The server
+will still attempt to service the packet. The sole argument provides a
+reason for unpacking error.
+
+% BOOTP_PACKET_UNPACK_FAILED failed to parse query from %1 to %2, received over interface %3, reason: %4
+This debug message is issued when received DHCPv4 query is malformed and
+can't be parsed by the buffer4_receive callout. The query will be
+dropped by the server. The first three arguments specify source IP address,
+destination IP address and the interface. The last argument provides a
+reason for failure.
+
 % BOOTP_UNLOAD Bootp hooks library has been unloaded
 This info message indicates that the Bootp hooks library has been unloaded.
index 56ef9cba99e0f990ab35fc22af313d4bcefd8fbe..1868be78b2ca346e8dcca185420a82f9845ba85f 100644 (file)
@@ -35,6 +35,7 @@ bootp_unittests_LDFLAGS  = $(AM_LDFLAGS) $(CRYPTO_LDFLAGS) $(GTEST_LDFLAGS)
 bootp_unittests_CXXFLAGS = $(AM_CXXFLAGS)
 
 bootp_unittests_LDADD  = $(top_builddir)/src/hooks/dhcp/bootp/libbootp.la
+bootp_unittests_LDADD += $(top_builddir)/src/lib/stats/libkea-stats.la
 bootp_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la
 bootp_unittests_LDADD += $(top_builddir)/src/lib/hooks/libkea-hooks.la
 bootp_unittests_LDADD += $(top_builddir)/src/lib/database/libkea-database.la
index c84bb7259cc7465cf34437431d27f0fe41a1c996..7f5657ef6cbe9e4f0e1101099fb473fcfcd26849 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2019 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2019-2020 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -24,7 +24,6 @@ using namespace isc::util;
 
 extern "C" {
 extern int buffer4_receive(CalloutHandle& handle);
-extern int pkt4_receive(CalloutHandle& handle);
 }
 
 namespace {
@@ -48,7 +47,7 @@ public:
         return(co_manager_);
     }
 
-    /// @brief Tests buffer4_receive and pkt4_receive callout.
+    /// @brief Tests buffer4_receive callout.
     ///
     /// @param pkt The packet to submit.
     /// @param processed True if the packet must be processed, false otherwise.
@@ -56,38 +55,32 @@ public:
         // Get callout handle.
         CalloutHandle handle(getCalloutManager());
 
-        // Fill data so it becomes possible to unpack a copy of it.
+        // Get type.
+        uint8_t type = pkt->getType();
+
+        // Get data so it becomes possible to reset it to unpacked state.
         ASSERT_NO_THROW(pkt->pack());
         const OutputBuffer& buffer = pkt->getBuffer();
-        pkt->data_.resize(buffer.getLength());
-        memmove(&pkt->data_[0], buffer.getData(), pkt->data_.size());
+        pkt.reset(new Pkt4(reinterpret_cast<const uint8_t*>(buffer.getData()),
+                           buffer.getLength()));
 
         // Set query.
         handle.setArgument("query4", pkt);
 
-        // Get type.
-        uint8_t type = pkt->getType();
-
         // Execute buffer4_receive callout.
         int ret;
         ASSERT_NO_THROW(ret = buffer4_receive(handle));
         EXPECT_EQ(0, ret);
 
-        // Verify processing.
-        if (processed) {
-            EXPECT_TRUE(pkt->inClass("BOOTP"));
-        } else {
-            EXPECT_FALSE(pkt->inClass("BOOTP"));
-        }
-
-        // Execute pkt4_receive callout.
-        ASSERT_NO_THROW(ret = pkt4_receive(handle));
-        EXPECT_EQ(0, ret);
+        // Verify status (SKIP means unpacked).
+        EXPECT_EQ(CalloutHandle::NEXT_STEP_SKIP, handle.getStatus());
 
         // Verify processing.
         if (processed) {
+            EXPECT_TRUE(pkt->inClass("BOOTP"));
             EXPECT_EQ(DHCPREQUEST, pkt->getType());
         } else {
+            EXPECT_FALSE(pkt->inClass("BOOTP"));
             EXPECT_EQ(type, pkt->getType());
         }
     }