d2_config.h 44.3 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 D2_CONFIG_H
#define D2_CONFIG_H

10
#include <asiolink/io_service.h>
11
#include <cc/data.h>
12
#include <dhcpsrv/parsers/dhcp_parsers.h>
13
#include <dns/tsig.h>
14
#include <exceptions/exceptions.h>
15
#include <process/d_cfg_mgr.h>
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

#include <boost/foreach.hpp>

#include <stdint.h>
#include <string>

namespace isc {
namespace d2 {

/// @file d2_config.h
/// @brief A collection of classes for housing and parsing the application
/// configuration necessary for the DHCP-DDNS application (aka D2).
///
/// This file contains the class declarations for the class hierarchy created
/// from the D2 configuration and the parser classes used to create it.
31 32 33
/// The application configuration consists of a set of scalar parameters,
/// a list of TSIG keys, and two managed lists of domains: one list for
/// forward domains and one list for reverse domains.
34
///
35
/// The key list consists of one or more TSIG keys, each entry described by
36 37
/// a name, the algorithm method name, optionally the minimum truncated
/// length, and its secret key component.
38
///
39
/// @todo  NOTE that TSIG configuration parsing is functional, the use of
40 41 42 43 44
/// TSIG Keys during the actual DNS update transactions is not.  This will be
/// implemented in a future release.
///
/// Each managed domain list consists of a list one or more domains and is
/// represented by the class DdnsDomainListMgr.
45 46
///
/// Each domain consists of a set of scalars parameters and a list of DNS
47 48 49 50
/// servers which support that domain. Among its scalars, is key_name, which
/// is the name of the TSIG Key to use for with this domain.  This value should
/// map to one of the TSIG Keys in the key list.  Domains are represented by
/// the class, DdnsDomain.
51 52 53 54 55
///
/// Each server consists of a set of scalars used to describe the server such
/// that the application can carry out DNS update exchanges with it. Servers
/// are represented by the class, DnsServerInfo.
///
56
/// The configuration specification for use with Kea is detailed in the file
57 58 59 60 61 62 63 64
/// dhcp-ddns.spec.
///
/// The parsing class hierarchy reflects this same scheme.  Working top down:
///
/// A DdnsDomainListMgrParser parses a managed domain list entry. It handles
/// any scalars which belong to the manager as well as creating and invoking a
/// DdnsDomainListParser to parse its list of domain entries.
///
65
/// A DdnsDomainListParser creates and invokes a DdnsDomainParser for each
66 67 68 69 70 71 72 73 74
/// domain entry in its list.
///
/// A DdnsDomainParser handles the scalars which belong to the domain as well as
/// creating and invoking a DnsSeverInfoListParser to parse its list of server
/// entries.
///
/// A DnsServerInfoListParser creates and invokes a DnsServerInfoParser for
/// each server entry in its list.
///
75
/// A DdnsServerInfoParser handles the scalars which belong to the server.
76 77 78 79 80 81
/// The following is sample configuration in JSON form with extra spacing
/// for clarity:
///
/// @code
/// {
///  "interface" : "eth1" ,
82
///  "ip-address" : "192.168.1.33" ,
83
///  "port" : 88 ,
84
///  "tsig-keys":
85 86 87 88 89 90 91
//// [
///    {
///     "name": "d2_key.tmark.org" ,
///     "algorithm": "md5" ,
///     "secret": "0123456989"
///    }
///  ],
92
///  "forward-ddns" :
93
///  {
94
///    "ddns-domains":
95 96 97
///    [
///      {
///        "name": "tmark.org." ,
98 99
///        "key-name": "d2_key.tmark.org" ,
///        "dns-servers" :
100 101 102 103 104 105 106
///        [
///          { "hostname": "fserver.tmark.org" },
///          { "hostname": "f2server.tmark.org" }
///        ]
///      },
///      {
///        "name": "pub.tmark.org." ,
107 108
///        "key-name": "d2_key.tmark.org" ,
///        "dns-servers" :
109 110 111 112 113 114
///        [
///          { "hostname": "f3server.tmark.org" }
///        ]
///      }
///    ]
///  },
115
///  "reverse-ddns" :
116
///  {
117
///    "ddns-domains":
118 119 120
///    [
///      {
///        "name": " 0.168.192.in.addr.arpa." ,
121 122
///        "key-name": "d2_key.tmark.org" ,
///        "dns-servers" :
123
///        [
124
///          { "ip-address": "127.0.0.101" , "port": 100 }
125 126 127 128 129 130
///        ]
///      }
///    ]
///  }
/// }
/// @endcode
131 132 133 134 135 136 137 138 139

/// @brief Exception thrown when the error during configuration handling
/// occurs.
class D2CfgError : public isc::Exception {
public:
    D2CfgError(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) { };
};

140 141 142 143
/// @brief Acts as a storage vault for D2 global scalar parameters
class D2Params {
public:
    /// @brief Default configuration constants.
144
    //@{
145 146 147 148 149 150 151
    /// @todo For now these are hard-coded as configuration layer cannot
    /// readily provide them (see Trac #3358).
    static const char *DFT_IP_ADDRESS;
    static const size_t DFT_PORT;
    static const size_t DFT_DNS_SERVER_TIMEOUT;
    static const char *DFT_NCR_PROTOCOL;
    static const char *DFT_NCR_FORMAT;
152
    //@}
153 154 155

    /// @brief Constructor
    ///
156 157 158 159 160 161 162 163 164 165 166 167 168
    /// @param ip_address IP address at which D2 should listen for NCRs
    /// @param port port on which D2 should listen NCRs
    /// @param dns_server_timeout  maximum amount of time in milliseconds to
    /// wait for a response to a single DNS update request.
    /// @param ncr_protocol socket protocol D2 should use to receive NCRS
    /// @param ncr_format packet format of the inbound NCRs
    ///
    /// @throw D2CfgError if:
    /// -# ip_address is 0.0.0.0 or ::
    /// -# port is 0
    /// -# dns_server_timeout is < 1
    /// -# ncr_protocol is invalid, currently only NCR_UDP is supported
    /// -# ncr_format is invalid, currently only FMT_JSON is supported
169 170
    D2Params(const isc::asiolink::IOAddress& ip_address,
                   const size_t port,
171
                   const size_t dns_server_timeout,
172 173 174 175 176 177 178 179 180 181
                   const dhcp_ddns::NameChangeProtocol& ncr_protocol,
                   const dhcp_ddns::NameChangeFormat& ncr_format);

