summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcin Siodelski <marcin@isc.org>2015-11-04 06:26:59 +0100
committerMarcin Siodelski <marcin@isc.org>2015-11-04 06:26:59 +0100
commitafad9d6db03c5f53bc21b734398d3bed5f721d9c (patch)
tree3f35a13190cf4f8783f94252ee39d69c3a3b5d43
parent[4106] Added new exception Dhcp4o6IpcError. (diff)
downloadkea-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.cc50
-rw-r--r--src/lib/dhcpsrv/tests/dhcp4o6_ipc_unittest.cc108
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