summaryrefslogtreecommitdiffstats
path: root/src/lib/d2srv/d2_cfg_mgr.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/d2srv/d2_cfg_mgr.cc')
-rw-r--r--src/lib/d2srv/d2_cfg_mgr.cc334
1 files changed, 334 insertions, 0 deletions
diff --git a/src/lib/d2srv/d2_cfg_mgr.cc b/src/lib/d2srv/d2_cfg_mgr.cc
new file mode 100644
index 0000000..17ac59b
--- /dev/null
+++ b/src/lib/d2srv/d2_cfg_mgr.cc
@@ -0,0 +1,334 @@
+// Copyright (C) 2014-2023 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <d2srv/d2_log.h>
+#include <d2srv/d2_cfg_mgr.h>
+#include <d2srv/d2_simple_parser.h>
+#include <cc/command_interpreter.h>
+#include <config/base_command_mgr.h>
+#include <util/encode/hex.h>
+
+#include <boost/foreach.hpp>
+
+using namespace isc::asiolink;
+using namespace isc::config;
+using namespace isc::data;
+using namespace isc::process;
+
+namespace isc {
+namespace d2 {
+
+namespace {
+
+typedef std::vector<uint8_t> ByteAddress;
+
+} // end of unnamed namespace
+
+// *********************** D2CfgContext *************************
+
+D2CfgContext::D2CfgContext()
+ : d2_params_(new D2Params()),
+ forward_mgr_(new DdnsDomainListMgr("forward-ddns")),
+ reverse_mgr_(new DdnsDomainListMgr("reverse-ddns")),
+ keys_(new TSIGKeyInfoMap()),
+ control_socket_(ConstElementPtr()) {
+}
+
+D2CfgContext::D2CfgContext(const D2CfgContext& rhs) : ConfigBase(rhs) {
+ d2_params_ = rhs.d2_params_;
+ if (rhs.forward_mgr_) {
+ forward_mgr_.reset(new DdnsDomainListMgr(rhs.forward_mgr_->getName()));
+ forward_mgr_->setDomains(rhs.forward_mgr_->getDomains());
+ }
+
+ if (rhs.reverse_mgr_) {
+ reverse_mgr_.reset(new DdnsDomainListMgr(rhs.reverse_mgr_->getName()));
+ reverse_mgr_->setDomains(rhs.reverse_mgr_->getDomains());
+ }
+
+ keys_ = rhs.keys_;
+
+ control_socket_ = rhs.control_socket_;
+
+ hooks_config_ = rhs.hooks_config_;
+}
+
+D2CfgContext::~D2CfgContext() {
+}
+
+ElementPtr
+D2CfgContext::toElement() const {
+ ElementPtr d2 = ConfigBase::toElement();
+ // Set user-context
+ contextToElement(d2);
+ // Set ip-address
+ const IOAddress& ip_address = d2_params_->getIpAddress();
+ d2->set("ip-address", Element::create(ip_address.toText()));
+ // Set port
+ size_t port = d2_params_->getPort();
+ d2->set("port", Element::create(static_cast<int64_t>(port)));
+ // Set dns-server-timeout
+ size_t dns_server_timeout = d2_params_->getDnsServerTimeout();
+ d2->set("dns-server-timeout",
+ Element::create(static_cast<int64_t>(dns_server_timeout)));
+ // Set ncr-protocol
+ const dhcp_ddns::NameChangeProtocol& ncr_protocol =
+ d2_params_->getNcrProtocol();
+ d2->set("ncr-protocol",
+ Element::create(dhcp_ddns::ncrProtocolToString(ncr_protocol)));
+ // Set ncr-format
+ const dhcp_ddns::NameChangeFormat& ncr_format = d2_params_->getNcrFormat();
+ d2->set("ncr-format",
+ Element::create(dhcp_ddns::ncrFormatToString(ncr_format)));
+ // Set forward-ddns
+ ElementPtr forward_ddns = Element::createMap();
+ forward_ddns->set("ddns-domains", forward_mgr_->toElement());
+ d2->set("forward-ddns", forward_ddns);
+ // Set reverse-ddns
+ ElementPtr reverse_ddns = Element::createMap();
+ reverse_ddns->set("ddns-domains", reverse_mgr_->toElement());
+ d2->set("reverse-ddns", reverse_ddns);
+ // Set tsig-keys
+ ElementPtr tsig_keys = Element::createList();
+ for (TSIGKeyInfoMap::const_iterator key = keys_->begin();
+ key != keys_->end(); ++key) {
+ tsig_keys->add(key->second->toElement());
+ }
+ d2->set("tsig-keys", tsig_keys);
+ // Set control-socket (skip if null as empty is not legal)
+ if (!isNull(control_socket_)) {
+ d2->set("control-socket", UserContext::toElement(control_socket_));
+ }
+ // Set hooks-libraries
+ d2->set("hooks-libraries", hooks_config_.toElement());
+ // Set DhcpDdns
+ ElementPtr result = Element::createMap();
+ result->set("DhcpDdns", d2);
+
+ return (result);
+}
+
+// *********************** D2CfgMgr *************************
+
+const char* D2CfgMgr::IPV4_REV_ZONE_SUFFIX = "in-addr.arpa.";
+
+const char* D2CfgMgr::IPV6_REV_ZONE_SUFFIX = "ip6.arpa.";
+
+D2CfgMgr::D2CfgMgr() : DCfgMgrBase(ConfigPtr(new D2CfgContext())) {
+}
+
+D2CfgMgr::~D2CfgMgr() {
+}
+
+ConfigPtr
+D2CfgMgr::createNewContext() {
+ return (ConfigPtr(new D2CfgContext()));
+}
+
+bool
+D2CfgMgr::forwardUpdatesEnabled() {
+ // Forward updates are not enabled if no forward servers are defined.
+ return (getD2CfgContext()->getForwardMgr()->size() > 0);
+}
+
+bool
+D2CfgMgr::reverseUpdatesEnabled() {
+ // Reverse updates are not enabled if no reverse servers are defined.
+ return (getD2CfgContext()->getReverseMgr()->size() > 0);
+}
+
+bool
+D2CfgMgr::matchForward(const std::string& fqdn, DdnsDomainPtr& domain) {
+ if (fqdn.empty()) {
+ // This is a programmatic error and should not happen.
+ isc_throw(D2CfgError, "matchForward passed an empty fqdn");
+ }
+
+ // Fetch the forward manager from the D2 context.
+ DdnsDomainListMgrPtr mgr = getD2CfgContext()->getForwardMgr();
+
+ // Call the manager's match method and return the result.
+ return (mgr->matchDomain(fqdn, domain));
+}
+
+bool
+D2CfgMgr::matchReverse(const std::string& ip_address, DdnsDomainPtr& domain) {
+ // Note, reverseIpAddress will throw if the ip_address is invalid.
+ std::string reverse_address = reverseIpAddress(ip_address);
+
+ // Fetch the reverse manager from the D2 context.
+ DdnsDomainListMgrPtr mgr = getD2CfgContext()->getReverseMgr();
+
+ return (mgr->matchDomain(reverse_address, domain));
+}
+
+std::string
+D2CfgMgr::reverseIpAddress(const std::string& address) {
+ try {
+ // Convert string address into an IOAddress and invoke the
+ // appropriate reverse method.
+ isc::asiolink::IOAddress ioaddr(address);
+ if (ioaddr.isV4()) {
+ return (reverseV4Address(ioaddr));
+ }
+
+ return (reverseV6Address(ioaddr));
+
+ } catch (const isc::Exception& ex) {
+ isc_throw(D2CfgError, "D2CfgMgr cannot reverse address: "
+ << address << " : " << ex.what());
+ }
+}
+
+std::string
+D2CfgMgr::reverseV4Address(const isc::asiolink::IOAddress& ioaddr) {
+ if (!ioaddr.isV4()) {
+ isc_throw(D2CfgError, "D2CfgMgr address is not IPv4 address :"
+ << ioaddr);
+ }
+
+ // Get the address in byte vector form.
+ const ByteAddress bytes = ioaddr.toBytes();
+
+ // Walk backwards through vector outputting each octet and a dot.
+ std::ostringstream stream;
+
+ // We have to set the following variable to get
+ // const_reverse_iterator type of rend(), otherwise Solaris GCC
+ // complains on operator!= by trying to use the non-const variant.
+ const ByteAddress::const_reverse_iterator end = bytes.rend();
+
+ for (ByteAddress::const_reverse_iterator rit = bytes.rbegin();
+ rit != end;
+ ++rit)
+ {
+ stream << static_cast<unsigned int>(*rit) << ".";
+ }
+
+ // Tack on the suffix and we're done.
+ stream << IPV4_REV_ZONE_SUFFIX;
+ return(stream.str());
+}
+
+std::string
+D2CfgMgr::reverseV6Address(const isc::asiolink::IOAddress& ioaddr) {
+ if (!ioaddr.isV6()) {
+ isc_throw(D2CfgError, "D2Cfg address is not IPv6 address: " << ioaddr);
+ }
+
+ // Turn the address into a string of digits.
+ const ByteAddress bytes = ioaddr.toBytes();
+ const std::string digits = isc::util::encode::encodeHex(bytes);
+
+ // Walk backwards through string outputting each digits and a dot.
+ std::ostringstream stream;
+
+ // We have to set the following variable to get
+ // const_reverse_iterator type of rend(), otherwise Solaris GCC
+ // complains on operator!= by trying to use the non-const variant.
+ const std::string::const_reverse_iterator end = digits.rend();
+
+ for (std::string::const_reverse_iterator rit = digits.rbegin();
+ rit != end;
+ ++rit)
+ {
+ stream << static_cast<char>(*rit) << ".";
+ }
+
+ // Tack on the suffix and we're done.
+ stream << IPV6_REV_ZONE_SUFFIX;
+ return(stream.str());
+}
+
+const D2ParamsPtr&
+D2CfgMgr::getD2Params() {
+ return (getD2CfgContext()->getD2Params());
+}
+
+const isc::data::ConstElementPtr
+D2CfgMgr::getControlSocketInfo() {
+ return (getD2CfgContext()->getControlSocketInfo());
+}
+
+std::string
+D2CfgMgr::getConfigSummary(const uint32_t) {
+ return (getD2Params()->getConfigSummary());
+}
+
+void
+D2CfgMgr::setCfgDefaults(ElementPtr mutable_config) {
+ D2SimpleParser::setAllDefaults(mutable_config);
+}
+
+isc::data::ConstElementPtr
+D2CfgMgr::parse(isc::data::ConstElementPtr config_set, bool check_only) {
+ // Do a sanity check first.
+ if (!config_set) {
+ isc_throw(D2CfgError, "Mandatory config parameter not provided");
+ }
+
+ D2CfgContextPtr ctx = getD2CfgContext();
+
+ // Set the defaults
+ ElementPtr cfg = boost::const_pointer_cast<Element>(config_set);
+ D2SimpleParser::setAllDefaults(cfg);
+
+ // And parse the configuration.
+ ConstElementPtr answer;
+ std::string excuse;
+ try {
+ // Do the actual parsing
+ D2SimpleParser parser;
+ parser.parse(ctx, cfg, check_only);
+ } catch (const isc::Exception& ex) {
+ excuse = ex.what();
+ answer = createAnswer(CONTROL_RESULT_ERROR, excuse);
+ } catch (...) {
+ excuse = "undefined configuration parsing error";
+ answer = createAnswer(CONTROL_RESULT_ERROR, excuse);
+ }
+
+ // At this stage the answer was created only in case of exception.
+ if (answer) {
+ if (check_only) {
+ LOG_ERROR(d2_logger, DHCP_DDNS_CONFIG_CHECK_FAIL).arg(excuse);
+ } else {
+ LOG_ERROR(d2_logger, DHCP_DDNS_CONFIG_FAIL).arg(excuse);
+ }
+ return (answer);
+ }
+
+ if (check_only) {
+ answer = createAnswer(CONTROL_RESULT_SUCCESS,
+ "Configuration check successful");
+ } else {
+
+ // Calculate hash of the configuration that was just set.
+ ConstElementPtr config = getContext()->toElement();
+ std::string hash = BaseCommandMgr::getHash(config);
+ ElementPtr params = Element::createMap();
+ params->set("hash", Element::create(hash));
+
+ answer = createAnswer(CONTROL_RESULT_SUCCESS,
+ "Configuration applied successfully.", params);
+ }
+
+ return (answer);
+}
+
+std::list<std::list<std::string>>
+D2CfgMgr::jsonPathsToRedact() const {
+ static std::list<std::list<std::string>> const list({
+ {"tsig-keys", "[]"},
+ {"hooks-libraries", "[]", "parameters", "*"},
+ });
+ return list;
+}
+
+} // namespace d2
+} // namespace isc