    /// @brief Default constructor
    /// The default constructor creates an instance that has updates disabled.
    D2Params();

    /// @brief Destructor
    virtual ~D2Params();

182
    /// @brief Return the IP address D2 listens on.
183 184 185 186
    const isc::asiolink::IOAddress& getIpAddress() const {
        return(ip_address_);
    }

187
    /// @brief Return the TCP/UPD port D2 listens on.
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
    size_t getPort() const {
        return(port_);
    }

    /// @brief Return the DNS server timeout value.
    size_t getDnsServerTimeout() const {
        return(dns_server_timeout_);
    }

    /// @brief Return the socket protocol in use.
    const dhcp_ddns::NameChangeProtocol& getNcrProtocol() const {
         return(ncr_protocol_);
    }

    /// @brief Return the expected format of inbound requests (NCRs).
    const dhcp_ddns::NameChangeFormat& getNcrFormat() const {
        return(ncr_format_);
    }

207 208 209 210 211 212 213 214 215
    /// @brief Return summary of the configuration used by D2.
    ///
    /// The returned summary of the configuration is meant to be appended to
    /// the log message informing about the successful completion of the
    /// D2 configuration.
    ///
    /// @return Configuration summary in the textual format.
    std::string getConfigSummary() const;

216
    /// @brief Compares two D2Params's for equality
217 218
    bool operator == (const D2Params& other) const;

219
    /// @brief Compares two D2Params's for inequality
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
    bool operator != (const D2Params& other) const;

    /// @brief Generates a string representation of the class contents.
    std::string toText() const;

protected:
    /// @brief Validates member values.
    ///
    /// Method is used by the constructor to validate member contents.
    /// Currently checks:
    /// -# ip_address is not 0.0.0.0 or ::
    /// -# port is not 0
    /// -# dns_server_timeout is 0
    /// -# ncr_protocol is UDP
    /// -# ncr_format is JSON
    ///
    /// @throw D2CfgError if contents are invalid
    virtual void validateContents();

private:
    /// @brief IP address D2 listens on.
    isc::asiolink::IOAddress ip_address_;

    /// @brief IP port D2 listens on.
    size_t port_;

    /// @brief Timeout for a single DNS packet exchange in milliseconds.
    size_t dns_server_timeout_;

    /// @brief The socket protocol to use.
    /// Currently only UDP is supported.
    dhcp_ddns::NameChangeProtocol ncr_protocol_;

    /// @brief Format of the inbound requests (NCRs).
    /// Currently only JSON format is supported.
    dhcp_ddns::NameChangeFormat ncr_format_;
};

258 259 260
/// @brief Dumps the contents of a D2Params as text to an output stream
///
/// @param os output stream to which text should be sent
261
/// @param config D2Param instance to dump
262 263 264 265 266 267
std::ostream&
operator<<(std::ostream& os, const D2Params& config);

/// @brief Defines a pointer for D2Params instances.
typedef boost::shared_ptr<D2Params> D2ParamsPtr;

268 269
/// @brief Represents a TSIG Key.
///
270 271 272 273 274
/// Acts as both a storage class containing the basic attributes which
/// describe a TSIG Key, as well as owning and providing access to an
/// instance of the actual key (@ref isc::dns::TSIGKey) that can be used
/// by the IO layer for signing and verifying messages.
///
275 276
class TSIGKeyInfo {
public:
277 278
    /// @brief Defines string values for the supported TSIG algorithms
    //@{
279 280 281 282 283 284
    static const char* HMAC_MD5_STR;
    static const char* HMAC_SHA1_STR;
    static const char* HMAC_SHA256_STR;
    static const char* HMAC_SHA224_STR;
    static const char* HMAC_SHA384_STR;
    static const char* HMAC_SHA512_STR;
285
    //}@
286 287 288 289

    /// @brief Constructor
    ///
    /// @param name the unique label used to identify this key
290
    /// @param algorithm the id of the encryption algorithm this key uses.
291
    /// Currently supported values are (case insensitive):
292 293 294 295 296 297
    /// -# "HMAC-MD5"
    /// -# "HMAC-SHA1"
    /// -# "HMAC-SHA224"
    /// -# "HMAC-SHA256"
    /// -# "HMAC-SHA384"
    /// -# "HMAC-SHA512"
298
    ///
299 300 301 302
    /// @param secret  The base-64 encoded secret component for this key.
    /// (A suitable string for use here could be obtained by running the
    /// BIND 9 dnssec-keygen program; the contents of resulting key file
    /// will look similar to:
303 304 305 306 307 308 309 310 311
    /// @code
    ///   Private-key-format: v1.3
    ///   Algorithm: 157 (HMAC_MD5)
    ///   Key: LSWXnfkKZjdPJI5QxlpnfQ==
    ///   Bits: AAA=
    ///   Created: 20140515143700
    ///   Publish: 20140515143700
    ///   Activate: 20140515143700
    /// @endcode
312
    /// where the value the "Key:" entry is the secret component of the key.)
313
    /// @param digestbits the minimum truncated length in bits
314
    ///
315 316
    /// @throw D2CfgError if values supplied are invalid:
    /// name cannot be blank, algorithm must be a supported value,
317
    /// secret must be a non-blank, base64 encoded string.
318
    TSIGKeyInfo(const std::string& name, const std::string& algorithm,
319
                const std::string& secret, uint32_t digestbits = 0);
320 321 322 323 324 325

    /// @brief Destructor
    virtual ~TSIGKeyInfo();

