dhcp_parsers.h 39.8 KB
Newer Older
1
// Copyright (C) 2013-2017 Internet Systems Consortium, Inc. ("ISC")
2
//
3 4 5
// 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
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 7 8 9

#ifndef DHCP_PARSERS_H
#define DHCP_PARSERS_H

10
#include <asiolink/io_address.h>
11 12
#include <cc/data.h>
#include <dhcp/option_definition.h>
13
#include <dhcp/option_space_container.h>
14
#include <dhcpsrv/d2_client_cfg.h>
15
#include <dhcpsrv/cfg_iface.h>
16
#include <dhcpsrv/cfg_option.h>
17
#include <dhcpsrv/subnet.h>
18
#include <dhcpsrv/cfg_option_def.h>
19 20
#include <dhcpsrv/cfg_mac_source.h>
#include <dhcpsrv/srv_config.h>
21
#include <dhcpsrv/parsers/dhcp_config_parser.h>
22
#include <cc/simple_parser.h>
23
#include <hooks/libinfo.h>
24
#include <exceptions/exceptions.h>
25
#include <util/optional_value.h>
26

27 28
#include <boost/shared_ptr.hpp>

29 30 31 32 33 34 35 36 37
#include <stdint.h>
#include <string>
#include <vector>

namespace isc {
namespace dhcp {

/// Collection of containers holding option spaces. Each container within
/// a particular option space holds so-called option descriptors.
38 39
typedef OptionSpaceContainer<OptionContainer, OptionDescriptor,
                             std::string> OptionStorage;
40
/// @brief Shared pointer to option storage.
41 42
typedef boost::shared_ptr<OptionStorage> OptionStoragePtr;

43 44
/// @brief A template class that stores named elements of a given data type.
///
45 46 47 48 49 50 51
/// This template class is provides data value storage for configuration
/// parameters of a given data type.  The values are stored by parameter name
/// and as instances of type "ValueType". Each value held in the storage has
/// a corresponding position within a configuration string (file) specified
/// as a: file name, line number and position within the line. The position
/// information is used for logging when the particular configuration value
/// causes a configuration error.
52
///
53
/// @tparam ValueType is the data type of the elements to store.
54 55
template<typename ValueType>
class ValueStorage {
56 57 58 59 60 61 62 63
public:
    /// @brief  Stores the the parameter, its value and the position in the
    /// store.
    ///
    /// If the parameter does not exist in the store, then it will be added,
    /// otherwise its data value and the position will be updated with the
    /// given values.
    ///
Francis Dupont's avatar
Francis Dupont committed
64
    /// @param name is the name of the parameter to store.
65 66 67 68 69 70 71 72
    /// @param value is the data value to store.
    /// @param position is the position of the data element within a
    /// configuration string (file).
    void setParam(const std::string& name, const ValueType& value,
                  const data::Element::Position& position) {
        values_[name] = value;
        positions_[name] = position;
    }
73

74 75 76 77 78 79
    /// @brief Returns the data value for the given parameter.
    ///
    /// Finds and returns the data value for the given parameter.
    /// @param name is the name of the parameter for which the data
    /// value is desired.
    ///
Francis Dupont's avatar
Francis Dupont committed
80
    /// @return The parameter's data value of type @c ValueType.
81 82 83 84 85 86 87 88
    /// @throw DhcpConfigError if the parameter is not found.
    ValueType getParam(const std::string& name) const {
        typename std::map<std::string, ValueType>::const_iterator param
            = values_.find(name);

        if (param == values_.end()) {
            isc_throw(DhcpConfigError, "Missing parameter '"
                      << name << "'");
89 90
        }

91 92
        return (param->second);
    }
93

94 95 96 97 98 99 100
    /// @brief Returns position of the data element in the configuration string.
    ///
    /// The returned object comprises file name, line number and the position
    /// within the particular line of the configuration string where the data
    /// element holding a particular value is located.
    ///
    /// @param name is the name of the parameter which position is desired.
101 102
    /// @param parent Pointer to a data element which position should be
    /// returned when position of the specified parameter is not found.
103 104 105 106
    ///
    /// @return Position of the data element or the position holding empty
    /// file name and two zeros if the position hasn't been specified for the
    /// particular value.
107 108 109
    const data::Element::Position&
    getPosition(const std::string& name, const data::ConstElementPtr parent =
                data::ConstElementPtr()) const {
110 111 112
        typename std::map<std::string, data::Element::Position>::const_iterator
            pos = positions_.find(name);
        if (pos == positions_.end()) {
113 114
            return (parent ? parent->getPosition() :
                    data::Element::ZERO_POSITION());
115 116
        }

117 118 119 120 121 122 123 124 125 126 127 128
        return (pos->second);
    }

    /// @brief Returns the data value for an optional parameter.
    ///
    /// Finds and returns the data value for the given parameter or
    /// a supplied default value if it is not found.
    ///
    /// @param name is the name of the parameter for which the data
    /// value is desired.
    /// @param default_value value to use the default
    ///
Francis Dupont's avatar
Francis Dupont committed
129
    /// @return The parameter's data value of type @c ValueType.
130 131 132 133 134 135 136
    ValueType getOptionalParam(const std::string& name,
                               const ValueType& default_value) const {
        typename std::map<std::string, ValueType>::const_iterator param
            = values_.find(name);

        if (param == values_.end()) {
            return (default_value);
137 138
        }

139 140 141 142 143 144 145 146
        return (param->second);
    }

