]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[5404] checkpoint: adding 4o6 support
authorFrancis Dupont <fdupont@isc.org>
Sat, 23 Dec 2017 19:31:48 +0000 (20:31 +0100)
committerFrancis Dupont <fdupont@isc.org>
Sat, 23 Dec 2017 19:31:48 +0000 (20:31 +0100)
src/bin/dhcp6/dhcp6_srv.h
src/bin/dhcp6/dhcp6to4_ipc.cc
src/lib/dhcp/dhcp6.h
src/lib/dhcp/std_option_defs.h
src/lib/dhcpsrv/dhcp4o6_ipc.cc
src/lib/dhcpsrv/dhcp4o6_ipc.h
src/lib/dhcpsrv/tests/dhcp4o6_ipc_unittest.cc

index 6b6b3bde186b96d4f6b80ac97566034d41bb2d8d..390ae19d4dc81983ade8b89bf6fbf4069d7235fe 100644 (file)
@@ -754,6 +754,10 @@ protected:
     void setStatusCode(boost::shared_ptr<Option6IA>& container,
                        const OptionPtr& status);
 
+public:
+
+    /// Used for DHCPv4-over-DHCPv6 too.
+
     /// @brief Check if the last relay added a relay-source-port option.
     ///
     /// @param query DHCPv6 message to be checked.
index 7ec9397973e7216ff87bd7ff24f849868532f347..71759732f37970194a0867ff08cd6ee86c42864d 100644 (file)
@@ -89,7 +89,8 @@ void Dhcp6to4Ipc::handler() {
     // getType() always returns the type of internal message.
     uint8_t msg_type = buf[0];
     if ((msg_type == DHCPV6_RELAY_FORW) || (msg_type == DHCPV6_RELAY_REPL)) {
-        pkt->setRemotePort(DHCP6_SERVER_PORT);
+        uint16_t relay_port = Dhcpv6Srv::testRelaySourcePort(pkt);
+        pkt->setRemotePort(relay_port ? relay_port : DHCP6_SERVER_PORT);
     } else {
         pkt->setRemotePort(DHCP6_CLIENT_PORT);
     }
index 78c8c07380e0091e4bda6d2d0e267f552b742a66..7b67badbb64c792dd6b20bfbdfb0be120377db38 100644 (file)
@@ -280,6 +280,7 @@ static const uint32_t ENTERPRISE_ID_ISC = 2495;
    codes for the ISC vendor specific options used in 4o6 */
 static const uint16_t ISC_V6_4O6_INTERFACE = 60000;
 static const uint16_t ISC_V6_4O6_SRC_ADDRESS = 60001;
+static const uint16_t ISC_V6_4O6_SRC_PORT = 60002;
 
 /* Offsets into IA_*'s where Option spaces commence.  */
 static const uint16_t IA_NA_OFFSET = 12; /* IAID, T1, T2, all 4 octets each */
index 47d9c2256a00dedf761aa9adce9b08ca5d16c866..e3db039e58c51eb7e14bea4a713383edc4b1ee85 100644 (file)
@@ -476,7 +476,9 @@ const OptionDefParams ISC_V6_OPTION_DEFINITIONS[] = {
     { "4o6-interface", ISC_V6_4O6_INTERFACE, OPT_STRING_TYPE, false,
         NO_RECORD_DEF, "" },
     { "4o6-source-address", ISC_V6_4O6_SRC_ADDRESS, OPT_IPV6_ADDRESS_TYPE,
-        false, NO_RECORD_DEF, "" }
+        false, NO_RECORD_DEF, "" },
+    { "4o6-source-port", ISC_V6_4O6_SRC_PORT, OPT_UINT16_TYPE, false,
+        NO_RECORD_DEF, "" }
 };
 
 const int ISC_V6_OPTION_DEFINITIONS_SIZE =
index 86dfafc378dfb3eb61c83f6d4da6b4f947ad8f48..031c805956e50029e34936626e43aa6190327067 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015-2017 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
@@ -10,6 +10,7 @@
 #include <dhcp/iface_mgr.h>
 #include <dhcp/option6_addrlst.h>
 #include <dhcp/option_custom.h>
+#include <dhcp/option_int.h>
 #include <dhcp/option_string.h>
 #include <dhcp/option_vendor.h>
 #include <dhcpsrv/dhcp4o6_ipc.h>