    /// @brief Getter which returns the key's name.
    ///
326
    /// @return returns the name as a std::string.
327 328 329 330
    const std::string getName() const {
        return (name_);
    }

331
    /// @brief Getter which returns the key's algorithm string ID
332
    ///
333
    /// @return returns the algorithm as a std::string.
334 335 336 337
    const std::string getAlgorithm() const {
        return (algorithm_);
    }

338 339 340 341 342 343 344
    /// @brief Getter which returns the key's minimum truncated length
    ///
    /// @return returns the minimum truncated length or 0 as an uint32_t
    uint32_t getDigestbits() const {
        return (digestbits_);
    }

345 346
    /// @brief Getter which returns the key's secret.
    ///
347
    /// @return returns the secret as a std::string.
348 349 350 351
    const std::string getSecret() const {
        return (secret_);
    }

352 353 354 355 356 357 358 359 360 361 362 363
    /// @brief Getter which returns the TSIG key used to sign and verify
    /// messages
    ///
    /// @return const pointer reference to dns::TSIGKey.
    const dns::TSIGKeyPtr& getTSIGKey() const {
        return (tsig_key_);
    }

    /// @brief Converts algorithm id to dns::TSIGKey algorithm dns::Name
    ///
    /// @param algorithm_id string value to translate into an algorithm name.
    /// Currently supported values are (case insensitive):
364 365 366 367 368 369
    /// -# "HMAC-MD5"
    /// -# "HMAC-SHA1"
    /// -# "HMAC-SHA224"
    /// -# "HMAC-SHA256"
    /// -# "HMAC-SHA384"
    /// -# "HMAC-SHA512"
370
    ///
371
    /// @return const reference to a dns::Name containing the algorithm name
372 373 374 375
    /// @throw BadValue if ID isn't recognized.
    static const dns::Name& stringToAlgorithmName(const std::string&
                                                  algorithm_id);

376
private:
377 378 379
    /// @brief Creates the actual TSIG key instance member
    ///
    /// Replaces this tsig_key member with a key newly created using the key
380
    /// name, algorithm id, digest bits, and secret.
381 382 383 384 385 386
    /// This method is currently only called by the constructor, however it
    /// could be called post-construction should keys ever support expiration.
    ///
    /// @throw D2CfgError with an explanation if the key could not be created.
    void remakeKey();

387 388
    /// @brief The name of the key.
    ///
389
    /// This value is the unique identifier that domains use to
390 391 392
    /// to specify which TSIG key they need.
    std::string name_;

393
    /// @brief The string ID of the algorithm that should be used for this key.
394 395
    std::string algorithm_;

396
    /// @brief The base64 encoded string secret value component of this key.
397
    std::string secret_;
398

399 400 401 402
    /// @brief The minimum truncated length in bits
    /// (0 means no truncation is allowed and is the default)
    uint32_t digestbits_;

403 404
    /// @brief The actual TSIG key.
    dns::TSIGKeyPtr tsig_key_;
405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
};

/// @brief Defines a pointer for TSIGKeyInfo instances.
typedef boost::shared_ptr<TSIGKeyInfo> TSIGKeyInfoPtr;

/// @brief Defines a map of TSIGKeyInfos, keyed by the name.
typedef std::map<std::string, TSIGKeyInfoPtr> TSIGKeyInfoMap;

/// @brief Defines a iterator pairing of name and TSIGKeyInfo
typedef std::pair<std::string, TSIGKeyInfoPtr> TSIGKeyInfoMapPair;

/// @brief Defines a pointer to map of TSIGkeyInfos
typedef boost::shared_ptr<TSIGKeyInfoMap> TSIGKeyInfoMapPtr;


420 421 422 423 424 425 426 427 428
/// @brief Represents a specific DNS Server.
/// It provides information about the server's network identity and typically
/// belongs to a list of servers supporting DNS for a given domain. It will
/// be used to establish communications with the server to carry out DNS
/// updates.
class DnsServerInfo {
public:

    /// @brief defines DNS standard port value
429
    static const uint32_t STANDARD_DNS_PORT = 53;
430 431

    /// @brief defines an "empty" string version of an ip address.
432 433
    static const char* EMPTY_IP_STR;

434 435 436 437 438 439 440 441 442 443 444 445 446 447

    /// @brief Constructor
    ///
    /// @param hostname is the resolvable name of the server. If not blank,
    /// then the server address should be resolved at runtime.
    /// @param ip_address is the static IP address of the server. If hostname
    /// is blank, then this address should be used to connect to the server.
    /// @param port is the port number on which the server listens.
    /// primarily meant for testing purposes.  Normally, DNS traffic is on
    /// is port 53. (NOTE the constructing code is responsible for setting
    /// the default.)
    /// @param enabled is a flag that indicates whether this server is
    /// enabled for use. It defaults to true.
    DnsServerInfo(const std::string& hostname,
448
                  isc::asiolink::IOAddress ip_address,
449
                  uint32_t port = STANDARD_DNS_PORT,
450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
                  bool enabled=true);

    /// @brief Destructor
    virtual ~DnsServerInfo();

    /// @brief Getter which returns the server's hostname.
    ///
    /// @return returns the hostname as as std::string.
    const std::string getHostname() const {
        return (hostname_);
    }

    /// @brief Getter which returns the server's port number.
    ///
    /// @return returns the port number as a unsigned integer.
    uint32_t getPort() const {
        return (port_);
    }

    /// @brief Getter which returns the server's ip_address.
    ///
    /// @return returns the address as an IOAddress reference.
    const isc::asiolink::IOAddress& getIpAddress() const {
        return (ip_address_);
    }

    /// @brief Convenience method which returns whether or not the
    /// server is enabled.
    ///
    /// @return returns true if the server is enabled, false otherwise.
    bool isEnabled() const {
        return (enabled_);
    }

    /// @brief Sets the server's enabled flag to true.
    void enable() {
        enabled_ = true;
    }

    /// @brief Sets the server's enabled flag to false.
    void disable() {
        enabled_ = false;
    }

494 495 496
    /// @brief Returns a text representation for the server.
    std::string toText() const;

497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514

private:
    /// @brief The resolvable name of the server. If not blank, then the
    /// server's IP address should be dynamically resolved at runtime.
    std::string hostname_;