    /// @brief  Remove the parameter from the store.
    ///
    /// Deletes the entry for the given parameter from the store if it
    /// exists.
    ///
Francis Dupont's avatar
Francis Dupont committed
147
    /// @param name is the name of the parameter to delete.
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
    void delParam(const std::string& name) {
        values_.erase(name);
        positions_.erase(name);
    }

    /// @brief Deletes all of the entries from the store.
    ///
    void clear() {
        values_.clear();
        positions_.clear();
    }

private:
    /// @brief An std::map of the data values, keyed by parameter names.
    std::map<std::string, ValueType> values_;

    /// @brief An std::map holding positions of the data elements in the
    /// configuration, which values are held in @c values_.
    ///
    /// The position is used for logging, when the particular value
    /// causes a configuration error.
    std::map<std::string, data::Element::Position> positions_;

171 172 173
};


174
/// @brief a collection of elements that store uint32 values
175 176 177 178 179 180 181 182 183 184
typedef ValueStorage<uint32_t> Uint32Storage;
typedef boost::shared_ptr<Uint32Storage> Uint32StoragePtr;

/// @brief a collection of elements that store string values
typedef ValueStorage<std::string> StringStorage;
typedef boost::shared_ptr<StringStorage> StringStoragePtr;

/// @brief Storage for parsed boolean values.
typedef ValueStorage<bool> BooleanStorage;
typedef boost::shared_ptr<BooleanStorage> BooleanStoragePtr;
185 186

/// @brief Container for the current parsing context. It provides a
187
/// single enclosure for the storage of configuration parameters,
188 189 190 191 192 193
/// options, option definitions, and other context specific information
/// that needs to be accessible throughout the parsing and parsing
/// constructs.
class ParserContext {
public:
    /// @brief Constructor
194
    ///
195
    /// @param universe is the Option::Universe value of this
196
    /// context.
197 198 199
    ParserContext(Option::Universe universe);

    /// @brief Copy constructor
200
    ParserContext(const ParserContext& rhs);
201 202 203 204 205 206 207 208 209 210

    /// @brief Storage for boolean parameters.
    BooleanStoragePtr boolean_values_;

    /// @brief Storage for uint32 parameters.
    Uint32StoragePtr uint32_values_;

    /// @brief Storage for string parameters.
    StringStoragePtr string_values_;

Stephen Morris's avatar
Stephen Morris committed
211 212 213 214 215 216 217 218 219 220 221 222
    /// @brief Hooks libraries pointer.
    ///
    /// The hooks libraries information is a vector of strings, each containing
    /// the name of a library.  Hooks libraries should only be reloaded if the
    /// list of names has changed, so the list of current DHCP parameters
    /// (in isc::dhcp::CfgMgr) contains an indication as to whether the list has
    /// altered.  This indication is implemented by storing a pointer to the
    /// list of library names which is cleared when the libraries are loaded.
    /// So either the pointer is null (meaning don't reload the libraries and
    /// the list of current names can be obtained from the HooksManager) or it
    /// is non-null (this is the new list of names, reload the libraries when
    /// possible).
223
    isc::hooks::HookLibsCollectionPtr hooks_libraries_;
Stephen Morris's avatar
Stephen Morris committed
224

225 226
    /// @brief The parsing universe of this context.
    Option::Universe universe_;
227 228 229

    /// @brief Assignment operator
    ParserContext& operator=(const ParserContext& rhs);
230 231 232 233 234 235 236 237 238 239 240 241 242

    /// @brief Copy the context fields.
    ///
    /// This class method initializes the context data by copying the data
    /// stored in the context instance provided as an argument. Note that
    /// this function will also handle copying the NULL pointers.
    ///
    /// @param ctx context to be copied.
    void copyContext(const ParserContext& ctx);

    template<typename T>
    void copyContextPointer(const boost::shared_ptr<T>& source_ptr,
                            boost::shared_ptr<T>& dest_ptr);
243 244
};

245
/// @brief Pointer to various parser context.
246 247
typedef boost::shared_ptr<ParserContext> ParserContextPtr;

248
/// @brief Simple data-type parser template class
249
///
250
/// This is the template class for simple data-type parsers. It supports
251 252 253
/// parsing a configuration parameter with specific data-type for its
/// possible values. It provides a common constructor, commit, and templated
/// data storage.  The "build" method implementation must be provided by a
254
/// declaring type.
Francis Dupont's avatar
Francis Dupont committed
255
/// @param ValueType is the data type of the configuration parameter value
256
/// the parser should handle.
257 258
template<typename ValueType>
class ValueParser : public DhcpConfigParser {
259 260 261 262 263
public:

