Kea  2.5.2
d2_cfg_mgr.cc
Go to the documentation of this file.
1 // Copyright (C) 2014-2023 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
7 #include <config.h>
8 
9 #include <d2srv/d2_log.h>
10 #include <d2srv/d2_cfg_mgr.h>
11 #include <d2srv/d2_simple_parser.h>
12 #include <cc/command_interpreter.h>
14 #include <util/encode/hex.h>
15 
16 #include <boost/foreach.hpp>
17 
18 using namespace isc::asiolink;
19 using namespace isc::config;
20 using namespace isc::data;
21 using namespace isc::process;
22 
23 namespace isc {
24 namespace d2 {
25 
26 namespace {
27 
28 typedef std::vector<uint8_t> ByteAddress;
29 
30 } // end of unnamed namespace
31 
32 // *********************** D2CfgContext *************************
33 
34 D2CfgContext::D2CfgContext()
35  : d2_params_(new D2Params()),
36  forward_mgr_(new DdnsDomainListMgr("forward-ddns")),
37  reverse_mgr_(new DdnsDomainListMgr("reverse-ddns")),
38  keys_(new TSIGKeyInfoMap()),
39  control_socket_(ConstElementPtr()) {
40 }
41 
43  d2_params_ = rhs.d2_params_;
44  if (rhs.forward_mgr_) {
45  forward_mgr_.reset(new DdnsDomainListMgr(rhs.forward_mgr_->getName()));
46  forward_mgr_->setDomains(rhs.forward_mgr_->getDomains());
47  }
48 
49  if (rhs.reverse_mgr_) {
50  reverse_mgr_.reset(new DdnsDomainListMgr(rhs.reverse_mgr_->getName()));
51  reverse_mgr_->setDomains(rhs.reverse_mgr_->getDomains());
52  }
53 
54  keys_ = rhs.keys_;
55 
56  control_socket_ = rhs.control_socket_;
57 
58  hooks_config_ = rhs.hooks_config_;
59 }
60 
62 }
63 
66  ElementPtr d2 = ConfigBase::toElement();
67  // Set user-context
68  contextToElement(d2);
69  // Set ip-address
70  const IOAddress& ip_address = d2_params_->getIpAddress();
71  d2->set("ip-address", Element::create(ip_address.toText()));
72  // Set port
73  size_t port = d2_params_->getPort();
74  d2->set("port", Element::create(static_cast<int64_t>(port)));
75  // Set dns-server-timeout
76  size_t dns_server_timeout = d2_params_->getDnsServerTimeout();
77  d2->set("dns-server-timeout",
78  Element::create(static_cast<int64_t>(dns_server_timeout)));
79  // Set ncr-protocol
80  const dhcp_ddns::NameChangeProtocol& ncr_protocol =
81  d2_params_->getNcrProtocol();
82  d2->set("ncr-protocol",
83  Element::create(dhcp_ddns::ncrProtocolToString(ncr_protocol)));
84  // Set ncr-format
85  const dhcp_ddns::NameChangeFormat& ncr_format = d2_params_->getNcrFormat();
86  d2->set("ncr-format",
87  Element::create(dhcp_ddns::ncrFormatToString(ncr_format)));
88  // Set forward-ddns
89  ElementPtr forward_ddns = Element::createMap();
90  forward_ddns->set("ddns-domains", forward_mgr_->toElement());
91  d2->set("forward-ddns", forward_ddns);
92  // Set reverse-ddns
93  ElementPtr reverse_ddns = Element::createMap();
94  reverse_ddns->set("ddns-domains", reverse_mgr_->toElement());
95  d2->set("reverse-ddns", reverse_ddns);
96  // Set tsig-keys
97  ElementPtr tsig_keys = Element::createList();
98  for (TSIGKeyInfoMap::const_iterator key = keys_->begin();
99  key != keys_->end(); ++key) {
100  tsig_keys->add(key->second->toElement());
101  }
102  d2->set("tsig-keys", tsig_keys);
103  // Set control-socket (skip if null as empty is not legal)
104  if (!isNull(control_socket_)) {
105  d2->set("control-socket", UserContext::toElement(control_socket_));
106  }
107  // Set hooks-libraries
108  d2->set("hooks-libraries", hooks_config_.toElement());
109  // Set DhcpDdns
110  ElementPtr result = Element::createMap();
111  result->set("DhcpDdns", d2);
112 
113  return (result);
114 }
115 
116 // *********************** D2CfgMgr *************************
117 
118 const char* D2CfgMgr::IPV4_REV_ZONE_SUFFIX = "in-addr.arpa.";
119 
120 const char* D2CfgMgr::IPV6_REV_ZONE_SUFFIX = "ip6.arpa.";
121 
123 }
124 
126 }
127 
128 ConfigPtr
130  return (ConfigPtr(new D2CfgContext()));
131 }
132 
133 bool
135  // Forward updates are not enabled if no forward servers are defined.
136  return (getD2CfgContext()->getForwardMgr()->size() > 0);
137 }
138 
139 bool
141  // Reverse updates are not enabled if no reverse servers are defined.
142  return (getD2CfgContext()->getReverseMgr()->size() > 0);
143 }
144 
145 bool
146 D2CfgMgr::matchForward(const std::string& fqdn, DdnsDomainPtr& domain) {
147  if (fqdn.empty()) {
148  // This is a programmatic error and should not happen.
149  isc_throw(D2CfgError, "matchForward passed an empty fqdn");
150  }
151 
152  // Fetch the forward manager from the D2 context.
153  DdnsDomainListMgrPtr mgr = getD2CfgContext()->getForwardMgr();
154 
155  // Call the manager's match method and return the result.
156  return (mgr->matchDomain(fqdn, domain));
157 }
158 
159 bool
160 D2CfgMgr::matchReverse(const std::string& ip_address, DdnsDomainPtr& domain) {
161  // Note, reverseIpAddress will throw if the ip_address is invalid.
162  std::string reverse_address = reverseIpAddress(ip_address);
163 
164  // Fetch the reverse manager from the D2 context.
165  DdnsDomainListMgrPtr mgr = getD2CfgContext()->getReverseMgr();
166 
167  return (mgr->matchDomain(reverse_address, domain));
168 }
169 
170 std::string
171 D2CfgMgr::reverseIpAddress(const std::string& address) {
172  try {
173  // Convert string address into an IOAddress and invoke the
174  // appropriate reverse method.
175  isc::asiolink::IOAddress ioaddr(address);
176  if (ioaddr.isV4()) {
177  return (reverseV4Address(ioaddr));
178  }
179 
180  return (reverseV6Address(ioaddr));
181 
182  } catch (const isc::Exception& ex) {
183  isc_throw(D2CfgError, "D2CfgMgr cannot reverse address: "
184  << address << " : " << ex.what());
185  }
186 }
187 
188 std::string
190  if (!ioaddr.isV4()) {
191  isc_throw(D2CfgError, "D2CfgMgr address is not IPv4 address :"
192  << ioaddr);
193  }
194 
195  // Get the address in byte vector form.
196  const ByteAddress bytes = ioaddr.toBytes();
197 
198  // Walk backwards through vector outputting each octet and a dot.
199  std::ostringstream stream;
200 
201  // We have to set the following variable to get
202  // const_reverse_iterator type of rend(), otherwise Solaris GCC
203  // complains on operator!= by trying to use the non-const variant.
204  const ByteAddress::const_reverse_iterator end = bytes.rend();
205 
206  for (ByteAddress::const_reverse_iterator rit = bytes.rbegin();
207  rit != end;
208  ++rit)
209  {
210  stream << static_cast<unsigned int>(*rit) << ".";
211  }
212 
213  // Tack on the suffix and we're done.
214  stream << IPV4_REV_ZONE_SUFFIX;
215  return(stream.str());
216 }
217 
218 std::string
220  if (!ioaddr.isV6()) {
221  isc_throw(D2CfgError, "D2Cfg address is not IPv6 address: " << ioaddr);
222  }
223 
224  // Turn the address into a string of digits.
225  const ByteAddress bytes = ioaddr.toBytes();
226  const std::string digits = isc::util::encode::encodeHex(bytes);
227 
228  // Walk backwards through string outputting each digits and a dot.
229  std::ostringstream stream;
230 
231  // We have to set the following variable to get
232  // const_reverse_iterator type of rend(), otherwise Solaris GCC
233  // complains on operator!= by trying to use the non-const variant.
234  const std::string::const_reverse_iterator end = digits.rend();
235 
236  for (std::string::const_reverse_iterator rit = digits.rbegin();
237  rit != end;
238  ++rit)
239  {
240  stream << static_cast<char>(*rit) << ".";
241  }
242 
243  // Tack on the suffix and we're done.
244  stream << IPV6_REV_ZONE_SUFFIX;
245  return(stream.str());
246 }
247 
248 const D2ParamsPtr&
250  return (getD2CfgContext()->getD2Params());
251 }
252 
256 }
257 
258 std::string
259 D2CfgMgr::getConfigSummary(const uint32_t) {
260  return (getD2Params()->getConfigSummary());
261 }
262 
263 void
265  D2SimpleParser::setAllDefaults(mutable_config);
266 }
267 
269 D2CfgMgr::parse(isc::data::ConstElementPtr config_set, bool check_only) {
270  // Do a sanity check first.
271  if (!config_set) {
272  isc_throw(D2CfgError, "Mandatory config parameter not provided");
273  }
274 
276 
277  // Set the defaults
278  ElementPtr cfg = boost::const_pointer_cast<Element>(config_set);
280 
281  // And parse the configuration.
282  ConstElementPtr answer;
283  std::string excuse;
284  try {
285  // Do the actual parsing
286  D2SimpleParser parser;
287  parser.parse(ctx, cfg, check_only);
288  } catch (const isc::Exception& ex) {
289  excuse = ex.what();
290  answer = createAnswer(CONTROL_RESULT_ERROR, excuse);
291  } catch (...) {
292  excuse = "undefined configuration parsing error";
293  answer = createAnswer(CONTROL_RESULT_ERROR, excuse);
294  }
295 
296  // At this stage the answer was created only in case of exception.
297  if (answer) {
298  if (check_only) {
300  } else {
302  }
303  return (answer);
304  }
305 
306  if (check_only) {
308  "Configuration check successful");
309  } else {
310 
311  // Calculate hash of the configuration that was just set.
312  ConstElementPtr config = getContext()->toElement();
313  std::string hash = BaseCommandMgr::getHash(config);
314  ElementPtr params = Element::createMap();
315  params->set("hash", Element::create(hash));
316 
318  "Configuration applied successfully.", params);
319  }
320 
321  return (answer);
322 }
323 
324 std::list<std::list<std::string>>
326  static std::list<std::list<std::string>> const list({
327  {"tsig-keys", "[]"},
328  {"hooks-libraries", "[]", "parameters", "*"},
329  });
330  return list;
331 }
332 
333 } // namespace d2
334 } // namespace isc
This is a base class for exceptions thrown from the DNS library module.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
DHCP-DDNS Configuration Context.
Definition: d2_cfg_mgr.h:34
virtual ~D2CfgContext()
Destructor.
Definition: d2_cfg_mgr.cc:61
virtual isc::data::ElementPtr toElement() const
Unparse a configuration object.
Definition: d2_cfg_mgr.cc:65
D2CfgContext()
Constructor.
Definition: d2_cfg_mgr.cc:34
Exception thrown when the error during configuration handling occurs.
Definition: d2_config.h:136
virtual ~D2CfgMgr()
Destructor.
Definition: d2_cfg_mgr.cc:125
bool matchForward(const std::string &fqdn, DdnsDomainPtr &domain)
Matches a given FQDN to a forward domain.
Definition: d2_cfg_mgr.cc:146
virtual process::ConfigPtr createNewContext() override
Creates an new, blank D2CfgContext context.
Definition: d2_cfg_mgr.cc:129
static std::string reverseIpAddress(const std::string &address)
Generate a reverse order string for the given IP address.
Definition: d2_cfg_mgr.cc:171
D2CfgContextPtr getD2CfgContext()
Convenience method that returns the D2 configuration context.
Definition: d2_cfg_mgr.h:180
bool reverseUpdatesEnabled()
Returns whether or not reverse updates are enabled.
Definition: d2_cfg_mgr.cc:140
virtual void setCfgDefaults(isc::data::ElementPtr mutable_config) override
Adds default values to the given config.
Definition: d2_cfg_mgr.cc:264
std::list< std::list< std::string > > jsonPathsToRedact() const final override
Return a list of all paths that contain passwords or secrets.
Definition: d2_cfg_mgr.cc:325
D2CfgMgr()
Constructor.
Definition: d2_cfg_mgr.cc:122
static const char * IPV6_REV_ZONE_SUFFIX
Reverse zone suffix added to IPv6 addresses for reverse lookups.
Definition: d2_cfg_mgr.h:169
static std::string reverseV4Address(const isc::asiolink::IOAddress &ioaddr)
Generate a reverse order string for the given IP address.
Definition: d2_cfg_mgr.cc:189
bool forwardUpdatesEnabled()
Returns whether or not forward updates are enabled.
Definition: d2_cfg_mgr.cc:134
bool matchReverse(const std::string &ip_address, DdnsDomainPtr &domain)
Matches a given IP address to a reverse domain.
Definition: d2_cfg_mgr.cc:160
virtual std::string getConfigSummary(const uint32_t selection) override
Returns configuration summary in the textual format.
Definition: d2_cfg_mgr.cc:259
static std::string reverseV6Address(const isc::asiolink::IOAddress &ioaddr)
Generate a reverse order string for the given IP address.
Definition: d2_cfg_mgr.cc:219
const D2ParamsPtr & getD2Params()
Convenience method fetches the D2Params from context.
Definition: d2_cfg_mgr.cc:249
const isc::data::ConstElementPtr getControlSocketInfo()
Convenience method fetches information about control socket from context.
Definition: d2_cfg_mgr.cc:254
virtual isc::data::ConstElementPtr parse(isc::data::ConstElementPtr config, bool check_only) override
Parses configuration of the D2.
Definition: d2_cfg_mgr.cc:269
static const char * IPV4_REV_ZONE_SUFFIX
Reverse zone suffix added to IPv4 addresses for reverse lookups.
Definition: d2_cfg_mgr.h:165
Acts as a storage vault for D2 global scalar parameters.
Definition: d2_config.h:143
void parse(const D2CfgContextPtr &ctx, const isc::data::ConstElementPtr &config, bool check_only)
Parses the whole D2 configuration.
static size_t setAllDefaults(data::ElementPtr global)
Sets all defaults for D2 configuration.
Provides storage for and management of a list of DNS domains.
Definition: d2_config.h:634
isc::data::ElementPtr toElement() const
Unparse a configuration object.
Base class for all configurations.
Definition: config_base.h:33
Configuration Manager.
Definition: d_cfg_mgr.h:108
ConfigPtr & getContext()
Fetches the configuration context.
Definition: d_cfg_mgr.h:151
This file contains several functions and constants that are used for handling commands and responses ...
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition: macros.h:32
const int CONTROL_RESULT_ERROR
Status code indicating a general failure.
ConstElementPtr createAnswer(const int status_code, const std::string &text, const ConstElementPtr &arg)
const int CONTROL_RESULT_SUCCESS
Status code indicating a successful operation.
boost::shared_ptr< DdnsDomainListMgr > DdnsDomainListMgrPtr
Defines a pointer for DdnsDomain instances.
Definition: d2_cfg_mgr.h:153
boost::shared_ptr< DdnsDomain > DdnsDomainPtr
Defines a pointer for DdnsDomain instances.
Definition: d2_config.h:612
const isc::log::MessageID DHCP_DDNS_CONFIG_CHECK_FAIL
Definition: d2_messages.h:19
std::map< std::string, TSIGKeyInfoPtr > TSIGKeyInfoMap
Defines a map of TSIGKeyInfos, keyed by the name.
Definition: d2_config.h:407
boost::shared_ptr< D2CfgContext > D2CfgContextPtr
Pointer to a configuration context.
Definition: d2_cfg_mgr.h:23
isc::log::Logger d2_logger("dhcpddns")
Defines the logger used within D2.
Definition: d2_log.h:18
boost::shared_ptr< D2Params > D2ParamsPtr
Defines a pointer for D2Params instances.
Definition: d2_config.h:257
const isc::log::MessageID DHCP_DDNS_CONFIG_FAIL
Definition: d2_messages.h:20
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:29
bool isNull(ConstElementPtr p)
Checks whether the given ElementPtr is a NULL pointer.
Definition: data.cc:1123
boost::shared_ptr< Element > ElementPtr
Definition: data.h:26
NameChangeFormat
Defines the list of data wire formats supported.
Definition: ncr_msg.h:60
NameChangeProtocol
Defines the list of socket protocols supported.
Definition: ncr_io.h:68
std::string ncrProtocolToString(NameChangeProtocol protocol)
Function which converts NameChangeProtocol enums to text labels.
Definition: ncr_io.cc:36
std::string ncrFormatToString(NameChangeFormat format)
Function which converts NameChangeFormat enums to text labels.
Definition: ncr_msg.cc:35
boost::shared_ptr< ConfigBase > ConfigPtr
Non-const pointer to the ConfigBase.
Definition: config_base.h:176
string encodeHex(const vector< uint8_t > &binary)
Encode binary data in the base16 ('hex') format.
Definition: base_n.cc:483
Defines the logger used by the top-level component of kea-lfc.
void contextToElement(data::ElementPtr map) const
Merge unparse a user_context object.
Definition: user_context.cc:15