    /// @brief The static IP address of the server. When hostname is blank,
    /// then this address should be used to connect to the server.
    isc::asiolink::IOAddress ip_address_;

    /// @brief The port number on which the server listens for DNS traffic.
    uint32_t port_;

    /// @param enabled is a flag that indicates whether this server is
    /// enabled for use. It defaults to true.
    bool enabled_;
};

515 516 517
std::ostream&
operator<<(std::ostream& os, const DnsServerInfo& server);

518 519 520 521 522 523 524 525 526 527 528 529 530 531
/// @brief Defines a pointer for DnsServerInfo instances.
typedef boost::shared_ptr<DnsServerInfo> DnsServerInfoPtr;

/// @brief Defines a storage container for DnsServerInfo pointers.
typedef std::vector<DnsServerInfoPtr> DnsServerInfoStorage;

/// @brief Defines a pointer to DnsServerInfo storage containers.
typedef boost::shared_ptr<DnsServerInfoStorage> DnsServerInfoStoragePtr;


/// @brief Represents a DNS domain that is may be updated dynamically.
/// This class specifies a DNS domain and the list of DNS servers that support
/// it.  It's primary use is to map a domain to the DNS server(s) responsible
/// for it.
532
/// @todo Currently the name entry for a domain is just an std::string. It
533 534
/// may be worthwhile to change this to a dns::Name for purposes of better
/// validation and matching capabilities.
535 536 537 538 539 540
class DdnsDomain {
public:
    /// @brief Constructor
    ///
    /// @param name is the domain name of the domain.
    /// @param servers is the list of server(s) supporting this domain.
541
    /// @param tsig_key_info pointer to the TSIGKeyInfo for the domain's key
542 543 544 545
    /// It defaults to an empty pointer, signifying the domain has no key.
    DdnsDomain(const std::string& name,
               DnsServerInfoStoragePtr servers,
               const TSIGKeyInfoPtr& tsig_key_info = TSIGKeyInfoPtr());
546 547 548 549 550 551 552 553 554 555 556

    /// @brief Destructor
    virtual ~DdnsDomain();

    /// @brief Getter which returns the domain's name.
    ///
    /// @return returns the name in an std::string.
    const std::string getName() const {
        return (name_);
    }

557
    /// @brief Convenience method which returns the domain's TSIG key name.
558
    ///
559 560 561
    /// @return returns the key name in an std::string. If domain has no
    /// TSIG key, the string will empty.
    const std::string getKeyName() const;
562 563 564 565 566 567 568 569

    /// @brief Getter which returns the domain's list of servers.
    ///
    /// @return returns the pointer to the server storage.
    const DnsServerInfoStoragePtr& getServers() {
        return (servers_);
    }

570 571 572 573
    /// @brief Getter which returns the domain's TSIGKey info
    ///
    /// @return returns the pointer to the server storage.  If the domain
    /// is not configured to use TSIG the pointer will be empty.
574 575 576 577
    const TSIGKeyInfoPtr& getTSIGKeyInfo() {
        return (tsig_key_info_);
    }

578 579 580 581 582 583
private:
    /// @brief The domain name of the domain.
    std::string name_;

    /// @brief The list of server(s) supporting this domain.
    DnsServerInfoStoragePtr servers_;
584

585 586
    /// @brief Pointer to domain's the TSIGKeyInfo.
    /// Value is empty if the domain is not configured for TSIG.
587
    TSIGKeyInfoPtr tsig_key_info_;
588 589 590 591 592
};

/// @brief Defines a pointer for DdnsDomain instances.
typedef boost::shared_ptr<DdnsDomain> DdnsDomainPtr;

593 594
/// @brief Defines a map of DdnsDomains, keyed by the domain name.
typedef std::map<std::string, DdnsDomainPtr> DdnsDomainMap;
595

596 597
/// @brief Defines a iterator pairing domain name and DdnsDomain
typedef std::pair<std::string, DdnsDomainPtr> DdnsDomainMapPair;
598

599 600
/// @brief Defines a pointer to DdnsDomain storage containers.
typedef boost::shared_ptr<DdnsDomainMap> DdnsDomainMapPtr;
601 602 603 604 605 606

/// @brief Provides storage for and management of a list of DNS domains.
/// In addition to housing the domain list storage, it provides domain matching
/// services.  These services are used to match a FQDN to a domain.  Currently
/// it supports a single matching service, which will return the matching
/// domain or a wild card domain if one is specified.  The wild card domain is
607 608 609 610 611
/// specified as a domain whose name is "*".  The wild card domain will match
/// any entry and is provided for flexibility in FQDNs  If for instance, all
/// forward requests are handled by the same servers, the configuration could
/// specify the wild card domain as the only forward domain. All forward DNS
/// updates would be sent to that one list of servers, regardless of the FQDN.
612 613 614
/// As matching capabilities evolve this class is expected to expand.
class DdnsDomainListMgr {
public:
615 616 617
    /// @brief defines the domain name for denoting the wildcard domain.
    static const char* wildcard_domain_name_;

618 619 620 621 622 623 624 625 626 627 628 629 630 631 632
    /// @brief Constructor
    ///
    /// @param name is an arbitrary label assigned to this manager.
    DdnsDomainListMgr(const std::string& name);

    /// @brief Destructor
    virtual ~DdnsDomainListMgr ();

    /// @brief Matches a given name to a domain based on a longest match
    /// scheme.
    ///
    /// Given a FQDN, search the list of domains, successively removing a
    /// sub-domain from the FQDN until a match is found.  If no match is found
    /// and the wild card domain is present in the list, then return it as the
    /// match.  If the wild card domain is the only domain in the list, then
633
    /// it will be returned immediately for any FQDN.
634 635
    ///
    /// @param fqdn is the name for which to look.
636 637
    /// @param domain receives the matching domain. If no match is found its
    /// contents will be unchanged.
638 639
    ///
    /// @return returns true if a match is found, false otherwise.
640 641 642 643
    /// @todo This is a very basic match method, which expects valid FQDNs
    /// both as input and for the DdnsDomain::getName().  Currently both are
    /// simple strings and there is no normalization (i.e. added trailing dots
    /// if missing).
644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670
    virtual bool matchDomain(const std::string& fqdn, DdnsDomainPtr& domain);