    /// @brief Constructor.
    ///
    /// @param param_name name of the parameter.
264 265
    /// @param storage is a pointer to the storage container where the parsed
    /// value be stored upon commit.
266 267
    /// @throw isc::dhcp::DhcpConfigError if a provided parameter's
    /// name is empty.
268
    /// @throw isc::dhcp::DhcpConfigError if storage is null.
269
    ValueParser(const std::string& param_name,
270
        boost::shared_ptr<ValueStorage<ValueType> > storage)
271
        : storage_(storage), param_name_(param_name), value_(), pos_() {
272 273 274 275 276 277
        // Empty parameter name is invalid.
        if (param_name_.empty()) {
            isc_throw(isc::dhcp::DhcpConfigError, "parser logic error:"
                << "empty parameter name provided");
        }

Francis Dupont's avatar
Francis Dupont committed
278
        // Null storage is invalid.
279 280 281 282 283 284
        if (!storage_) {
            isc_throw(isc::dhcp::DhcpConfigError, "parser logic error:"
                << "storage may not be NULL");
        }
    }

285
    /// @brief Parse a given element into a value of type @c ValueType
286 287 288
    ///
    /// @param value a value to be parsed.
    ///
289
    /// @throw isc::BadValue Typically the implementing type will throw
290
    /// a BadValue exception when given an invalid Element to parse.
291
    void build(isc::data::ConstElementPtr value);
292 293

    /// @brief Put a parsed value to the storage.
294 295 296
    void commit() {
        // If a given parameter already exists in the storage we override
        // its value. If it doesn't we insert a new element.
297
        storage_->setParam(param_name_, value_, pos_);
298
    }
299

300
private:
301 302 303 304 305 306 307 308 309 310 311 312 313

    /// @brief Performs operations common for all specializations of the
    /// @c build function.
    ///
    /// This method should be called by all specializations of the @c build
    /// method.
    ///
    /// @param value a value being parsed.
    void buildCommon(isc::data::ConstElementPtr value) {
        // Remember position of the data element.
        pos_ = value->getPosition();
    }

314
    /// Pointer to the storage where committed value is stored.
315
    boost::shared_ptr<ValueStorage<ValueType> > storage_;
316

317 318
    /// Name of the parameter which value is parsed with this parser.
    std::string param_name_;
319

320
    /// Parsed value.
321
    ValueType value_;
322 323

