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.
-// 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
.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,
opt = def->optionFactory(Option::V4, code, buf.cbegin(), buf.cend());
query->addOption(opt);
}
-}
+}
void
Dhcpv4Srv::startD2() {
-// 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
// 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);
// 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);
// 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);
// 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);
// 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);
// 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);
// 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);
// 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);
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.
-// 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
/// 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)
-// 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
;
}
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());
}
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");
-// 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
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));
}
-// 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
/// @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
-// 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>
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
-// 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
/// @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
-// 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 (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