    /// @brief Fetches the manager's name.
    ///
    /// @return returns a std::string containing the name of the manager.
    const std::string getName() const {
        return (name_);
    }

    /// @brief Returns the number of domains in the domain list.
    ///
    /// @brief returns an unsigned int containing the domain count.
    uint32_t size() const {
        return (domains_->size());
    }

    /// @brief Fetches the wild card domain.
    ///
    /// @return returns a pointer reference to the domain.  The pointer will
    /// empty if the wild card domain is not present.
    const DdnsDomainPtr& getWildcardDomain() {
        return (wildcard_domain_);
    }

    /// @brief Fetches the domain list.
    ///
    /// @return returns a pointer reference to the list of domains.
671
    const DdnsDomainMapPtr &getDomains() {
672 673 674 675 676 677
        return (domains_);
    }

    /// @brief Sets the manger's domain list to the given list of domains.
    /// This method will scan the inbound list for the wild card domain and
    /// set the internal wild card domain pointer accordingly.
678
    void setDomains(DdnsDomainMapPtr domains);
679 680 681 682 683

private:
    /// @brief An arbitrary label assigned to this manager.
    std::string name_;

684 685
    /// @brief Map of the domains, keyed by name.
    DdnsDomainMapPtr domains_;
686 687 688 689 690 691 692 693 694

    /// @brief Pointer to the wild card domain.
    DdnsDomainPtr wildcard_domain_;
};

/// @brief Defines a pointer for DdnsDomain instances.
typedef boost::shared_ptr<DdnsDomainListMgr> DdnsDomainListMgrPtr;

/// @brief Storage container for scalar configuration parameters.
695
///
696 697
/// This class is useful for implementing parsers for more complex configuration
/// elements (e.g. those of item type "map").  It provides a convenient way to
698
/// add storage to the parser for an arbitrary number and variety of scalar
699 700
/// configuration items (e.g. ints, bools, strings...) without explicitly adding
/// storage for each individual type needed by the parser.
701 702 703
///
/// This class implements a concrete version of the base class by supplying a
/// "clone" method.
704
class DScalarContext : public process::DCfgContextBase {
705 706 707 708 709 710 711 712 713 714 715 716
public:

    /// @brief Constructor
    DScalarContext() {
    };

    /// @brief Destructor
    virtual ~DScalarContext() {
    }

    /// @brief Creates a clone of a DStubContext.
    ///
717
    /// @return returns a pointer to the new clone.
718 719
    virtual process::DCfgContextBasePtr clone() {
        return (process::DCfgContextBasePtr(new DScalarContext(*this)));
720 721 722 723
    }

protected:
    /// @brief Copy constructor
724
    DScalarContext(const DScalarContext& rhs) : DCfgContextBase(rhs) {
725 726 727 728 729 730 731
    }

private:
    /// @brief Private assignment operator, not implemented.
    DScalarContext& operator=(const DScalarContext& rhs);
};

732 733 734
/// @brief Defines a pointer for DScalarContext instances.
typedef boost::shared_ptr<DScalarContext> DScalarContextPtr;

735 736
/// @brief Parser for  TSIGKeyInfo
///
737
/// This class parses the configuration element "tsig-key" defined in
738 739 740 741 742 743 744 745
/// src/bin/d2/dhcp-ddns.spec and creates an instance of a TSIGKeyInfo.
class TSIGKeyInfoParser : public  isc::dhcp::DhcpConfigParser {
public:
    /// @brief Constructor
    ///
    /// @param entry_name is an arbitrary label assigned to this configuration
    /// definition. Since servers are specified in a list this value is likely
    /// be something akin to "key:0", set during parsing.
746
    /// @param keys is a pointer to the storage area to which the parser
747 748 749 750 751 752
    /// should commit the newly created TSIGKeyInfo instance.
    TSIGKeyInfoParser(const std::string& entry_name, TSIGKeyInfoMapPtr keys);

    /// @brief Destructor
    virtual ~TSIGKeyInfoParser();

753
    /// @brief Performs the actual parsing of the given  "tsig-key" element.
754
    ///
755 756 757
    /// Parses a configuration for the elements needed to instantiate a
    /// TSIGKeyInfo, validates those entries, creates a TSIGKeyInfo instance
    /// then attempts to add to a list of keys
758
    ///
759
    /// @param key_config is the "tsig-key" configuration to parse
760 761
    virtual void build(isc::data::ConstElementPtr key_config);

762
    /// @brief Creates a parser for the given "tsig-key" member element id.
763 764 765 766
    ///
    /// The key elements currently supported are(see dhcp-ddns.spec):
    ///   1. name
    ///   2. algorithm
767 768
    ///   3. digestbits
    ///   4. secret
769 770
    ///
    /// @param config_id is the "item_name" for a specific member element of
771
    /// the "tsig-key" specification.
772 773
    /// @param pos position within the configuration text (or file) of element
    /// to be parsed.  This is passed for error messaging.
774 775
    ///
    /// @return returns a pointer to newly created parser.
776 777 778 779 780 781 782
    ///
    /// @throw D2CfgError if configuration contains an unknown parameter
    virtual isc::dhcp::ParserPtr
    createConfigParser(const std::string& config_id,
                       const isc::data::Element::Position& pos =
                       isc::data::Element::ZERO_POSITION());

783
    /// @brief Commits the TSIGKeyInfo configuration
784 785
    /// Currently this method is a NOP, as the key instance is created and
    /// then added to a local list of keys in build().
786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805
    virtual void commit();

private:
    /// @brief Arbitrary label assigned to this parser instance.
    /// Since servers are specified in a list this value is likely be something
    /// akin to "key:0", set during parsing.  Primarily here for diagnostics.
    std::string entry_name_;