    data::Element::Position pos_;
324 325
};

326 327 328 329 330 331
/// @brief typedefs for simple data type parsers
typedef ValueParser<bool> BooleanParser;
typedef ValueParser<uint32_t> Uint32Parser;
typedef ValueParser<std::string> StringParser;

/// @brief a dummy configuration parser
332
///
333 334 335 336 337
/// It is a debugging parser. It does not configure anything,
/// will accept any configuration and will just print it out
/// on commit. Useful for debugging existing configurations and
/// adding new ones.
class DebugParser : public DhcpConfigParser {
338 339
public:

340
    /// @brief Constructor
341
    ///
342 343 344 345
    /// See @ref DhcpConfigParser class for details.
    ///
    /// @param param_name name of the parsed parameter
    DebugParser(const std::string& param_name);
346

347
    /// @brief builds parameter value
348
    ///
349
    /// See @ref DhcpConfigParser class for details.
350
    ///
351 352
    /// @param new_config pointer to the new configuration
    virtual void build(isc::data::ConstElementPtr new_config);
353

354 355 356 357 358 359
    /// @brief pretends to apply the configuration
    ///
    /// This is a method required by base class. It pretends to apply the
    /// configuration, but in fact it only prints the parameter out.
    ///
    /// See @ref DhcpConfigParser class for details.
360 361 362
    virtual void commit();

private:
363
    /// name of the parsed parameter
364 365
    std::string param_name_;

366 367 368
    /// pointer to the actual value of the parameter
    isc::data::ConstElementPtr value_;

369 370
};

Francis Dupont's avatar
Francis Dupont committed
371
/// @brief parser for MAC/hardware acquisition sources
372 373
///
/// This parser handles Dhcp6/mac-sources entry.
Francis Dupont's avatar
Francis Dupont committed
374
/// It contains a list of MAC/hardware acquisition source, i.e. methods how
375 376
/// MAC address can possibly by obtained in DHCPv6. For a currently supported
/// methods, see @ref isc::dhcp::Pkt::getMAC.
377
class MACSourcesListConfigParser : public isc::data::SimpleParser {
378 379 380 381 382 383 384
public:
    /// @brief parses parameters value
    ///
    /// Parses configuration entry (list of sources) and adds each element
    /// to the sources list.
    ///
    /// @param value pointer to the content of parsed values
385
    /// @param mac_sources parsed sources will be stored here
386
    void parse(CfgMACSource& mac_sources, isc::data::ConstElementPtr value);
387 388
};

389 390 391 392
/// @brief Parser for the control-socket structure
///
/// It does not parse anything, simply stores the element in
/// the staging config.
393
class ControlSocketParser : public isc::data::SimpleParser {
394
public:
395 396 397 398 399 400
    /// @brief "Parses" control-socket structure
    ///
    /// Since the SrvConfig structure takes the socket definition
    /// as ConstElementPtr, there's really nothing to parse here.
    /// It only does basic sanity checks and throws DhcpConfigError
    /// if the value is null or is not a map.
401
    ///
402
    /// @param srv_cfg parsed values will be stored here
403
    /// @param value pointer to the content of parsed values
404
    void parse(SrvConfig& srv_cfg, isc::data::ConstElementPtr value);
405
};
406

407
/// @brief Parser for hooks library list
Stephen Morris's avatar
Stephen Morris committed
408 409 410
///
/// This parser handles the list of hooks libraries.  This is an optional list,
/// which may be empty.
411 412 413 414 415 416 417
///
/// However, the parser does more than just check the list of library names.
/// It does two other things:
///
/// -# The problem faced with the hooks libraries is that we wish to avoid
/// reloading the libraries if they have not changed.  (This would cause the
/// "unload" and "load" methods to run.  Although libraries should be written
Francis Dupont's avatar
Francis Dupont committed
418 419
/// to cope with this, it is feasible that such an action may be costly in
/// terms of time and resources, or may cause side effects such as clearing
420 421 422 423 424 425 426
/// an internal cache.)  To this end, the parser also checks the list against
/// the list of libraries current loaded and notes if there are changes.
/// -# If there are, the parser validates the libraries; it opens them and
/// checks that the "version" function exists and returns the correct value.
///
/// Only if the library list has changed and the libraries are valid will the
/// change be applied.
427
class HooksLibrariesParser : public isc::data::SimpleParser {
Stephen Morris's avatar
Stephen Morris committed
428 429
public:

430
    /// @brief Parses parameters value
Stephen Morris's avatar
Stephen Morris committed
431 432
    ///
    /// Parses configuration entry (list of parameters) and adds each element
433
    /// to the hooks libraries list.  The method also checks whether the
434 435 436
    /// list of libraries is the same as that already loaded.  If not, it
    /// checks each of the libraries in the list for validity (they exist and
    /// have a "version" function that returns the correct value).
Stephen Morris's avatar
Stephen Morris committed
437
    ///
Stephen Morris's avatar
Stephen Morris committed
438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
    /// The syntax for specifying hooks libraries allow for library-specific
    /// parameters to be specified along with the library, e.g.
    ///
    /// @code
    ///      "hooks-libraries": [
    ///          {
    ///              "library": "hook-lib-1.so",
    ///              "parameters": {
    ///                  "alpha": "a string",
    ///                  "beta": 42
    ///              }
    ///          },
    ///          :
    ///      ]
    /// @endcode
    ///
454
    /// The parsing code only checks that:
Stephen Morris's avatar
Stephen Morris committed
455 456
    ///
    /// -# Each element in the hooks-libraries list is a map
457 458 459
    /// -# The map contains an element "library" whose value is a not blank string
    /// -# That there is an optional 'parameters' element.
    /// -# That there are no other element.
460 461 462 463 464
    ///
    /// If you want to check whether the library is really present (if the file
    /// is on disk, it is really a library and that it could be loaded), call
    /// @ref verifyLibraries().
    ///
465
    /// This method stores parsed libraries in libraries_.
Stephen Morris's avatar
Stephen Morris committed
466
    ///
Stephen Morris's avatar
Stephen Morris committed
467
    /// @param value pointer to the content of parsed values
468 469
    void parse(isc::data::ConstElementPtr value);

470
    /// @brief Verifies that libraries stored in libraries_ are valid.
471
    ///
472 473
    /// This method is a smart wrapper around @ref
    /// isc::hooks::HooksManager::validateLibraries().
474
    /// It tries to validate all the libraries stored in libraries_.
475
    /// @throw DhcpConfigError if any issue is discovered.
476
    void verifyLibraries();
Stephen Morris's avatar
Stephen Morris committed
477

478 479
    /// @brief Commits hooks libraries data
    ///
480 481 482 483 484 485 486
    /// This method calls necessary methods in HooksManager that will unload
    /// any libraries that may be currently loaded and will load the actual
    /// libraries. Providing that the specified libraries are valid and are
    /// different to those already loaded, this method loads the new set of
    /// libraries (and unloads the existing set).
    ///
    /// @throw DhcpConfigError if the call to HooksManager fails.
487
    void loadLibraries();
Stephen Morris's avatar
Stephen Morris committed
488

489 490 491 492 493 494
    /// @brief Returns list of parsed libraries
    ///
    /// Principally for testing, this returns the list of libraries as well as
    /// an indication as to whether the list is different from the list of
    /// libraries already loaded.
    ///
495
    /// @param [out] libraries List of libraries that were specified in the
496
    ///        new configuration.
497
    void getLibraries(isc::hooks::HookLibsCollection& libraries);
498

Stephen Morris's avatar
Stephen Morris committed
499
private:
500 501
    /// List of hooks libraries with their configuration parameters
    isc::hooks::HookLibsCollection libraries_;
Stephen Morris's avatar
Stephen Morris committed
502

503 504 505
    /// Position of the original element is stored in case we need to report an
    /// error later.
    isc::data::Element::Position position_;
Stephen Morris's avatar
Stephen Morris committed
506
};
507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525

/// @brief Parser for option data value.
///
/// This parser parses configuration entries that specify value of
/// a single option. These entries include option name, option code
/// and data carried by the option. The option data can be specified
/// in one of the two available formats: binary value represented as
/// a string of hexadecimal digits or a list of comma separated values.
/// The format being used is controlled by csv-format configuration
/// parameter. When setting this value to True, the latter format is
/// used. The subsequent values in the CSV format apply to relevant
/// option data fields in the configured option. For example the
/// configuration: "data" : "192.168.2.0, 56, hello world" can be
/// used to set values for the option comprising IPv4 address,
/// integer and string data field. Note that order matters. If the
/// order of values does not match the order of data fields within
/// an option the configuration will not be accepted. If parsing
/// is successful then an instance of an option is created and
/// added to the storage provided by the calling class.
526
class OptionDataParser : public isc::data::SimpleParser {
527 528 529
public:
    /// @brief Constructor.
    ///
530
    /// @param address_family Address family: @c AF_INET or @c AF_INET6.
531
    OptionDataParser(const uint16_t address_family);
532

533
    /// @brief Parses ElementPtr containing option definition
534
    ///
Francis Dupont's avatar
Francis Dupont committed
535
    /// This method parses ElementPtr containing the option definition,
536
    /// instantiates the option for it and then returns a pair
Francis Dupont's avatar
Francis Dupont committed
537
    /// of option descriptor (that holds that new option) and
538
    /// a string that specifies the option space.
539
    ///
540 541
    /// Note: ElementPtr is expected to contain all fields. If your
    /// ElementPtr does not have them, please use
542
    /// @ref isc::data::SimpleParser::setDefaults to fill the missing fields
543 544
    /// with default values.
    ///
Francis Dupont's avatar
Francis Dupont committed
545
    /// @param single_option ElementPtr containing option definition
546 547 548 549
    /// @return Option object wrapped in option description and an option
    ///         space
    std::pair<OptionDescriptor, std::string>
    parse(isc::data::ConstElementPtr single_option);
550
private:
551 552