@@ -191,14 +192,29 @@ Pkt6Ptr Dhcp4o6IpcBase::receive() {
                   "or has incorrect type)");
     }
 
+    // Get the option holding source port.
+    OptionPtr sport = option_vendor->getOption(ISC_V6_4O6_SRC_PORT);
+    if (!sport || (sport->len() - sport->getHeaderLen() != 2)) {
+        LOG_WARN(dhcpsrv_logger, DHCPSRV_DHCP4O6_RECEIVED_BAD_PACKET)
+            .arg("no source port suboption");
+        isc_throw(Dhcp4o6IpcError,
+                  "malformed packet (source port suboption missing "
+                  "or has incorrect length)");
+    }
+    const OptionBuffer& sport_buf = sport->getData();
+    uint16_t sport_value = static_cast<uint16_t>(sport_buf[0]) << 8;
+    sport_value |= static_cast<uint16_t>(sport_buf[1]);
+
     // Update the packet.
     pkt->setRemoteAddr(srcs->readAddress());
+    pkt->setRemotePort(sport_value);
     pkt->setIface(iface->getName());
     pkt->setIndex(iface->getIndex());
 
     // Remove options that have been added by the IPC sender.
     static_cast<void>(option_vendor->delOption(ISC_V6_4O6_INTERFACE));
     static_cast<void>(option_vendor->delOption(ISC_V6_4O6_SRC_ADDRESS));
+    static_cast<void>(option_vendor->delOption(ISC_V6_4O6_SRC_PORT));
 
     // If there are no more options, the IPC sender has probably created the
     // vendor option, in which case we should remove it here.