    /// @brief Pointer to the storage area to which the parser should commit
    /// the newly created TSIGKeyInfo instance. This is given to us as a
    /// constructor argument by an upper level.
    TSIGKeyInfoMapPtr keys_;

    /// @brief Local storage area for scalar parameter values. Use to hold
    /// data until time to commit.
    DScalarContext local_scalars_;
};

/// @brief Parser for a list of TSIGKeyInfos
///
806
/// This class parses a list of "tsig-key" configuration elements.
807 808 809 810 811 812 813 814 815 816 817 818 819 820 821
/// (see src/bin/d2/dhcp-ddns.spec). The TSIGKeyInfo instances are added
/// to the given storage upon commit.
class TSIGKeyInfoListParser : public isc::dhcp::DhcpConfigParser {
public:

    /// @brief Constructor
    ///
    /// @param list_name is an arbitrary label assigned to this parser instance.
    /// @param keys is a pointer to the storage area to which the parser
    /// should commit the newly created TSIGKeyInfo instance.
    TSIGKeyInfoListParser(const std::string& list_name, TSIGKeyInfoMapPtr keys);

    /// @brief Destructor
    virtual ~TSIGKeyInfoListParser();

822
    /// @brief Performs the parsing of the given list "tsig-key" elements.
823 824 825 826 827 828 829 830 831 832 833 834
    ///
    /// It iterates over each key entry in the list:
    ///   1. Instantiate a TSIGKeyInfoParser for the entry
    ///   2. Pass the element configuration to the parser's build method
    ///   3. Add the parser instance to local storage
    ///
    /// The net effect is to parse all of the key entries in the list
    /// prepping them for commit.
    ///
    /// @param key_list_config is the list of "tsig_key" elements to parse.
    virtual void build(isc::data::ConstElementPtr key_list_config);

835
    /// @brief Commits the list of TSIG keys
836 837
    ///
    /// Iterates over the internal list of TSIGKeyInfoParsers, invoking
838 839
    /// commit on each one.  Then commits the local list of keys to
    /// storage.
840 841 842 843 844 845 846 847 848 849
    virtual void commit();

private:
    /// @brief Arbitrary label assigned to this parser instance.
    std::string list_name_;

    /// @brief Pointer to the storage area to which the parser should commit
    /// the list of newly created TSIGKeyInfo instances. This is given to us
    /// as a constructor argument by an upper level.
    TSIGKeyInfoMapPtr keys_;
850

851 852
    /// @brief Local storage area to which individual key parsers commit.
    TSIGKeyInfoMapPtr local_keys_;
853 854 855 856 857

    /// @brief Local storage of TSIGKeyInfoParser instances
    isc::dhcp::ParserCollection parsers_;
};

858 859
/// @brief Parser for  DnsServerInfo
///
860
/// This class parses the configuration element "dns-server" defined in
861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876
/// src/bin/d2/dhcp-ddns.spec and creates an instance of a DnsServerInfo.
class DnsServerInfoParser : public  isc::dhcp::DhcpConfigParser {
public:
    /// @brief Constructor
    ///
    /// @param entry_name is an arbitrary label assigned to this configuration
    /// definition. Since servers are specified in a list this value is likely
    /// be something akin to "server:0", set during parsing.
    /// @param servers is a pointer to the storage area to which the parser
    /// should commit the newly created DnsServerInfo instance.
    DnsServerInfoParser(const std::string& entry_name,
                        DnsServerInfoStoragePtr servers);

    /// @brief Destructor
    virtual ~DnsServerInfoParser();

877
    /// @brief Performs the actual parsing of the given  "dns-server" element.
878 879 880 881
    ///
    /// Parses a configuration for the elements needed to instantiate a
    /// DnsServerInfo, validates those entries, creates a DnsServerInfo instance
    /// then attempts to add to a list of  servers.
882
    ///
883
    /// @param server_config is the "dns-server" configuration to parse
884 885 886 887 888
    ///
    /// @throw D2CfgError if:
    /// -# hostname is not blank, hostname is not yet supported
    /// -# ip_address is invalid
    /// -# port is 0
889 890
    virtual void build(isc::data::ConstElementPtr server_config);

891
    /// @brief Creates a parser for the given "dns-server" member element id.
892 893 894 895
    ///
    /// The server elements currently supported are(see dhcp-ddns.spec):
    ///   1. hostname
    ///   2. ip_address
896
    ///   3. port
897 898
    ///
    /// @param config_id is the "item_name" for a specific member element of
899
    /// the "dns-server" specification.
900 901
    /// @param pos position within the configuration text (or file) of element
    /// to be parsed.  This is passed for error messaging.
902 903
    ///
    /// @return returns a pointer to newly created parser.
904 905 906 907 908 909
    ///
    /// @throw D2CfgError if configuration contains an unknown parameter
    virtual isc::dhcp::ParserPtr
    createConfigParser(const std::string& config_id,
                       const isc::data::Element::Position& =
                       isc::data::Element::ZERO_POSITION());
910

911
    /// @brief Commits the configured DnsServerInfo
912 913
    /// Currently this method is a NOP, as the server instance is created and
    /// then added to the list of servers in build().
914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933
    virtual void commit();

private:
    /// @brief Arbitrary label assigned to this parser instance.
    /// Since servers are specified in a list this value is likely be something
    /// akin to "server:0", set during parsing.  Primarily here for diagnostics.
    std::string entry_name_;

    /// @brief Pointer to the storage area to which the parser should commit
    /// the newly created DnsServerInfo instance. This is given to us as a
    /// constructor argument by an upper level.
    DnsServerInfoStoragePtr servers_;

    /// @brief Local storage area for scalar parameter values. Use to hold
    /// data until time to commit.
    DScalarContext local_scalars_;
};

/// @brief Parser for a list of DnsServerInfos
///
934
/// This class parses a list of "dns-server" configuration elements.
935 936 937 938 939 940 941 942 943 944 945
/// (see src/bin/d2/dhcp-ddns.spec). The DnsServerInfo instances are added
/// to the given storage upon commit.
class DnsServerInfoListParser : public isc::dhcp::DhcpConfigParser {
public:

