]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[5551] kea-dhcp4 now attempts to process packets with truncated VIVSO
authorThomas Markwalder <tmark@isc.org>
Tue, 27 Feb 2018 19:46:40 +0000 (14:46 -0500)
committerThomas Markwalder <tmark@isc.org>
Tue, 27 Feb 2018 19:46:40 +0000 (14:46 -0500)
src/lib/dhcp/option.h
    SkipRemainingOptionsError - new error to signal
    that unpacking skipped options
src/lib/dhcp/option_vendor.cc
    OptionVendor::unpack() - modified to throw
    SkipRemainingOptions on truncated length

src/lib/dhcp/option_definition.cc
    OptionDefinition::optionFactory()
    Added catch-rethrow of SkipRemainginOptionsError

src/bin/dhcp4/dhcp4_messages.mes
    Added DHCP4_PACKET_OPTIONS_SKIPPED log message

src/bin/dhcp4/dhcp4_srv.cc
    Dhcpv4Srv::processPacket() - added explicit catch
    of SkipRemainingOptionsError which logs the error
    but allows the processing to continue.

src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
    TEST_F(Dhcpv4SrvTest, truncatedVIVSOOption) -
    new test to verify skip-options logic for truncated
    vendor option

src/lib/dhcp/tests/pkt4_unittest.cc
    TEST_F(Pkt4Test, truncatedVendorLength) - new
    test that verifies Pkt4 unpacking of truncated VIVSO

src/lib/dhcp/tests/pkt_captures4.cc
    Pkt4Ptr PktCaptures::discoverWithValidVIVSO()
    Pkt4Ptr PktCaptures::discoverWithTruncatedVIVSO() -
    new captured discovers

src/bin/dhcp4/dhcp4_messages.mes
src/bin/dhcp4/dhcp4_srv.cc
src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
src/lib/dhcp/option.h
src/lib/dhcp/option_definition.cc
src/lib/dhcp/option_vendor.cc
src/lib/dhcp/option_vendor.h
src/lib/dhcp/tests/pkt4_unittest.cc
src/lib/dhcp/tests/pkt_captures.h
src/lib/dhcp/tests/pkt_captures4.cc

index fef6ef62dc4d988dc509d299e113c864bf6fd009..c7ff62fe030c7c3be929d8814457147959aa8663 100644 (file)
@@ -376,6 +376,11 @@ server is about to open sockets on the specified port.
 A warning message issued when IfaceMgr fails to open and bind a socket. The reason
 for the failure is appended as an argument of the log message.
 
+% DHCP4_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 packet.  The server will
+server will still attempt to service the packet
+
 % DHCP4_PACKET_DROP_0001 failed to parse packet from %1 to %2, received over interface %3, reason: %4
 The DHCPv4 server has received a packet that it is unable to
 interpret. The reason why the packet is invalid is included in the message.
