"re-detect": true
},
+ // Option 43 last resort definition can make legal messages to be
+ // rejected because they use not compatible "raw" value.
+ // The option definition can be applied to avoid this problem.
+ "option-def": [ {
+ "name": "vendor-encapsulated-options",
+ "code": 43,
+ "type": "binary"
+ } ],
+
// We need to specify the the database used to store leases. As of
// September 2016, four database backends are supported: MySQL,
// PostgreSQL, Cassandra, and the in-memory database, Memfile.
// In this particular class, we want to set specific values
// of certain DHCPv4 fields. If the incoming packet matches the
// test, those fields will be set in outgoing responses.
+// The option 43 is defined to encapsulate suboption inf the aastra space.
{
"name": "VoIP",
"test": "substring(option[60].hex,0,6) == 'Aastra'",
"next-server": "192.0.2.254",
"server-hostname": "hal9000",
- "boot-file-name": "/dev/null"
+ "boot-file-name": "/dev/null",
+ "option-def": [ {
+ "name": "vendor-encapsulated-options",
+ "code": 43,
+ "type": "empty",
+ "encapsulate": "aastra" } ]
}
],
-// Copyright (C) 2011-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-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
// Null container.
const OptionDefContainerPtr null_option_def_container_(new OptionDefContainer());
+// Option 43 definition.
+OptionDefinitionPtr LibDHCP::last_resort_option43_def;
+
// Those two vendor classes are used for cable modems:
/// DOCSIS3.0 compatible cable modem
runtime_option_defs_.commit();
}
+bool
+LibDHCP::deferOption(const std::string& space, const uint16_t code) {
+ return ((space == DHCP4_OPTION_SPACE) &&
+ ((code == DHO_VENDOR_ENCAPSULATED_OPTIONS) ||
+ ((code >= 224) && (code <= 254))));
+}
+
OptionPtr
LibDHCP::optionFactory(Option::Universe u,
uint16_t type,
num_defs = distance(range.first, range.second);
}
+ // Check if option unpacking must be deferred
+ if (deferOption(option_space, opt_type)) {
+ num_defs = 0;
+ }
+
OptionPtr opt;
if (num_defs > 1) {
// Multiple options of the same code are not supported right now!
LibDHCP::initStdOptionDefs4() {
initOptionSpace(v4option_defs_, STANDARD_V4_OPTION_DEFINITIONS,
STANDARD_V4_OPTION_DEFINITIONS_SIZE);
+ last_resort_option43_def.reset(new OptionDefinition(
+ LAST_RESORT_OPTION43_DEFINITION.name,
+ LAST_RESORT_OPTION43_DEFINITION.code,
+ LAST_RESORT_OPTION43_DEFINITION.type,
+ LAST_RESORT_OPTION43_DEFINITION.array));
}
void
static OptionDefContainerPtr
getRuntimeOptionDefs(const std::string& space);
+ /// @brief Checks if an option unpacking has to be deferred.
+ ///
+ /// DHCPv4 option 43 and 224-254 unpacking is done after classification.
+ ///
+ /// @space Option space name.
+ /// @param code Option code.
+ ///
+ /// @return True if option processing should be deferred.
+ static bool deferOption(const std::string& space, const uint16_t code);
+
+ /// @brief Last resort definition for DHCPv4 option 43
+ static OptionDefinitionPtr last_resort_option43_def;
+
/// @brief Factory function to create instance of option.
///
/// Factory method creates instance of specified option. The option
{ "nis-domain", DHO_NIS_DOMAIN, OPT_STRING_TYPE, false, NO_RECORD_DEF, "" },
{ "nis-servers", DHO_NIS_SERVERS, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF, "" },
{ "ntp-servers", DHO_NTP_SERVERS, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF, "" },
- { "vendor-encapsulated-options", DHO_VENDOR_ENCAPSULATED_OPTIONS,
- OPT_EMPTY_TYPE, false, NO_RECORD_DEF, "vendor-encapsulated-options-space" },
+ /// vendor-encapsulated-options (43) is deferred
{ "netbios-name-servers", DHO_NETBIOS_NAME_SERVERS,
OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF, "" },
{ "netbios-dd-server", DHO_NETBIOS_DD_SERVER,
const int STANDARD_V4_OPTION_DEFINITIONS_SIZE =
sizeof(STANDARD_V4_OPTION_DEFINITIONS) / sizeof(STANDARD_V4_OPTION_DEFINITIONS[0]);
+/// Last resort definition for option 43
+const OptionDefParams LAST_RESORT_OPTION43_DEFINITION = {
+ "vendor-encapsulated-options", DHO_VENDOR_ENCAPSULATED_OPTIONS,
+ OPT_EMPTY_TYPE, false, NO_RECORD_DEF, "vendor-encapsulated-options-space"
+};
+
/// Start Definition of DHCPv6 options
// client-fqdn
ASSERT_EQ(1, addresses.size());
EXPECT_EQ("10.0.0.10", addresses[0].toText());
+#if 0
// Vendor Specific Information option
x = options.find(43);
ASSERT_FALSE(x == options.end());
ASSERT_TRUE(eso);
EXPECT_EQ(0xdc, eso->getType());
EXPECT_EQ(2, eso->len());
+#endif
// Checking DHCP Relay Agent Information Option.
x = options.find(DHO_DHCP_AGENT_OPTIONS);
LibDhcpTest::testStdOptionDefs4(DHO_NTP_SERVERS, begin, end,
typeid(Option4AddrLst));
+#if 0
// The following option requires well formed buffer to be created from.
// Not just a dummy one. This buffer includes some suboptions.
OptionBuffer vendor_opts_buf = createVendorOption();
vendor_opts_buf.end(),
typeid(OptionCustom),
"vendor-encapsulated-options-space");
+#endif
LibDhcpTest::testStdOptionDefs4(DHO_NETBIOS_NAME_SERVERS, begin, end,
typeid(Option4AddrLst));
*match_expr_ = *(rhs.match_expr_);
}
+ if (rhs.cfg_option_def_) {
+ rhs.cfg_option_def_->copyTo(*cfg_option_def_);
+ }
+
if (rhs.cfg_option_) {
rhs.cfg_option_->copyTo(*cfg_option_);
}
test_ = test;
}
+const CfgOptionDefPtr&
+ClientClassDef::getCfgOptionDef() const {
+ return (cfg_option_def_);
+}
+
+void
+ClientClassDef::setCfgOptionDef(const CfgOptionDefPtr& cfg_option_def) {
+ cfg_option_def_ = cfg_option_def;
+}
+
const CfgOptionPtr&
ClientClassDef::getCfgOption() const {
return (cfg_option_);
((!cfg_option_ && !other.cfg_option_) ||
(cfg_option_ && other.cfg_option_ &&
(*cfg_option_ == *other.cfg_option_))) &&
+ ((!cfg_option_def_ && !other.cfg_option_def_) ||
+ (cfg_option_def_ && other.cfg_option_def_ &&
+ (*cfg_option_def_ == *other.cfg_option_def_))) &&
(next_server_ == other.next_server_) &&
(sname_ == other.sname_) &&
(filename_ == other.filename_));
if (!test_.empty()) {
result->set("test", Element::create(test_));
}
+ // Set option-def
+ if (cfg_option_def_) {
+ result->set("option-def", cfg_option_def_->toElement());
+ }
// Set option-data
result->set("option-data", cfg_option_->toElement());
if (family != AF_INET) {
const ExpressionPtr& match_expr,
const std::string& test,
const CfgOptionPtr& cfg_option,
+ CfgOptionDefPtr cfg_option_def,
asiolink::IOAddress next_server,
const std::string& sname,
const std::string& filename) {
ClientClassDefPtr cclass(new ClientClassDef(name, match_expr, cfg_option));
cclass->setTest(test);
+ cclass->setCfgOptionDef(cfg_option_def);
cclass->setNextServer(next_server);
cclass->setSname(sname);
cclass->setFilename(filename);
#include <cc/cfg_to_element.h>
#include <dhcpsrv/cfg_option.h>
+#include <dhcpsrv/cfg_option_def.h>
#include <eval/token.h>
#include <exceptions/exceptions.h>
/// @param test the original expression to assign the class
void setTest(const std::string& test);
+ /// @brief Fetches the class's option definitions
+ const CfgOptionDefPtr& getCfgOptionDef() const;
+
+ /// @brief Sets the class's option definition collection
+ ///
+ /// @param cfg_option_def the option definitions to assign the class
+ void setCfgOptionDef(const CfgOptionDefPtr& cfg_option_def);
+
/// @brief Fetches the class's option collection
const CfgOptionPtr& getCfgOption() const;
/// this class.
std::string test_;
+ /// @brief The option definition configuration for this class
+ CfgOptionDefPtr cfg_option_def_;
+
/// @brief The option data configuration for this class
CfgOptionPtr cfg_option_;
/// @param match_expr Expression the class will use to determine membership
/// @param test Original version of match_expr
/// @param options Collection of options members should be given
+ /// @param defs Option definitions (optional)
/// @param next_server next-server value for this class (optional)
/// @param sname server-name value for this class (optional)
/// @param filename boot-file-name value for this class (optional)
/// others.
void addClass(const std::string& name, const ExpressionPtr& match_expr,
const std::string& test, const CfgOptionPtr& options,
+ CfgOptionDefPtr defs = 0,
asiolink::IOAddress next_server = asiolink::IOAddress("0.0.0.0"),
const std::string& sname = std::string(),
const std::string& filename = std::string());
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <config.h>
+#include <dhcp/libdhcp++.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/client_class_def.h>
#include <dhcpsrv/parsers/dhcp_parsers.h>
test = test_cfg->stringValue();
}
+ // Parse option def
+ CfgOptionDefPtr defs(new CfgOptionDef());
+ ConstElementPtr option_defs = class_def_cfg->get("option-def");
+ if (option_defs) {
+ OptionDefParser parser;
+ BOOST_FOREACH(ConstElementPtr option_def, option_defs->listValue()) {
+ OptionDefinitionTuple def;
+
+ def = parser.parse(option_def);
+ // Verify if the defition is for an option which are
+ // in a deferred processing list.
+ if (!LibDHCP::deferOption(def.second, def.first->getCode())) {
+ isc_throw(DhcpConfigError,
+ "Not allowed option definition for code '"
+ << def.first->getCode() << "' in space '"
+ << def.second << "' at ("
+ << option_def->getPosition() << ")");
+ }
+ try {
+ defs->add(def.first, def.second);
+ } catch (const std::exception& ex) {
+ isc_throw(DhcpConfigError, ex.what() << " ("
+ << option_def->getPosition() << ")");
+ }
+ }
+ }
+
// Parse option data
CfgOptionPtr options(new CfgOption());
ConstElementPtr option_data = class_def_cfg->get("option-data");
// Add the client class definition
try {
class_dictionary->addClass(name, match_expr, test, options,
- next_server, sname, filename);
+ defs, next_server, sname, filename);
} catch (const std::exception& ex) {
isc_throw(DhcpConfigError, "Can't add class: " << ex.what()
<< " (" << class_def_cfg->getPosition() << ")");
///
/// These parsers are used to parse lists of client class definitions
/// into a ClientClassDictionary of ClientClassDef instances. Each
-/// ClientClassDef consists of (at least) a name, an expression, and
-/// option-data. The latter two are currently optional.
+/// ClientClassDef consists of (at least) a name, an expression, option-def
+/// and option-data. Currently only a not empty name is required.
///
/// There parsers defined are:
///
/// -# "test" - a string containing the logical expression used to determine
/// membership in the class. This is passed into the eval parser.
///
+/// -# "option-def" - a list which defines the options which processing
+/// is deferred. This element is optional and parsed using the @ref
+/// isc::dhcp::OptionDefParser. A check is done to verify definitions
+/// are only for deferred processing option (DHCPv4 43 and 224-254).
+///
/// -# "option-data" - a list which defines the options that should be
/// assigned to remembers of the class. This element is optional and parsed
/// using the @ref isc::dhcp::OptionDataListParser.