    /// @brief Constructor
    ///
    /// @param list_name is an arbitrary label assigned to this parser instance.
    /// @param servers is a pointer to the storage area to which the parser
    /// should commit the newly created DnsServerInfo instance.
    DnsServerInfoListParser(const std::string& list_name,
946
                            DnsServerInfoStoragePtr servers);
947 948 949 950

    /// @brief Destructor
    virtual ~DnsServerInfoListParser();

951
    /// @brief Performs the actual parsing of the given list "dns-server"
952 953 954 955 956 957 958 959 960
    /// elements.
    /// It iterates over each server entry in the list:
    ///   1. Instantiate a DnsServerInfoParser for the entry
    ///   2. Pass the element configuration to the parser's build method
    ///   3. Add the parser instance to local storage
    ///
    /// The net effect is to parse all of the server entries in the list
    /// prepping them for commit.
    ///
961
    /// @param server_list_config is the list of "dns-server" elements to parse.
962 963
    virtual void build(isc::data::ConstElementPtr server_list_config);

964
    /// @brief Commits the list of DnsServerInfos
965 966 967
    ///
    /// Iterates over the internal list of DdnsServerInfoParsers, invoking
    /// commit on each one.
968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984
    virtual void commit();

private:
    /// @brief Arbitrary label assigned to this parser instance.
    std::string list_name_;

    /// @brief Pointer to the storage area to which the parser should commit
    /// the list of newly created DnsServerInfo instances. This is given to us
    /// as a constructor argument by an upper level.
    DnsServerInfoStoragePtr servers_;

    /// @brief Local storage of DnsServerInfoParser instances
    isc::dhcp::ParserCollection parsers_;
};

/// @brief Parser for  DdnsDomain
///
985
/// This class parses the configuration element "ddns-domain" defined in
986 987 988 989 990 991 992
/// src/bin/d2/dhcp-ddns.spec and creates an instance of a DdnsDomain.
class DdnsDomainParser : public isc::dhcp::DhcpConfigParser {
public:
    /// @brief Constructor
    ///
    /// @param entry_name is an arbitrary label assigned to this configuration
    /// definition. Since domains are specified in a list this value is likely
993
    /// be something akin to "forward-ddns:0", set during parsing.
994
    /// @param domains is a pointer to the storage area to which the parser
995
    /// @param keys is a pointer to a map of the defined TSIG keys.
996
    /// should commit the newly created DdnsDomain instance.
997 998
    DdnsDomainParser(const std::string& entry_name, DdnsDomainMapPtr domains,
                     TSIGKeyInfoMapPtr keys);
999 1000 1001 1002

    /// @brief Destructor
    virtual ~DdnsDomainParser();

1003
    /// @brief Performs the actual parsing of the given  "ddns-domain" element.
1004 1005 1006 1007
    ///
    /// Parses a configuration for the elements needed to instantiate a
    /// DdnsDomain, validates those entries, creates a DdnsDomain instance
    /// then attempts to add it to a list of domains.
1008
    ///
1009
    /// @param domain_config is the "ddns-domain" configuration to parse
1010 1011
    virtual void build(isc::data::ConstElementPtr domain_config);

1012
    /// @brief Creates a parser for the given "ddns-domain" member element id.
1013 1014 1015 1016 1017 1018 1019
    ///
    /// The domain elements currently supported are(see dhcp-ddns.spec):
    ///   1. name
    ///   2. key_name
    ///   3. dns_servers
    ///
    /// @param config_id is the "item_name" for a specific member element of
1020
    /// the "ddns-domain" specification.
1021 1022
    /// @param pos position within the configuration text (or file) of element
    /// to be parsed.  This is passed for error messaging.
1023 1024
    ///
    /// @return returns a pointer to newly created parser.
1025 1026 1027 1028 1029 1030
    ///
    /// @throw D2CfgError if configuration contains an unknown parameter
    virtual isc::dhcp::ParserPtr
    createConfigParser(const std::string& config_id,
                       const isc::data::Element::Position& pos =
                       isc::data::Element::ZERO_POSITION());
1031

1032
    /// @brief Commits the configured DdnsDomain
1033 1034
    /// Currently this method is a NOP, as the domain instance is created and
    /// then added to the list of domains in build().
1035 1036 1037 1038 1039 1040 1041 1042 1043 1044
    virtual void commit();

private:

    /// @brief Arbitrary label assigned to this parser instance.
    std::string entry_name_;

    /// @brief Pointer to the storage area to which the parser should commit
    /// the newly created DdnsDomain instance. This is given to us as a
    /// constructor argument by an upper level.
1045 1046 1047 1048 1049 1050 1051
    DdnsDomainMapPtr domains_;

    /// @brief Pointer to the map of defined TSIG keys.
    /// This map is passed into us and contains all of the TSIG keys defined
    /// for this configuration.  It is used to validate the key name entry of
    /// DdnsDomains that specify one.
    TSIGKeyInfoMapPtr keys_;
1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065

    /// @brief Local storage for DnsServerInfo instances. This is passed into
    /// DnsServerInfoListParser(s), which in turn passes it into each
    /// DnsServerInfoParser.  When the DnsServerInfoParsers "commit" they add
    /// their server instance to this storage.
    DnsServerInfoStoragePtr local_servers_;

    /// @brief Local storage area for scalar parameter values. Use to hold
    /// data until time to commit.
    DScalarContext local_scalars_;
};

/// @brief Parser for a list of DdnsDomains
///
1066
/// This class parses a list of "ddns-domain" configuration elements.
1067 1068 1069 1070 1071 1072 1073 1074 1075
/// (see src/bin/d2/dhcp-ddns.spec). The DdnsDomain instances are added
/// to the given storage upon commit.
class DdnsDomainListParser : public isc::dhcp::DhcpConfigParser {
public:

    /// @brief Constructor
    ///
    /// @param list_name is an arbitrary label assigned to this parser instance.
    /// @param domains is a pointer to the storage area to which the parser
1076
    /// @param keys is a pointer to a map of the defined TSIG keys.
1077 1078
    /// should commit the newly created DdnsDomain instance.
    DdnsDomainListParser(const std::string& list_name,
1079
                         DdnsDomainMapPtr domains, TSIGKeyInfoMapPtr keys);
1080 1081 1082 1083

