|
@@ -168,157 +168,11 @@ void ControlSocketParser::parse(SrvConfig& srv_cfg, isc::data::ConstElementPtr v
|
|
|
srv_cfg.setControlSocketInfo(value);
|
|
|
}
|
|
|
|
|
|
-// **************************** OptionDataParser *************************
|
|
|
-OptionDataParser::OptionDataParser(const uint16_t address_family)
|
|
|
- : address_family_(address_family) {
|
|
|
-}
|
|
|
-
|
|
|
-std::pair<OptionDescriptor, std::string>
|
|
|
-OptionDataParser::parse(isc::data::ConstElementPtr single_option) {
|
|
|
-
|
|
|
- // Try to create the option instance.
|
|
|
- std::pair<OptionDescriptor, std::string> opt = createOption(single_option);
|
|
|
-
|
|
|
- if (!opt.first.option_) {
|
|
|
- isc_throw(isc::InvalidOperation,
|
|
|
- "parser logic error: no option has been configured and"
|
|
|
- " thus there is nothing to commit. Has build() been called?");
|
|
|
- }
|
|
|
-
|
|
|
- return (opt);
|
|
|
-}
|
|
|
-
|
|
|
-OptionalValue<uint32_t>
|
|
|
-OptionDataParser::extractCode(ConstElementPtr parent) const {
|
|
|
- uint32_t code;
|
|
|
- try {
|
|
|
- code = getInteger(parent, "code");
|
|
|
-
|
|
|
- } catch (const exception&) {
|
|
|
- // The code parameter was not found. Return an unspecified
|
|
|
- // value.
|
|
|
- return (OptionalValue<uint32_t>());
|
|
|
- }
|
|
|
-
|
|
|
- if (code == 0) {
|
|
|
- isc_throw(DhcpConfigError, "option code must not be zero "
|
|
|
- "(" << getPosition("code", parent) << ")");
|
|
|
-
|
|
|
- } else if (address_family_ == AF_INET &&
|
|
|
- code > std::numeric_limits<uint8_t>::max()) {
|
|
|
- isc_throw(DhcpConfigError, "invalid option code '" << code
|
|
|
- << "', it must not be greater than '"
|
|
|
- << static_cast<int>(std::numeric_limits<uint8_t>::max())
|
|
|
- << "' (" << getPosition("code", parent)
|
|
|
- << ")");
|
|
|
-
|
|
|
- } else if (address_family_ == AF_INET6 &&
|
|
|
- code > std::numeric_limits<uint16_t>::max()) {
|
|
|
- isc_throw(DhcpConfigError, "invalid option code '" << code
|
|
|
- << "', it must not exceed '"
|
|
|
- << std::numeric_limits<uint16_t>::max()
|
|
|
- << "' (" << getPosition("code", parent)
|
|
|
- << ")");
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- return (OptionalValue<uint32_t>(code, OptionalValueState(true)));
|
|
|
-}
|
|
|
-
|
|
|
-OptionalValue<std::string>
|
|
|
-OptionDataParser::extractName(ConstElementPtr parent) const {
|
|
|
- std::string name;
|
|
|
- try {
|
|
|
- name = getString(parent, "name");
|
|
|
-
|
|
|
- } catch (...) {
|
|
|
- return (OptionalValue<std::string>());
|
|
|
- }
|
|
|
|
|
|
- if (name.find(" ") != std::string::npos) {
|
|
|
- isc_throw(DhcpConfigError, "invalid option name '" << name
|
|
|
- << "', space character is not allowed ("
|
|
|
- << getPosition("name", parent) << ")");
|
|
|
- }
|
|
|
-
|
|
|
- return (OptionalValue<std::string>(name, OptionalValueState(true)));
|
|
|
-}
|
|
|
|
|
|
-std::string
|
|
|
-OptionDataParser::extractData(ConstElementPtr parent) const {
|
|
|
- std::string data;
|
|
|
- try {
|
|
|
- data = getString(parent, "data");
|
|
|
-
|
|
|
- } catch (...) {
|
|
|
- // The "data" parameter was not found. Return an empty value.
|
|
|
- return (data);
|
|
|
- }
|
|
|
|
|
|
- return (data);
|
|
|
-}
|
|
|
|
|
|
-OptionalValue<bool>
|
|
|
-OptionDataParser::extractCSVFormat(ConstElementPtr parent) const {
|
|
|
- bool csv_format = true;
|
|
|
- try {
|
|
|
- csv_format = getBoolean(parent, "csv-format");
|
|
|
|
|
|
- } catch (...) {
|
|
|
- return (OptionalValue<bool>(csv_format));
|
|
|
- }
|
|
|
-
|
|
|
- return (OptionalValue<bool>(csv_format, OptionalValueState(true)));
|
|
|
-}
|
|
|
-
|
|
|
-std::string
|
|
|
-OptionDataParser::extractSpace(ConstElementPtr parent) const {
|
|
|
- std::string space = address_family_ == AF_INET ?
|
|
|
- DHCP4_OPTION_SPACE : DHCP6_OPTION_SPACE;
|
|
|
- try {
|
|
|
- space = getString(parent, "space");
|
|
|
-
|
|
|
- } catch (...) {
|
|
|
- return (space);
|
|
|
- }
|
|
|
-
|
|
|
- try {
|
|
|
- if (!OptionSpace::validateName(space)) {
|
|
|
- isc_throw(DhcpConfigError, "invalid option space name '"
|
|
|
- << space << "'");
|
|
|
- }
|
|
|
-
|
|
|
- if ((space == DHCP4_OPTION_SPACE) && (address_family_ == AF_INET6)) {
|
|
|
- isc_throw(DhcpConfigError, "'" << DHCP4_OPTION_SPACE
|
|
|
- << "' option space name is reserved for DHCPv4 server");
|
|
|
-
|
|
|
- } else if ((space == DHCP6_OPTION_SPACE) &&
|
|
|
- (address_family_ == AF_INET)) {
|
|
|
- isc_throw(DhcpConfigError, "'" << DHCP6_OPTION_SPACE
|
|
|
- << "' option space name is reserved for DHCPv6 server");
|
|
|
- }
|
|
|
-
|
|
|
- } catch (std::exception& ex) {
|
|
|
- // Append position of the option space parameter.
|
|
|
- isc_throw(DhcpConfigError, ex.what() << " ("
|
|
|
- << getPosition("space", parent) << ")");
|
|
|
- }
|
|
|
-
|
|
|
- return (space);
|
|
|
-}
|
|
|
-
|
|
|
-OptionalValue<bool>
|
|
|
-OptionDataParser::extractPersistent(ConstElementPtr parent) const {
|
|
|
- bool persist = false;
|
|
|
- try {
|
|
|
- persist = getBoolean(parent, "always-send");
|
|
|
-
|
|
|
- } catch (...) {
|
|
|
- return (OptionalValue<bool>(persist));
|
|
|
- }
|
|
|
-
|
|
|
- return (OptionalValue<bool>(persist, OptionalValueState(true)));
|
|
|
-}
|
|
|
|
|
|
template<typename SearchKey>
|
|
|
OptionDefinitionPtr
|
|
@@ -346,163 +200,6 @@ OptionDataParser::findOptionDefinition(const std::string& option_space,
|
|
|
return (def);
|
|
|
}
|
|
|
|
|
|
-std::pair<OptionDescriptor, std::string>
|
|
|
-OptionDataParser::createOption(ConstElementPtr option_data) {
|
|
|
- const Option::Universe universe = address_family_ == AF_INET ?
|
|
|
- Option::V4 : Option::V6;
|
|
|
-
|
|
|
- OptionalValue<uint32_t> code_param = extractCode(option_data);
|
|
|
- OptionalValue<std::string> name_param = extractName(option_data);
|
|
|
- OptionalValue<bool> csv_format_param = extractCSVFormat(option_data);
|
|
|
- OptionalValue<bool> persist_param = extractPersistent(option_data);
|
|
|
- std::string data_param = extractData(option_data);
|
|
|
- std::string space_param = extractSpace(option_data);
|
|
|
-
|
|
|
- // Require that option code or option name is specified.
|
|
|
- if (!code_param.isSpecified() && !name_param.isSpecified()) {
|
|
|
- isc_throw(DhcpConfigError, "option data configuration requires one of"
|
|
|
- " 'code' or 'name' parameters to be specified"
|
|
|
- << " (" << option_data->getPosition() << ")");
|
|
|
- }
|
|
|
-
|
|
|
- // Try to find a corresponding option definition using option code or
|
|
|
- // option name.
|
|
|
- OptionDefinitionPtr def = code_param.isSpecified() ?
|
|
|
- findOptionDefinition(space_param, code_param) :
|
|
|
- findOptionDefinition(space_param, name_param);
|
|
|
-
|
|
|
- // If there is no definition, the user must not explicitly enable the
|
|
|
- // use of csv-format.
|
|
|
- if (!def) {
|
|
|
- // If explicitly requested that the CSV format is to be used,
|
|
|
- // the option definition is a must.
|
|
|
- if (csv_format_param.isSpecified() && csv_format_param) {
|
|
|
- isc_throw(DhcpConfigError, "definition for the option '"
|
|
|
- << space_param << "." << name_param
|
|
|
- << "' having code '" << code_param
|
|
|
- << "' does not exist ("
|
|
|
- << getPosition("name", option_data)
|
|
|
- << ")");
|
|
|
-
|
|
|
- // If there is no option definition and the option code is not specified
|
|
|
- // we have no means to find the option code.
|
|
|
- } else if (name_param.isSpecified() && !code_param.isSpecified()) {
|
|
|
- isc_throw(DhcpConfigError, "definition for the option '"
|
|
|
- << space_param << "." << name_param
|
|
|
- << "' does not exist ("
|
|
|
- << getPosition("name", option_data)
|
|
|
- << ")");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Transform string of hexadecimal digits into binary format.
|
|
|
- std::vector<uint8_t> binary;
|
|
|
- std::vector<std::string> data_tokens;
|
|
|
-
|
|
|
- // If the definition is available and csv-format hasn't been explicitly
|
|
|
- // disabled, we will parse the data as comma separated values.
|
|
|
- if (def && (!csv_format_param.isSpecified() || csv_format_param)) {
|
|
|
- // If the option data is specified as a string of comma
|
|
|
- // separated values then we need to split this string into
|
|
|
- // individual values - each value will be used to initialize
|
|
|
- // one data field of an option.
|
|
|
- // It is the only usage of the escape option: this allows
|
|
|
- // to embed commas in individual values and to return
|
|
|
- // for instance a string value with embedded commas.
|
|
|
- data_tokens = isc::util::str::tokens(data_param, ",", true);
|
|
|
-
|
|
|
- } else {
|
|
|
- // Otherwise, the option data is specified as a string of
|
|
|
- // hexadecimal digits that we have to turn into binary format.
|
|
|
- try {
|
|
|
- // The decodeHex function expects that the string contains an
|
|
|
- // even number of digits. If we don't meet this requirement,
|
|
|
- // we have to insert a leading 0.
|
|
|
- if (!data_param.empty() && ((data_param.length() % 2) != 0)) {
|
|
|
- data_param = data_param.insert(0, "0");
|
|
|
- }
|
|
|
- util::encode::decodeHex(data_param, binary);
|
|
|
- } catch (...) {
|
|
|
- isc_throw(DhcpConfigError, "option data is not a valid"
|
|
|
- << " string of hexadecimal digits: " << data_param
|
|
|
- << " ("
|
|
|
- << getPosition("data", option_data)
|
|
|
- << ")");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- OptionPtr option;
|
|
|
- OptionDescriptor desc(false);
|
|
|
-
|
|
|
- if (!def) {
|
|
|
- // @todo We have a limited set of option definitions initialized at
|
|
|
- // the moment. In the future we want to initialize option definitions
|
|
|
- // for all options. Consequently an error will be issued if an option
|
|
|
- // definition does not exist for a particular option code. For now it is
|
|
|
- // ok to create generic option if definition does not exist.
|
|
|
- OptionPtr option(new Option(universe, static_cast<uint16_t>(code_param),
|
|
|
- binary));
|
|
|
-
|
|
|
- desc.option_ = option;
|
|
|
- desc.persistent_ = persist_param.isSpecified() && persist_param;
|
|
|
- } else {
|
|
|
-
|
|
|
- // Option name is specified it should match the name in the definition.
|
|
|
- if (name_param.isSpecified() && (def->getName() != name_param.get())) {
|
|
|
- isc_throw(DhcpConfigError, "specified option name '"
|
|
|
- << name_param << "' does not match the "
|
|
|
- << "option definition: '" << space_param
|
|
|
- << "." << def->getName() << "' ("
|
|
|
- << getPosition("name", option_data)
|
|
|
- << ")");
|
|
|
- }
|
|
|
-
|
|
|
- // Option definition has been found so let's use it to create
|
|
|
- // an instance of our option.
|
|
|
- try {
|
|
|
- bool use_csv = !csv_format_param.isSpecified() || csv_format_param;
|
|
|
- OptionPtr option = use_csv ?
|
|
|
- def->optionFactory(universe, def->getCode(), data_tokens) :
|
|
|
- def->optionFactory(universe, def->getCode(), binary);
|
|
|
- desc.option_ = option;
|
|
|
- desc.persistent_ = persist_param.isSpecified() && persist_param;
|
|
|
- if (use_csv) {
|
|
|
- desc.formatted_value_ = data_param;
|
|
|
- }
|
|
|
- } catch (const isc::Exception& ex) {
|
|
|
- isc_throw(DhcpConfigError, "option data does not match"
|
|
|
- << " option definition (space: " << space_param
|
|
|
- << ", code: " << def->getCode() << "): "
|
|
|
- << ex.what() << " ("
|
|
|
- << getPosition("data", option_data)
|
|
|
- << ")");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // All went good, so we can set the option space name.
|
|
|
- return make_pair(desc, space_param);
|
|
|
-}
|
|
|
-
|
|
|
-// **************************** OptionDataListParser *************************
|
|
|
-OptionDataListParser::OptionDataListParser(//const std::string&,
|
|
|
- //const CfgOptionPtr& cfg,
|
|
|
- const uint16_t address_family)
|
|
|
- : address_family_(address_family) {
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-void OptionDataListParser::parse(const CfgOptionPtr& cfg,
|
|
|
- isc::data::ConstElementPtr option_data_list) {
|
|
|
- OptionDataParser option_parser(address_family_);
|
|
|
- BOOST_FOREACH(ConstElementPtr data, option_data_list->listValue()) {
|
|
|
- std::pair<OptionDescriptor, std::string> option =
|
|
|
- option_parser.parse(data);
|
|
|
- // Use the option description to keep the formatted value
|
|
|
- cfg->add(option.first, option.second);
|
|
|
- cfg->encapsulate();
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
// ******************************** OptionDefParser ****************************
|
|
|
|
|
|
std::pair<isc::dhcp::OptionDefinitionPtr, std::string>
|