mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-30 13:37:55 +00:00
[master] Finishing merge of trac5404 (port relay)
This commit is contained in:
commit
2a6049947a
@ -1,3 +1,11 @@
|
||||
1382. [func] fdupont
|
||||
Added support for generalized UDP Source Port for DHCP Relay
|
||||
(RFC 8357) for DHCPv4, DHCPv6 and DHCPv4-over-DHCPv6. Note
|
||||
this required changes to the inter-server protocol used by
|
||||
our 4o6 implementation, and is therefore not backwardly
|
||||
compatible.
|
||||
(Trac #5404, git xxx)
|
||||
|
||||
1381. [bug] marcin
|
||||
Corrected a bug in the libkea-asiolink library which caused
|
||||
the DHCP servers to crash while processing commands over
|
||||
|
@ -2996,7 +2996,8 @@ It is merely echoed by the server
|
||||
<para>DHCPv4-over-DHCPv6 support is experimental and the
|
||||
details of the inter-process communication can change: both
|
||||
the DHCPv4 and DHCPv6 sides should be running the same version
|
||||
of Kea.</para>
|
||||
of Kea. For instance the support of port relay (RFC 8357) introduced
|
||||
such incompatible change.</para>
|
||||
</note>
|
||||
<para>
|
||||
The <command>dhcp4o6-port</command> global parameter specifies
|
||||
|
@ -2718,6 +2718,8 @@ should include options from the isc option space:
|
||||
DHCPv4-over-DHCPv6 support is experimental and the details of
|
||||
the inter-process communication can change: both the
|
||||
DHCPv4 and DHCPv6 sides should be running the same version of Kea.
|
||||
For instance the support of port relay (RFC 8357) introduced such
|
||||
such incompatible change.
|
||||
</note>
|
||||
<para>
|
||||
There is only one specific parameter for the DHCPv6 side:
|
||||
|
@ -207,11 +207,11 @@ A malformed DHCPv4o6 packet was received.
|
||||
This debug message is printed when the server is receiving a DHCPv4o6
|
||||
from the DHCPv4 server over inter-process communication.
|
||||
|
||||
% DHCP4_DHCP4O6_PACKET_SEND %1: trying to send packet %2 (type %3) to %4 on interface %5 encapsulating %6: %7 (type %8)
|
||||
% DHCP4_DHCP4O6_PACKET_SEND %1: trying to send packet %2 (type %3) to %4 port %5 on interface %6 encapsulating %7: %8 (type %9)
|
||||
The arguments specify the client identification information (HW address
|
||||
and client identifier), DHCPv6 message name and type, source IPv6
|
||||
address and interface name, DHCPv4 client identification, message
|
||||
name and type.
|
||||
address and port, and interface name, DHCPv4 client identification,
|
||||
message name and type.
|
||||
|
||||
% DHCP4_DHCP4O6_PACKET_SEND_FAIL %1: failed to send DHCPv4o6 packet: %2
|
||||
This error is output if the IPv4 DHCP server fails to send an
|
||||
@ -755,3 +755,10 @@ will drop its message if the received message was DHCPDISCOVER,
|
||||
and will send DHCPNAK if the received message was DHCPREQUEST.
|
||||
The argument includes the client and the transaction identification
|
||||
information.
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
|
||||
% DHCP6_DHCP4O6_PACKET_RECEIVED received DHCPv4o6 packet from DHCPv6 server (type %1) for %2 port %3 on interface %4
|
||||
This debug message is printed when the server is receiving a DHCPv4o6
|
||||
from the DHCPv6 server over inter-process communication.
|
||||
>>>>>>> trac5404
|
||||
|
@ -211,10 +211,11 @@ Dhcpv4Exchange::initResponse4o6() {
|
||||
if (!query6->relay_info_.empty()) {
|
||||
resp6->copyRelayInfo(query6);
|
||||
}
|
||||
// Copy interface and remote address
|
||||
// Copy interface, and remote address and port
|
||||
resp6->setIface(query6->getIface());
|
||||
resp6->setIndex(query6->getIndex());
|
||||
resp6->setRemoteAddr(query6->getRemoteAddr());
|
||||
resp6->setRemotePort(query6->getRemotePort());
|
||||
resp_.reset(new Pkt4o6(resp_, resp6));
|
||||
}
|
||||
|
||||
@ -2206,6 +2207,19 @@ Dhcpv4Srv::assignLease(Dhcpv4Exchange& ex) {
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t
|
||||
Dhcpv4Srv::checkRelayPort(const Dhcpv4Exchange& ex) {
|
||||
|
||||
// Look for a relay-port RAI sub-option in the query.
|
||||
const Pkt4Ptr& query = ex.getQuery();
|
||||
const OptionPtr& rai = query->getOption(DHO_DHCP_AGENT_OPTIONS);
|
||||
if (rai && rai->getOption(RAI_OPTION_RELAY_PORT)) {
|
||||
// Got the sub-option so use the remote port set by the relay.
|
||||
return (query->getRemotePort());
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
Dhcpv4Srv::adjustIfaceData(Dhcpv4Exchange& ex) {
|
||||
adjustRemoteAddr(ex);
|
||||
@ -2232,7 +2246,9 @@ Dhcpv4Srv::adjustIfaceData(Dhcpv4Exchange& ex) {
|
||||
response->setRemotePort(DHCP4_CLIENT_PORT);
|
||||
|
||||
} else {
|
||||
response->setRemotePort(DHCP4_SERVER_PORT);
|
||||
// RFC 8357 section 5.1
|
||||
uint16_t relay_port = checkRelayPort(ex);
|
||||
response->setRemotePort(relay_port ? relay_port : DHCP4_SERVER_PORT);
|
||||
}
|
||||
|
||||
CfgIfacePtr cfg_iface = CfgMgr::instance().getCurrentCfg()->getCfgIface();
|
||||
|
@ -719,6 +719,12 @@ protected:
|
||||
/// server's response.
|
||||
static void appendServerID(Dhcpv4Exchange& ex);
|
||||
|
||||
/// @brief Check if the relay port RAI sub-option was set in the query.
|
||||
///
|
||||
/// @param ex The exchange holding the client's message
|
||||
/// @return the port to use to join the relay or 0 for the default
|
||||
static uint16_t checkRelayPort(const Dhcpv4Exchange& ex);
|
||||
|
||||
/// @brief Set IP/UDP and interface parameters for the DHCPv4 response.
|
||||
///
|
||||
/// This method sets the following parameters for the DHCPv4 message being
|
||||
|
@ -66,6 +66,7 @@ void Dhcp4to6Ipc::handler() {
|
||||
LOG_DEBUG(packet4_logger, DBG_DHCP4_BASIC, DHCP4_DHCP4O6_PACKET_RECEIVED)
|
||||
.arg(static_cast<int>(pkt->getType()))
|
||||
.arg(pkt->getRemoteAddr().toText())
|
||||
.arg(pkt->getRemotePort())
|
||||
.arg(pkt->getIface());
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
@ -155,6 +156,7 @@ void Dhcp4to6Ipc::handler() {
|
||||
.arg(rsp6->getName())
|
||||
.arg(static_cast<int>(rsp6->getType()))
|
||||
.arg(rsp6->getRemoteAddr())
|
||||
.arg(rsp6->getRemotePort())
|
||||
.arg(rsp6->getIface())
|
||||
.arg(rsp->getLabel())
|
||||
.arg(rsp->getName())
|
||||
|
@ -162,6 +162,9 @@ TEST_F(Dhcpv4SrvTest, adjustIfaceDataRelay) {
|
||||
req->setIface("eth1");
|
||||
req->setIndex(1);
|
||||
|
||||
// Set remote port (it will be used in the next test).
|
||||
req->setRemotePort(1234);
|
||||
|
||||
// Create the exchange using the req.
|
||||
Dhcpv4Exchange ex = createExchange(req);
|
||||
|
||||
@ -205,6 +208,75 @@ TEST_F(Dhcpv4SrvTest, adjustIfaceDataRelay) {
|
||||
EXPECT_EQ("192.0.1.50", resp->getRemoteAddr().toText());
|
||||
}
|
||||
|
||||
// This test verifies that the remote port is adjusted when
|
||||
// the query carries a relay port RAI sub-option.
|
||||
TEST_F(Dhcpv4SrvTest, adjustIfaceDataRelayPort) {
|
||||
IfaceMgrTestConfig test_config(true);
|
||||
IfaceMgr::instance().openSockets4();
|
||||
|
||||
// Create the instance of the incoming packet.
|
||||
boost::shared_ptr<Pkt4> req(new Pkt4(DHCPDISCOVER, 1234));
|
||||
// Set the giaddr to non-zero address and hops to non-zero value
|
||||
// as if it was relayed.
|
||||
req->setGiaddr(IOAddress("192.0.1.1"));
|
||||
req->setHops(2);
|
||||
// Set ciaddr to zero. This simulates the client which applies
|
||||
// for the new lease.
|
||||
req->setCiaddr(IOAddress("0.0.0.0"));
|
||||
// Clear broadcast flag.
|
||||
req->setFlags(0x0000);
|
||||
|
||||
// Set local address, port and interface.
|
||||
req->setLocalAddr(IOAddress("192.0.2.5"));
|
||||
req->setLocalPort(1001);
|
||||
req->setIface("eth1");
|
||||
req->setIndex(1);
|
||||
|
||||
// Set remote port.
|
||||
req->setRemotePort(1234);
|
||||
|
||||
// Add a RAI relay-port sub-option (the only difference with the previous test).
|
||||
OptionDefinitionPtr rai_def =
|
||||
LibDHCP::getOptionDef(DHCP4_OPTION_SPACE, DHO_DHCP_AGENT_OPTIONS);
|
||||
ASSERT_TRUE(rai_def);
|
||||
OptionCustomPtr rai(new OptionCustom(*rai_def, Option::V4));
|
||||
ASSERT_TRUE(rai);
|
||||
req->addOption(rai);
|
||||
OptionPtr relay_port(new Option(Option::V4, RAI_OPTION_RELAY_PORT));
|
||||
ASSERT_TRUE(relay_port);
|
||||
rai->addOption(relay_port);
|
||||
|
||||
// Create the exchange using the req.
|
||||
Dhcpv4Exchange ex = createExchange(req);
|
||||
|
||||
Pkt4Ptr resp = ex.getResponse();
|
||||
resp->setYiaddr(IOAddress("192.0.1.100"));
|
||||
// Clear the remote address.
|
||||
resp->setRemoteAddr(IOAddress("0.0.0.0"));
|
||||
// Set hops value for the response.
|
||||
resp->setHops(req->getHops());
|
||||
|
||||
// Set the remote port to 67 as we know it will be updated.
|
||||
resp->setRemotePort(67);
|
||||
|
||||
// This function never throws.
|
||||
ASSERT_NO_THROW(NakedDhcpv4Srv::adjustIfaceData(ex));
|
||||
|
||||
// Now the destination address should be relay's address.
|
||||
EXPECT_EQ("192.0.1.1", resp->getRemoteAddr().toText());
|
||||
// The query has been relayed, so the response should be sent to the
|
||||
// port 67, but here there is a relay port RAI so another value is used.
|
||||
EXPECT_EQ(1234, resp->getRemotePort());
|
||||
// Local address should be the address assigned to interface eth1.
|
||||
EXPECT_EQ("192.0.2.5", resp->getLocalAddr().toText());
|
||||
// The local port is always DHCPv4 server port 67.
|
||||
EXPECT_EQ(DHCP4_SERVER_PORT, resp->getLocalPort());
|
||||
// We will send response over the same interface which was used to receive
|
||||
// query.
|
||||
EXPECT_EQ("eth1", resp->getIface());
|
||||
EXPECT_EQ(1, resp->getIndex());
|
||||
}
|
||||
|
||||
// This test verifies that it is possible to configure the server to use
|
||||
// routing information to determine the right outbound interface to sent
|
||||
// responses to a relayed client.
|
||||
|
@ -232,7 +232,7 @@ received in Decline message. It's expected that the option will contain an
|
||||
address that is being declined. Specific information will be printed in a
|
||||
separate message.
|
||||
|
||||
% DHCP6_DHCP4O6_PACKET_RECEIVED received DHCPv4o6 packet from DHCPv4 server (type %1) for %2 on interface %3
|
||||
% DHCP6_DHCP4O6_PACKET_RECEIVED received DHCPv4o6 packet from DHCPv4 server (type %1) for %2 port %3 on interface %4
|
||||
This debug message is printed when the server is receiving a DHCPv4o6
|
||||
from the DHCPv4 server over inter-process communication.
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
// 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
|
||||
@ -791,7 +791,8 @@ Dhcpv6Srv::processPacket(Pkt6Ptr& query, Pkt6Ptr& rsp) {
|
||||
rsp->setRemotePort(DHCP6_CLIENT_PORT);
|
||||
} else {
|
||||
// Relayed traffic, send back to the relay agent
|
||||
rsp->setRemotePort(DHCP6_SERVER_PORT);
|
||||
uint16_t relay_port = checkRelaySourcePort(query);
|
||||
rsp->setRemotePort(relay_port ? relay_port : DHCP6_SERVER_PORT);
|
||||
}
|
||||
|
||||
rsp->setLocalPort(DHCP6_SERVER_PORT);
|
||||
@ -3464,6 +3465,22 @@ void Dhcpv6Srv::processRSOO(const Pkt6Ptr& query, const Pkt6Ptr& rsp) {
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t Dhcpv6Srv::checkRelaySourcePort(const Pkt6Ptr& query) {
|
||||
|
||||
if (query->relay_info_.empty()) {
|
||||
// No relay agent
|
||||
return (0);
|
||||
}
|
||||
|
||||
// Did the last relay agent add a relay-source-port?
|
||||
if (query->getRelayOption(D6O_RELAY_SOURCE_PORT, 0)) {
|
||||
// RFC 8357 section 5.2
|
||||
return (query->getRemotePort());
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void Dhcpv6Srv::processStatsReceived(const Pkt6Ptr& query) {
|
||||
// Note that we're not bumping pkt6-received statistic as it was
|
||||
// increased early in the packet reception code.
|
||||
|
@ -1,4 +1,4 @@
|
||||
// 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
|
||||
@ -758,6 +758,16 @@ 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.
|
||||
/// @return the port to use to join the relay or 0 for the default.
|
||||
static uint16_t checkRelaySourcePort(const Pkt6Ptr& query);
|
||||
|
||||
private:
|
||||
|
||||
/// @public
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2015-2017 Internet Systems Consortium, Inc. ("ISC")
|
||||
// Copyright (C) 2015-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
|
||||
@ -64,6 +64,7 @@ void Dhcp6to4Ipc::handler() {
|
||||
LOG_DEBUG(packet6_logger, DBG_DHCP6_BASIC, DHCP6_DHCP4O6_PACKET_RECEIVED)
|
||||
.arg(static_cast<int>(pkt->getType()))
|
||||
.arg(pkt->getRemoteAddr().toText())
|
||||
.arg(pkt->getRemotePort())
|
||||
.arg(pkt->getIface());
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
@ -77,6 +78,9 @@ void Dhcp6to4Ipc::handler() {
|
||||
|
||||
// Should we check it is a DHCPV6_DHCPV4_RESPONSE?
|
||||
|
||||
// Handle relay port
|
||||
uint16_t relay_port = Dhcpv6Srv::checkRelaySourcePort(pkt);
|
||||
|
||||
// The received message has been unpacked by the receive() function. This
|
||||
// method could have modified the message so it's better to pack() it
|
||||
// again because we'll be forwarding it to a client.
|
||||
@ -89,7 +93,7 @@ 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);
|
||||
pkt->setRemotePort(relay_port ? relay_port : DHCP6_SERVER_PORT);
|
||||
} else {
|
||||
pkt->setRemotePort(DHCP6_CLIENT_PORT);
|
||||
}
|
||||
|
@ -1572,6 +1572,97 @@ TEST_F(Dhcpv6SrvTest, portsRelayedTraffic) {
|
||||
EXPECT_EQ(DHCP6_SERVER_PORT, adv->getRemotePort());
|
||||
}
|
||||
|
||||
// Test that the server processes relay-source-port option correctly.
|
||||
TEST_F(Dhcpv6SrvTest, relaySourcePort) {
|
||||
|
||||
NakedDhcpv6Srv srv(0);
|
||||
|
||||
string config =
|
||||
"{"
|
||||
" \"preferred-lifetime\": 3000,"
|
||||
" \"rebind-timer\": 2000, "
|
||||
" \"renew-timer\": 1000, "
|
||||
" \"subnet6\": [ { "
|
||||
" \"pools\": [ { \"pool\": \"2001:db8::/64\" } ],"
|
||||
" \"subnet\": \"2001:db8::/48\" "
|
||||
" } ],"
|
||||
" \"valid-lifetime\": 4000"
|
||||
"}";
|
||||
|
||||
EXPECT_NO_THROW(configure(config, srv));
|
||||
|
||||
// Create a solicit
|
||||
Pkt6Ptr sol(new Pkt6(DHCPV6_SOLICIT, 1234));
|
||||
sol->setRemoteAddr(IOAddress("fe80::abcd"));
|
||||
sol->setIface("eth0");
|
||||
sol->addOption(generateIA(D6O_IA_NA, 234, 1500, 3000));
|
||||
OptionPtr clientid = generateClientId();
|
||||
sol->addOption(clientid);
|
||||
|
||||
// Pretend the packet came via one relay.
|
||||
Pkt6::RelayInfo relay;
|
||||
relay.msg_type_ = DHCPV6_RELAY_FORW;
|
||||
relay.hop_count_ = 1;
|
||||
relay.linkaddr_ = IOAddress("2001:db8::1");
|
||||
relay.peeraddr_ = IOAddress("fe80::1");
|
||||
|
||||
// Set the source port
|
||||
sol->setRemotePort(1234);
|
||||
|
||||
// Simulate that we have received that traffic
|
||||
sol->pack();
|
||||
|
||||
// Add a relay-source-port option
|
||||
OptionBuffer zero(2, 0);
|
||||
OptionPtr opt(new Option(Option::V6, D6O_RELAY_SOURCE_PORT, zero));
|
||||
relay.options_.insert(make_pair(opt->getType(), opt));
|
||||
sol->relay_info_.push_back(relay);
|
||||
|
||||
// Simulate that we have received that traffic
|
||||
sol->pack();
|
||||
EXPECT_EQ(DHCPV6_RELAY_FORW, sol->getBuffer()[0]);
|
||||
Pkt6Ptr query(new Pkt6(static_cast<const uint8_t*>
|
||||
(sol->getBuffer().getData()),
|
||||
sol->getBuffer().getLength()));
|
||||
query->setRemoteAddr(sol->getRemoteAddr());
|
||||
query->setRemotePort(sol->getRemotePort());
|
||||
query->setLocalAddr(sol->getLocalAddr());
|
||||
query->setLocalPort(sol->getLocalPort());
|
||||
query->setIface(sol->getIface());
|
||||
|
||||
srv.fakeReceive(query);
|
||||
|
||||
// Server will now process to run its normal loop, but instead of calling
|
||||
// IfaceMgr::receive6(), it will read all packets from the list set by
|
||||
// fakeReceive()
|
||||
srv.run();
|
||||
|
||||
// Check trace of processing
|
||||
EXPECT_EQ(1234, query->getRemotePort());
|
||||
ASSERT_EQ(1, query->relay_info_.size());
|
||||
EXPECT_TRUE(query->getRelayOption(D6O_RELAY_SOURCE_PORT, 0));
|
||||
|
||||
// Get Response...
|
||||
ASSERT_FALSE(srv.fake_sent_.empty());
|
||||
Pkt6Ptr rsp = srv.fake_sent_.front();
|
||||
ASSERT_TRUE(rsp);
|
||||
|
||||
// Check it
|
||||
EXPECT_EQ(1234, rsp->getRemotePort());
|
||||
EXPECT_EQ(DHCPV6_RELAY_REPL, rsp->getBuffer()[0]);
|
||||
|
||||
// Get Advertise
|
||||
Pkt6Ptr adv(new Pkt6(static_cast<const uint8_t*>
|
||||
(rsp->getBuffer().getData()),
|
||||
rsp->getBuffer().getLength()));
|
||||
adv->unpack();
|
||||
|
||||
// Check it
|
||||
EXPECT_EQ(DHCPV6_ADVERTISE, adv->getType());
|
||||
ASSERT_EQ(1, adv->relay_info_.size());
|
||||
EXPECT_TRUE(adv->getRelayOption(D6O_RELAY_SOURCE_PORT, 0));
|
||||
}
|
||||
|
||||
// Checks effect of persistency (aka always-true) flag on the ORO
|
||||
TEST_F(Dhcpv6SrvTest, prlPersistency) {
|
||||
IfaceMgrTestConfig test_config(true);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2017 Internet Systems Consortium, Inc. ("ISC")
|
||||
* Copyright (C) 2004-2018 Internet Systems Consortium, Inc. ("ISC")
|
||||
* Copyright (c) 1995-2003 by Internet Software Consortium
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
@ -273,6 +273,7 @@ static const uint16_t RAI_OPTION_ACCESS_POINT_NAME = 15; // RFC7839
|
||||
static const uint16_t RAI_OPTION_ACCESS_POINT_BSSID = 16; // RFC7839
|
||||
static const uint16_t RAI_OPTION_OPERATOR_ID = 17; // RFC7839
|
||||
static const uint16_t RAI_OPTION_OPERATOR_REALM = 18; // RFC7839
|
||||
static const uint16_t RAI_OPTION_RELAY_PORT = 19; // RFC8357
|
||||
static const uint16_t RAI_OPTION_VIRTUAL_SUBNET_SELECT = 151; //RFC6607
|
||||
static const uint16_t RAI_OPTION_VIRTUAL_SUBNET_SELECT_CTRL = 152; //RFC6607
|
||||
|
||||
|
@ -152,7 +152,8 @@ enum DHCPv6OptionType {
|
||||
// D6O_F_SERVER_STATE = 132, /* RFC8156 */
|
||||
// D6O_F_START_TIME_OF_STATE = 133, /* RFC8156 */
|
||||
// D6O_F_STATE_EXPIRATION_TIME = 134, /* RFC8156 */
|
||||
// 135-142 unassigned
|
||||
D6O_RELAY_SOURCE_PORT = 135, /* RFC8357 */
|
||||
// 136-142 unassigned
|
||||
D6O_IPV6_ADDRESS_ANDSF = 143, /* RFC6153 */
|
||||
|
||||
// The following are EXPERIMENTAL and may change when IANA assigns official
|
||||
@ -278,6 +279,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 */
|
||||
|
@ -794,6 +794,12 @@ void Pkt6::copyRelayInfo(const Pkt6Ptr& question) {
|
||||
info.options_.insert(make_pair(opt->getType(), opt));
|
||||
}
|
||||
|
||||
// Same for relay-source-port option
|
||||
opt = question->getNonCopiedRelayOption(D6O_RELAY_SOURCE_PORT, i);
|
||||
if (opt) {
|
||||
info.options_.insert(make_pair(opt->getType(), opt));
|
||||
}
|
||||
|
||||
/// @todo: Implement support for ERO (Echo Request Option, RFC4994)
|
||||
|
||||
// Add this relay-forw info (client's message) to our relay-repl
|
||||
|
@ -444,6 +444,7 @@ const OptionDefParams STANDARD_V6_OPTION_DEFINITIONS[] = {
|
||||
NO_RECORD_DEF, "" },
|
||||
{ "v6-captive-portal", D6O_V6_CAPTIVE_PORTAL, OPT_STRING_TYPE, false,
|
||||
NO_RECORD_DEF, "" },
|
||||
{ "relay-source-port", D6O_RELAY_SOURCE_PORT, OPT_UINT16_TYPE, false, NO_RECORD_DEF, "" },
|
||||
{ "ipv6-address-andsf", D6O_IPV6_ADDRESS_ANDSF, OPT_IPV6_ADDRESS_TYPE, true,
|
||||
NO_RECORD_DEF, "" },
|
||||
{ "public-key", D6O_PUBLIC_KEY, OPT_BINARY_TYPE, false,
|
||||
@ -489,7 +490,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 =
|
||||
|
@ -1736,6 +1736,9 @@ TEST_F(LibDhcpTest, stdOptionDefs6) {
|
||||
LibDhcpTest::testStdOptionDefs6(D6O_V6_CAPTIVE_PORTAL, begin, end,
|
||||
typeid(OptionString));
|
||||
|
||||
LibDhcpTest::testStdOptionDefs6(D6O_RELAY_SOURCE_PORT, begin, begin + 2,
|
||||
typeid(OptionInt<uint16_t>));
|
||||
|
||||
LibDhcpTest::testStdOptionDefs6(D6O_IPV6_ADDRESS_ANDSF, begin, end,
|
||||
typeid(Option6AddrLst));
|
||||
|
||||
|
@ -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,27 @@ Pkt6Ptr Dhcp4o6IpcBase::receive() {
|
||||
"or has incorrect type)");
|
||||
}
|
||||
|
||||
// Get the option holding source port.
|
||||
OptionUint16Ptr sport = boost::dynamic_pointer_cast<
|
||||
OptionUint16>(option_vendor->getOption(ISC_V6_4O6_SRC_PORT));
|
||||
if (!sport) {
|
||||
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 type)");
|
||||
}
|
||||
|
||||
// Update the packet.
|
||||
pkt->setRemoteAddr(srcs->readAddress());
|
||||
pkt->setRemotePort(sport->getValue());
|
||||
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 +257,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();
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user