    /// @brief Destructor
    virtual ~DdnsDomainListParser();

1084
    /// @brief Performs the actual parsing of the given list "ddns-domain"
1085
    /// elements.
1086
    /// It iterates over each domain entry in the list:
1087 1088 1089 1090 1091 1092 1093
    ///   1. Instantiate a DdnsDomainParser for the entry
    ///   2. Pass the element configuration to the parser's build method
    ///   3. Add the parser instance to local storage
    ///
    /// The net effect is to parse all of the domain entries in the list
    /// prepping them for commit.
    ///
1094
    /// @param domain_list_config is the list of "ddns-domain" elements to
1095 1096 1097
    /// parse.
    virtual void build(isc::data::ConstElementPtr domain_list_config);

1098 1099 1100 1101
    /// @brief Commits the list of DdnsDomains
    ///
    /// Iterates over the internal list of DdnsDomainParsers, invoking
    /// commit on each one.
1102 1103 1104 1105 1106 1107 1108 1109 1110
    virtual void commit();

private:
    /// @brief Arbitrary label assigned to this parser instance.
    std::string list_name_;

    /// @brief Pointer to the storage area to which the parser should commit
    /// the list of newly created DdnsDomain instances. This is given to us
    /// as a constructor argument by an upper level.
1111 1112 1113 1114 1115 1116 1117
    DdnsDomainMapPtr domains_;

    /// @brief Pointer to the map of defined TSIG keys.
    /// This map is passed into us and contains all of the TSIG keys defined
    /// for this configuration.  It is used to validate the key name entry of
    /// DdnsDomains that specify one.
    TSIGKeyInfoMapPtr keys_;
1118 1119 1120 1121 1122 1123 1124

    /// @brief Local storage of DdnsDomainParser instances
    isc::dhcp::ParserCollection parsers_;
};

/// @brief Parser for DdnsDomainListMgr
///
1125 1126
/// This class parses the configuration elements "forward-ddns" and
/// "reverse-ddns" as defined in src/bin/d2/dhcp-ddns.spec.  It populates the
1127 1128 1129 1130 1131 1132 1133 1134 1135 1136
/// given DdnsDomainListMgr with parsed information upon commit.  Note that
/// unlike other parsers, this parser does NOT instantiate the final object
/// during the commit phase, it populates it.  It must pre-exist.
class DdnsDomainListMgrParser : public isc::dhcp::DhcpConfigParser {
public:
    /// @brief Constructor
    ///
    /// @param entry_name is an arbitrary label assigned to this configuration
    /// definition.
    /// @param mgr is a pointer to the DdnsDomainListMgr to populate.
1137
    /// @param keys is a pointer to a map of the defined TSIG keys.
1138 1139
    /// @throw throws D2CfgError if mgr pointer is empty.
    DdnsDomainListMgrParser(const std::string& entry_name,
1140
                     DdnsDomainListMgrPtr mgr, TSIGKeyInfoMapPtr keys);
1141 1142 1143 1144 1145

    /// @brief Destructor
    virtual ~DdnsDomainListMgrParser();

    /// @brief Performs the actual parsing of the given manager element.
1146 1147 1148 1149
    ///
    /// Parses a configuration for the elements needed to instantiate a
    /// DdnsDomainListMgr, validates those entries, then creates a
    /// DdnsDomainListMgr.
1150 1151 1152 1153 1154 1155 1156
    ///
    /// @param mgr_config is the manager configuration to parse
    virtual void build(isc::data::ConstElementPtr mgr_config);

    /// @brief Creates a parser for the given manager member element id.
    ///
    /// The manager elements currently supported are (see dhcp-ddns.spec):
1157
    ///     1. ddns_domains
1158 1159 1160
    ///
    /// @param config_id is the "item_name" for a specific member element of
    /// the manager specification.
1161 1162
    /// @param pos position within the configuration text (or file) of element
    /// to be parsed.  This is passed for error messaging.
1163 1164
    ///
    /// @return returns a pointer to newly created parser.
1165 1166 1167 1168 1169 1170
    ///
    /// @throw D2CfgError if configuration contains an unknown parameter
    virtual isc::dhcp::ParserPtr
    createConfigParser(const std::string& config_id,
                       const isc::data::Element::Position& pos =
                       isc::data::Element::ZERO_POSITION());
1171

1172
    /// @brief Commits the configured DdsnDomainListMgr
1173 1174
    /// Currently this method is a NOP, as the manager instance is created
    /// in build().
1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185
    virtual void commit();

private:
    /// @brief Arbitrary label assigned to this parser instance.
    std::string entry_name_;

    /// @brief Pointer to manager instance to which the parser should commit
    /// the parsed data. This is given to us as a constructor argument by an
    /// upper level.
    DdnsDomainListMgrPtr mgr_;

1186 1187 1188 1189 1190 1191
    /// @brief Pointer to the map of defined TSIG keys.
    /// This map is passed into us and contains all of the TSIG keys defined
    /// for this configuration.  It is used to validate the key name entry of
    /// DdnsDomains that specify one.
    TSIGKeyInfoMapPtr keys_;

1192 1193 1194 1195
    /// @brief Local storage for DdnsDomain instances. This is passed into a
    /// DdnsDomainListParser(s), which in turn passes it into each
    /// DdnsDomainParser.  When the DdnsDomainParsers "commit" they add their
    /// domain instance to this storage.
1196
    DdnsDomainMapPtr local_domains_;
1197 1198 1199

    /// @brief Local storage area for scalar parameter values. Use to hold
    /// data until time to commit.
1200
    /// @todo Currently, the manager has no scalars but this is likely to
1201 1202 1203 1204 1205 1206 1207 1208 1209
    /// change as matching capabilities expand.
    DScalarContext local_scalars_;
};


}; // end of isc::d2 namespace
}; // end of isc namespace

#endif // D2_CONFIG_H