From ee38d93ecf16eca1bac00a9df1ef54c7f1a404ae Mon Sep 17 00:00:00 2001 From: Francis Dupont Date: Sat, 12 Oct 2019 22:46:39 +0200 Subject: [PATCH] [950-harden-deferred-unpack] Hardened deffered unpacking so it no longer throws --- src/bin/dhcp4/dhcp4_messages.cc | 6 ++++-- src/bin/dhcp4/dhcp4_messages.h | 3 ++- src/bin/dhcp4/dhcp4_messages.mes | 7 ++++++- src/bin/dhcp4/dhcp4_srv.cc | 18 ++++++++++++++++-- src/bin/dhcp4/tests/vendor_opts_unittest.cc | 12 +++++++----- 5 files changed, 35 insertions(+), 11 deletions(-) diff --git a/src/bin/dhcp4/dhcp4_messages.cc b/src/bin/dhcp4/dhcp4_messages.cc index 807b8147da..f3e3a0edba 100644 --- a/src/bin/dhcp4/dhcp4_messages.cc +++ b/src/bin/dhcp4/dhcp4_messages.cc @@ -1,4 +1,4 @@ -// File created from ../../../src/bin/dhcp4/dhcp4_messages.mes on Wed Jul 10 2019 15:10 +// File created from ../../../src/bin/dhcp4/dhcp4_messages.mes on Sat Oct 12 2019 22:27 #include #include @@ -100,6 +100,7 @@ extern const isc::log::MessageID DHCP4_PACKET_NAK_0002 = "DHCP4_PACKET_NAK_0002" extern const isc::log::MessageID DHCP4_PACKET_NAK_0003 = "DHCP4_PACKET_NAK_0003"; extern const isc::log::MessageID DHCP4_PACKET_NAK_0004 = "DHCP4_PACKET_NAK_0004"; extern const isc::log::MessageID DHCP4_PACKET_OPTIONS_SKIPPED = "DHCP4_PACKET_OPTIONS_SKIPPED"; +extern const isc::log::MessageID DHCP4_PACKET_OPTION_UNPACK_FAIL = "DHCP4_PACKET_OPTION_UNPACK_FAIL"; extern const isc::log::MessageID DHCP4_PACKET_PACK = "DHCP4_PACKET_PACK"; extern const isc::log::MessageID DHCP4_PACKET_PACK_FAIL = "DHCP4_PACKET_PACK_FAIL"; extern const isc::log::MessageID DHCP4_PACKET_PROCESS_EXCEPTION = "DHCP4_PACKET_PROCESS_EXCEPTION"; @@ -236,7 +237,8 @@ const char* values[] = { "DHCP4_PACKET_NAK_0002", "%1: invalid address %2 requested by INIT-REBOOT", "DHCP4_PACKET_NAK_0003", "%1: failed to advertise a lease, client sent ciaddr %2, requested-ip-address %3", "DHCP4_PACKET_NAK_0004", "%1: failed to grant a lease, client sent ciaddr %2, requested-ip-address %3", - "DHCP4_PACKET_OPTIONS_SKIPPED", "An error upacking an option, caused subsequent options to be skipped: %1", + "DHCP4_PACKET_OPTIONS_SKIPPED", "An error unpacking an option, caused subsequent options to be skipped: %1", + "DHCP4_PACKET_OPTION_UNPACK_FAIL", "An error unpacking the option %1: %2", "DHCP4_PACKET_PACK", "%1: preparing on-wire format of the packet to be sent", "DHCP4_PACKET_PACK_FAIL", "%1: preparing on-wire-format of the packet to be sent failed %2", "DHCP4_PACKET_PROCESS_EXCEPTION", "exception occurred during packet processing", diff --git a/src/bin/dhcp4/dhcp4_messages.h b/src/bin/dhcp4/dhcp4_messages.h index f58ca25bbe..c62bd16d5a 100644 --- a/src/bin/dhcp4/dhcp4_messages.h +++ b/src/bin/dhcp4/dhcp4_messages.h @@ -1,4 +1,4 @@ -// File created from ../../../src/bin/dhcp4/dhcp4_messages.mes on Wed Jul 10 2019 15:10 +// File created from ../../../src/bin/dhcp4/dhcp4_messages.mes on Sat Oct 12 2019 22:27 #ifndef DHCP4_MESSAGES_H #define DHCP4_MESSAGES_H @@ -101,6 +101,7 @@ extern const isc::log::MessageID DHCP4_PACKET_NAK_0002; extern const isc::log::MessageID DHCP4_PACKET_NAK_0003; extern const isc::log::MessageID DHCP4_PACKET_NAK_0004; extern const isc::log::MessageID DHCP4_PACKET_OPTIONS_SKIPPED; +extern const isc::log::MessageID DHCP4_PACKET_OPTION_UNPACK_FAIL; extern const isc::log::MessageID DHCP4_PACKET_PACK; extern const isc::log::MessageID DHCP4_PACKET_PACK_FAIL; extern const isc::log::MessageID DHCP4_PACKET_PROCESS_EXCEPTION; diff --git a/src/bin/dhcp4/dhcp4_messages.mes b/src/bin/dhcp4/dhcp4_messages.mes index 7a0b1c19f2..888ca4fe17 100644 --- a/src/bin/dhcp4/dhcp4_messages.mes +++ b/src/bin/dhcp4/dhcp4_messages.mes @@ -552,7 +552,12 @@ identification information. The second argument contains the IPv4 address in the ciaddr field. The third argument contains the IPv4 address in the requested-ip-address option (if present). -% DHCP4_PACKET_OPTIONS_SKIPPED An error upacking an option, caused subsequent options to be skipped: %1 +% DHCP4_PACKET_OPTION_UNPACK_FAIL An error unpacking the option %1: %2 +A debug message issued when an option failed to unpack correctly, making it +to be left unpacked in the packet. The first argument is the option code, +the second the error. + +% DHCP4_PACKET_OPTIONS_SKIPPED An error unpacking 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 packet. The server will server will still attempt to service the packet. diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc index 456c6d9d89..db5dffc5c6 100644 --- a/src/bin/dhcp4/dhcp4_srv.cc +++ b/src/bin/dhcp4/dhcp4_srv.cc @@ -3572,14 +3572,28 @@ Dhcpv4Srv::deferredUnpack(Pkt4Ptr& query) OptionPtr opt = query->getOption(code); if (!opt) { // should not happen but do not crash anyway + LOG_DEBUG(bad_packet4_logger, DBG_DHCP4_DETAIL, + DHCP4_PACKET_OPTION_UNPACK_FAIL) + .arg(code) + .arg("can't find the option in the query"); continue; } const OptionBuffer buf = opt->getData(); + try { + // Unpack the option + opt = def->optionFactory(Option::V4, code, buf); + } catch (const std::exception& e) { + // Failed to parse the option. + LOG_DEBUG(bad_packet4_logger, DBG_DHCP4_DETAIL, + DHCP4_PACKET_OPTION_UNPACK_FAIL) + .arg(code) + .arg(e.what()); + continue; + } while (query->delOption(code)) { // continue } - // Unpack the option and add it - opt = def->optionFactory(Option::V4, code, buf.cbegin(), buf.cend()); + // Add the unpacked option. query->addOption(opt); } } diff --git a/src/bin/dhcp4/tests/vendor_opts_unittest.cc b/src/bin/dhcp4/tests/vendor_opts_unittest.cc index 2f94205a71..c13cabe889 100644 --- a/src/bin/dhcp4/tests/vendor_opts_unittest.cc +++ b/src/bin/dhcp4/tests/vendor_opts_unittest.cc @@ -684,7 +684,7 @@ TEST_F(VendorOptsTest, option43FailRaw) { // The vendor-encapsulated-options has an incompatible data // so won't have the expected content. Here the processing // of suboptions tries to unpack the uitn32 foo suboption and - // raises an exception. + // raises an exception which is caught so the option stays unpacked. string config = "{ \"interfaces-config\": {" " \"interfaces\": [ \"*\" ] }, " "\"subnet4\": [ " @@ -742,7 +742,9 @@ TEST_F(VendorOptsTest, option43FailRaw) { query->addOption(prl); srv.classifyPacket(query); - EXPECT_THROW(srv.deferredUnpack(query), InvalidOptionValue); + EXPECT_NO_THROW(srv.deferredUnpack(query)); + ASSERT_TRUE(query->getOption(vopt->getType())); + EXPECT_EQ(vopt, query->getOption(vopt->getType())); } // Verifies raw option 43 can be handled (global) @@ -1321,7 +1323,7 @@ TEST_F(VendorOptsTest, clientOption43FailRaw) { // The vendor-encapsulated-options has an incompatible data // so won't have the expected content. Here the processing // of suboptions tries to unpack the uint32 foo suboption and - // raises an exception. + // raises an exception which is caught. string config = "{ \"interfaces-config\": {" " \"interfaces\": [ \"*\" ] }, " "\"subnet4\": [ " @@ -1346,9 +1348,9 @@ TEST_F(VendorOptsTest, clientOption43FailRaw) { client.addExtraOption(vopt); // Let's check whether the server is not able to process this packet - // and raises an exception so the response is empty. + // and raises an exception which is caught so the response is not empty. EXPECT_NO_THROW(client.doDiscover()); - EXPECT_FALSE(client.getContext().response_); + EXPECT_TRUE(client.getContext().response_); } // Verifies raw option 43 sent by a client can be handled (global) -- 2.47.2