diff options
author | Marcin Siodelski <marcin@isc.org> | 2015-11-04 06:26:59 +0100 |
---|---|---|
committer | Marcin Siodelski <marcin@isc.org> | 2015-11-04 06:26:59 +0100 |
commit | afad9d6db03c5f53bc21b734398d3bed5f721d9c (patch) | |
tree | 3f35a13190cf4f8783f94252ee39d69c3a3b5d43 | |
parent | [4106] Added new exception Dhcp4o6IpcError. (diff) | |
download | kea-afad9d6db03c5f53bc21b734398d3bed5f721d9c.tar.xz kea-afad9d6db03c5f53bc21b734398d3bed5f721d9c.zip |
[4106] Throw exception of the packet sent over IPC is invalid.
-rw-r--r-- | src/lib/dhcpsrv/dhcp4o6_ipc.cc | 50 | ||||
-rw-r--r-- | src/lib/dhcpsrv/tests/dhcp4o6_ipc_unittest.cc | 108 |
2 files changed, 146 insertions, 12 deletions
diff --git a/src/lib/dhcpsrv/dhcp4o6_ipc.cc b/src/lib/dhcpsrv/dhcp4o6_ipc.cc index 5664756a0b..e16955e2d1 100644 --- a/src/lib/dhcpsrv/dhcp4o6_ipc.cc +++ b/src/lib/dhcpsrv/dhcp4o6_ipc.cc @@ -139,22 +139,48 @@ Pkt6Ptr Dhcp4o6IpcBase::receive() { OptionVendorPtr vendor = boost::dynamic_pointer_cast<OptionVendor>(pkt->getOption(D6O_VENDOR_OPTS)); - if (!vendor || vendor->getVendorId() != ENTERPRISE_ID_ISC) { - return (Pkt6Ptr()); + + // Vendor option must exist. + if (!vendor) { + isc_throw(Dhcp4o6IpcError, "option " << D6O_VENDOR_OPTS + << " not present in the DHCP4o6 message sent between the " + " servers"); + } + + // The vendor option must require appropriate enterprise-id. + if (vendor->getVendorId() != ENTERPRISE_ID_ISC) { + isc_throw(Dhcp4o6IpcError, "option " << D6O_VENDOR_OPTS + << " in the DHCP4o6 message contains invalid enterprise-id '" + << vendor->getVendorId() << "'. Expected enterprise-id '" + << ENTERPRISE_ID_ISC << "'"); } - OptionStringPtr ifname = - boost::dynamic_pointer_cast<OptionString>(vendor->getOption(ISC_V6_4O6_INTERFACE)); + + // The option carrying interface name is required. + OptionStringPtr ifname = boost::dynamic_pointer_cast< + OptionString>(vendor->getOption(ISC_V6_4O6_INTERFACE)); if (!ifname) { - return (Pkt6Ptr()); + isc_throw(Dhcp4o6IpcError, "option " << D6O_VENDOR_OPTS + << " doesn't contain the " << ISC_V6_4O6_INTERFACE + << " option required in the DHCP4o6 message sent" + " between Kea servers"); } + + // Check if this interface is present in the system. IfacePtr iface = IfaceMgr::instance().getIface(ifname->getValue()); if (!iface) { - return (Pkt6Ptr()); + isc_throw(Dhcp4o6IpcError, "option " << ISC_V6_4O6_INTERFACE + << " sent in the DHCP4o6 message contains non-existing" + " interface name '" << ifname->getValue() << "'"); } + + // Get the option holding source IPv6 address. OptionCustomPtr srcs = boost::dynamic_pointer_cast<OptionCustom>(vendor->getOption(ISC_V6_4O6_SRC_ADDRESS)); if (!srcs) { - return (Pkt6Ptr()); + isc_throw(Dhcp4o6IpcError, "option " << D6O_VENDOR_OPTS + << " doesn't contain the " << ISC_V6_4O6_SRC_ADDRESS + << " option required in the DHCP4o6 message sent" + " between Kea servers"); } // Update the packet and return it @@ -180,11 +206,11 @@ void Dhcp4o6IpcBase::send(const Pkt6Ptr& pkt) { OptionVendorPtr vendor(new OptionVendor(Option::V6, ENTERPRISE_ID_ISC)); // Push interface name and source address in it - vendor->addOption(OptionPtr(new OptionString(Option::V6, - ISC_V6_4O6_INTERFACE, - pkt->getIface()))); - vendor->addOption(OptionPtr(new Option6AddrLst(ISC_V6_4O6_SRC_ADDRESS, - pkt->getRemoteAddr()))); + vendor->addOption(OptionStringPtr(new OptionString(Option::V6, + ISC_V6_4O6_INTERFACE, + pkt->getIface()))); + vendor->addOption(Option6AddrLstPtr(new Option6AddrLst(ISC_V6_4O6_SRC_ADDRESS, + pkt->getRemoteAddr()))); pkt->addOption(vendor); // Get packet content diff --git a/src/lib/dhcpsrv/tests/dhcp4o6_ipc_unittest.cc b/src/lib/dhcpsrv/tests/dhcp4o6_ipc_unittest.cc index cdd6112cfd..8cd389fb1d 100644 --- a/src/lib/dhcpsrv/tests/dhcp4o6_ipc_unittest.cc +++ b/src/lib/dhcpsrv/tests/dhcp4o6_ipc_unittest.cc @@ -17,6 +17,9 @@ #include <dhcp/option_vendor.h> #include <dhcp/pkt6.h> #include <dhcp/tests/iface_mgr_test_config.h> +#include <dhcp/option6_addrlst.h> +#include <dhcp/option_string.h> +#include <dhcp/option_vendor.h> #include <dhcpsrv/dhcp4o6_ipc.h> #include <boost/bind.hpp> #include <gtest/gtest.h> @@ -164,6 +167,11 @@ protected: void testSendReceive(const uint16_t iterations_num, const int src, const int dest); + /// @brief Tests that error is reported when invalid message is received. + /// + /// @param pkt Pointer to the invalid message. + void testReceiveError(const Pkt6Ptr& pkt); + private: /// @brief Holds the fake configuration of the interfaces. @@ -269,6 +277,32 @@ Dhcp4o6IpcBaseTest::testSendReceive(const uint16_t iterations_num, } } +void +Dhcp4o6IpcBaseTest::testReceiveError(const Pkt6Ptr& pkt) { + TestIpc ipc_src(TEST_PORT, ENDPOINT_TYPE_V6); + TestIpc ipc_dest(TEST_PORT, ENDPOINT_TYPE_V4); + + // Open the IPC on both ends. + ASSERT_NO_THROW(ipc_src.open()); + ASSERT_NO_THROW(ipc_dest.open()); + + pkt->setIface("eth0"); + pkt->setRemoteAddr(IOAddress("2001:db8:1::1")); + pkt->addOption(createDHCPv4MsgOption(ENDPOINT_TYPE_V6)); + + OutputBuffer& buf = pkt->getBuffer(); + buf.clear(); + ASSERT_NO_THROW(pkt->pack()); + + ASSERT_NE(-1, ::send(ipc_src.getSocketFd(), buf.getData(), + buf.getLength(), 0)); + + // Call receive with a timeout. The data should appear on the socket + // within this time. + ASSERT_THROW(IfaceMgr::instance().receive6(1, 0), Dhcp4o6IpcError); +} + + // This test verifies that the IPC can transmit messages between the // DHCPv6 and DHCPv4 server. TEST_F(Dhcp4o6IpcBaseTest, send4To6) { @@ -339,4 +373,78 @@ TEST_F(Dhcp4o6IpcBaseTest, openError) { } +// This test verifies that receiving packet over the IPC fails when there +// is no vendor option present. +TEST_F(Dhcp4o6IpcBaseTest, receiveWithoutVendorOption) { + Pkt6Ptr pkt(new Pkt6(DHCPV6_DHCPV4_QUERY, 0)); + testReceiveError(pkt); +} + +// This test verifies that receving packet over the IPC fails when the +// enterprise ID carried in the vendor option is invalid. +TEST_F(Dhcp4o6IpcBaseTest, receiveInvalidEnterpriseId) { + Pkt6Ptr pkt(new Pkt6(DHCPV6_DHCPV4_QUERY, 0)); + OptionVendorPtr option_vendor(new OptionVendor(Option::V6, 1)); + option_vendor->addOption( + OptionStringPtr(new OptionString(Option::V6, ISC_V6_4O6_INTERFACE, + "eth0"))); + option_vendor->addOption( + Option6AddrLstPtr(new Option6AddrLst(ISC_V6_4O6_SRC_ADDRESS, + IOAddress("2001:db8:1::1"))) + ); + + pkt->addOption(option_vendor); + testReceiveError(pkt); +} + +// This test verifies that receiving pakcet over the IPC fails when the +// interface option is not present. +TEST_F(Dhcp4o6IpcBaseTest, receiveWithoutInterfaceOption) { + Pkt6Ptr pkt(new Pkt6(DHCPV6_DHCPV4_QUERY, 0)); + OptionVendorPtr option_vendor(new OptionVendor(Option::V6, + ENTERPRISE_ID_ISC)); + option_vendor->addOption( + Option6AddrLstPtr(new Option6AddrLst(ISC_V6_4O6_SRC_ADDRESS, + IOAddress("2001:db8:1::1"))) + ); + + pkt->addOption(option_vendor); + testReceiveError(pkt); +} + +// This test verifies that receiving packet over the IPC fails when the +// interface which name is carried in the option is not present in the +// system. +TEST_F(Dhcp4o6IpcBaseTest, receiveWithInvalidInterface) { + Pkt6Ptr pkt(new Pkt6(DHCPV6_DHCPV4_QUERY, 0)); + OptionVendorPtr option_vendor(new OptionVendor(Option::V6, + ENTERPRISE_ID_ISC)); + option_vendor->addOption( + OptionStringPtr(new OptionString(Option::V6, ISC_V6_4O6_INTERFACE, + "ethX"))); + option_vendor->addOption( + Option6AddrLstPtr(new Option6AddrLst(ISC_V6_4O6_SRC_ADDRESS, + IOAddress("2001:db8:1::1"))) + ); + + pkt->addOption(option_vendor); + testReceiveError(pkt); +} + + +// This test verifies that receving packet over the IPC fails when the +// source address option is not present. +TEST_F(Dhcp4o6IpcBaseTest, receiveWithoutSourceAddressOption) { + Pkt6Ptr pkt(new Pkt6(DHCPV6_DHCPV4_QUERY, 0)); + OptionVendorPtr option_vendor(new OptionVendor(Option::V6, + ENTERPRISE_ID_ISC)); + option_vendor->addOption( + OptionStringPtr(new OptionString(Option::V6, ISC_V6_4O6_INTERFACE, + "eth0"))); + + pkt->addOption(option_vendor); + testReceiveError(pkt); +} + + } // end of anonymous namespace |