index 03b3873d73af1a62481b030b3e25a212d95b42fa..20b9b480f07b5ccbe229995b2617ce0146700d33 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2011-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2018 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
@@ -964,6 +964,12 @@ Dhcpv4Srv::processPacket(Pkt4Ptr& query, Pkt4Ptr& rsp) {
                 .arg(query->getLocalAddr().toText())
                 .arg(query->getIface());
             query->unpack();
+        } catch (const SkipRemainingOptionsError& e) {
+            // 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(options4_logger, DBG_DHCP4_DETAIL,
+                      DHCP4_PACKET_OPTIONS_SKIPPED)
+                .arg(e.what());
         } catch (const std::exception& e) {
             // Failed to parse the packet.
             LOG_DEBUG(bad_packet4_logger, DBG_DHCP4_DETAIL,
@@ -3107,7 +3113,7 @@ Dhcpv4Srv::deferredUnpack(Pkt4Ptr& query)
         opt = def->optionFactory(Option::V4, code, buf.cbegin(), buf.cend());
         query->addOption(opt);
     }
-}                          
+}
 
 void
 Dhcpv4Srv::startD2() {
index 25b540c1ffe9d60539988c4b8fd35f45c0d68028..d7158c0148586e3c65c2a40b7fe711185c6b13ae 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2011-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2018 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
@@ -2458,7 +2458,7 @@ TEST_F(Dhcpv4SrvTest, option43LastResort) {
 
     // Check if we get response at all
     checkResponse(offer, DHCPOFFER, 1234);
-    
+
     // Processing should add a vendor-class-identifier (code 60)
     OptionPtr opt = offer->getOption(DHO_VENDOR_CLASS_IDENTIFIER);
     EXPECT_TRUE(opt);
@@ -2549,7 +2549,7 @@ TEST_F(Dhcpv4SrvTest, option43BadRaw) {
 
     // Check if we get response at all
     checkResponse(offer, DHCPOFFER, 1234);
-    
+
     // Processing should add a vendor-class-identifier (code 60)
     OptionPtr opt = offer->getOption(DHO_VENDOR_CLASS_IDENTIFIER);
     EXPECT_TRUE(opt);
@@ -2713,7 +2713,7 @@ TEST_F(Dhcpv4SrvTest, option43RawGlobal) {
 
     // Check if we get response at all
     checkResponse(offer, DHCPOFFER, 1234);
-    
+
     // Processing should add a vendor-class-identifier (code 60)
     OptionPtr opt = offer->getOption(DHO_VENDOR_CLASS_IDENTIFIER);
     EXPECT_TRUE(opt);
@@ -2808,7 +2808,7 @@ TEST_F(Dhcpv4SrvTest, option43RawClass) {
 
     // Check if we get response at all
     checkResponse(offer, DHCPOFFER, 1234);
-    
+
     // Processing should add a vendor-class-identifier (code 60)
     OptionPtr opt = offer->getOption(DHO_VENDOR_CLASS_IDENTIFIER);
     EXPECT_TRUE(opt);
@@ -2920,7 +2920,7 @@ TEST_F(Dhcpv4SrvTest, option43Class) {
 
     // Check if we get response at all
     checkResponse(offer, DHCPOFFER, 1234);
-    
+
     // Processing should add a vendor-class-identifier (code 60)
     OptionPtr opt = offer->getOption(DHO_VENDOR_CLASS_IDENTIFIER);
     EXPECT_TRUE(opt);
@@ -3054,7 +3054,7 @@ TEST_F(Dhcpv4SrvTest, option43ClassPriority) {
 
     // Check if we get response at all
     checkResponse(offer, DHCPOFFER, 1234);
-    
+
     // Processing should add a vendor-class-identifier (code 60)
     OptionPtr opt = offer->getOption(DHO_VENDOR_CLASS_IDENTIFIER);
     EXPECT_TRUE(opt);
@@ -3194,7 +3194,7 @@ TEST_F(Dhcpv4SrvTest, option43Classes) {
 
     // Check if we get response at all
     checkResponse(offer, DHCPOFFER, 1234);
-    
+
     // Processing should add a vendor-class-identifier (code 60)
     OptionPtr opt = offer->getOption(DHO_VENDOR_CLASS_IDENTIFIER);
     EXPECT_TRUE(opt);
@@ -3305,7 +3305,7 @@ TEST_F(Dhcpv4SrvTest, privateOption) {
 
     // Check if we get response at all
     checkResponse(offer, DHCPOFFER, 1234);
-    
+
     // Processing should add an option with code 234
     OptionPtr opt = offer->getOption(234);
     EXPECT_TRUE(opt);
@@ -4118,6 +4118,64 @@ TEST_F(Dhcpv4SrvTest, userContext) {
     EXPECT_EQ("{ \"value\": 42 }", pools[0]->getContext()->str());
 }
 
+// Verifies that an a client query with a truncated length in
+// vendor option (125) will still be processed by the server.
+TEST_F(Dhcpv4SrvTest, truncatedVIVSOOption) {
+    IfaceMgrTestConfig test_config(true);
+    IfaceMgr::instance().openSockets4();
+
+    NakedDhcpv4Srv srv(0);
+
+    string config = "{ \"interfaces-config\": {"
+        "    \"interfaces\": [ \"*\" ]"
+        "},"
+        "\"rebind-timer\": 2000, "
+        "\"renew-timer\": 1000, "
+        "\"subnet4\": [ { "
+        "    \"pools\": [ { \"pool\": \"10.206.80.0/25\" } ],"
+        "    \"subnet\": \"10.206.80.0/24\", "
+        "    \"rebind-timer\": 2000, "
+        "    \"renew-timer\": 1000, "
+        "    \"valid-lifetime\": 4000,"
+        "    \"interface\": \"eth0\" "
+        " } ],"
+        "\"valid-lifetime\": 4000 }";
+
+    ConstElementPtr json;
+    ASSERT_NO_THROW(json = parseDHCP4(config));
+    ConstElementPtr status;
+
+    // Configure the server and make sure the config is accepted
+    EXPECT_NO_THROW(status = configureDhcp4Server(srv, json));
+    ASSERT_TRUE(status);
+    comment_ = config::parseAnswer(rcode_, status);
+    ASSERT_EQ(0, rcode_);
+
+    CfgMgr::instance().commit();
+
+    // Create a DISCOVER with a VIVSO option whose length is
+    // too short.
+    Pkt4Ptr dis;
+    ASSERT_NO_THROW(dis = PktCaptures::discoverWithTruncatedVIVSO());
+
+    // Simulate that we have received that traffic
+    srv.fakeReceive(dis);
+
+    // Server will now process to run its normal loop, but instead of calling
+    // IfaceMgr::receive4(), it will read all packets from the list set by
+    // fakeReceive()
+    // In particular, it should call registered buffer4_receive callback.
+    srv.run();
+
+    // Check that the server did send a response
+    ASSERT_EQ(1, srv.fake_sent_.size());
+
+    // Make sure that we received an response and it was an offer
+    Pkt4Ptr offer = srv.fake_sent_.front();
+    ASSERT_TRUE(offer);
+}
+
+
 /// @todo: Implement proper tests for MySQL lease/host database,
 ///        see ticket #4214.
 
index 3d0868c808f85870a9f60680e75e76e98725fb48..6afe4205bd10a5ef546cbbfeb1d8ab8f5b873ec7 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2011-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2018 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
@@ -42,6 +42,13 @@ typedef std::multimap<unsigned int, OptionPtr> OptionCollection;
 /// A pointer to an OptionCollection
 typedef boost::shared_ptr<OptionCollection> OptionCollectionPtr;
 
+/// @brief Exception thrown during option unpacking
+class SkipRemainingOptionsError : public Exception {
+public:
+    SkipRemainingOptionsError (const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) { };
+};
+
 class Option {
 public:
     /// length of the usual DHCPv4 option header (there are exceptions)
index 8f07b971193a331dc225c8e022d62c6e3a86fb17..4f77621a3312559a201371e2ab568c8463fe30f6 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2012-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2018 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
@@ -221,6 +221,9 @@ OptionDefinition::optionFactory(Option::Universe u, uint16_t type,
             ;
         }
         return (OptionPtr(new OptionCustom(*this, u, begin, end)));
+    } catch (const SkipRemainingOptionsError& ex) {
+        // We need to throw this one as is.
+        throw ex;
     } catch (const Exception& ex) {
         isc_throw(InvalidOptionValue, ex.what());
     }
@@ -813,7 +816,7 @@ OptionPtr
 OptionDefinition::factoryFqdnList(Option::Universe u,
                                   OptionBufferConstIter begin,
                                   OptionBufferConstIter end) const {
-    
+
     const std::vector<uint8_t> data(begin, end);
     if (data.empty()) {
         isc_throw(InvalidOptionValue, "FQDN list option has invalid length of 0");
index aa137f7b4c71a6172309bcc56c9f7f6c73a485c2..ff223796027392bcc0687f243f3d9e321a5e5a67 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2018 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,12 @@ void OptionVendor::pack(isc::util::OutputBuffer& buf) const {
 
 void OptionVendor::unpack(OptionBufferConstIter begin,
                           OptionBufferConstIter end) {
+
+    // We throw SkipRemainingOptionsError so callers can
+    // abandon further unpacking, if desired.
     if (distance(begin, end) < sizeof(uint32_t)) {
-        isc_throw(OutOfRange, "Truncated vendor-specific information option"
+        isc_throw(SkipRemainingOptionsError,
+                  "Truncated vendor-specific information option"
                   << ", length=" << distance(begin, end));
     }
 
index f8a55a54a7d256bfc0304d0771fd9dd5c9251a16..c566eae2180479db34a4ae83fe4a450a6b6cc40d 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2018 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
@@ -67,7 +67,8 @@ public:
     /// @param begin iterator to first byte of option data
     /// @param end iterator to end of option data (first byte after option end)
     ///
-    /// @throw isc::OutOfRange if provided buffer is shorter than data size.
+    /// @throw isc::SkipRemainingOptionsBuffer if provided buffer is
+    /// shorter than data size.
     virtual void unpack(OptionBufferConstIter begin, OptionBufferConstIter end);
 
     /// @brief Sets enterprise identifier
index d02c2cb28eed754fa5372ed2913effb13426691a..a20c8aa9390e5df4ac63cd5eb0683301d54c629a 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2011-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2018 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
 #include <dhcp/option_int.h>
 #include <dhcp/option_string.h>
 #include <dhcp/option4_addrlst.h>
+#include <dhcp/option_vendor.h>
 #include <dhcp/pkt4.h>
 #include <exceptions/exceptions.h>
 #include <util/buffer.h>
+#include <util/encode/hex.h>
+#include <pkt_captures.h>
 
 #include <boost/shared_array.hpp>
 #include <boost/shared_ptr.hpp>
@@ -1131,4 +1134,76 @@ TEST_F(Pkt4Test, getType) {
     EXPECT_TRUE(pkt.getName());
 }
 
+// Verifies that when the VIVSO option 125 has length that is too
+// short (i.e. less than sizeof(uint8_t), unpack throws a
+// SkipRemainingOptionsError exception
+TEST_F(Pkt4Test, truncatedVendorLength) {
+    // Raw data for a valid DISCOVER packet. Its option 125 has a valid length
+    // of 133 (x85). Look for 303a7d: next two digits = 85
+    const char* good_discover =
+        "010106012d5d43cb000080000000000000000000000000000ace50017896845ef7af0"
+        "000000000000000000000000000000000000000000000000000000000000000000000"
+        "000000000000000000000000000000000000000000000000000000000000000000000"
+        "000000000000000000000000000000000000000000000000000000000000000000000"
+        "000000000000000000000000000000000000000000000000000000000000000000000"
+        "000000000000000000000000000000000000000000000000000000000000000000000"
+        "000000000000000000000000000000000000000000000000000000000063825363350"
+        "10137070102030407067d3c0a646f63736973332e303a7d850000118b80010102057b"
+        "01010102010303010104010105010106010107010f0801100901030a01010b01180c0"
+        "1010d0201000e0201000f010110040000000211010113010114010015013f16010117"
+        "01011801041901041a01041b01201c01021d01081e01201f011020011021010222010"
+        "1230100240100250101260200ff2701012801d82b7c020345434d030b45434d3a4552"
+        "4f5554455208030020400418333936373739343234343335353037373031303134303"
+        "035050131061e534247365838322d382e362e302e302d47412d30312d3937312d4e4f"
+        "5348070432343030090a534247363738322d41430a144d6f746f726f6c6120436f727"
+        "06f726174696f6e3d0fff845ef7af000300017896845ef7af390205dc521b01048005"
+        "03f802067896845ef7af090b0000118b06010401020300ff";
+
+    // Same DISCOVER as above but with the option 125 length changed to 01.
+    const char* bad_discover =
+        "010106012d5d43cb000080000000000000000000000000000ace50017896845ef7af0"
+        "000000000000000000000000000000000000000000000000000000000000000000000"
+        "000000000000000000000000000000000000000000000000000000000000000000000"
+        "000000000000000000000000000000000000000000000000000000000000000000000"
+        "000000000000000000000000000000000000000000000000000000000000000000000"
+        "000000000000000000000000000000000000000000000000000000000000000000000"
+        "000000000000000000000000000000000000000000000000000000000063825363350"
+        "10137070102030407067d3c0a646f63736973332e303a7d010000118b80010102057b"
+        "01010102010303010104010105010106010107010f0801100901030a01010b01180c0"
+        "1010d0201000e0201000f010110040000000211010113010114010015013f16010117"
+        "01011801041901041a01041b01201c01021d01081e01201f011020011021010222010"
+        "1230100240100250101260200ff2701012801d82b7c020345434d030b45434d3a4552"
+        "4f5554455208030020400418333936373739343234343335353037373031303134303"
+        "035050131061e534247365838322d382e362e302e302d47412d30312d3937312d4e4f"
+        "5348070432343030090a534247363738322d41430a144d6f746f726f6c6120436f727"
+        "06f726174696f6e3d0fff845ef7af000300017896845ef7af390205dc521b01048005"
+        "03f802067896845ef7af090b0000118b06010401020300ff";
+
+    // Build a good discover packet
+    Pkt4Ptr pkt = test::PktCaptures::discoverWithValidVIVSO();
+
+    // Unpacking should not throw
+    ASSERT_NO_THROW(pkt->unpack());
+    ASSERT_EQ(DHCPDISCOVER, pkt->getType());
+
+    // VIVSO option should be there
+    OptionPtr x = pkt->getOption(DHO_VIVSO_SUBOPTIONS);
+    ASSERT_TRUE(x);
+    ASSERT_EQ(DHO_VIVSO_SUBOPTIONS, x->getType());
+    OptionVendorPtr vivso = boost::dynamic_pointer_cast<OptionVendor>(x);
+    ASSERT_TRUE(vivso);
+    EXPECT_EQ(133+2, vivso->len()); // data + opt code + len
+
+    // Build a bad discover packet
+    pkt = test::PktCaptures::discoverWithTruncatedVIVSO();
+
+    // Unpack should throw Skip exception
+    ASSERT_THROW(pkt->unpack(), SkipRemainingOptionsError);
+    ASSERT_EQ(DHCPDISCOVER, pkt->getType());
+
+    // VIVSO option should not be there
+    x = pkt->getOption(DHO_VIVSO_SUBOPTIONS);
+    ASSERT_FALSE(x);
+}
+
 } // end of anonymous namespace
index 5b499a2c6d470b8b1831ab92d521d21133154e43..9b280cd383f74620fdab1b524fe1e42d87914b31 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2018 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
@@ -33,6 +33,20 @@ public:
     /// @return relayed DISCOVER
     static isc::dhcp::Pkt4Ptr captureRelayedDiscover2();
 
+    /// @brief returns captured DISCOVER that contains a valid VIVSO option
+    ///
+    /// See method code for a detailed explanation.
+    ///
+    /// @return relayed DISCOVER
+    static isc::dhcp::Pkt4Ptr discoverWithValidVIVSO();
+
+    /// @brief returns captured DISCOVER that contains a truncated VIVSO option
+    ///
+    /// See method code for a detailed explanation.
+    ///
+    /// @return relayed DISCOVER
+    static isc::dhcp::Pkt4Ptr discoverWithTruncatedVIVSO();
+
     // see pkt_captures6.cc for descriptions
     // The descriptions are too large and too closely related to the
     // code, so it is kept in .cc rather than traditionally in .h
index a7eaa13b3a1a2e218dd509ab6916551ca8ae212d..75596384b71f6fea6d2894c6d73bd62a26bba36b 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2018 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
@@ -178,6 +178,110 @@ Bootstrap Protocol
     return (packetFromCapture(hex_string));
 }
 
+Pkt4Ptr PktCaptures::discoverWithValidVIVSO() {
+/* DISCOVER that contains a valid VIVSO option 125
+User    Datagram    Protocol,   Src Port:   67, Dst Port:   67
+Bootstrap   Protocol    (Discover)
+    Message type:   Boot    Request (1)
+    Hardware    type:   Ethernet    (0x01)
+    Hardware    address length: 6
+    Hops:   1
+    Transaction ID: 0x2d5d43cb
+    Seconds elapsed:    0
+    Bootp   flags:  0x8000, Broadcast   flag    (Broadcast)
+    Client  IP  address:    0.0.0.0
+    Your    (client)    IP  address:    0.0.0.0
+    Next    server  IP  address:    0.0.0.0
+    Relay   agent   IP  address:    10.206.80.1
+    Client  MAC address:    ArrisGro_5e:f7:af   (78:96:84:5e:f7:af)
+    Client  hardware    address padding:    00000000000000000000
+    Server  host    name    not given
+    Boot    file    name    not given
+    Magic   cookie: DHCP
+    Option: (53)    DHCP    Message Type    (Discover)
+    Option: (55)    Parameter   Request List
+    Option: (60)    Vendor  class   identifier
+    Option: (125)   V-I Vendor-specific Information
+    Option: (43)    Vendor-Specific Information (CableLabs)
+    Option: (61)    Client  identifier
+    Option: (57)    Maximum DHCP    Message Size
+    Option: (82)    Agent   Information Option
+    Option: (255)   End
+*/
+    string hex_string =
+        "010106012d5d43cb000080000000000000000000000000000ace50017896845ef7af0"
+        "000000000000000000000000000000000000000000000000000000000000000000000"
+        "000000000000000000000000000000000000000000000000000000000000000000000"
+        "000000000000000000000000000000000000000000000000000000000000000000000"
+        "000000000000000000000000000000000000000000000000000000000000000000000"
+        "000000000000000000000000000000000000000000000000000000000000000000000"
+        "000000000000000000000000000000000000000000000000000000000063825363350"
+        "10137070102030407067d3c0a646f63736973332e303a7d850000118b80010102057b"
+        "01010102010303010104010105010106010107010f0801100901030a01010b01180c0"
+        "1010d0201000e0201000f010110040000000211010113010114010015013f16010117"
+        "01011801041901041a01041b01201c01021d01081e01201f011020011021010222010"
+        "1230100240100250101260200ff2701012801d82b7c020345434d030b45434d3a4552"
+        "4f5554455208030020400418333936373739343234343335353037373031303134303"
+        "035050131061e534247365838322d382e362e302e302d47412d30312d3937312d4e4f"
+        "5348070432343030090a534247363738322d41430a144d6f746f726f6c6120436f727"
+        "06f726174696f6e3d0fff845ef7af000300017896845ef7af390205dc521b01048005"
+        "03f802067896845ef7af090b0000118b06010401020300ff";
+
+    return (packetFromCapture(hex_string));
+}
+
+Pkt4Ptr PktCaptures::discoverWithTruncatedVIVSO() {
+/* DISCOVER that contains VIVSO option 125 with an INVALID length of 01
+User    Datagram    Protocol,   Src Port:   67, Dst Port:   67
+Bootstrap   Protocol    (Discover)
+    Message type:   Boot    Request (1)
+    Hardware    type:   Ethernet    (0x01)
+    Hardware    address length: 6
+    Hops:   1
+    Transaction ID: 0x2d5d43cb
+    Seconds elapsed:    0
+    Bootp   flags:  0x8000, Broadcast   flag    (Broadcast)
+    Client  IP  address:    0.0.0.0
+    Your    (client)    IP  address:    0.0.0.0
+    Next    server  IP  address:    0.0.0.0
+    Relay   agent   IP  address:    10.206.80.1
+    Client  MAC address:    ArrisGro_5e:f7:af   (78:96:84:5e:f7:af)
+    Client  hardware    address padding:    00000000000000000000
+    Server  host    name    not given
+    Boot    file    name    not given
+    Magic   cookie: DHCP
+    Option: (53)    DHCP    Message Type    (Discover)
+    Option: (55)    Parameter   Request List
+    Option: (60)    Vendor  class   identifier
+    Option: (125)   V-I Vendor-specific Information
+    Option: (43)    Vendor-Specific Information (CableLabs)
+    Option: (61)    Client  identifier
+    Option: (57)    Maximum DHCP    Message Size
+    Option: (82)    Agent   Information Option
+    Option: (255)   End
+*/
+    string hex_string =
+        "010106012d5d43cb000080000000000000000000000000000ace50017896845ef7af0"
+        "000000000000000000000000000000000000000000000000000000000000000000000"
+        "000000000000000000000000000000000000000000000000000000000000000000000"
+        "000000000000000000000000000000000000000000000000000000000000000000000"
+        "000000000000000000000000000000000000000000000000000000000000000000000"
+        "000000000000000000000000000000000000000000000000000000000000000000000"
+        "000000000000000000000000000000000000000000000000000000000063825363350"
+        "10137070102030407067d3c0a646f63736973332e303a7d010000118b80010102057b"
+        "01010102010303010104010105010106010107010f0801100901030a01010b01180c0"
+        "1010d0201000e0201000f010110040000000211010113010114010015013f16010117"
+        "01011801041901041a01041b01201c01021d01081e01201f011020011021010222010"
+        "1230100240100250101260200ff2701012801d82b7c020345434d030b45434d3a4552"
+        "4f5554455208030020400418333936373739343234343335353037373031303134303"
+        "035050131061e534247365838322d382e362e302e302d47412d30312d3937312d4e4f"
+        "5348070432343030090a534247363738322d41430a144d6f746f726f6c6120436f727"
+        "06f726174696f6e3d0fff845ef7af000300017896845ef7af390205dc521b01048005"
+        "03f802067896845ef7af090b0000118b06010401020300ff";
+
+    return (packetFromCapture(hex_string));
+}
+
 }; // end of isc::dhcp::test namespace
 }; // end of isc::dhcp namespace
 }; // end of isc namespace