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.
// 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);
}
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 */
{ "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 =
-// 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
#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>
"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.
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();
-// 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
/// 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:
/// @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.
#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>
// 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;
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));
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();
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);
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);
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);