@@ -243,6 +259,9 @@ void Dhcp4o6IpcBase::send(const Pkt6Ptr& pkt) {
     option_vendor->addOption(Option6AddrLstPtr(new Option6AddrLst(
                                                        ISC_V6_4O6_SRC_ADDRESS,
                                                        pkt->getRemoteAddr())));
+    option_vendor->addOption(OptionUint16Ptr(new OptionUint16(Option::V6,
+                                                       ISC_V6_4O6_SRC_PORT,
+                                                       pkt->getRemotePort())));
     // Get packet content
     OutputBuffer& buf = pkt->getBuffer();
     buf.clear();
index fd7c4d8c1603b92ce653ad5f341323a91bb53289..d67f2d217620f0a85a93ff3a7719bfb573625158 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015-2017 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
@@ -54,10 +54,10 @@ public:
 /// the original DHCPv4 query message sent by the client. This
 /// information is known by the DHCPv6 server and needs to be conveyed
 /// to the DHCPv4 server. The IPC conveys it in the
-/// @c ISC_V6_4O6_INTERFACE and @c ISC_V6_4O6_SRC_ADDRESS options
-/// within the Vendor Specific Information option, with ISC
-/// enterprise id. These options are added by the IPC sender and removed
-/// by the IPC receiver.
+/// @c ISC_V6_4O6_INTERFACE, @c ISC_V6_4O6_SRC_ADDRESS and @c
+/// ISC_V6_4O6_SRC_PORT options within the Vendor Specific Information
+/// option, with ISC enterprise id. These options are added by the IPC
+/// sender and removed by the IPC receiver.
 class Dhcp4o6IpcBase : public boost::noncopyable {
 public:
 
@@ -105,11 +105,11 @@ public:
 
     /// @brief Send message over IPC.
     ///
-    /// The IPC uses @c ISC_V6_4O6_INTERFACE and @c ISC_V6_4O6_SRC_ADDRESS
-    /// options conveyed within the Vendor Specific Information option, with
-    /// ISC enterprise id, to communicate the client remote address and the
-    /// interface on which the DHCPv4 query was received. These options will
-    /// be removed by the receiver.
+    /// The IPC uses @c ISC_V6_4O6_INTERFACE, @c ISC_V6_4O6_SRC_ADDRESS
+    /// and @c ISC_V6_4O6_SRC_PORT options conveyed within the Vendor
+    /// Specific Information option, with ISC enterprise id, to communicate
+    /// the client remote address and the interface on which the DHCPv4 query
+    /// was received. These options will be removed by the receiver.
     ///
     /// @param pkt Pointer to a DHCPv6 message with interface and remote
     /// address.
index 07ac8bd3261baaa1c84e96d17e1b724457e3a0f4..84b6d10ae2a0345259b235fa3e000b6034f638db 100644 (file)
@@ -12,6 +12,7 @@
 #include <dhcp/option6_addrlst.h>
 #include <dhcp/option_string.h>
 #include <dhcp/option_vendor.h>
+#include <dhcp/option_int.h>
 #include <dhcpsrv/dhcp4o6_ipc.h>
 #include <dhcpsrv/testutils/dhcp4o6_test_ipc.h>
 #include <boost/bind.hpp>
@@ -173,6 +174,10 @@ Dhcp4o6IpcBaseTest::createDHCPv4o6Message(uint16_t msg_type,
     // right address.
     pkt->setRemoteAddr(IOAddress(concatenate("2001:db8:1::", postfix)));
 
+    // The remote port of the sender of the DHCPv6 packet is carried
+    // between the servers in the dedicated option.
+    pkt->setRemotePort(10000 + (postfix % 1000));
+
     // Determine the endpoint type using the message type.
     TestIpc::EndpointType src = (msg_type ==  DHCPV6_DHCPV4_QUERY) ?
         TestIpc::ENDPOINT_TYPE_V6 : TestIpc::ENDPOINT_TYPE_V4;
@@ -286,6 +291,9 @@ Dhcp4o6IpcBaseTest::testSendReceive(uint16_t iterations_num,
         EXPECT_EQ(concatenate("2001:db8:1::", i),
                   pkt_received->getRemoteAddr().toText());
 
+        // Check that the port conveyed is correct.
+        EXPECT_EQ(10000 + (i % 1000), pkt_received->getRemotePort());
+
         // Check that encapsulated DHCPv4 message has been received.
         EXPECT_TRUE(pkt_received->getOption(D6O_DHCPV4_MSG));
 
@@ -320,6 +328,7 @@ Dhcp4o6IpcBaseTest::testReceiveError(const Pkt6Ptr& pkt) {
 
     pkt->setIface("eth0");
     pkt->setRemoteAddr(IOAddress("2001:db8:1::1"));
+    pkt->setRemotePort(TEST_PORT);
     pkt->addOption(createDHCPv4MsgOption(TestIpc::ENDPOINT_TYPE_V6));
 
     OutputBuffer& buf = pkt->getBuffer();
@@ -476,6 +485,10 @@ TEST_F(Dhcp4o6IpcBaseTest, receiveWithoutInterfaceOption) {
         Option6AddrLstPtr(new Option6AddrLst(ISC_V6_4O6_SRC_ADDRESS,
                                              IOAddress("2001:db8:1::1")))
     );
+    option_vendor->addOption(
+        OptionUint16Ptr(new OptionUint16(Option::V6,
+                                         ISC_V6_4O6_SRC_PORT,
+                                         TEST_PORT)));
 
     pkt->addOption(option_vendor);
     testReceiveError(pkt);
@@ -495,6 +508,10 @@ TEST_F(Dhcp4o6IpcBaseTest, receiveWithInvalidInterface) {
         Option6AddrLstPtr(new Option6AddrLst(ISC_V6_4O6_SRC_ADDRESS,
                                              IOAddress("2001:db8:1::1")))
     );
+    option_vendor->addOption(
+        OptionUint16Ptr(new OptionUint16(Option::V6,
+                                         ISC_V6_4O6_SRC_PORT,
+                                         TEST_PORT)));
 
     pkt->addOption(option_vendor);
     testReceiveError(pkt);
@@ -510,6 +527,28 @@ TEST_F(Dhcp4o6IpcBaseTest, receiveWithoutSourceAddressOption) {
     option_vendor->addOption(
         OptionStringPtr(new OptionString(Option::V6, ISC_V6_4O6_INTERFACE,
                                          "eth0")));
+    option_vendor->addOption(
+        OptionUint16Ptr(new OptionUint16(Option::V6,
+                                         ISC_V6_4O6_SRC_PORT,
+                                         TEST_PORT)));
+
+    pkt->addOption(option_vendor);
+    testReceiveError(pkt);
+}
+
+// This test verifies that receiving packet over the IPC fails when the
+// source port option is not present.
+TEST_F(Dhcp4o6IpcBaseTest, receiveWithoutSourcePortOption) {
+    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")));
+    option_vendor->addOption(
+        Option6AddrLstPtr(new Option6AddrLst(ISC_V6_4O6_SRC_ADDRESS,
+                                             IOAddress("2001:db8:1::1")))
+    );
 
     pkt->addOption(option_vendor);
     testReceiveError(pkt);