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