specifies the client and transaction identification information, the
second argument specifies packet type.
+% DHCP6_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.
+
% DHCP6_PACKET_PROCESS_EXCEPTION exception occurred during packet processing
This error message indicates that a non-standard exception was raised
during packet processing that was not caught by other, more specific
.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(options6_logger, DBG_DHCP6_DETAIL,
+ DHCP6_PACKET_OPTIONS_SKIPPED)
+ .arg(e.what());
} catch (const std::exception &e) {
// Failed to parse the packet.
LOG_DEBUG(bad_packet6_logger, DBG_DHCP6_DETAIL,
-// 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
EXPECT_EQ("{ \"type\": \"prefixes\" }", pools[0]->getContext()->str());
}
+// Verifies that the server will still process a packet which fails to
+// parse with a SkipRemainingOptions exception
+TEST_F(Dhcpv6SrvTest, truncatedVIVSO) {
+ NakedDhcpv6Srv srv(0);
+
+ // Let's create a SOLICIT with a VIVSO whose length is too short
+ Pkt6Ptr sol = PktCaptures::captureSolicitWithTruncatedVIVSO();
+
+ // Simulate that we have received that traffic
+ srv.fakeReceive(sol);
+
+ // Server will now process to run its normal loop, but instead of calling
+ // IfaceMgr::receive6(), it will read all packets from the list set by
+ // fakeReceive()
+ srv.run();
+
+ // Make sure we got an Advertise...
+ ASSERT_FALSE(srv.fake_sent_.empty());
+ Pkt6Ptr adv = srv.fake_sent_.front();
+ ASSERT_TRUE(adv);
+}
+
/// @todo: Add more negative tests for processX(), e.g. extend sanityCheck() test
/// to call processX() methods.
-// 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
// a two-byte type code and a two-byte length field.
while (offset < length) {
if (offset + 4 > length) {
- isc_throw(OutOfRange,
+ isc_throw(SkipRemainingOptionsError,
"Vendor option parse failed: truncated header");
}
offset += 2;
if (offset + opt_len > length) {
- isc_throw(OutOfRange, "Vendor option parse failed. Tried to parse "
- << offset + opt_len << " bytes from " << length
- << "-byte long buffer.");
+ isc_throw(SkipRemainingOptionsError,
+ "Vendor option parse failed. Tried to parse "
+ << offset + opt_len << " bytes from " << length
+ << "-byte long buffer.");
}
OptionPtr opt;
if (offset + data_len > buf.size()) {
// The option is truncated.
- isc_throw(OutOfRange, "Attempt to parse truncated vendor option");
+ isc_throw(SkipRemainingOptionsError,
+ "Attempt to parse truncated vendor option");
}
uint8_t offset_end = offset + data_len;
// opt_type must be cast to integer so as it is not
// treated as unsigned char value (a number is
// presented in error message).
- isc_throw(OutOfRange,
+ isc_throw(SkipRemainingOptionsError,
"Attempt to parse truncated vendor option "
<< static_cast<int>(opt_type));
}
uint8_t opt_len = buf[offset++];
if (offset + opt_len > offset_end) {
- isc_throw(OutOfRange, "Option parse failed. Tried to parse "
+ isc_throw(SkipRemainingOptionsError,
+ "Option parse failed. Tried to parse "
<< offset + opt_len << " bytes from " << buf.size()
<< "-byte long buffer.");
}
typedef boost::shared_ptr<OptionCollection> OptionCollectionPtr;
/// @brief Exception thrown during option unpacking
+/// This exception is thrown when an error has occurred, unpacking
+/// an option from a packet and we wish to abandon any any further
+/// unpacking efforts and allow the server to attempt to process
+/// the packet as it stands. In other words, the option that failed
+/// is perhaps optional, and rather than drop the packet as unusable
+/// we wish to attempt to proces it.
class SkipRemainingOptionsError : public Exception {
public:
SkipRemainingOptionsError (const char* file, size_t line, const char* what) :
/// @param begin iterator to first byte of option data
/// @param end iterator to end of option data (first byte after option end)
///
- /// @throw isc::SkipRemainingOptionsBuffer if provided buffer is
- /// shorter than data size.
+ /// @throw isc::SkipRemainingOptionsBuffer if an error is encountered
+ /// unpacking the option. This exception is thrown to indicate to the
+ /// caller that a: remaining options cannot be parsed and b: the packet
+ /// should be considered for processing anyway.
virtual void unpack(OptionBufferConstIter begin, OptionBufferConstIter end);
/// @brief Sets enterprise identifier
baddatalen.resize(orig.size() - 5);
baddatalen[full_len_index] = 10;
Pkt4Ptr bad_data_len_pkt(new Pkt4(&baddatalen[0], baddatalen.size()));
- EXPECT_THROW(bad_data_len_pkt->unpack(), InvalidOptionValue);
+ EXPECT_THROW(bad_data_len_pkt->unpack(), SkipRemainingOptionsError);
// A suboption must have a length byte
vector<uint8_t> nolength = orig;
nolength[full_len_index] = 11;
nolength[data_len_index] = 6;
Pkt4Ptr no_length_pkt(new Pkt4(&nolength[0], nolength.size()));
- EXPECT_THROW(no_length_pkt->unpack(), InvalidOptionValue);
+ EXPECT_THROW(no_length_pkt->unpack(), SkipRemainingOptionsError);
// Truncated data is not accepted either
vector<uint8_t> shorty = orig;
shorty[full_len_index] = 14;
shorty[data_len_index] = 9;
Pkt4Ptr too_short_pkt(new Pkt4(&shorty[0], shorty.size()));
- EXPECT_THROW(too_short_pkt->unpack(), InvalidOptionValue);
+ EXPECT_THROW(too_short_pkt->unpack(), SkipRemainingOptionsError);
}
// This test verifies methods that are used for manipulating meta fields
// 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();
-// 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
shorth.resize(orig.size() - 4);
shorth[len_index] = 12;
Pkt6Ptr too_short_header_pkt(new Pkt6(&shorth[0], shorth.size()));
- EXPECT_THROW(too_short_header_pkt->unpack(), OutOfRange);
+ EXPECT_THROW(too_short_header_pkt->unpack(), SkipRemainingOptionsError);
// Truncated option data is not accepted
vector<uint8_t> shorto = orig;
shorto.resize(orig.size() - 2);
shorto[len_index] = 16;
Pkt6Ptr too_short_option_pkt(new Pkt6(&shorto[0], shorto.size()));
- EXPECT_THROW(too_short_option_pkt->unpack(), OutOfRange);
+ EXPECT_THROW(too_short_option_pkt->unpack(), SkipRemainingOptionsError);
}
// This test verifies that options can be added (addOption()), retrieved
EXPECT_EQ("duid=[no info], tid=0x2312", pkt.getLabel());
}
+// Verifies that when the VIVSO, 17, has length that is too
+// short (i.e. less than sizeof(uint8_t), unpack throws a
+// SkipRemainingOptionsError exception
+TEST_F(Pkt6Test, truncatedVendorLength) {
+
+ // Build a good discover packet
+ Pkt6Ptr pkt = test::PktCaptures::captureSolicitWithVIVSO();
+
+ // Unpacking should not throw
+ ASSERT_NO_THROW(pkt->unpack());
+ ASSERT_EQ(DHCPV6_SOLICIT, pkt->getType());
+
+ // VIVSO option should be there
+ OptionPtr x = pkt->getOption(D6O_VENDOR_OPTS);
+ ASSERT_TRUE(x);
+ ASSERT_EQ(D6O_VENDOR_OPTS, x->getType());
+ OptionVendorPtr vivso = boost::dynamic_pointer_cast<OptionVendor>(x);
+ ASSERT_TRUE(vivso);
+ EXPECT_EQ(8, vivso->len()); // data + opt code + len
+
+ // Build a bad discover packet
+ pkt = test::PktCaptures::captureSolicitWithTruncatedVIVSO();
+
+ // Unpack should throw Skip exception
+ ASSERT_THROW(pkt->unpack(), SkipRemainingOptionsError);
+ ASSERT_EQ(DHCPV6_SOLICIT, pkt->getType());
+
+ // VIVSO option should not be there
+ x = pkt->getOption(D6O_VENDOR_OPTS);
+ ASSERT_FALSE(x);
+}
+
}
// 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
+// 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
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef PKT_CAPTURES_H
static isc::dhcp::Pkt6Ptr captureeRouterRelayedSolicit();
static isc::dhcp::Pkt6Ptr captureCableLabsShortVendorClass();
static isc::dhcp::Pkt6Ptr captureRelayed2xRSOO();
+ static isc::dhcp::Pkt6Ptr captureSolicitWithVIVSO();
+ static isc::dhcp::Pkt6Ptr captureSolicitWithTruncatedVIVSO();
protected:
/// @brief Auxiliary method that sets Pkt6 fields
-// 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
return (pkt);
}
+isc::dhcp::Pkt6Ptr PktCaptures::captureSolicitWithVIVSO() {
+
+ // Message type: Solicit (1)
+ // Transaction ID: 0xba048e
+ // Client Identifier
+ // Option: Client Identifier (1)
+ // Length: 10
+ // Value: 0003000108002725d3f4
+ // DUID: 0003000108002725d3f4
+ // DUID Type: link-layer address (3)
+ // Hardware type: Ethernet (1)
+ // Link-layer address: 08:00:27:25:d3:f4
+ // Identity Association for Non-temporary Address
+ // Option: Identity Association for Non-temporary Address (3)
+ // Length: 40
+ // Value: 00aabbcc0000000000000000000500180000000000000000...
+ // IAID: 00aabbcc
+ // T1: 0
+ // T2: 0
+ // IA Address
+ // Option: IA Address (5)
+ // Length: 24
+ // Value: 000000000000000000000000000000000000000000000000
+ // IPv6 address: ::
+ // Preferred lifetime: 0
+ // Valid lifetime:
+ // Option Request
+ // Option: Option Request (6)
+ // Length: 6
+ // Value: 00d100d2000c
+ // Vendor-specific Information
+ // Option: Vendor-specific Information (17)
+ // Length: 4
+ // Value: 00001e61
+ // Enterprise ID: E-DYNAMICS.ORG (7777)
+ string hex_string =
+ "01ba048e0001000a0003000108002725d3f40003002800aabbcc"
+ "00000000000000000005001800000000000000000000000000000"
+ "00000000000000000000006000600d100d2000c0011000400001e61";
+
+ std::vector<uint8_t> bin;
+
+ // Decode the hex string and store it in bin (which happens
+ // to be OptionBuffer format)
+ isc::util::encode::decodeHex(hex_string, bin);
+
+ Pkt6Ptr pkt(new Pkt6(&bin[0], bin.size()));
+ pkt->setRemotePort(547);
+ pkt->setRemoteAddr(IOAddress("fe80::1234"));
+ pkt->setLocalPort(547);
+ pkt->setLocalAddr(IOAddress("ff05::1:3"));
+ pkt->setIndex(2);
+ pkt->setIface("eth0");
+ return (pkt);
+}
+
+isc::dhcp::Pkt6Ptr PktCaptures::captureSolicitWithTruncatedVIVSO() {
+
+ // Message type: Solicit (1)
+ // Transaction ID: 0xba048e
+ // Client Identifier
+ // Option: Client Identifier (1)
+ // Length: 10
+ // Value: 0003000108002725d3f4
+ // DUID: 0003000108002725d3f4
+ // DUID Type: link-layer address (3)
+ // Hardware type: Ethernet (1)
+ // Link-layer address: 08:00:27:25:d3:f4
+ // Identity Association for Non-temporary Address
+ // Option: Identity Association for Non-temporary Address (3)
+ // Length: 40
+ // Value: 00aabbcc0000000000000000000500180000000000000000...
+ // IAID: 00aabbcc
+ // T1: 0
+ // T2: 0
+ // IA Address
+ // Option: IA Address (5)
+ // Length: 24
+ // Value: 000000000000000000000000000000000000000000000000
+ // IPv6 address: ::
+ // Preferred lifetime: 0
+ // Valid lifetime:
+ // Option Request
+ // Option: Option Request (6)
+ // Length: 6
+ // Value: 00d100d2000c
+ // Vendor-specific Information
+ // Option: Vendor-specific Information (17)
+ // Length: 1 <-------- length too short!
+ // Value: 00001e61
+ // Enterprise ID: E-DYNAMICS.ORG (7777)
+ string hex_string =
+ "01ba048e0001000a0003000108002725d3f40003002800aabbcc"
+ "00000000000000000005001800000000000000000000000000000"
+ "00000000000000000000006000600d100d2000c0011000100001e61";
+
+ std::vector<uint8_t> bin;
+
+ // Decode the hex string and store it in bin (which happens
+ // to be OptionBuffer format)
+ isc::util::encode::decodeHex(hex_string, bin);
+
+ Pkt6Ptr pkt(new Pkt6(&bin[0], bin.size()));
+ pkt->setRemotePort(547);
+ pkt->setRemoteAddr(IOAddress("fe80::1234"));
+ pkt->setLocalPort(547);
+ pkt->setLocalAddr(IOAddress("ff05::1:3"));
+ pkt->setIndex(2);
+ pkt->setIface("eth0");
+ return (pkt);
+}
+
}; // end of isc::dhcp::test namespace
}; // end of isc::dhcp namespace
}; // end of isc namespace