    /// @brief Finds an option definition within an option space
553
    ///
Francis Dupont's avatar
Francis Dupont committed
554 555
    /// Given an option space and an option code, find the corresponding
    /// option definition within the option definition storage.
556
    ///
557
    /// @param option_space name of the parameter option space
558 559 560 561 562
    /// @param search_key an option code or name to be used to lookup the
    /// option definition.
    /// @tparam A numeric type for searching using an option code or the
    /// string for searching using the option name.
    ///
Francis Dupont's avatar
Francis Dupont committed
563
    /// @return OptionDefinitionPtr of the option definition or an
564
    /// empty OptionDefinitionPtr if not found.
565
    /// @throw DhcpConfigError if the option space requested is not valid
566
    /// for this server.
567 568 569
    template<typename SearchKey>
    OptionDefinitionPtr findOptionDefinition(const std::string& option_space,
                                             const SearchKey& search_key) const;
570 571 572 573 574 575 576

    /// @brief Create option instance.
    ///
    /// Creates an instance of an option and adds it to the provided
    /// options storage. If the option data parsed by \ref build function
    /// are invalid or insufficient this function emits an exception.
    ///
577 578 579
    /// @param option_data An element holding data for a single option being
    /// created.
    ///
580 581
    /// @return created option descriptor
    ///
582 583
    /// @throw DhcpConfigError if parameters provided in the configuration
    /// are invalid.
584 585
    std::pair<OptionDescriptor, std::string>
    createOption(isc::data::ConstElementPtr option_data);
586

587 588 589 590 591 592 593 594
    /// @brief Retrieves parsed option code as an optional value.
    ///
    /// @param parent A data element holding full option data configuration.
    ///
    /// @return Option code, possibly unspecified.
    /// @throw DhcpConfigError if option code is invalid.
    util::OptionalValue<uint32_t>
    extractCode(data::ConstElementPtr parent) const;
595

596 597 598 599 600 601 602 603
    /// @brief Retrieves parsed option name as an optional value.
    ///
    /// @param parent A data element holding full option data configuration.
    ///
    /// @return Option name, possibly unspecified.
    /// @throw DhcpConfigError if option name is invalid.
    util::OptionalValue<std::string>
    extractName(data::ConstElementPtr parent) const;
604

605 606 607
    /// @brief Retrieves csv-format parameter as an optional value.
    ///
    /// @return Value of the csv-format parameter, possibly unspecified.
608
    util::OptionalValue<bool> extractCSVFormat(data::ConstElementPtr parent) const;
609

610 611
    /// @brief Retrieves option data as a string.
    ///
612
    /// @param parent A data element holding full option data configuration.
613 614
    /// @return Option data as a string. It will return empty string if
    /// option data is unspecified.
615
    std::string extractData(data::ConstElementPtr parent) const;
616

617 618 619 620 621 622
    /// @brief Retrieves option space name.
    ///
    /// If option space name is not specified in the configuration the
    /// 'dhcp4' or 'dhcp6' option space name is returned, depending on
    /// the universe specified in the parser context.
    ///
623 624
    /// @param parent A data element holding full option data configuration.
    ///
625
    /// @return Option space name.
626
    std::string extractSpace(data::ConstElementPtr parent) const;
627 628 629

