d2_client.cc 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. // Copyright (C) 2013-2014 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <dhcpsrv/d2_client.h>
  15. #include <dhcpsrv/dhcpsrv_log.h>
  16. #include <string>
  17. using namespace std;
  18. namespace isc {
  19. namespace dhcp {
  20. D2ClientConfig::D2ClientConfig(const bool enable_updates,
  21. const isc::asiolink::IOAddress& server_ip,
  22. const size_t server_port,
  23. const dhcp_ddns::
  24. NameChangeProtocol& ncr_protocol,
  25. const dhcp_ddns::
  26. NameChangeFormat& ncr_format,
  27. const bool always_include_fqdn,
  28. const bool override_no_update,
  29. const bool override_client_update,
  30. const bool replace_client_name,
  31. const std::string& generated_prefix,
  32. const std::string& qualifying_suffix)
  33. : enable_updates_(enable_updates),
  34. server_ip_(server_ip),
  35. server_port_(server_port),
  36. ncr_protocol_(ncr_protocol),
  37. ncr_format_(ncr_format),
  38. always_include_fqdn_(always_include_fqdn),
  39. override_no_update_(override_no_update),
  40. override_client_update_(override_client_update),
  41. replace_client_name_(replace_client_name),
  42. generated_prefix_(generated_prefix),
  43. qualifying_suffix_(qualifying_suffix) {
  44. validateContents();
  45. }
  46. D2ClientConfig::D2ClientConfig()
  47. : enable_updates_(false),
  48. server_ip_(isc::asiolink::IOAddress("0.0.0.0")),
  49. server_port_(0),
  50. ncr_protocol_(dhcp_ddns::NCR_UDP),
  51. ncr_format_(dhcp_ddns::FMT_JSON),
  52. always_include_fqdn_(false),
  53. override_no_update_(false),
  54. override_client_update_(false),
  55. replace_client_name_(false),
  56. generated_prefix_("myhost"),
  57. qualifying_suffix_("example.com") {
  58. validateContents();
  59. }
  60. D2ClientConfig::~D2ClientConfig(){};
  61. void
  62. D2ClientConfig::validateContents() {
  63. if (ncr_format_ != dhcp_ddns::FMT_JSON) {
  64. isc_throw(D2ClientError, "D2ClientConfig: NCR Format:"
  65. << dhcp_ddns::ncrFormatToString(ncr_format_)
  66. << " is not yet supported");
  67. }
  68. if (ncr_protocol_ != dhcp_ddns::NCR_UDP) {
  69. isc_throw(D2ClientError, "D2ClientConfig: NCR Protocol:"
  70. << dhcp_ddns::ncrProtocolToString(ncr_protocol_)
  71. << " is not yet supported");
  72. }
  73. /// @todo perhaps more validation we should do yet?
  74. /// Are there any invalid combinations of options we need to test against?
  75. }
  76. bool
  77. D2ClientConfig::operator == (const D2ClientConfig& other) const {
  78. return ((enable_updates_ == other.enable_updates_) &&
  79. (server_ip_ == other.server_ip_) &&
  80. (server_port_ == other.server_port_) &&
  81. (ncr_protocol_ == other.ncr_protocol_) &&
  82. (ncr_format_ == other.ncr_format_) &&
  83. (always_include_fqdn_ == other.always_include_fqdn_) &&
  84. (override_no_update_ == other.override_no_update_) &&
  85. (override_client_update_ == other.override_client_update_) &&
  86. (replace_client_name_ == other.replace_client_name_) &&
  87. (generated_prefix_ == other.generated_prefix_) &&
  88. (qualifying_suffix_ == other.qualifying_suffix_));
  89. }
  90. bool
  91. D2ClientConfig::operator != (const D2ClientConfig& other) const {
  92. return (!(*this == other));
  93. }
  94. std::string
  95. D2ClientConfig::toText() const {
  96. std::ostringstream stream;
  97. stream << "enable_updates: " << (enable_updates_ ? "yes" : "no");
  98. if (enable_updates_) {
  99. stream << ", server_ip: " << server_ip_.toText()
  100. << ", server_port: " << server_port_
  101. << ", ncr_protocol: " << ncr_protocol_
  102. << ", ncr_format: " << ncr_format_
  103. << ", always_include_fqdn: " << (always_include_fqdn_ ?
  104. "yes" : "no")
  105. << ", override_no_update: " << (override_no_update_ ?
  106. "yes" : "no")
  107. << ", override_client_update: " << (override_client_update_ ?
  108. "yes" : "no")
  109. << ", replace_client_name: " << (replace_client_name_ ?
  110. "yes" : "no")
  111. << ", generated_prefix: [" << generated_prefix_ << "]"
  112. << ", qualifying_suffix: [" << qualifying_suffix_ << "]";
  113. }
  114. return (stream.str());
  115. }
  116. std::ostream&
  117. operator<<(std::ostream& os, const D2ClientConfig& config) {
  118. os << config.toText();
  119. return (os);
  120. }
  121. D2ClientMgr::D2ClientMgr() : d2_client_config_(new D2ClientConfig()) {
  122. // Default constructor initializes with a disabled configuration.
  123. }
  124. D2ClientMgr::~D2ClientMgr(){
  125. }
  126. void
  127. D2ClientMgr::setD2ClientConfig(D2ClientConfigPtr& new_config) {
  128. if (!new_config) {
  129. isc_throw(D2ClientError,
  130. "D2ClientMgr cannot set DHCP-DDNS configuration to NULL.");
  131. }
  132. // @todo When NameChangeSender is integrated, we will need to handle these
  133. // scenarios:
  134. // 1. D2 was enabled but now it is disabled
  135. // - destroy the sender, flush any queued
  136. // 2. D2 is still enabled but server parameters have changed
  137. // - preserve any queued, reconnect based on sender parameters
  138. // 3. D2 was was disabled now it is enabled.
  139. // - create sender
  140. //
  141. // For now we just update the configuration.
  142. d2_client_config_ = new_config;
  143. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_CFGMGR_CFG_DHCP_DDNS)
  144. .arg(!ddnsEnabled() ? "DHCP-DDNS updates disabled" :
  145. "DHCP_DDNS updates enabled");
  146. }
  147. bool
  148. D2ClientMgr::ddnsEnabled() {
  149. return (d2_client_config_->getEnableUpdates());
  150. }
  151. const D2ClientConfigPtr&
  152. D2ClientMgr::getD2ClientConfig() const {
  153. return (d2_client_config_);
  154. }
  155. void
  156. D2ClientMgr::analyzeFqdn(const bool client_s, const bool client_n,
  157. bool& server_s, bool& server_n) const {
  158. // Per RFC 4702 & 4704, the client N and S flags allow the client to
  159. // request one of three options:
  160. //
  161. // N flag S flag Option
  162. // ------------------------------------------------------------------
  163. // 0 0 client wants to do forward updates (section 3.2)
  164. // 0 1 client wants server to do forward updates (section 3.3)
  165. // 1 0 client wants no one to do updates (section 3.4)
  166. // 1 1 invalid combination
  167. // (Note section numbers cited are for 4702, for 4704 see 5.1, 5.2, and 5.3)
  168. //
  169. // Make a bit mask from the client's flags and use it to set the response
  170. // flags accordingly.
  171. const uint8_t mask = ((client_n ? 2 : 0) + (client_s ? 1 : 0));
  172. switch (mask) {
  173. case 0:
  174. // If updates are enabled and we are overriding client delegation
  175. // then S flag should be true.
  176. server_s = (d2_client_config_->getEnableUpdates() &&
  177. d2_client_config_->getOverrideClientUpdate());
  178. break;
  179. case 1:
  180. server_s = d2_client_config_->getEnableUpdates();
  181. break;
  182. case 2:
  183. // If updates are enabled and we are overriding "no updates" then
  184. // S flag should be true.
  185. server_s = (d2_client_config_->getEnableUpdates() &&
  186. d2_client_config_->getOverrideNoUpdate());
  187. break;
  188. default:
  189. // RFCs declare this an invalid combination.
  190. isc_throw(isc::BadValue,
  191. "Invalid client FQDN - N and S cannot both be 1");
  192. break;
  193. }
  194. /// @todo Currently we are operating under the premise that N should be 1
  195. /// if the server is not doing updates nor do we have configuration
  196. /// controls to govern forward and reverse updates independently.
  197. /// In addition, the client FQDN flags cannot explicitly suggest what to
  198. /// do with reverse updates. They request either forward updates or no
  199. /// updates. In other words, the client cannot request the server do or
  200. /// not do reverse updates. For now, we are either going to do updates in
  201. /// both directions or none at all. If and when additional configuration
  202. /// parameters are added this logic will have to be reassessed.
  203. server_n = !server_s;
  204. }
  205. std::string
  206. D2ClientMgr::generateFqdn(const asiolink::IOAddress& address) const {
  207. std::string hostname = address.toText();
  208. std::replace(hostname.begin(), hostname.end(),
  209. (address.isV4() ? '.' : ':'), '-');
  210. std::ostringstream gen_name;
  211. gen_name << d2_client_config_->getGeneratedPrefix() << "-" << hostname;
  212. return (qualifyName(gen_name.str()));
  213. }
  214. std::string
  215. D2ClientMgr::qualifyName(const std::string& partial_name) const {
  216. std::ostringstream gen_name;
  217. gen_name << partial_name << "." << d2_client_config_->getQualifyingSuffix();
  218. // Tack on a trailing dot in case suffix doesn't have one.
  219. std::string str = gen_name.str();
  220. size_t len = str.length();
  221. if ((len > 0) && (str[len - 1] != '.')) {
  222. gen_name << ".";
  223. }
  224. return (gen_name.str());
  225. }
  226. }; // namespace dhcp
  227. }; // namespace isc