nc_trans.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. // Copyright (C) 2013 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 <d2/d2_log.h>
  15. #include <d2/nc_trans.h>
  16. #include <dns/rdata.h>
  17. namespace isc {
  18. namespace d2 {
  19. // Common transaction states
  20. const int NameChangeTransaction::READY_ST;
  21. const int NameChangeTransaction::SELECTING_FWD_SERVER_ST;
  22. const int NameChangeTransaction::SELECTING_REV_SERVER_ST;
  23. const int NameChangeTransaction::PROCESS_TRANS_OK_ST;
  24. const int NameChangeTransaction::PROCESS_TRANS_FAILED_ST;
  25. const int NameChangeTransaction::NCT_DERIVED_STATE_MIN;
  26. // Common transaction events
  27. const int NameChangeTransaction::SELECT_SERVER_EVT;
  28. const int NameChangeTransaction::SERVER_SELECTED_EVT;
  29. const int NameChangeTransaction::SERVER_IO_ERROR_EVT;
  30. const int NameChangeTransaction::NO_MORE_SERVERS_EVT;
  31. const int NameChangeTransaction::IO_COMPLETED_EVT;
  32. const int NameChangeTransaction::UPDATE_OK_EVT;
  33. const int NameChangeTransaction::UPDATE_FAILED_EVT;
  34. const int NameChangeTransaction::NCT_DERIVED_EVENT_MIN;
  35. const unsigned int NameChangeTransaction::DNS_UPDATE_DEFAULT_TIMEOUT;
  36. const unsigned int NameChangeTransaction::MAX_UPDATE_TRIES_PER_SERVER;
  37. NameChangeTransaction::
  38. NameChangeTransaction(IOServicePtr& io_service,
  39. dhcp_ddns::NameChangeRequestPtr& ncr,
  40. DdnsDomainPtr& forward_domain,
  41. DdnsDomainPtr& reverse_domain)
  42. : io_service_(io_service), ncr_(ncr), forward_domain_(forward_domain),
  43. reverse_domain_(reverse_domain), dns_client_(), dns_update_request_(),
  44. dns_update_status_(DNSClient::OTHER), dns_update_response_(),
  45. forward_change_completed_(false), reverse_change_completed_(false),
  46. current_server_list_(), current_server_(), next_server_pos_(0),
  47. update_attempts_(0) {
  48. // @todo if io_service is NULL we are multi-threading and should
  49. // instantiate our own
  50. if (!io_service_) {
  51. isc_throw(NameChangeTransactionError, "IOServicePtr cannot be null");
  52. }
  53. if (!ncr_) {
  54. isc_throw(NameChangeTransactionError,
  55. "NameChangeRequest cannot be null");
  56. }
  57. if (ncr_->isForwardChange() && !(forward_domain_)) {
  58. isc_throw(NameChangeTransactionError,
  59. "Forward change must have a forward domain");
  60. }
  61. if (ncr_->isReverseChange() && !(reverse_domain_)) {
  62. isc_throw(NameChangeTransactionError,
  63. "Reverse change must have a reverse domain");
  64. }
  65. }
  66. NameChangeTransaction::~NameChangeTransaction(){
  67. }
  68. void
  69. NameChangeTransaction::startTransaction() {
  70. startModel(READY_ST);
  71. }
  72. void
  73. NameChangeTransaction::operator()(DNSClient::Status status) {
  74. // Stow the completion status and re-enter the run loop with the event
  75. // set to indicate IO completed.
  76. // runModel is exception safe so we are good to call it here.
  77. // It won't exit until we hit the next IO wait or the state model ends.
  78. setDnsUpdateStatus(status);
  79. runModel(IO_COMPLETED_EVT);
  80. }
  81. void
  82. NameChangeTransaction::sendUpdate(bool /* use_tsig_ */) {
  83. try {
  84. ++update_attempts_;
  85. // @todo add logic to add/replace TSIG key info in request if
  86. // use_tsig_ is true. We should be able to navigate to the TSIG key
  87. // for the current server. If not we would need to add that.
  88. // @todo time out should ultimately be configurable, down to
  89. // server level?
  90. dns_client_->doUpdate(*io_service_, current_server_->getIpAddress(),
  91. current_server_->getPort(), *dns_update_request_,
  92. DNS_UPDATE_DEFAULT_TIMEOUT);
  93. // Message is on its way, so the next event should be NOP_EVT.
  94. postNextEvent(NOP_EVT);
  95. } catch (const std::exception& ex) {
  96. // We were unable to initiate the send.
  97. // It is presumed that any throw from doUpdate is due to a programmatic
  98. // error, such as an unforeseen permutation of data, rather than an IO
  99. // failure. IO errors should be caught by the underlying asiolink
  100. // mechanisms and manifested as an unsuccessful IO status in the
  101. // DNSClient callback. Any problem here most likely means the request
  102. // is corrupt in some way and cannot be completed, therefore we will
  103. // log it and transition it to failure.
  104. LOG_ERROR(dctl_logger, DHCP_DDNS_TRANS_SEND_ERROR).arg(ex.what());
  105. transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
  106. }
  107. }
  108. void
  109. NameChangeTransaction::defineEvents() {
  110. // Call superclass impl first.
  111. StateModel::defineEvents();
  112. // Define NCT events.
  113. defineEvent(SELECT_SERVER_EVT, "SELECT_SERVER_EVT");
  114. defineEvent(SERVER_SELECTED_EVT, "SERVER_SELECTED_EVT");
  115. defineEvent(SERVER_IO_ERROR_EVT, "SERVER_IO_ERROR_EVT");
  116. defineEvent(NO_MORE_SERVERS_EVT, "NO_MORE_SERVERS_EVT");
  117. defineEvent(IO_COMPLETED_EVT, "IO_COMPLETED_EVT");
  118. defineEvent(UPDATE_OK_EVT, "UPDATE_OK_EVT");
  119. defineEvent(UPDATE_FAILED_EVT, "UPDATE_FAILED_EVT");
  120. }
  121. void
  122. NameChangeTransaction::verifyEvents() {
  123. // Call superclass impl first.
  124. StateModel::verifyEvents();
  125. // Verify NCT events.
  126. getEvent(SELECT_SERVER_EVT);
  127. getEvent(SERVER_SELECTED_EVT);
  128. getEvent(SERVER_IO_ERROR_EVT);
  129. getEvent(NO_MORE_SERVERS_EVT);
  130. getEvent(IO_COMPLETED_EVT);
  131. getEvent(UPDATE_OK_EVT);
  132. getEvent(UPDATE_FAILED_EVT);
  133. }
  134. void
  135. NameChangeTransaction::defineStates() {
  136. // Call superclass impl first.
  137. StateModel::defineStates();
  138. // This class is "abstract" in that it does not supply handlers for its
  139. // states, derivations must do that therefore they must define them.
  140. }
  141. void
  142. NameChangeTransaction::verifyStates() {
  143. // Call superclass impl first.
  144. StateModel::verifyStates();
  145. // Verify NCT states. This ensures that derivations provide the handlers.
  146. getState(READY_ST);
  147. getState(SELECTING_FWD_SERVER_ST);
  148. getState(SELECTING_REV_SERVER_ST);
  149. getState(PROCESS_TRANS_OK_ST);
  150. getState(PROCESS_TRANS_FAILED_ST);
  151. }
  152. void
  153. NameChangeTransaction::onModelFailure(const std::string& explanation) {
  154. setNcrStatus(dhcp_ddns::ST_FAILED);
  155. LOG_ERROR(dctl_logger, DHCP_DDNS_STATE_MODEL_UNEXPECTED_ERROR)
  156. .arg(explanation);
  157. }
  158. void
  159. NameChangeTransaction::retryTransition(const int fail_to_state) {
  160. if (update_attempts_ < MAX_UPDATE_TRIES_PER_SERVER) {
  161. // Re-enter the current state with same server selected.
  162. transition(getCurrState(), SERVER_SELECTED_EVT);
  163. } else {
  164. // Transition to given fail_to_state state if we are out
  165. // of retries.
  166. transition(fail_to_state, SERVER_IO_ERROR_EVT);
  167. }
  168. }
  169. void
  170. NameChangeTransaction::setDnsUpdateRequest(D2UpdateMessagePtr& request) {
  171. dns_update_request_ = request;
  172. }
  173. void
  174. NameChangeTransaction::clearDnsUpdateRequest() {
  175. dns_update_request_.reset();
  176. }
  177. void
  178. NameChangeTransaction::setDnsUpdateStatus(const DNSClient::Status& status) {
  179. dns_update_status_ = status;
  180. }
  181. void
  182. NameChangeTransaction::setDnsUpdateResponse(D2UpdateMessagePtr& response) {
  183. dns_update_response_ = response;
  184. }
  185. void
  186. NameChangeTransaction::clearDnsUpdateResponse() {
  187. dns_update_response_.reset();
  188. }
  189. void
  190. NameChangeTransaction::setForwardChangeCompleted(const bool value) {
  191. forward_change_completed_ = value;
  192. }
  193. void
  194. NameChangeTransaction::setReverseChangeCompleted(const bool value) {
  195. reverse_change_completed_ = value;
  196. }
  197. void
  198. NameChangeTransaction::setUpdateAttempts(const size_t value) {
  199. update_attempts_ = value;
  200. }
  201. D2UpdateMessagePtr
  202. NameChangeTransaction::prepNewRequest(DdnsDomainPtr domain) {
  203. if (!domain) {
  204. isc_throw(NameChangeTransactionError,
  205. "prepNewRequest - domain cannot be null");
  206. }
  207. try {
  208. // Create a "blank" update request.
  209. D2UpdateMessagePtr request(new D2UpdateMessage(D2UpdateMessage::
  210. OUTBOUND));
  211. // Construct the Zone Section.
  212. dns::Name zone_name(domain->getName());
  213. request->setZone(zone_name, dns::RRClass::IN());
  214. return (request);
  215. } catch (const std::exception& ex) {
  216. isc_throw(NameChangeTransactionError, "Cannot create new request :"
  217. << ex.what());
  218. }
  219. }
  220. void
  221. NameChangeTransaction::addLeaseAddressRdata(dns::RRsetPtr& rrset) {
  222. if (!rrset) {
  223. isc_throw(NameChangeTransactionError,
  224. "addLeaseAddressRdata - RRset cannot cannot be null");
  225. }
  226. try {
  227. // Manufacture an RData from the lease address then add it to the RR.
  228. dns::rdata::ConstRdataPtr rdata;
  229. if (ncr_->isV4()) {
  230. rdata.reset(new dns::rdata::in::A(ncr_->getIpAddress()));
  231. } else {
  232. rdata.reset(new dns::rdata::in::AAAA(ncr_->getIpAddress()));
  233. }
  234. rrset->addRdata(rdata);
  235. } catch (const std::exception& ex) {
  236. isc_throw(NameChangeTransactionError, "Cannot add address rdata: "
  237. << ex.what());
  238. }
  239. }
  240. void
  241. NameChangeTransaction::addDhcidRdata(dns::RRsetPtr& rrset) {
  242. if (!rrset) {
  243. isc_throw(NameChangeTransactionError,
  244. "addDhcidRdata - RRset cannot cannot be null");
  245. }
  246. try {
  247. const std::vector<uint8_t>& ncr_dhcid = ncr_->getDhcid().getBytes();
  248. util::InputBuffer buffer(ncr_dhcid.data(), ncr_dhcid.size());
  249. dns::rdata::ConstRdataPtr rdata (new dns::rdata::in::
  250. DHCID(buffer, ncr_dhcid.size()));
  251. rrset->addRdata(rdata);
  252. } catch (const std::exception& ex) {
  253. isc_throw(NameChangeTransactionError, "Cannot add DCHID rdata: "
  254. << ex.what());
  255. }
  256. }
  257. void
  258. NameChangeTransaction::addPtrRdata(dns::RRsetPtr& rrset) {
  259. if (!rrset) {
  260. isc_throw(NameChangeTransactionError,
  261. "addPtrRdata - RRset cannot cannot be null");
  262. }
  263. try {
  264. dns::rdata::ConstRdataPtr rdata(new dns::rdata::generic::
  265. PTR(getNcr()->getFqdn()));
  266. rrset->addRdata(rdata);
  267. } catch (const std::exception& ex) {
  268. isc_throw(NameChangeTransactionError, "Cannot add PTR rdata: "
  269. << ex.what());
  270. }
  271. }
  272. const dhcp_ddns::NameChangeRequestPtr&
  273. NameChangeTransaction::getNcr() const {
  274. return (ncr_);
  275. }
  276. const TransactionKey&
  277. NameChangeTransaction::getTransactionKey() const {
  278. return (ncr_->getDhcid());
  279. }
  280. dhcp_ddns::NameChangeStatus
  281. NameChangeTransaction::getNcrStatus() const {
  282. return (ncr_->getStatus());
  283. }
  284. DdnsDomainPtr&
  285. NameChangeTransaction::getForwardDomain() {
  286. return (forward_domain_);
  287. }
  288. DdnsDomainPtr&
  289. NameChangeTransaction::getReverseDomain() {
  290. return (reverse_domain_);
  291. }
  292. void
  293. NameChangeTransaction::initServerSelection(const DdnsDomainPtr& domain) {
  294. if (!domain) {
  295. isc_throw(NameChangeTransactionError,
  296. "initServerSelection called with an empty domain");
  297. }
  298. current_server_list_ = domain->getServers();
  299. next_server_pos_ = 0;
  300. current_server_.reset();
  301. }
  302. bool
  303. NameChangeTransaction::selectNextServer() {
  304. if ((current_server_list_) &&
  305. (next_server_pos_ < current_server_list_->size())) {
  306. current_server_ = (*current_server_list_)[next_server_pos_];
  307. dns_update_response_.reset(new
  308. D2UpdateMessage(D2UpdateMessage::INBOUND));
  309. // @todo Protocol is set on DNSClient constructor. We need
  310. // to propagate a configuration value downward, probably starting
  311. // at global, then domain, then server
  312. // Once that is supported we need to add it here.
  313. dns_client_.reset(new DNSClient(dns_update_response_ , this,
  314. DNSClient::UDP));
  315. ++next_server_pos_;
  316. return (true);
  317. }
  318. return (false);
  319. }
  320. const DNSClientPtr&
  321. NameChangeTransaction::getDNSClient() const {
  322. return (dns_client_);
  323. }
  324. const DnsServerInfoPtr&
  325. NameChangeTransaction::getCurrentServer() const {
  326. return (current_server_);
  327. }
  328. void
  329. NameChangeTransaction::setNcrStatus(const dhcp_ddns::NameChangeStatus& status) {
  330. return (ncr_->setStatus(status));
  331. }
  332. const D2UpdateMessagePtr&
  333. NameChangeTransaction::getDnsUpdateRequest() const {
  334. return (dns_update_request_);
  335. }
  336. DNSClient::Status
  337. NameChangeTransaction::getDnsUpdateStatus() const {
  338. return (dns_update_status_);
  339. }
  340. const D2UpdateMessagePtr&
  341. NameChangeTransaction::getDnsUpdateResponse() const {
  342. return (dns_update_response_);
  343. }
  344. bool
  345. NameChangeTransaction::getForwardChangeCompleted() const {
  346. return (forward_change_completed_);
  347. }
  348. bool
  349. NameChangeTransaction::getReverseChangeCompleted() const {
  350. return (reverse_change_completed_);
  351. }
  352. size_t
  353. NameChangeTransaction::getUpdateAttempts() const {
  354. return (update_attempts_);
  355. }
  356. const dns::RRType&
  357. NameChangeTransaction::getAddressRRType() const {
  358. return (ncr_->isV4() ? dns::RRType::A() : dns::RRType::AAAA());
  359. }
  360. } // namespace isc::d2
  361. } // namespace isc