nc_trans.cc 13 KB

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