1 // Copyright (C) 2013-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 <d2/nc_remove.h>
10 #include <d2srv/d2_cfg_mgr.h>
11 #include <d2srv/d2_log.h>
12 
13 #include <functional>
14 
15 namespace isc {
16 namespace d2 {
17 
18 
19 // NameRemoveTransaction states
20 const int NameRemoveTransaction::REMOVING_FWD_ADDRS_ST;
21 const int NameRemoveTransaction::REMOVING_FWD_RRS_ST;
22 const int NameRemoveTransaction::REMOVING_REV_PTRS_ST;
23 
24 // NameRemoveTransaction events
25 // Currently NameRemoveTransaction does not define any events.
26 
27 NameRemoveTransaction::
NameRemoveTransaction(asiolink::IOServicePtr & io_service,dhcp_ddns::NameChangeRequestPtr & ncr,DdnsDomainPtr & forward_domain,DdnsDomainPtr & reverse_domain,D2CfgMgrPtr & cfg_mgr)28 NameRemoveTransaction(asiolink::IOServicePtr& io_service,
29                    dhcp_ddns::NameChangeRequestPtr& ncr,
30                    DdnsDomainPtr& forward_domain,
31                    DdnsDomainPtr& reverse_domain,
32                    D2CfgMgrPtr& cfg_mgr)
33     : NameChangeTransaction(io_service, ncr, forward_domain, reverse_domain,
34                             cfg_mgr) {
35     if (ncr->getChangeType() != isc::dhcp_ddns::CHG_REMOVE) {
36         isc_throw (NameRemoveTransactionError,
37                    "NameRemoveTransaction, request type must be CHG_REMOVE");
38     }
39 }
40 
~NameRemoveTransaction()41 NameRemoveTransaction::~NameRemoveTransaction(){
42 }
43 
44 void
defineEvents()45 NameRemoveTransaction::defineEvents() {
46     // Call superclass impl first.
47     NameChangeTransaction::defineEvents();
48 
49     // Define NameRemoveTransaction events.
50     // Currently NameRemoveTransaction does not define any events.
51     // defineEvent(TBD_EVENT, "TBD_EVT");
52 }
53 
54 void
verifyEvents()55 NameRemoveTransaction::verifyEvents() {
56     // Call superclass implementation first to verify its events. These are
57     // events common to all transactions, and they must be defined.
58     // SELECT_SERVER_EVT
59     // SERVER_SELECTED_EVT
60     // SERVER_IO_ERROR_EVT
61     // NO_MORE_SERVERS_EVT
62     // IO_COMPLETED_EVT
63     // UPDATE_OK_EVT
64     // UPDATE_FAILED_EVT
65     NameChangeTransaction::verifyEvents();
66 
67     // Verify NameRemoveTransaction events by attempting to fetch them.
68     // Currently NameRemoveTransaction does not define any events.
69     // getEvent(TBD_EVENT);
70 }
71 
72 void
defineStates()73 NameRemoveTransaction::defineStates() {
74     // Call superclass impl first.
75     NameChangeTransaction::defineStates();
76 
77     // Define NameRemoveTransaction states.
78     defineState(READY_ST, "READY_ST",
79                 std::bind(&NameRemoveTransaction::readyHandler, this));
80 
81     defineState(SELECTING_FWD_SERVER_ST, "SELECTING_FWD_SERVER_ST",
82                 std::bind(&NameRemoveTransaction::selectingFwdServerHandler,
83                           this));
84 
85     defineState(SELECTING_REV_SERVER_ST, "SELECTING_REV_SERVER_ST",
86                 std::bind(&NameRemoveTransaction::selectingRevServerHandler,
87                           this));
88 
89     defineState(REMOVING_FWD_ADDRS_ST, "REMOVING_FWD_ADDRS_ST",
90                 std::bind(&NameRemoveTransaction::removingFwdAddrsHandler,
91                           this));
92 
93     defineState(REMOVING_FWD_RRS_ST, "REMOVING_FWD_RRS_ST",
94                 std::bind(&NameRemoveTransaction::removingFwdRRsHandler,
95                           this));
96 
97     defineState(REMOVING_REV_PTRS_ST, "REMOVING_REV_PTRS_ST",
98                 std::bind(&NameRemoveTransaction::removingRevPtrsHandler,
99                           this));
100 
101     defineState(PROCESS_TRANS_OK_ST, "PROCESS_TRANS_OK_ST",
102                 std::bind(&NameRemoveTransaction::processRemoveOkHandler,
103                           this));
104 
105     defineState(PROCESS_TRANS_FAILED_ST, "PROCESS_TRANS_FAILED_ST",
106                 std::bind(&NameRemoveTransaction::processRemoveFailedHandler,
107                           this));
108 }
109 
110 void
verifyStates()111 NameRemoveTransaction::verifyStates() {
112     // Call superclass implementation first to verify its states. These are
113     // states common to all transactions, and they must be defined.
114     // READY_ST
115     // SELECTING_FWD_SERVER_ST
116     // SELECTING_REV_SERVER_ST
117     // PROCESS_TRANS_OK_ST
118     // PROCESS_TRANS_FAILED_ST
119     NameChangeTransaction::verifyStates();
120 
121     // Verify NameRemoveTransaction states by attempting to fetch them.
122     getStateInternal(REMOVING_FWD_ADDRS_ST);
123     getStateInternal(REMOVING_FWD_RRS_ST);
124     getStateInternal(REMOVING_REV_PTRS_ST);
125 }
126 
127 void
readyHandler()128 NameRemoveTransaction::readyHandler() {
129     switch(getNextEvent()) {
130     case START_EVT:
131         if (getForwardDomain()) {
132             // Request includes a forward change, do that first.
133             transition(SELECTING_FWD_SERVER_ST, SELECT_SERVER_EVT);
134         } else {
135             // Reverse change only, transition accordingly.
136             transition(SELECTING_REV_SERVER_ST, SELECT_SERVER_EVT);
137         }
138 
139         break;
140     default:
141         // Event is invalid.
142         isc_throw(NameRemoveTransactionError,
143                   "Wrong event for context: " << getContextStr());
144     }
145 }
146 
147 void
selectingFwdServerHandler()148 NameRemoveTransaction::selectingFwdServerHandler() {
149     switch(getNextEvent()) {
150     case SELECT_SERVER_EVT:
151         // First time through for this transaction, so initialize server
152         // selection.
153         initServerSelection(getForwardDomain());
154         break;
155     case SERVER_IO_ERROR_EVT:
156         // We failed to communicate with current server. Attempt to select
157         // another one below.
158         break;
159     default:
160         // Event is invalid.
161         isc_throw(NameRemoveTransactionError,
162                   "Wrong event for context: " << getContextStr());
163     }
164 
165     // Select the next server from the list of forward servers.
166     if (selectNextServer()) {
167         // We have a server to try.
168         transition(REMOVING_FWD_ADDRS_ST, SERVER_SELECTED_EVT);
169     }
170     else {
171         // Server list is exhausted, so fail the transaction.
172         transition(PROCESS_TRANS_FAILED_ST, NO_MORE_SERVERS_EVT);
173     }
174 }
175 
176 void
removingFwdAddrsHandler()177 NameRemoveTransaction::removingFwdAddrsHandler() {
178     if (doOnEntry()) {
179         // Clear the update attempts count on initial transition.
180         clearUpdateAttempts();
181     }
182 
183     switch(getNextEvent()) {
184     case SERVER_SELECTED_EVT:
185         try {
186             clearDnsUpdateRequest();
187             buildRemoveFwdAddressRequest();
188         } catch (const std::exception& ex) {
189             // While unlikely, the build might fail if we have invalid
190             // data.  Should that be the case, we need to fail the
191             // transaction.
192             LOG_ERROR(d2_to_dns_logger,
193                       DHCP_DDNS_FORWARD_REMOVE_ADDRS_BUILD_FAILURE)
194                 .arg(getRequestId())
195                 .arg(getNcr()->toText())
196                 .arg(ex.what());
197             transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
198             break;
199         }
200 
201         // Call sendUpdate() to initiate the async send. Note it also sets
202         // next event to NOP_EVT.
203         sendUpdate("Forward A/AAAA Remove");
204         break;
205 
206     case IO_COMPLETED_EVT: {
207         switch (getDnsUpdateStatus()) {
208         case DNSClient::SUCCESS: {
209             // We successfully received a response packet from the server.
210             // The RCODE will be based on a value-dependent RRset search,
211             // see RFC 2136 section 3.2.3/3.2.4.
212             const dns::Rcode& rcode = getDnsUpdateResponse()->getRcode();
213             if ((rcode == dns::Rcode::NOERROR()) ||
214                 (rcode == dns::Rcode::NXRRSET())) {
215                 // We were able to remove it or it wasn't there, now we
216                 // need to remove any other RRs for this FQDN.
217                 transition(REMOVING_FWD_RRS_ST, UPDATE_OK_EVT);
218             } else {
219                 // Per RFC4703 any other value means cease.
220                 // If we get not authorized should we try the next server in
221                 // the list? @todo  This needs some discussion perhaps.
222                 LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_FORWARD_REMOVE_ADDRS_REJECTED)
223                           .arg(getRequestId())
224                           .arg(getCurrentServer()->toText())
225                           .arg(getNcr()->getFqdn())
226                           .arg(rcode.getCode());
227                 transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
228             }
229 
230             break;
231         }
232 
233         case DNSClient::TIMEOUT:
234         case DNSClient::OTHER:
235             // We couldn't send to the current server, log it and set up
236             // to select the next server for a retry.
237             // @note For now we treat OTHER as an IO error like TIMEOUT. It
238             // is not entirely clear if this is accurate.
239             LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_FORWARD_REMOVE_ADDRS_IO_ERROR)
240                       .arg(getRequestId())
241                       .arg(getNcr()->getFqdn())
242                       .arg(getCurrentServer()->toText());
243 
244             retryTransition(SELECTING_FWD_SERVER_ST);
245             break;
246 
247         case DNSClient::INVALID_RESPONSE:
248             // A response was received but was corrupt. Retry it like an IO
249             // error.
250             LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_FORWARD_REMOVE_ADDRS_RESP_CORRUPT)
251                       .arg(getRequestId())
252                       .arg(getCurrentServer()->toText())
253                       .arg(getNcr()->getFqdn());
254 
255             retryTransition(SELECTING_FWD_SERVER_ST);
256             break;
257 
258         default:
259             // Any other value and we will fail this transaction, something
260             // bigger is wrong.
261             LOG_ERROR(d2_to_dns_logger,
262                       DHCP_DDNS_FORWARD_REMOVE_ADDRS_BAD_DNSCLIENT_STATUS)
263                       .arg(getRequestId())
264                       .arg(getDnsUpdateStatus())
265                       .arg(getNcr()->getFqdn())
266                       .arg(getCurrentServer()->toText());
267 
268             transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
269             break;
270         } // end switch on dns_status
271 
272         break;
273     } // end case IO_COMPLETE_EVT
274 
275     default:
276         // Event is invalid.
277         isc_throw(NameRemoveTransactionError,
278                   "Wrong event for context: " << getContextStr());
279     }
280 }
281 
282 
283 void
removingFwdRRsHandler()284 NameRemoveTransaction::removingFwdRRsHandler() {
285     if (doOnEntry()) {
286         // Clear the update attempts count on initial transition.
287         clearUpdateAttempts();
288     }
289 
290     switch(getNextEvent()) {
291     case UPDATE_OK_EVT:
292     case SERVER_SELECTED_EVT:
293         try {
294             clearDnsUpdateRequest();
295             buildRemoveFwdRRsRequest();
296         } catch (const std::exception& ex) {
297             // While unlikely, the build might fail if we have invalid
298             // data.  Should that be the case, we need to fail the
299             // transaction.
300             LOG_ERROR(d2_to_dns_logger,
301                       DHCP_DDNS_FORWARD_REMOVE_RRS_BUILD_FAILURE)
302                 .arg(getRequestId())
303                 .arg(getNcr()->toText())
304                 .arg(ex.what());
305             transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
306             break;
307         }
308 
309         // Call sendUpdate() to initiate the async send. Note it also sets
310         // next event to NOP_EVT.
311         sendUpdate("Forward RR Remove");
312         break;
313 
314     case IO_COMPLETED_EVT: {
315         switch (getDnsUpdateStatus()) {
316         case DNSClient::SUCCESS: {
317             // We successfully received a response packet from the server.
318             // The RCODE will be based on a value-dependent RRset search,
319             // see RFC 2136 section 3.2.3/3.2.4.
320             const dns::Rcode& rcode = getDnsUpdateResponse()->getRcode();
321             if ((rcode == dns::Rcode::NOERROR()) ||
322                 (rcode == dns::Rcode::NXRRSET())) {
323                 // We were able to remove them or they were not there (
324                 // Rcode of NXRRSET means there are no matching RRsets).
325                 // In either case, we consider it success and mark it as done.
326                 setForwardChangeCompleted(true);
327 
328                 // If request calls for reverse update then do that next,
329                 // otherwise we can process ok.
330                 if (getReverseDomain()) {
331                     transition(SELECTING_REV_SERVER_ST, SELECT_SERVER_EVT);
332                 } else {
333                     transition(PROCESS_TRANS_OK_ST, UPDATE_OK_EVT);
334                 }
335             } else {
336                 // Per RFC4703 any other value means cease.
337                 // If we get not authorized should try the next server in
338                 // the list? @todo  This needs some discussion perhaps.
339                 LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_FORWARD_REMOVE_RRS_REJECTED)
340                           .arg(getRequestId())
341                           .arg(getCurrentServer()->toText())
342                           .arg(getNcr()->getFqdn())
343                           .arg(rcode.getCode());
344                 transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
345             }
346 
347             break;
348         }
349 
350         case DNSClient::TIMEOUT:
351         case DNSClient::OTHER:
352             // We couldn't send to the current server, log it and set up
353             // to select the next server for a retry.
354             // @note For now we treat OTHER as an IO error like TIMEOUT. It
355             // is not entirely clear if this is accurate.
356             LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_FORWARD_REMOVE_RRS_IO_ERROR)
357                       .arg(getRequestId())
358                       .arg(getNcr()->getFqdn())
359                       .arg(getCurrentServer()->toText());
360 
361             // @note If we exhaust the IO retries for the current server
362             // due to IO failures, we will abort the remaining updates.
363             // The rational is that we are only in this state, if the remove
364             // of the forward address RR succeeded (removingFwdAddrsHandler)
365             // on the current server. Therefore  we should not attempt another
366             // removal on a different server.  This is perhaps a point
367             // for discussion.
368             // @todo Should we go ahead with the reverse remove?
369             retryTransition(PROCESS_TRANS_FAILED_ST);
370             break;
371 
372         case DNSClient::INVALID_RESPONSE:
373             // A response was received but was corrupt. Retry it like an IO
374             // error.
375             LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_FORWARD_REMOVE_RRS_RESP_CORRUPT)
376                       .arg(getRequestId())
377                       .arg(getCurrentServer()->toText())
378                       .arg(getNcr()->getFqdn());
379 
380             // If we are out of retries on this server abandon the transaction.
381             // (Same logic as the case for TIMEOUT above).
382             retryTransition(PROCESS_TRANS_FAILED_ST);
383             break;
384 
385         default:
386             // Any other value and we will fail this transaction, something
387             // bigger is wrong.
388             LOG_ERROR(d2_to_dns_logger,
389                       DHCP_DDNS_FORWARD_REMOVE_RRS_BAD_DNSCLIENT_STATUS)
390                       .arg(getRequestId())
391                       .arg(getDnsUpdateStatus())
392                       .arg(getNcr()->getFqdn())
393                       .arg(getCurrentServer()->toText());
394 
395             transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
396             break;
397         } // end switch on dns_status
398 
399         break;
400     } // end case IO_COMPLETE_EVT
401 
402     default:
403         // Event is invalid.
404         isc_throw(NameRemoveTransactionError,
405                   "Wrong event for context: " << getContextStr());
406     }
407 }
408 
409 
410 void
selectingRevServerHandler()411 NameRemoveTransaction::selectingRevServerHandler() {
412     switch(getNextEvent()) {
413     case SELECT_SERVER_EVT:
414         // First time through for this transaction, so initialize server
415         // selection.
416         initServerSelection(getReverseDomain());
417         break;
418     case SERVER_IO_ERROR_EVT:
419         // We failed to communicate with current server. Attempt to select
420         // another one below.
421         break;
422     default:
423         // Event is invalid.
424         isc_throw(NameRemoveTransactionError,
425                   "Wrong event for context: " << getContextStr());
426     }
427 
428     // Select the next server from the list of forward servers.
429     if (selectNextServer()) {
430         // We have a server to try.
431         transition(REMOVING_REV_PTRS_ST, SERVER_SELECTED_EVT);
432     }
433     else {
434         // Server list is exhausted, so fail the transaction.
435         transition(PROCESS_TRANS_FAILED_ST, NO_MORE_SERVERS_EVT);
436     }
437 }
438 
439 
440 void
removingRevPtrsHandler()441 NameRemoveTransaction::removingRevPtrsHandler() {
442     if (doOnEntry()) {
443         // Clear the update attempts count on initial transition.
444         clearUpdateAttempts();
445     }
446 
447     switch(getNextEvent()) {
448     case SERVER_SELECTED_EVT:
449         try {
450             clearDnsUpdateRequest();
451             buildRemoveRevPtrsRequest();
452         } catch (const std::exception& ex) {
453             // While unlikely, the build might fail if we have invalid
454             // data.  Should that be the case, we need to fail the
455             // transaction.
456             LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_REVERSE_REMOVE_BUILD_FAILURE)
457                 .arg(getRequestId())
458                 .arg(getNcr()->toText())
459                 .arg(ex.what());
460             transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
461             break;
462         }
463 
464         // Call sendUpdate() to initiate the async send. Note it also sets
465         // next event to NOP_EVT.
466         sendUpdate("Reverse Remove");
467         break;
468 
469     case IO_COMPLETED_EVT: {
470         switch (getDnsUpdateStatus()) {
471         case DNSClient::SUCCESS: {
472             // We successfully received a response packet from the server.
473             // The RCODE will be based on a value-dependent RRset search,
474             // see RFC 2136 section 3.2.3/3.2.4.
475             const dns::Rcode& rcode = getDnsUpdateResponse()->getRcode();
476             if ((rcode == dns::Rcode::NOERROR()) ||
477                 (rcode == dns::Rcode::NXRRSET())) {
478                 // We were able to remove the reverse mapping or they were
479                 // not there (Rcode of NXRRSET means there are no matching
480                 // RRsets). In either case, mark it as done.
481                 setReverseChangeCompleted(true);
482                 transition(PROCESS_TRANS_OK_ST, UPDATE_OK_EVT);
483             } else {
484                 // Per RFC4703 any other value means cease.
485                 // If we get not authorized should try the next server in
486                 // the list? @todo  This needs some discussion perhaps.
487                 LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_REVERSE_REMOVE_REJECTED)
488                           .arg(getRequestId())
489                           .arg(getCurrentServer()->toText())
490                           .arg(getNcr()->getFqdn())
491                           .arg(rcode.getCode());
492                 transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
493             }
494 
495             break;
496         }
497 
498         case DNSClient::TIMEOUT:
499         case DNSClient::OTHER:
500             // We couldn't send to the current server, log it and set up
501             // to select the next server for a retry.
502             // @note For now we treat OTHER as an IO error like TIMEOUT. It
503             // is not entirely clear if this is accurate.
504             LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_REVERSE_REMOVE_IO_ERROR)
505                       .arg(getRequestId())
506                       .arg(getNcr()->getFqdn())
507                       .arg(getCurrentServer()->toText());
508 
509             // If we are out of retries on this server, we go back and start
510             // all over on a new server.
511             retryTransition(SELECTING_REV_SERVER_ST);
512             break;
513 
514         case DNSClient::INVALID_RESPONSE:
515             // A response was received but was corrupt. Retry it like an IO
516             // error.
517             LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_REVERSE_REMOVE_RESP_CORRUPT)
518                       .arg(getRequestId())
519                       .arg(getCurrentServer()->toText())
520                       .arg(getNcr()->getFqdn());
521 
522             // If we are out of retries on this server, we go back and start
523             // all over on a new server.
524             retryTransition(SELECTING_REV_SERVER_ST);
525             break;
526 
527         default:
528             // Any other value and we will fail this transaction, something
529             // bigger is wrong.
530             LOG_ERROR(d2_to_dns_logger,
531                       DHCP_DDNS_REVERSE_REMOVE_BAD_DNSCLIENT_STATUS)
532                       .arg(getRequestId())
533                       .arg(getDnsUpdateStatus())
534                       .arg(getNcr()->getFqdn())
535                       .arg(getCurrentServer()->toText());
536 
537             transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
538             break;
539         } // end switch on dns_status
540 
541         break;
542     } // end case IO_COMPLETE_EVT
543 
544     default:
545         // Event is invalid.
546         isc_throw(NameRemoveTransactionError,
547                   "Wrong event for context: " << getContextStr());
548     }
549 }
550 
551 
552 void
processRemoveOkHandler()553 NameRemoveTransaction::processRemoveOkHandler() {
554     switch(getNextEvent()) {
555     case UPDATE_OK_EVT:
556         LOG_INFO(d2_to_dns_logger, DHCP_DDNS_REMOVE_SUCCEEDED)
557                 .arg(getRequestId())
558                 .arg(getNcr()->toText());
559         setNcrStatus(dhcp_ddns::ST_COMPLETED);
560         endModel();
561         break;
562     default:
563         // Event is invalid.
564         isc_throw(NameRemoveTransactionError,
565                   "Wrong event for context: " << getContextStr());
566     }
567 }
568 
569 void
processRemoveFailedHandler()570 NameRemoveTransaction::processRemoveFailedHandler() {
571     switch(getNextEvent()) {
572     case UPDATE_FAILED_EVT:
573     case NO_MORE_SERVERS_EVT:
574     case SERVER_IO_ERROR_EVT:
575         setNcrStatus(dhcp_ddns::ST_FAILED);
576         LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_REMOVE_FAILED)
577                   .arg(getRequestId())
578                   .arg(transactionOutcomeString());
579         endModel();
580         break;
581     default:
582         // Event is invalid.
583         isc_throw(NameRemoveTransactionError,
584                   "Wrong event for context: " << getContextStr());
585     }
586 }
587 
588 void
buildRemoveFwdAddressRequest()589 NameRemoveTransaction::buildRemoveFwdAddressRequest() {
590     // Construct an empty request.
591     D2UpdateMessagePtr request = prepNewRequest(getForwardDomain());
592 
593     // Content on this request is based on RFC 4703, section 5.5, paragraph 4.
594     // Construct dns::Name from NCR fqdn.
595     dns::Name fqdn(dns::Name(getNcr()->getFqdn()));
596     // First build the Prerequisite Section
597 
598     // Create an DHCID matches prerequisite RR and add it to the
599     // pre-requisite section
600     // Based on RFC 2136, section 2.4.2.
601     dns::RRsetPtr prereq(new dns::RRset(fqdn, dns::RRClass::IN(),
602                                         dns::RRType::DHCID(), dns::RRTTL(0)));
603     addDhcidRdata(prereq);
604     request->addRRset(D2UpdateMessage::SECTION_PREREQUISITE, prereq);
605 
606     // Next build the Update Section
607 
608     // Create the FQDN/IP 'delete' RR and add it to the update section.
609     // Add the RR to update section.
610     // Based on 2136 section 2.5.4
611     dns::RRsetPtr update(new dns::RRset(fqdn, dns::RRClass::NONE(),
612                          getAddressRRType(), dns::RRTTL(0)));
613     addLeaseAddressRdata(update);
614     request->addRRset(D2UpdateMessage::SECTION_UPDATE, update);
615 
616     // Set the transaction's update request to the new request.
617     setDnsUpdateRequest(request);
618 }
619 
620 void
buildRemoveFwdRRsRequest()621 NameRemoveTransaction::buildRemoveFwdRRsRequest() {
622     // Construct an empty request.
623     D2UpdateMessagePtr request = prepNewRequest(getForwardDomain());
624 
625     // Construct dns::Name from NCR fqdn.
626     dns::Name fqdn(dns::Name(getNcr()->getFqdn()));
627 
628     // Content on this request is based on RFC 4703, section 5.5, paragraph 5.
629     // First build the Prerequisite Section.
630 
631     // Now create an DHCID matches prerequisite RR.
632     // Set the RR's RData to DHCID.
633     // Add it to the pre-requisite section.
634     // Based on RFC 2136, section 2.4.2.
635     dns::RRsetPtr prereq(new dns::RRset(fqdn, dns::RRClass::IN(),
636                          dns::RRType::DHCID(), dns::RRTTL(0)));
637     addDhcidRdata(prereq);
638     request->addRRset(D2UpdateMessage::SECTION_PREREQUISITE, prereq);
639 
640     // Create an assertion that there are no A RRs for the FQDN.
641     // Add it to the pre-reqs.
642     // Based on RFC 2136, section 2.4.3.
643     prereq.reset(new dns::RRset(fqdn, dns::RRClass::NONE(),
644                                 dns::RRType::A(), dns::RRTTL(0)));
645     request->addRRset(D2UpdateMessage::SECTION_PREREQUISITE, prereq);
646 
647     // Create an assertion that there are no A RRs for the FQDN.
648     // Add it to the pre-reqs.
649     // Based on RFC 2136, section 2.4.3.
650     prereq.reset(new dns::RRset(fqdn, dns::RRClass::NONE(),
651                                 dns::RRType::AAAA(), dns::RRTTL(0)));
652     request->addRRset(D2UpdateMessage::SECTION_PREREQUISITE, prereq);
653 
654     // Next build the Update Section.
655 
656     // Create the 'delete' of all RRs for FQDN.
657     // Set the message RData to lease address.
658     // Add the RR to update section.
659     // Based on RFC 2136, section 2.5.3.
660     dns::RRsetPtr update(new dns::RRset(fqdn, dns::RRClass::ANY(),
661                          dns::RRType::ANY(), dns::RRTTL(0)));
662     request->addRRset(D2UpdateMessage::SECTION_UPDATE, update);
663 
664     // Set the transaction's update request to the new request.
665     setDnsUpdateRequest(request);
666 }
667 
668 void
buildRemoveRevPtrsRequest()669 NameRemoveTransaction::buildRemoveRevPtrsRequest() {
670     // Construct an empty request.
671     D2UpdateMessagePtr request = prepNewRequest(getReverseDomain());
672 
673     // Create the reverse IP address "FQDN".
674     std::string rev_addr = D2CfgMgr::reverseIpAddress(getNcr()->getIpAddress());
675     dns::Name rev_ip(rev_addr);
676 
677     // Content on this request is based on RFC 4703, section 5.5, paragraph 2.
678     // First build the Prerequisite Section.
679     // (Note that per RFC 4703, section 5.4, there is no need to validate
680     // DHCID RR for PTR entries.)
681 
682     // Create an assertion that the PTRDNAME in the PTR record matches the
683     // client's FQDN for the address that was released.
684     // Based on RFC 2136, section 3.2.3
685     dns::RRsetPtr prereq(new dns::RRset(rev_ip, dns::RRClass::IN(),
686                                         dns::RRType::PTR(), dns::RRTTL(0)));
687     addPtrRdata(prereq);
688     request->addRRset(D2UpdateMessage::SECTION_PREREQUISITE, prereq);
689 
690     // Now, build the Update section.
691 
692     // Create a delete of any RRs for the FQDN and add it to update section.
693     // Based on RFC 2136, section 3.4.2.3
694     dns::RRsetPtr update(new dns::RRset(rev_ip, dns::RRClass::ANY(),
695                          dns::RRType::ANY(), dns::RRTTL(0)));
696     request->addRRset(D2UpdateMessage::SECTION_UPDATE, update);
697 
698     // Set the transaction's update request to the new request.
699     setDnsUpdateRequest(request);
700 }
701 
702 } // namespace isc::d2
703 } // namespace isc
704