    /// @brief Address family: @c AF_INET or @c AF_INET6.
    uint16_t address_family_;
630 631 632
};

///@brief Function pointer for OptionDataParser factory methods
633
typedef OptionDataParser *OptionDataParserFactory(const std::string&,
634
                     OptionStoragePtr options, ParserContextPtr global_context);
635 636 637 638 639 640 641

/// @brief Parser for option data values within a subnet.
///
/// This parser iterates over all entries that define options
/// data for a particular subnet and creates a collection of options.
/// If parsing is successful, all these options are added to the Subnet
/// object.
642
class OptionDataListParser : public isc::data::SimpleParser {
643 644 645
public:
    /// @brief Constructor.
    ///
646
    /// @param address_family Address family: @c AF_INET or AF_INET6
647
    OptionDataListParser(const uint16_t address_family);
648

649
    /// @brief Parses a list of options, instantiates them and stores in cfg
650
    ///
651 652 653
    /// This method expects to get a list of options in option_data_list,
    /// iterates over them, creates option objects, wraps them with
    /// option descriptor and stores in specified cfg.
654
    ///
655 656 657 658
    /// @param cfg created options will be stored here
    /// @param option_data_list configuration that describes the options
    void parse(const CfgOptionPtr& cfg,
               isc::data::ConstElementPtr option_data_list);
659
private:
660 661
    /// @brief Address family: @c AF_INET or @c AF_INET6
    uint16_t address_family_;
662 663
};

664
typedef std::pair<isc::dhcp::OptionDefinitionPtr, std::string> OptionDefinitionTuple;
665 666 667 668

/// @brief Parser for a single option definition.
///
/// This parser creates an instance of a single option definition.
669
class OptionDefParser : public isc::data::SimpleParser {
670 671 672 673
public:
    /// @brief Parses an entry that describes single option definition.
    ///
    /// @param option_def a configuration entry to be parsed.
674
    /// @return tuple (option definition, option space) of the parsed structure
675 676
    ///
    /// @throw DhcpConfigError if parsing was unsuccessful.
677 678
    OptionDefinitionTuple
    parse(isc::data::ConstElementPtr option_def);
679 680 681 682 683 684 685 686
};

/// @brief Parser for a list of option definitions.
///
/// This parser iterates over all configuration entries that define
/// option definitions and creates instances of these definitions.
/// If the parsing is successful, the collection of created definitions
/// is put into the provided storage.
687
class OptionDefListParser : public isc::data::SimpleParser {
688
public:
Francis Dupont's avatar
Francis Dupont committed
689
    /// @brief Parses a list of option definitions, create them and store in cfg
690
    ///
Francis Dupont's avatar
Francis Dupont committed
691 692
    /// This method iterates over def_list, which is a JSON list of option definitions,
    /// then creates corresponding option definitions and store them in the
693
    /// configuration structure.
694
    ///
695 696 697
    /// @param def_list JSON list describing option definitions
    /// @param cfg parsed option definitions will be stored here
    void parse(CfgOptionDefPtr cfg, isc::data::ConstElementPtr def_list);
698 699 700 701 702 703 704 705 706
};

/// @brief a collection of pools
///
/// That type is used as intermediate storage, when pools are parsed, but there is
/// no subnet object created yet to store them.
typedef std::vector<PoolPtr> PoolStorage;
typedef boost::shared_ptr<PoolStorage> PoolStoragePtr;

707
/// @brief parser for a single pool definition
708 709 710 711 712
///
/// This abstract parser handles pool definitions, i.e. a list of entries of one
/// of two syntaxes: min-max and prefix/len. Pool objects are created
/// and stored in chosen PoolStorage container.
///
713
/// It is useful for parsing Dhcp<4/6>/subnet<4/6>[X]/pools[X] structure.
714 715 716 717
class PoolParser : public DhcpConfigParser {
public:

    /// @brief constructor.
718
    ///
719 720
    /// @param dummy first argument is ignored, all Parser constructors
    /// accept string as first argument.
721 722
    /// @param pools is the storage in which to store the parsed pool
    /// upon "commit".
723
    /// @param address_family AF_INET (for DHCPv4) or AF_INET6 (for DHCPv6).
724
    /// @throw isc::dhcp::DhcpConfigError if storage is null.
725 726
    PoolParser(const std::string& dummy, PoolStoragePtr pools,
               const uint16_t address_family);
727

728
    /// @brief parses the actual structure
729 730 731 732
    ///
    /// This method parses the actual list of interfaces.
    /// No validation is done at this stage, everything is interpreted as
    /// interface name.
733
    /// @param pool_structure a single entry on a list of pools
734
    /// @throw isc::dhcp::DhcpConfigError when pool parsing fails
735
    virtual void build(isc::data::ConstElementPtr pool_structure);
736 737 738 739 740 741 742 743 744 745

    /// @brief Stores the parsed values in a storage provided
    ///        by an upper level parser.
    virtual void commit();

protected:
    /// @brief Creates a Pool object given a IPv4 prefix and the prefix length.
    ///
    /// @param addr is the IP  prefix of the pool.
    /// @param len is the prefix length.
746
    /// @param ptype is the type of pool to create.
747 748
    /// @return returns a PoolPtr to the new Pool object.
    virtual PoolPtr poolMaker(isc::asiolink::IOAddress &addr, uint32_t len,
749 750 751 752 753 754 755 756
                           int32_t ptype=0) = 0;

