mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-30 21:45:37 +00:00
[3705] Address review comments.
This commit is contained in:
@@ -885,6 +885,9 @@ temporarily override a list of interface names and listen on all interfaces.
|
||||
<row><entry>clt-time</entry><entry>46</entry><entry>uint32</entry><entry>false</entry></row>
|
||||
<row><entry>lq-relay-data</entry><entry>47</entry><entry>record</entry><entry>false</entry></row>
|
||||
<row><entry>lq-client-link</entry><entry>48</entry><entry>ipv6-address</entry><entry>true</entry></row>
|
||||
<row><entry>erp-local-domain-name</entry><entry>65</entry><entry>fqdn</entry><entry>false</entry></row>
|
||||
<row><entry>rsoo</entry><entry>66</entry><entry>empty</entry><entry>false</entry></row>
|
||||
<row><entry>client-linklayer-addr</entry><entry>79</entry><entry>binary</entry><entry>false</entry></row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
@@ -1371,7 +1374,7 @@ should include options from the isc option space:
|
||||
<section id="dhcp6-rsoo">
|
||||
<title>Relay-Supplied Options</title>
|
||||
<para><ulink url="http://tools.ietf.org/html/rfc6422">RFC 6422</ulink>
|
||||
defines a mechanism called Relay supplied options. In certain cases relay
|
||||
defines a mechanism called Relay-Supplied DHCP Options. In certain cases relay
|
||||
agents are the only entities that may have specific information. They can
|
||||
insert options when relaying messages from the client to the server. The
|
||||
server will then do certain checks and copy those options to the response
|
||||
@@ -1381,11 +1384,11 @@ should include options from the isc option space:
|
||||
included. First, the server must not provide the option by itself. In
|
||||
other words, if both relay and server provide an option, the server always
|
||||
takes precedence. Second, the option must be RSOO-enabled. IANA mantains a
|
||||
list of RSOO-enabled options here: <ulink url="http://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml#options-relay-supplied">List of RSOO-enabled options</ulink>.
|
||||
However, there may cases when system administrators want to echo other
|
||||
list of RSOO-enabled options <ulink url="http://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml#options-relay-supplied">here</ulink>.
|
||||
However, there may be cases when system administrators want to echo other
|
||||
options. Kea can be instructed to treat other options as RSOO-enabled.
|
||||
For example, to mark options 110, 120 and 130 as RSOO-enabled, the following
|
||||
syntax may be used:
|
||||
syntax should be used:
|
||||
<screen>
|
||||
"Dhcp6": {
|
||||
<userinput>"relay-supplied-options": [ "110", "120", "130" ],</userinput>
|
||||
|
@@ -2739,42 +2739,31 @@ void Dhcpv6Srv::processRSOO(const Pkt6Ptr& query, const Pkt6Ptr& rsp) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the global options info. We'll use it to check whether an
|
||||
// option is RSOO-enabled or not.
|
||||
ConstCfgOptionPtr global_opts = CfgMgr::instance().getCurrentCfg()->
|
||||
getCfgOption();
|
||||
// Get RSOO configuration.
|
||||
ConstCfgRSOOPtr cfg_rsoo = CfgMgr::instance().getCurrentCfg()->getCfgRSOO();
|
||||
|
||||
// Let's get over all relays (encapsulation levels). We need to do
|
||||
// it in the same order as the client packet traversed the relays.
|
||||
for (int i = query->relay_info_.size(); i > 0 ; --i) {
|
||||
OptionPtr rsoo_container = query->getRelayOption(D6O_RSOO, i - 1);
|
||||
if (!rsoo_container) {
|
||||
// No relay-supplied options by this relay? Ok, carry on.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rsoo_container) {
|
||||
// There are RSOO options. Let's get through them one by one
|
||||
// and if it's RSOO-enabled and there's no such option provided yet,
|
||||
// copy it to the server's response
|
||||
const OptionCollection& rsoo = rsoo_container->getOptions();
|
||||
for (OptionCollection::const_iterator opt = rsoo.begin(); opt != rsoo.end();
|
||||
++opt) {
|
||||
if (!global_opts->isRSOOEnabled(opt->second->getType())) {
|
||||
// We didn't copy this option, because it's not RSOO-enabled.
|
||||
continue;
|
||||
}
|
||||
for (OptionCollection::const_iterator opt = rsoo.begin();
|
||||
opt != rsoo.end(); ++opt) {
|
||||
|
||||
if (rsp->getOption(opt->second->getType())) {
|
||||
// There is such an option in the server's response already,
|
||||
// we'll skip relay's option
|
||||
continue;
|
||||
}
|
||||
|
||||
// All checks went ok, let's add this option.
|
||||
// Echo option if it is RSOO enabled option and there is no such
|
||||
// option added yet.
|
||||
if (cfg_rsoo->enabled(opt->second->getType()) &&
|
||||
!rsp->getOption(opt->second->getType())) {
|
||||
rsp->addOption(opt->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
|
@@ -41,6 +41,7 @@
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
@@ -575,10 +576,14 @@ public:
|
||||
ParserCollection subnets_;
|
||||
};
|
||||
|
||||
/// @brief parser for list of RSOO options
|
||||
/// @brief Parser for list of RSOO options
|
||||
///
|
||||
/// This parser handles Dhcp6/relay-supplied-options entry.
|
||||
/// It contains a list of option codes.
|
||||
/// This parser handles Dhcp6/relay-supplied-options entry. It contains a
|
||||
/// list of RSOO-enabled options which should be sent back to the client.
|
||||
///
|
||||
/// The option on this list can be specified using an option code or option
|
||||
/// name. Therefore, the values on the list should always be enclosed in
|
||||
/// "quotes".
|
||||
class RSOOListConfigParser : public DhcpConfigParser {
|
||||
public:
|
||||
|
||||
@@ -603,19 +608,26 @@ public:
|
||||
///
|
||||
/// @param value pointer to the content of parsed values
|
||||
virtual void build(isc::data::ConstElementPtr value) {
|
||||
|
||||
// By default, there's only one RSOO option defined: 65
|
||||
// http://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml
|
||||
CfgMgr::instance().getStagingCfg()->getCfgOption()->clearRSOO();
|
||||
CfgMgr::instance().getStagingCfg()->getCfgOption()->addRSOO(D6O_ERP_LOCAL_DOMAIN_NAME);
|
||||
|
||||
try {
|
||||
BOOST_FOREACH(ConstElementPtr source_elem, value->listValue()) {
|
||||
|
||||
std::string option_str = source_elem->stringValue();
|
||||
// This option can be either code (integer) or name. Let's try code first
|
||||
uint16_t code = 0;
|
||||
int64_t code = 0;
|
||||
try {
|
||||
code = boost::lexical_cast<uint16_t>(option_str);
|
||||
code = boost::lexical_cast<int64_t>(option_str);
|
||||
// Protect against the negative value and too high value.
|
||||
if (code < 0) {
|
||||
isc_throw(BadValue, "invalid option code value specified '"
|
||||
<< option_str << "', the option code must be a"
|
||||
" non-negative value");
|
||||
|
||||
} else if (code > std::numeric_limits<uint16_t>::max()) {
|
||||
isc_throw(BadValue, "invalid option code value specified '"
|
||||
<< option_str << "', the option code must not be"
|
||||
" greater than '" << std::numeric_limits<uint16_t>::max()
|
||||
<< "'");
|
||||
}
|
||||
|
||||
} catch (const boost::bad_lexical_cast &) {
|
||||
// Oh well, it's not a number
|
||||
}
|
||||
@@ -625,12 +637,18 @@ public:
|
||||
if (def) {
|
||||
code = def->getCode();
|
||||
} else {
|
||||
isc_throw(BadValue, "Unable to convert '" << option_str
|
||||
<< "' to option code while parsing allowed"
|
||||
<< "relay-supplied-options");
|
||||
isc_throw(BadValue, "unable to find option code for the "
|
||||
" specified option name '" << option_str << "'"
|
||||
" while parsing the list of enabled"
|
||||
" relay-supplied-options");
|
||||
}
|
||||
}
|
||||
CfgMgr::instance().getStagingCfg()->getCfgOption()->addRSOO(code);
|
||||
CfgMgr::instance().getStagingCfg()->getCfgRSOO()->enable(code);
|
||||
}
|
||||
} catch (const std::exception& ex) {
|
||||
// Rethrow exception with the appended position of the parsed
|
||||
// element.
|
||||
isc_throw(DhcpConfigError, ex.what() << " (" << value->getPosition() << ")");
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -3798,18 +3798,18 @@ TEST_F(Dhcp6ParserTest, rsooNumbers) {
|
||||
checkResult(status, 0);
|
||||
|
||||
// The following codes should be enabled now
|
||||
EXPECT_TRUE(CfgMgr::instance().getStagingCfg()->getCfgOption()->isRSOOEnabled(10));
|
||||
EXPECT_TRUE(CfgMgr::instance().getStagingCfg()->getCfgOption()->isRSOOEnabled(20));
|
||||
EXPECT_TRUE(CfgMgr::instance().getStagingCfg()->getCfgOption()->isRSOOEnabled(30));
|
||||
EXPECT_TRUE(CfgMgr::instance().getStagingCfg()->getCfgRSOO()->enabled(10));
|
||||
EXPECT_TRUE(CfgMgr::instance().getStagingCfg()->getCfgRSOO()->enabled(20));
|
||||
EXPECT_TRUE(CfgMgr::instance().getStagingCfg()->getCfgRSOO()->enabled(30));
|
||||
|
||||
// This option is on the IANA list, so it should be allowed all the time
|
||||
// (http://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml)
|
||||
EXPECT_TRUE(CfgMgr::instance().getStagingCfg()->getCfgOption()
|
||||
->isRSOOEnabled(D6O_ERP_LOCAL_DOMAIN_NAME));
|
||||
EXPECT_TRUE(CfgMgr::instance().getStagingCfg()->getCfgRSOO()
|
||||
->enabled(D6O_ERP_LOCAL_DOMAIN_NAME));
|
||||
|
||||
// Those options are not enabled
|
||||
EXPECT_FALSE(CfgMgr::instance().getStagingCfg()->getCfgOption()->isRSOOEnabled(25));
|
||||
EXPECT_FALSE(CfgMgr::instance().getStagingCfg()->getCfgOption()->isRSOOEnabled(1));
|
||||
EXPECT_FALSE(CfgMgr::instance().getStagingCfg()->getCfgRSOO()->enabled(25));
|
||||
EXPECT_FALSE(CfgMgr::instance().getStagingCfg()->getCfgRSOO()->enabled(1));
|
||||
}
|
||||
|
||||
/// The goal of this test is to verify that configuration can include
|
||||
@@ -3831,39 +3831,68 @@ TEST_F(Dhcp6ParserTest, rsooNames) {
|
||||
checkResult(status, 0);
|
||||
|
||||
for (uint16_t code = 0; code < D6O_NAME_SERVERS; ++code) {
|
||||
EXPECT_FALSE(CfgMgr::instance().getStagingCfg()->getCfgOption()
|
||||
->isRSOOEnabled(code)) << " for option code " << code;
|
||||
EXPECT_FALSE(CfgMgr::instance().getStagingCfg()->getCfgRSOO()
|
||||
->enabled(code)) << " for option code " << code;
|
||||
}
|
||||
|
||||
// The following codes should be enabled now
|
||||
EXPECT_TRUE(CfgMgr::instance().getStagingCfg()->getCfgOption()
|
||||
->isRSOOEnabled(D6O_NAME_SERVERS));
|
||||
EXPECT_TRUE(CfgMgr::instance().getStagingCfg()->getCfgRSOO()
|
||||
->enabled(D6O_NAME_SERVERS));
|
||||
|
||||
for (uint16_t code = D6O_NAME_SERVERS + 1; code < D6O_REMOTE_ID; ++code) {
|
||||
EXPECT_FALSE(CfgMgr::instance().getStagingCfg()->getCfgOption()
|
||||
->isRSOOEnabled(code)) << " for option code " << code;
|
||||
EXPECT_FALSE(CfgMgr::instance().getStagingCfg()->getCfgRSOO()
|
||||
->enabled(code)) << " for option code " << code;
|
||||
}
|
||||
|
||||
// Check remote-id. It should be enabled.
|
||||
EXPECT_TRUE(CfgMgr::instance().getStagingCfg()->getCfgOption()
|
||||
->isRSOOEnabled(D6O_REMOTE_ID));
|
||||
EXPECT_TRUE(CfgMgr::instance().getStagingCfg()->getCfgRSOO()
|
||||
->enabled(D6O_REMOTE_ID));
|
||||
for (uint16_t code = D6O_REMOTE_ID + 1; code < D6O_ERP_LOCAL_DOMAIN_NAME; ++code) {
|
||||
EXPECT_FALSE(CfgMgr::instance().getStagingCfg()->getCfgOption()
|
||||
->isRSOOEnabled(code)) << " for option code " << code;
|
||||
EXPECT_FALSE(CfgMgr::instance().getStagingCfg()->getCfgRSOO()
|
||||
->enabled(code)) << " for option code " << code;
|
||||
}
|
||||
|
||||
// This option is on the IANA list, so it should be allowed all the time
|
||||
// (http://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml)
|
||||
EXPECT_TRUE(CfgMgr::instance().getStagingCfg()->getCfgOption()
|
||||
->isRSOOEnabled(D6O_ERP_LOCAL_DOMAIN_NAME));
|
||||
EXPECT_TRUE(CfgMgr::instance().getStagingCfg()->getCfgRSOO()
|
||||
->enabled(D6O_ERP_LOCAL_DOMAIN_NAME));
|
||||
|
||||
for (uint16_t code = D6O_ERP_LOCAL_DOMAIN_NAME + 1; code < 300; ++code) {
|
||||
EXPECT_FALSE(CfgMgr::instance().getStagingCfg()->getCfgOption()
|
||||
->isRSOOEnabled(code)) << " for option code " << code;
|
||||
EXPECT_FALSE(CfgMgr::instance().getStagingCfg()->getCfgRSOO()
|
||||
->enabled(code)) << " for option code " << code;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(Dhcp6ParserTest, rsooNegativeNumber) {
|
||||
ConstElementPtr status;
|
||||
EXPECT_NO_THROW(status = configureDhcp6Server(srv_,
|
||||
Element::fromJSON("{ " + genIfaceConfig() + ","
|
||||
"\"relay-supplied-options\": [ \"80\", \"-2\" ],"
|
||||
"\"preferred-lifetime\": 3000,"
|
||||
"\"rebind-timer\": 2000, "
|
||||
"\"renew-timer\": 1000, "
|
||||
"\"subnet6\": [ ], "
|
||||
"\"valid-lifetime\": 4000 }")));
|
||||
|
||||
// returned value should be 0 (success)
|
||||
checkResult(status, 1);
|
||||
EXPECT_TRUE(errorContainsPosition(status, "<string>"));
|
||||
}
|
||||
|
||||
TEST_F(Dhcp6ParserTest, rsooBogusName) {
|
||||
ConstElementPtr status;
|
||||
EXPECT_NO_THROW(status = configureDhcp6Server(srv_,
|
||||
Element::fromJSON("{ " + genIfaceConfig() + ","
|
||||
"\"relay-supplied-options\": [ \"bogus\", \"dns-servers\" ],"
|
||||
"\"preferred-lifetime\": 3000,"
|
||||
"\"rebind-timer\": 2000, "
|
||||
"\"renew-timer\": 1000, "
|
||||
"\"subnet6\": [ ], "
|
||||
"\"valid-lifetime\": 4000 }")));
|
||||
|
||||
// returned value should be 0 (success)
|
||||
checkResult(status, 1);
|
||||
EXPECT_TRUE(errorContainsPosition(status, "<string>"));
|
||||
}
|
||||
|
||||
};
|
||||
|
@@ -110,6 +110,21 @@ public:
|
||||
status_code_ = 0;
|
||||
received_status_code_ = false;
|
||||
}
|
||||
|
||||
/// @brief Finds an option with the specific code in the received
|
||||
/// configuration.
|
||||
///
|
||||
/// @param code Option code.
|
||||
///
|
||||
/// @return Pointer to the option if the option exists, or NULL if
|
||||
/// the option doesn't exist.
|
||||
OptionPtr findOption(const uint16_t code) const {
|
||||
std::multimap<unsigned int, OptionPtr>::const_iterator it = options_.find(code);
|
||||
if (it != options_.end()) {
|
||||
return (it->second);
|
||||
}
|
||||
return (OptionPtr());
|
||||
}
|
||||
};
|
||||
|
||||
/// @brief Holds the DHCPv6 messages taking part in transaction between
|
||||
|
@@ -2277,6 +2277,80 @@ TEST_F(Dhcpv6SrvTest, rsoo2relays) {
|
||||
EXPECT_EQ(expected, opt120->getData());
|
||||
}
|
||||
|
||||
// This test verifies that the server will send the option for which it
|
||||
// has a candidate, rather than the option sent by the relay in the RSOO.
|
||||
TEST_F(Dhcpv6SrvTest, rsooOverride) {
|
||||
Dhcp6Client client;
|
||||
// The client will be requesting specific options.
|
||||
client.useORO(true);
|
||||
|
||||
// The following configuration enables RSOO options: 110 and 120.
|
||||
// It also configures the server with option 120 which should
|
||||
// "override" the option 120 sent in the RSOO by the relay.
|
||||
string config =
|
||||
"{"
|
||||
" \"relay-supplied-options\": [ \"110\", \"120\" ],"
|
||||
" \"option-def\": [ {"
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 120,"
|
||||
" \"type\": \"binary\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"dhcp6\","
|
||||
" \"encapsulate\": \"\""
|
||||
" } ],"
|
||||
" \"option-data\": [ {"
|
||||
" \"code\": 120,"
|
||||
" \"data\": \"05\""
|
||||
" } ],"
|
||||
" \"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, *client.getServer()));
|
||||
|
||||
// Fabricate the 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");
|
||||
vector<uint16_t> rsoo;
|
||||
// The relay will send 2 options: 110, 120
|
||||
rsoo.push_back(110);
|
||||
rsoo.push_back(120);
|
||||
// Use 0x1 as payload
|
||||
OptionPtr opt = createRSOO(rsoo, 1);
|
||||
relay.options_.insert(make_pair(opt->getType(), opt));
|
||||
client.relay_info_.push_back(relay);
|
||||
|
||||
// Client should request option 120 in the ORO so as the server
|
||||
// sends the configured option 120 to the client.
|
||||
client.requestOption(120);
|
||||
client.doSARR();
|
||||
|
||||
// The option 110 should be the one injected by the relay.
|
||||
opt = client.config_.findOption(110);
|
||||
ASSERT_TRUE(opt);
|
||||
// We check that this is the option injected by the relay by
|
||||
// checking option length. It should has 10 bytes long payload.
|
||||
ASSERT_EQ(10, opt->getData().size());
|
||||
|
||||
// The second option should be the one configured on the server,
|
||||
// rather than the one injected by the relay.
|
||||
opt = client.config_.findOption(120);
|
||||
ASSERT_TRUE(opt);
|
||||
// It should have the size of 1.
|
||||
ASSERT_EQ(1, opt->getData().size());
|
||||
}
|
||||
|
||||
|
||||
/// @todo: Add more negative tests for processX(), e.g. extend sanityCheck() test
|
||||
/// to call processX() methods.
|
||||
|
||||
|
@@ -327,7 +327,7 @@ const OptionDefParams OPTION_DEF_PARAMS6[] = {
|
||||
RECORD_DEF(LQ_RELAY_DATA_RECORDS), "" },
|
||||
{ "lq-client-link", D6O_LQ_CLIENT_LINK, OPT_IPV6_ADDRESS_TYPE, true,
|
||||
NO_RECORD_DEF, "" },
|
||||
{ "rsoo", D6O_RSOO, OPT_EMPTY_TYPE, false, NO_RECORD_DEF, "dhcp4" },
|
||||
{ "rsoo", D6O_RSOO, OPT_EMPTY_TYPE, false, NO_RECORD_DEF, "rsoo-opts" },
|
||||
{ "client-linklayer-addr", D6O_CLIENT_LINKLAYER_ADDR, OPT_BINARY_TYPE, false,
|
||||
NO_RECORD_DEF, "" }
|
||||
|
||||
|
@@ -351,6 +351,7 @@ Pkt6Ptr isc::test::PktCaptures::captureCableLabsShortVendorClass() {
|
||||
/// - rsoo (66)
|
||||
/// - option 255 (len 4)
|
||||
/// - option 256 (len 9)
|
||||
/// - remote-id option (37)
|
||||
/// - RELAY-FORW
|
||||
/// - SOLICIT
|
||||
/// - client-id option
|
||||
|
@@ -70,6 +70,7 @@ libkea_dhcpsrv_la_SOURCES += cfg_hosts.cc cfg_hosts.h
|
||||
libkea_dhcpsrv_la_SOURCES += cfg_iface.cc cfg_iface.h
|
||||
libkea_dhcpsrv_la_SOURCES += cfg_option.cc cfg_option.h
|
||||
libkea_dhcpsrv_la_SOURCES += cfg_option_def.cc cfg_option_def.h
|
||||
libkea_dhcpsrv_la_SOURCES += cfg_rsoo.cc cfg_rsoo.h
|
||||
libkea_dhcpsrv_la_SOURCES += cfg_subnets4.cc cfg_subnets4.h
|
||||
libkea_dhcpsrv_la_SOURCES += cfg_subnets6.cc cfg_subnets6.h
|
||||
libkea_dhcpsrv_la_SOURCES += cfg_mac_source.cc cfg_mac_source.h
|
||||
|
@@ -29,10 +29,6 @@ OptionDescriptor::equals(const OptionDescriptor& other) const {
|
||||
}
|
||||
|
||||
CfgOption::CfgOption() {
|
||||
|
||||
// By default, the only allowed Relay-Supplied Options option is
|
||||
// ERP local domain name. Other options may be added in configuration.
|
||||
rsoo_options_.insert(D6O_ERP_LOCAL_DOMAIN_NAME);
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -198,20 +194,5 @@ CfgOption::optionSpaceToVendorId(const std::string& option_space) {
|
||||
return (static_cast<uint32_t>(check));
|
||||
}
|
||||
|
||||
void CfgOption::clearRSOO() {
|
||||
rsoo_options_.clear();
|
||||
}
|
||||
|
||||
bool CfgOption::isRSOOEnabled(uint16_t code) const {
|
||||
return (rsoo_options_.find(code) != rsoo_options_.end());
|
||||
}
|
||||
|
||||
void CfgOption::addRSOO(uint16_t code) {
|
||||
if (rsoo_options_.find(code) == rsoo_options_.end()) {
|
||||
// If there's no such code added yet, let's add it
|
||||
rsoo_options_.insert(code);
|
||||
}
|
||||
}
|
||||
|
||||
} // end of namespace isc::dhcp
|
||||
} // end of namespace isc
|
||||
|
@@ -195,11 +195,6 @@ typedef OptionContainer::nth_index<2>::type OptionContainerPersistIndex;
|
||||
/// options is useful when the client requests stateless configuration from
|
||||
/// the DHCP server and no subnet is selected for this client. This client
|
||||
/// will only receive global options.
|
||||
///
|
||||
/// isRSSOEnabled(), addRSOO(), clearRSOO() are methods related to
|
||||
/// Relay-Supplied Options option. This information does not provide any values
|
||||
/// about the options themselves, but rather contain a list of options that
|
||||
/// are allowed in RSOO ("RSOO-enabled").
|
||||
class CfgOption {
|
||||
public:
|
||||
|
||||
@@ -357,23 +352,6 @@ public:
|
||||
/// @return vendor id.
|
||||
static uint32_t optionSpaceToVendorId(const std::string& option_space);
|
||||
|
||||
/// @brief Removes designation of all options as RSOO-enabled.
|
||||
///
|
||||
/// This method removes all designations of all options as being RSOO-enabled.
|
||||
/// Note that the list is maintained by IANA and option 65 is officially
|
||||
/// RSOO-enabled. This list may be extended in the future. Also, the user may
|
||||
/// add extra options here.
|
||||
void clearRSOO();
|
||||
|
||||
/// @brief Returns whether specific option code is RSOO-enabled.
|
||||
/// @param code option code to check
|
||||
/// @return true, if it is allowed in Relay-Supplied Options option
|
||||
bool isRSOOEnabled(uint16_t code) const;
|
||||
|
||||
/// @brief Marks specified option code as RSOO-enabled.
|
||||
/// @param code option to be enabled in RSOO
|
||||
void addRSOO(uint16_t code);
|
||||
|
||||
private:
|
||||
|
||||
/// @brief Appends encapsulated options to the options in an option space.
|
||||
@@ -419,15 +397,6 @@ private:
|
||||
uint32_t> VendorOptionSpaceCollection;
|
||||
/// @brief Container holding options grouped by vendor id.
|
||||
VendorOptionSpaceCollection vendor_options_;
|
||||
|
||||
/// @brief Contains a list of options that are allowed in RSOO option
|
||||
///
|
||||
/// RSOO stands for Relay-Supplied Options option. This is an option that
|
||||
/// is inserted by the relay agent with the intention that the server will
|
||||
/// echo those options back to the client. Only those options marked as
|
||||
/// RSOO-enabled may appear in the RSOO. Currently only option 65 is marked
|
||||
/// as such, but more options may be added in the future. See RFC6422 for details.
|
||||
std::set<uint16_t> rsoo_options_;
|
||||
};
|
||||
|
||||
/// @name Pointers to the @c CfgOption objects.
|
||||
|
46
src/lib/dhcpsrv/cfg_rsoo.cc
Normal file
46
src/lib/dhcpsrv/cfg_rsoo.cc
Normal file
@@ -0,0 +1,46 @@
|
||||
// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#include <dhcp/dhcp6.h>
|
||||
#include <dhcpsrv/cfg_rsoo.h>
|
||||
|
||||
namespace isc {
|
||||
namespace dhcp {
|
||||
|
||||
CfgRSOO::CfgRSOO()
|
||||
: rsoo_options_() {
|
||||
rsoo_options_.insert(D6O_ERP_LOCAL_DOMAIN_NAME);
|
||||
}
|
||||
|
||||
void
|
||||
CfgRSOO::clear() {
|
||||
rsoo_options_.clear();
|
||||
}
|
||||
|
||||
bool
|
||||
CfgRSOO::enabled(const uint16_t code) const {
|
||||
return (rsoo_options_.find(code) != rsoo_options_.end());
|
||||
}
|
||||
|
||||
void
|
||||
CfgRSOO::enable(const uint16_t code) {
|
||||
if (rsoo_options_.find(code) == rsoo_options_.end()) {
|
||||
// If there's no such code added yet, let's add it
|
||||
rsoo_options_.insert(code);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
82
src/lib/dhcpsrv/cfg_rsoo.h
Normal file
82
src/lib/dhcpsrv/cfg_rsoo.h
Normal file
@@ -0,0 +1,82 @@
|
||||
// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#ifndef CFG_RSOO_H
|
||||
#define CFG_RSOO_H
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <set>
|
||||
|
||||
namespace isc {
|
||||
namespace dhcp {
|
||||
|
||||
/// @brief Represents configuration of the RSOO options for the DHCP server.
|
||||
///
|
||||
/// This class holds the set of RSOO-enabled options (see RFC6422). The list
|
||||
/// of RSOO-enabled options is maintained by IANA and currently the option
|
||||
/// 65 is officially RSSO-enabled. The list may be extended in the future
|
||||
/// and this class allows for specifying any future RSOO-enabled options.
|
||||
/// The administrator may also use existing options as RSOO-enabled.
|
||||
class CfgRSOO {
|
||||
public:
|
||||
|
||||
/// @brief Constructor.
|
||||
///
|
||||
/// It adds the default (officially) RSOO-enabled options:
|
||||
/// - OPTION_ERP_LOCAL_DOMAIN_NAME
|
||||
CfgRSOO();
|
||||
|
||||
/// @brief Removes designation of all options as RSOO_enabled.
|
||||
///
|
||||
/// This method removes all designations of all options as being RSOO-enabled.
|
||||
void clear();
|
||||
|
||||
/// @brief Returns whether specific option code is RSOO-enabled.
|
||||
///
|
||||
/// @param code Option code to check
|
||||
/// @return true, if it is allowed in Relay-Supplied Options option
|
||||
bool enabled(const uint16_t code) const;
|
||||
|
||||
/// @brief Marks specified option code as RSOO-enabled.
|
||||
///
|
||||
/// @param code option to be enabled in RSOO
|
||||
void enable(const uint16_t code);
|
||||
|
||||
private:
|
||||
|
||||
/// @brief Contains a set of options that are allowed in RSOO option
|
||||
///
|
||||
/// RSOO stands for Relay-Supplied Options option. This is an option that
|
||||
/// is inserted by the relay agent with the intention that the server will
|
||||
/// echo those options back to the client. Only those options marked as
|
||||
/// RSOO-enabled may appear in the RSOO. Currently only option 65 is marked
|
||||
/// as such, but more options may be added in the future. See RFC6422 for details.
|
||||
std::set<uint16_t> rsoo_options_;
|
||||
|
||||
};
|
||||
|
||||
/// @name Pointers to the @c CfgRSOO objects.
|
||||
//@{
|
||||
/// @brief Pointer to the Non-const object.
|
||||
typedef boost::shared_ptr<CfgRSOO> CfgRSOOPtr;
|
||||
|
||||
/// @brief Pointer to the const object.
|
||||
typedef boost::shared_ptr<const CfgRSOO> ConstCfgRSOOPtr;
|
||||
|
||||
//@}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // CFG_RSOO_H
|
@@ -29,14 +29,14 @@ SrvConfig::SrvConfig()
|
||||
: sequence_(0), cfg_iface_(new CfgIface()),
|
||||
cfg_option_def_(new CfgOptionDef()), cfg_option_(new CfgOption()),
|
||||
cfg_subnets4_(new CfgSubnets4()), cfg_subnets6_(new CfgSubnets6()),
|
||||
cfg_hosts_(new CfgHosts()) {
|
||||
cfg_hosts_(new CfgHosts()), cfg_rsoo_(new CfgRSOO()) {
|
||||
}
|
||||
|
||||
SrvConfig::SrvConfig(const uint32_t sequence)
|
||||
: sequence_(sequence), cfg_iface_(new CfgIface()),
|
||||
cfg_option_def_(new CfgOptionDef()), cfg_option_(new CfgOption()),
|
||||
cfg_subnets4_(new CfgSubnets4()), cfg_subnets6_(new CfgSubnets6()),
|
||||
cfg_hosts_(new CfgHosts()) {
|
||||
cfg_hosts_(new CfgHosts()), cfg_rsoo_(new CfgRSOO()) {
|
||||
}
|
||||
|
||||
std::string
|
||||
|
@@ -19,6 +19,7 @@
|
||||
#include <dhcpsrv/cfg_iface.h>
|
||||
#include <dhcpsrv/cfg_option.h>
|
||||
#include <dhcpsrv/cfg_option_def.h>
|
||||
#include <dhcpsrv/cfg_rsoo.h>
|
||||
#include <dhcpsrv/cfg_subnets4.h>
|
||||
#include <dhcpsrv/cfg_subnets6.h>
|
||||
#include <dhcpsrv/cfg_mac_source.h>
|
||||
@@ -239,6 +240,24 @@ public:
|
||||
return (cfg_hosts_);
|
||||
}
|
||||
|
||||
/// @brief Returns pointer to the non-const object representing
|
||||
/// set of RSOO-enabled options.
|
||||
///
|
||||
/// @return Pointer to the non-const object holding RSOO-enabled
|
||||
/// options.
|
||||
CfgRSOOPtr getCfgRSOO() {
|
||||
return (cfg_rsoo_);
|
||||
}
|
||||
|
||||
/// @brief Returns pointer to the const object representing set
|
||||
/// of RSOO-enabled options.
|
||||
///
|
||||
/// @return Pointer to the const object holding RSOO-enabled
|
||||
/// options.
|
||||
ConstCfgRSOOPtr getCfgRSOO() const {
|
||||
return (cfg_rsoo_);
|
||||
}
|
||||
|
||||
//@}
|
||||
|
||||
/// @brief Returns non-const reference to an array that stores
|
||||
@@ -371,6 +390,12 @@ private:
|
||||
|
||||
/// @brief A list of configured MAC sources.
|
||||
CfgMACSource cfg_mac_source_;
|
||||
|
||||
/// @brief Pointer to the configuration for RSOO-enabled options.
|
||||
///
|
||||
/// This object holds a set of RSOO-enabled options. See the
|
||||
/// RFC 6422 for the definition of RSOO-enabled option.
|
||||
CfgRSOOPtr cfg_rsoo_;
|
||||
};
|
||||
|
||||
/// @name Pointers to the @c SrvConfig object.
|
||||
|
@@ -64,6 +64,7 @@ libdhcpsrv_unittests_SOURCES += cfg_iface_unittest.cc
|
||||
libdhcpsrv_unittests_SOURCES += cfg_mac_source_unittest.cc
|
||||
libdhcpsrv_unittests_SOURCES += cfg_option_unittest.cc
|
||||
libdhcpsrv_unittests_SOURCES += cfg_option_def_unittest.cc
|
||||
libdhcpsrv_unittests_SOURCES += cfg_rsoo_unittest.cc
|
||||
libdhcpsrv_unittests_SOURCES += cfg_subnets4_unittest.cc
|
||||
libdhcpsrv_unittests_SOURCES += cfg_subnets6_unittest.cc
|
||||
libdhcpsrv_unittests_SOURCES += cfgmgr_unittest.cc
|
||||
|
@@ -477,33 +477,5 @@ TEST(CfgOptionTest, addVendorOptions) {
|
||||
EXPECT_TRUE(options->empty());
|
||||
}
|
||||
|
||||
// This test verifies that Relay-Supplied Options option (RSOO) is handled
|
||||
// properly.
|
||||
TEST(CfgOptionTest, rsoo) {
|
||||
CfgOption cfg;
|
||||
|
||||
// All options from 0..64 are not RSOO-enabled
|
||||
for (uint16_t code = 0; code < D6O_ERP_LOCAL_DOMAIN_NAME; ++code) {
|
||||
EXPECT_FALSE(cfg.isRSOOEnabled(code));
|
||||
}
|
||||
|
||||
// Option 65 is the only one so far that is enabled
|
||||
EXPECT_TRUE(cfg.isRSOOEnabled(D6O_ERP_LOCAL_DOMAIN_NAME));
|
||||
|
||||
// Let's check other options. They should not be enabled.
|
||||
for (uint16_t code = D6O_ERP_LOCAL_DOMAIN_NAME + 1; code < 300; ++code) {
|
||||
EXPECT_FALSE(cfg.isRSOOEnabled(code)) << " for option code " << code;
|
||||
}
|
||||
|
||||
// Let's clear it.
|
||||
cfg.clearRSOO();
|
||||
|
||||
// Now not even option 65 is enabled.
|
||||
EXPECT_FALSE(cfg.isRSOOEnabled(D6O_ERP_LOCAL_DOMAIN_NAME));
|
||||
|
||||
// Should be possible to specify that an option is RSOO-enabled
|
||||
EXPECT_NO_THROW(cfg.addRSOO(200));
|
||||
EXPECT_TRUE(cfg.isRSOOEnabled(200));
|
||||
}
|
||||
|
||||
} // end of anonymous namespace
|
||||
|
99
src/lib/dhcpsrv/tests/cfg_rsoo_unittest.cc
Normal file
99
src/lib/dhcpsrv/tests/cfg_rsoo_unittest.cc
Normal file
@@ -0,0 +1,99 @@
|
||||
// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#include <config.h>
|
||||
#include <dhcp/dhcp6.h>
|
||||
#include <dhcpsrv/cfg_rsoo.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace isc;
|
||||
using namespace isc::dhcp;
|
||||
|
||||
namespace {
|
||||
|
||||
// This test verifies that the RSOO configuration holds the default
|
||||
// RSOO-enabled options.
|
||||
TEST(CfgRSOOTest, defaults) {
|
||||
CfgRSOO rsoo;
|
||||
EXPECT_TRUE(rsoo.enabled(D6O_ERP_LOCAL_DOMAIN_NAME));
|
||||
for (uint16_t code = 0; code < 200; ++code) {
|
||||
if (code != D6O_ERP_LOCAL_DOMAIN_NAME) {
|
||||
EXPECT_FALSE(rsoo.enabled(code))
|
||||
<< "expected that the option with code "
|
||||
<< code << " is by default RSOO-disabled, but"
|
||||
" it is enabled";
|
||||
}
|
||||
}
|
||||
|
||||
// Now, let's see if we can remove the default options.
|
||||
ASSER_NO_THROW(rsoo.clear());
|
||||
EXPECT_FALSE(rsoo.enabled(D6O_ERP_LOCAL_DOMAIN_NAME));
|
||||
|
||||
// Make sure it can be added again.
|
||||
ASSERT_NO_THROW(rsoo.enable(D6O_ERP_LOCAL_DOMAIN_NAME));
|
||||
EXPECT_TRUE(rsoo.enabled(D6O_ERP_LOCAL_DOMAIN_NAME));
|
||||
}
|
||||
|
||||
// This test verifies that it is possible to enable more RSOO options
|
||||
// and later remove all of them.
|
||||
TEST(CfgRSOOTest, enableAndClear) {
|
||||
CfgRSOO rsoo;
|
||||
EXPECT_TRUE(rsoo.enabled(D6O_ERP_LOCAL_DOMAIN_NAME));
|
||||
|
||||
// Enable option 88.
|
||||
ASSERT_FALSE(rsoo.enabled(88));
|
||||
ASSERT_NO_THROW(rsoo.enable(88));
|
||||
EXPECT_TRUE(rsoo.enabled(88));
|
||||
|
||||
// Enable option 89.
|
||||
ASSERT_FALSE(rsoo.enabled(89));
|
||||
ASSERT_NO_THROW(rsoo.enable(89));
|
||||
EXPECT_TRUE(rsoo.enabled(89));
|
||||
|
||||
// Remove them and make sure they have been removed.
|
||||
ASSERT_NO_THROW(rsoo.clear());
|
||||
for (uint16_t code = 0; code < 200; ++code) {
|
||||
EXPECT_FALSE(rsoo.enabled(code))
|
||||
<< "expected that the option with code "
|
||||
<< code << " is RSOO-disabled after clearing"
|
||||
" the RSOO configuration, but it is not";
|
||||
}
|
||||
}
|
||||
|
||||
// This test verfies that the same option may be specified
|
||||
// multiple times and that the code doesn't fail.
|
||||
TEST(CfgRSOOTest, enableTwice) {
|
||||
CfgRSOO rsoo;
|
||||
// By default there should be the default option enabled.
|
||||
// Let's try to enable it again. It should pass.
|
||||
ASSERT_NO_THROW(rsoo.enable(D6O_ERP_LOCAL_DOMAIN_NAME));
|
||||
EXPECT_TRUE(rsoo.enabled(D6O_ERP_LOCAL_DOMAIN_NAME));
|
||||
|
||||
// Enable option 88.
|
||||
ASSERT_FALSE(rsoo.enabled(88));
|
||||
ASSERT_NO_THROW(rsoo.enable(88));
|
||||
EXPECT_TRUE(rsoo.enabled);
|
||||
|
||||
// And enable it again.
|
||||
ASSERT_NO_THROW(rsoo.enabled(88));
|
||||
EXPECT_TRUE(rsoo.enabled(88));
|
||||
|
||||
// Remove all.
|
||||
ASSERT_NO_THROW(rsoo.clear());
|
||||
ASSERT_FALSE(rsoo.enabled(D6O_ERP_LOCAL_DOMAIN_NAME));
|
||||
ASSERT_FALSE(rsoo.enabled(88));
|
||||
}
|
||||
|
||||
} // end of anonymous namespace
|
Reference in New Issue
Block a user