    /// @brief Creates a Pool object given starting and ending IP addresses.
    ///
    /// @param min is the first IP address in the pool.
    /// @param max is the last IP address in the pool.
    /// @param ptype is the type of pool to create (not used by all derivations)
    /// @return returns a PoolPtr to the new Pool object.
757
    virtual PoolPtr poolMaker(isc::asiolink::IOAddress &min,
758 759 760 761 762 763 764 765 766 767 768
                           isc::asiolink::IOAddress &max, int32_t ptype=0) = 0;

    /// @brief pointer to the actual Pools storage
    ///
    /// That is typically a storage somewhere in Subnet parser
    /// (an upper level parser).
    PoolStoragePtr pools_;

    /// A temporary storage for pools configuration. It is a
    /// storage where pools are stored by build function.
    PoolStorage local_pools_;
769 770 771

    /// A storage for pool specific option values.
    CfgOptionPtr options_;
772 773 774

    /// @brief Address family: AF_INET (for DHCPv4) or AF_INET6 for DHCPv6.
    uint16_t address_family_;
775 776
};

777 778 779 780 781 782 783 784 785 786 787 788 789 790
/// @brief Parser for a list of pools
///
/// This parser parses a list pools. Each element on that list gets its own
/// parser, created with poolParserMaker() method. That method must be specified
/// for each protocol family (v4 or v6) separately.
///
/// This class is not intended to be used directly. Instead, derived classes
/// should implement poolParserMaker() method.
class PoolsListParser :  public DhcpConfigParser {
public:

    /// @brief constructor.
    ///
    /// @param dummy first argument is ignored, all Parser constructors
791
    /// accept a string as the first argument.
792 793 794 795 796 797 798 799 800 801 802 803 804 805
    /// @param pools is the storage in which to store the parsed pool
    /// upon "commit".
    /// @throw isc::dhcp::DhcpConfigError if storage is null.
    PoolsListParser(const std::string& dummy, PoolStoragePtr pools);

    /// @brief parses the actual structure
    ///
    /// This method parses the actual list of pools. It creates a parser
    /// for each structure using poolParserMaker().
    ///
    /// @param pools_list a list of pool structures
    /// @throw isc::dhcp::DhcpConfigError when pool parsing fails
    virtual void build(isc::data::ConstElementPtr pools_list);

806
    /// @brief Stores the parsed values in storage provided
807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823
    ///        by an upper level parser.
    virtual void commit();

protected:

    /// @brief Creates a PoolParser object
    ///
    /// Instantiates appropriate (v4 or v6) PoolParser object.
    /// @param storage parameter that is passed to ParserMaker() constructor.
    virtual ParserPtr poolParserMaker(PoolStoragePtr storage) = 0;

    /// @brief pointer to the actual Pools storage
    ///
    /// That is typically a storage somewhere in Subnet parser
    /// (an upper level parser).
    PoolStoragePtr pools_;

824 825
    /// A temporary storage for pools configuration. It is the
    /// storage where pools are stored by the build function.
826
    PoolStoragePtr local_pools_;
827 828 829

    /// Collection of parsers;
    ParserCollection parsers_;
830 831
};

832 833
/// @brief parser for additional relay information
///
Francis Dupont's avatar
Francis Dupont committed
834
/// This concrete parser handles RelayInfo structure definitions.
835 836 837 838
/// So far that structure holds only relay IP (v4 or v6) address, but it
/// is expected that the number of parameters will increase over time.
///
/// It is useful for parsing Dhcp<4/6>/subnet<4/6>[x]/relay parameters.
839
class RelayInfoParser : public isc::data::SimpleParser {
840 841 842
public:

    /// @brief constructor
Tomek Mrugalski's avatar
Tomek Mrugalski committed
843
    /// @param family specifies protocol family (IPv4 or IPv6)
844
    RelayInfoParser(const isc::dhcp::Option::Universe& family);
845 846

    /// @brief parses the actual relay parameters
Tomek Mrugalski's avatar
Tomek Mrugalski committed
847 848 849 850
    ///
    /// The elements currently supported are:
    /// -# ip-address
    ///
851 852 853 854
    /// @param cfg configuration will be stored here
    /// @param relay_info JSON structure holding relay parameters to parse
    void parse(const isc::dhcp::Subnet::RelayInfoPtr& cfg,
               isc::data::ConstElementPtr relay_info);
Tomek Mrugalski's avatar
Tomek Mrugalski committed
855

856
protected:
Tomek Mrugalski's avatar
Tomek Mrugalski committed
857 858
    /// Protocol family (IPv4 or IPv6)
    Option::Universe family_;
859 860
};

861 862 863 864 865 866 867 868
/// @brief this class parses a single subnet
///
/// This class parses the whole subnet definition. It creates parsers
/// for received configuration parameters as needed.
class SubnetConfigParser : public DhcpConfigParser {
public:

    /// @brief constructor
869 870 871 872 873
    ///
    /// @param global_context
    /// @param default_addr default IP address (0.0.0.0 for IPv4, :: for IPv6)
    SubnetConfigParser(const std::string&, ParserContextPtr global_context,
                       const isc::asiolink::IOAddress& default_addr);
874 875 876 877 878 879

    /// @brief parses parameter value
    ///
    /// @param subnet pointer to the content of subnet definition
    ///
    /// @throw isc::DhcpConfigError if subnet configuration parsing failed.
880
    virtual void build(isc::data::ConstElementPtr subnet);
881 882 883 884 885 886 887

    /// @brief Adds the created subnet to a server's configuration.
    virtual void commit() = 0;

protected:
    /// @brief creates parsers for entries in subnet definition
    ///
Francis Dupont's avatar
Francis Dupont committed
888
    /// @param config_id name of the entry
889 890 891 892 893 894 895 896
    ///
    /// @return parser object for specified entry name
    /// @throw isc::dhcp::DhcpConfigError if trying to create a parser
    ///        for unknown config element
    virtual DhcpConfigParser* createSubnetConfigParser(
                                            const std::string& config_id) = 0;

    /// @brief Issues a server specific warning regarding duplicate subnet
897 898
    /// options.
    ///
899
    /// @param code is the numeric option code of the duplicate option
900
    /// @param addr is the subnet address
901 902
    /// @todo a means to know the correct logger and perhaps a common
    /// message would allow this method to be emitted by the base class.
903
    virtual void duplicate_option_warning(uint32_t code,
904 905
        isc::asiolink::IOAddress& addr) = 0;

906 907 908
    /// @brief Instantiates the subnet based on a given IP prefix and prefix
    /// length.
    ///
909
    /// @param addr is the IP prefix of the subnet.
910
    /// @param len is the prefix length
911 912 913 914 915 916 917 918 919 920 921 922
    virtual void initSubnet(isc::asiolink::IOAddress addr, uint8_t len) = 0;

    /// @brief Returns value for a given parameter (after using inheritance)
    ///
    /// This method implements inheritance. For a given parameter name, it first
    /// checks if there is a global value for it and overwrites it with specific
    /// value if such value was defined in subnet.
    ///
    /// @param name name of the parameter
    /// @return triplet with the parameter name
    /// @throw DhcpConfigError when requested parameter is not present
    isc::dhcp::Triplet<uint32_t> getParam(const std::string& name);
923 924 925 926 927 928 929 930 931 932 933 934

    /// @brief Returns optional value for a given parameter.
    ///
    /// This method checks if an optional parameter has been specified for
    /// a subnet. If not, it will try to use a global value. If the global
    /// value is not specified it will return an object representing an
    /// unspecified value.
    ///
    /// @param name name of the configuration parameter.
    /// @return An optional value or a @c Triplet object representing
    /// unspecified value.
    isc::dhcp::Triplet<uint32_t> getOptionalParam(const std::string& name);
935

Tomek Mrugalski's avatar
Tomek Mrugalski committed
936 937 938 939 940
    /// @brief Attempts to convert text representation to HRMode enum.
    ///
    /// Allowed values are "disabled", "off" (alias for disabled),
    /// "out-of-pool" and "all". See Subnet::HRMode for their exact meaning.
    ///
941 942
    /// @param txt Host Reservation mode in the textual form.
    ///
Tomek Mrugalski's avatar
Tomek Mrugalski committed
943 944 945 946 947
    /// @throw BadValue if the text cannot be converted.
    ///
    /// @return one of allowed HRMode values
    static Subnet::HRMode hrModeFromText(const std::string& txt);

948 949 950 951
private:

    /// @brief Create a new subnet using a data from child parsers.
    ///
952
    /// @throw isc::dhcp::DhcpConfigError if subnet configuration parsing
953 954 955 956 957 958 959
    /// failed.
    void createSubnet();

protected:

    /// Storage for subnet-specific integer values.
    Uint32StoragePtr uint32_values_;
960

961 962
    /// Storage for subnet-specific string values.
    StringStoragePtr string_values_;
963

964 965 966
    /// Storage for subnet-specific boolean values.
    BooleanStoragePtr boolean_values_;

967 968 969 970 971 972 973 974 975
    /// Storage for pools belonging to this subnet.
    PoolStoragePtr pools_;

    /// Parsers are stored here.
    ParserCollection parsers_;

    /// Pointer to the created subnet object.
    isc::dhcp::SubnetPtr subnet_;

976
    /// Parsing context which contains global values, options and option
977 978
    /// definitions.
    ParserContextPtr global_context_;
979 980 981

    /// Pointer to relay information
    isc::dhcp::Subnet::RelayInfoPtr relay_info_;
982 983 984

    /// Pointer to the options configuration.
    CfgOptionPtr options_;
985 986
};

987 988 989
/// @brief Parser for  D2ClientConfig
///
/// This class parses the configuration element "dhcp-ddns" common to the
990
/// config files for both dhcp4 and dhcp6. It creates an instance of a
991
/// D2ClientConfig.
992
class D2ClientConfigParser : public  isc::data::SimpleParser {
993 994
public:

995
    /// @brief Parses a given dhcp-ddns element into D2ClientConfig.