nc_remove.cc 26.3 KB
Newer Older
1
// Copyright (C) 2013-2015 Internet Systems Consortium, Inc. ("ISC")
2 3 4 5 6 7 8 9 10 11 12 13 14
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.

15 16
#include <config.h>

17
#include <d2/d2_log.h>
18
#include <d2/d2_cfg_mgr.h>
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
#include <d2/nc_remove.h>

#include <boost/function.hpp>
#include <boost/bind.hpp>

namespace isc {
namespace d2 {


// NameRemoveTransaction states
const int NameRemoveTransaction::REMOVING_FWD_ADDRS_ST;
const int NameRemoveTransaction::REMOVING_FWD_RRS_ST;
const int NameRemoveTransaction::REMOVING_REV_PTRS_ST;

// NameRemoveTransaction events
34
// Currently NameRemoveTransaction does not define any events.
35 36

NameRemoveTransaction::
37
NameRemoveTransaction(asiolink::IOServicePtr& io_service,
38 39
                   dhcp_ddns::NameChangeRequestPtr& ncr,
                   DdnsDomainPtr& forward_domain,
40 41 42 43
                   DdnsDomainPtr& reverse_domain,
                   D2CfgMgrPtr& cfg_mgr)
    : NameChangeTransaction(io_service, ncr, forward_domain, reverse_domain,
                            cfg_mgr) {
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
    if (ncr->getChangeType() != isc::dhcp_ddns::CHG_REMOVE) {
        isc_throw (NameRemoveTransactionError,
                   "NameRemoveTransaction, request type must be CHG_REMOVE");
    }
}

NameRemoveTransaction::~NameRemoveTransaction(){
}

void
NameRemoveTransaction::defineEvents() {
    // Call superclass impl first.
    NameChangeTransaction::defineEvents();

    // Define NameRemoveTransaction events.
59
    // Currently NameRemoveTransaction does not define any events.
60 61 62 63 64
    // defineEvent(TBD_EVENT, "TBD_EVT");
}

void
NameRemoveTransaction::verifyEvents() {
65 66 67 68 69 70 71 72 73
    // Call superclass implementation first to verify its events. These are
    // events common to all transactions, and they must be defined.
    // SELECT_SERVER_EVT
    // SERVER_SELECTED_EVT
    // SERVER_IO_ERROR_EVT
    // NO_MORE_SERVERS_EVT
    // IO_COMPLETED_EVT
    // UPDATE_OK_EVT
    // UPDATE_FAILED_EVT
74 75
    NameChangeTransaction::verifyEvents();

76
    // Verify NameRemoveTransaction events by attempting to fetch them.
77
    // Currently NameRemoveTransaction does not define any events.
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
    // getEvent(TBD_EVENT);
}

void
NameRemoveTransaction::defineStates() {
    // Call superclass impl first.
    NameChangeTransaction::defineStates();

    // Define NameRemoveTransaction states.
    defineState(READY_ST, "READY_ST",
                boost::bind(&NameRemoveTransaction::readyHandler, this));

    defineState(SELECTING_FWD_SERVER_ST, "SELECTING_FWD_SERVER_ST",
                boost::bind(&NameRemoveTransaction::selectingFwdServerHandler,
                            this));

    defineState(SELECTING_REV_SERVER_ST, "SELECTING_REV_SERVER_ST",
                boost::bind(&NameRemoveTransaction::selectingRevServerHandler,
                            this));

    defineState(REMOVING_FWD_ADDRS_ST, "REMOVING_FWD_ADDRS_ST",
                boost::bind(&NameRemoveTransaction::removingFwdAddrsHandler,
                            this));

    defineState(REMOVING_FWD_RRS_ST, "REMOVING_FWD_RRS_ST",
                boost::bind(&NameRemoveTransaction::removingFwdRRsHandler,
                            this));

    defineState(REMOVING_REV_PTRS_ST, "REMOVING_REV_PTRS_ST",
                boost::bind(&NameRemoveTransaction::removingRevPtrsHandler,
                            this));

    defineState(PROCESS_TRANS_OK_ST, "PROCESS_TRANS_OK_ST",
                boost::bind(&NameRemoveTransaction::processRemoveOkHandler,
                            this));

    defineState(PROCESS_TRANS_FAILED_ST, "PROCESS_TRANS_FAILED_ST",
                boost::bind(&NameRemoveTransaction::processRemoveFailedHandler,
                            this));
}

void
NameRemoveTransaction::verifyStates() {
121 122 123 124 125 126 127
    // Call superclass implementation first to verify its states. These are
    // states common to all transactions, and they must be defined.
    // READY_ST
    // SELECTING_FWD_SERVER_ST
    // SELECTING_REV_SERVER_ST
    // PROCESS_TRANS_OK_ST
    // PROCESS_TRANS_FAILED_ST
128 129
    NameChangeTransaction::verifyStates();

130
    // Verify NameRemoveTransaction states by attempting to fetch them.
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
    getState(REMOVING_FWD_ADDRS_ST);
    getState(REMOVING_FWD_RRS_ST);
    getState(REMOVING_REV_PTRS_ST);
}

void
NameRemoveTransaction::readyHandler() {
    switch(getNextEvent()) {
    case START_EVT:
        if (getForwardDomain()) {
            // Request includes a forward change, do that first.
            transition(SELECTING_FWD_SERVER_ST, SELECT_SERVER_EVT);
        } else {
            // Reverse change only, transition accordingly.
            transition(SELECTING_REV_SERVER_ST, SELECT_SERVER_EVT);
        }

        break;
    default:
        // Event is invalid.
        isc_throw(NameRemoveTransactionError,
                  "Wrong event for context: " << getContextStr());
    }
}

void
NameRemoveTransaction::selectingFwdServerHandler() {
    switch(getNextEvent()) {
    case SELECT_SERVER_EVT:
        // First time through for this transaction, so initialize server
        // selection.
        initServerSelection(getForwardDomain());
        break;
    case SERVER_IO_ERROR_EVT:
        // We failed to communicate with current server. Attempt to select
        // another one below.
        break;
    default:
        // Event is invalid.
        isc_throw(NameRemoveTransactionError,
                  "Wrong event for context: " << getContextStr());
    }

    // Select the next server from the list of forward servers.
    if (selectNextServer()) {
        // We have a server to try.
        transition(REMOVING_FWD_ADDRS_ST, SERVER_SELECTED_EVT);
    }
    else {
        // Server list is exhausted, so fail the transaction.
        transition(PROCESS_TRANS_FAILED_ST, NO_MORE_SERVERS_EVT);
    }
}

void
NameRemoveTransaction::removingFwdAddrsHandler() {
    if (doOnEntry()) {
        // Clear the request on initial transition. This allows us to reuse
        // the request on retries if necessary.
        clearDnsUpdateRequest();
    }

    switch(getNextEvent()) {
    case SERVER_SELECTED_EVT:
        if (!getDnsUpdateRequest()) {
            // Request hasn't been constructed yet, so build it.
            try {
                buildRemoveFwdAddressRequest();
            } catch (const std::exception& ex) {
                // While unlikely, the build might fail if we have invalid
                // data.  Should that be the case, we need to fail the
                // transaction.
203
                LOG_ERROR(dctl_logger,
204 205 206 207 208 209 210 211 212 213
                          DHCP_DDNS_FORWARD_REMOVE_ADDRS_BUILD_FAILURE)
                          .arg(getNcr()->toText())
                          .arg(ex.what());
                transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
                break;
            }
        }

        // Call sendUpdate() to initiate the async send. Note it also sets
        // next event to NOP_EVT.
214
        sendUpdate("Forward A/AAAA Remove");
215 216 217 218 219 220
        break;

    case IO_COMPLETED_EVT: {
        switch (getDnsUpdateStatus()) {
        case DNSClient::SUCCESS: {
            // We successfully received a response packet from the server.
221 222
            // The RCODE will be based on a value-dependent RRset search,
            // see RFC 2136 section 3.2.3/3.2.4.
223 224
            const dns::Rcode& rcode = getDnsUpdateResponse()->getRcode();
            if ((rcode == dns::Rcode::NOERROR()) ||
225
                (rcode == dns::Rcode::NXRRSET())) {
226 227 228 229 230 231 232 233
                // We were able to remove it or it wasn't there, now we
                // need to remove any other RRs for this FQDN.
                transition(REMOVING_FWD_RRS_ST, UPDATE_OK_EVT);
            } else {
                // Per RFC4703 any other value means cease.
                // If we get not authorized should we try the next server in
                // the list? @todo  This needs some discussion perhaps.
                LOG_ERROR(dctl_logger, DHCP_DDNS_FORWARD_REMOVE_ADDRS_REJECTED)
234
                          .arg(getCurrentServer()->toText())
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
                          .arg(getNcr()->getFqdn())
                          .arg(rcode.getCode());
                transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
            }

            break;
        }

        case DNSClient::TIMEOUT:
        case DNSClient::OTHER:
            // We couldn't send to the current server, log it and set up
            // to select the next server for a retry.
            // @note For now we treat OTHER as an IO error like TIMEOUT. It
            // is not entirely clear if this is accurate.
            LOG_ERROR(dctl_logger, DHCP_DDNS_FORWARD_REMOVE_ADDRS_IO_ERROR)
                      .arg(getNcr()->getFqdn())
251
                      .arg(getCurrentServer()->toText());
252 253 254 255 256 257 258 259

            retryTransition(SELECTING_FWD_SERVER_ST);
            break;

        case DNSClient::INVALID_RESPONSE:
            // A response was received but was corrupt. Retry it like an IO
            // error.
            LOG_ERROR(dctl_logger, DHCP_DDNS_FORWARD_REMOVE_ADDRS_RESP_CORRUPT)
260
                      .arg(getCurrentServer()->toText())
261 262 263 264 265 266 267 268
                      .arg(getNcr()->getFqdn());

            retryTransition(SELECTING_FWD_SERVER_ST);
            break;

        default:
            // Any other value and we will fail this transaction, something
            // bigger is wrong.
269
            LOG_ERROR(dctl_logger,
270 271 272
                      DHCP_DDNS_FORWARD_REMOVE_ADDRS_BAD_DNSCLIENT_STATUS)
                      .arg(getDnsUpdateStatus())
                      .arg(getNcr()->getFqdn())
273
                      .arg(getCurrentServer()->toText());
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308

            transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
            break;
        } // end switch on dns_status

        break;
    } // end case IO_COMPLETE_EVT

    default:
        // Event is invalid.
        isc_throw(NameRemoveTransactionError,
                  "Wrong event for context: " << getContextStr());
    }
}


void
NameRemoveTransaction::removingFwdRRsHandler() {
    if (doOnEntry()) {
        // Clear the request on initial transition. This allows us to reuse
        // the request on retries if necessary.
        clearDnsUpdateRequest();
    }

    switch(getNextEvent()) {
    case UPDATE_OK_EVT:
    case SERVER_SELECTED_EVT:
        if (!getDnsUpdateRequest()) {
            // Request hasn't been constructed yet, so build it.
            try {
                buildRemoveFwdRRsRequest();
            } catch (const std::exception& ex) {
                // While unlikely, the build might fail if we have invalid
                // data.  Should that be the case, we need to fail the
                // transaction.
309
                LOG_ERROR(dctl_logger,
310 311 312 313 314 315 316 317 318 319
                          DHCP_DDNS_FORWARD_REMOVE_RRS_BUILD_FAILURE)
                          .arg(getNcr()->toText())
                          .arg(ex.what());
                transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
                break;
            }
        }

        // Call sendUpdate() to initiate the async send. Note it also sets
        // next event to NOP_EVT.
320
        sendUpdate("Forward RR Remove");
321 322 323 324 325 326
        break;

    case IO_COMPLETED_EVT: {
        switch (getDnsUpdateStatus()) {
        case DNSClient::SUCCESS: {
            // We successfully received a response packet from the server.
327 328
            // The RCODE will be based on a value-dependent RRset search,
            // see RFC 2136 section 3.2.3/3.2.4.
329
            const dns::Rcode& rcode = getDnsUpdateResponse()->getRcode();
330
            if ((rcode == dns::Rcode::NOERROR()) ||
331
                (rcode == dns::Rcode::NXRRSET())) {
332 333 334
                // We were able to remove them or they were not there (
                // Rcode of NXRRSET means there are no matching RRsets).
                // In either case, we consider it success and mark it as done.
335 336 337 338 339 340 341 342 343 344 345 346 347 348
                setForwardChangeCompleted(true);

                // If request calls for reverse update then do that next,
                // otherwise we can process ok.
                if (getReverseDomain()) {
                    transition(SELECTING_REV_SERVER_ST, SELECT_SERVER_EVT);
                } else {
                    transition(PROCESS_TRANS_OK_ST, UPDATE_OK_EVT);
                }
            } else {
                // Per RFC4703 any other value means cease.
                // If we get not authorized should try the next server in
                // the list? @todo  This needs some discussion perhaps.
                LOG_ERROR(dctl_logger, DHCP_DDNS_FORWARD_REMOVE_RRS_REJECTED)
349
                          .arg(getCurrentServer()->toText())
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
                          .arg(getNcr()->getFqdn())
                          .arg(rcode.getCode());
                transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
            }

            break;
        }

        case DNSClient::TIMEOUT:
        case DNSClient::OTHER:
            // We couldn't send to the current server, log it and set up
            // to select the next server for a retry.
            // @note For now we treat OTHER as an IO error like TIMEOUT. It
            // is not entirely clear if this is accurate.
            LOG_ERROR(dctl_logger, DHCP_DDNS_FORWARD_REMOVE_RRS_IO_ERROR)
                      .arg(getNcr()->getFqdn())
366
                      .arg(getCurrentServer()->toText());
367

368 369 370 371
            // @note If we exhaust the IO retries for the current server
            // due to IO failures, we will abort the remaining updates.
            // The rational is that we are only in this state, if the remove
            // of the forward address RR succeeded (removingFwdAddrsHandler)
372 373
            // on the current server. Therefore  we should not attempt another
            // removal on a different server.  This is perhaps a point
374
            // for discussion.
375 376 377 378 379 380 381 382
            // @todo Should we go ahead with the reverse remove?
            retryTransition(PROCESS_TRANS_FAILED_ST);
            break;

        case DNSClient::INVALID_RESPONSE:
            // A response was received but was corrupt. Retry it like an IO
            // error.
            LOG_ERROR(dctl_logger, DHCP_DDNS_FORWARD_REMOVE_RRS_RESP_CORRUPT)
383
                      .arg(getCurrentServer()->toText())
384 385 386 387 388 389 390 391 392 393 394 395 396 397
                      .arg(getNcr()->getFqdn());

            // If we are out of retries on this server abandon the transaction.
            // (Same logic as the case for TIMEOUT above).
            retryTransition(PROCESS_TRANS_FAILED_ST);
            break;

        default:
            // Any other value and we will fail this transaction, something
            // bigger is wrong.
            LOG_ERROR(dctl_logger,
                      DHCP_DDNS_FORWARD_REMOVE_RRS_BAD_DNSCLIENT_STATUS)
                      .arg(getDnsUpdateStatus())
                      .arg(getNcr()->getFqdn())
398
                      .arg(getCurrentServer()->toText());
399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472

            transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
            break;
        } // end switch on dns_status

        break;
    } // end case IO_COMPLETE_EVT

    default:
        // Event is invalid.
        isc_throw(NameRemoveTransactionError,
                  "Wrong event for context: " << getContextStr());
    }
}


void
NameRemoveTransaction::selectingRevServerHandler() {
    switch(getNextEvent()) {
    case SELECT_SERVER_EVT:
        // First time through for this transaction, so initialize server
        // selection.
        initServerSelection(getReverseDomain());
        break;
    case SERVER_IO_ERROR_EVT:
        // We failed to communicate with current server. Attempt to select
        // another one below.
        break;
    default:
        // Event is invalid.
        isc_throw(NameRemoveTransactionError,
                  "Wrong event for context: " << getContextStr());
    }

    // Select the next server from the list of forward servers.
    if (selectNextServer()) {
        // We have a server to try.
        transition(REMOVING_REV_PTRS_ST, SERVER_SELECTED_EVT);
    }
    else {
        // Server list is exhausted, so fail the transaction.
        transition(PROCESS_TRANS_FAILED_ST, NO_MORE_SERVERS_EVT);
    }
}


void
NameRemoveTransaction::removingRevPtrsHandler() {
    if (doOnEntry()) {
        // Clear the request on initial transition. This allows us to reuse
        // the request on retries if necessary.
        clearDnsUpdateRequest();
    }

    switch(getNextEvent()) {
    case SERVER_SELECTED_EVT:
        if (!getDnsUpdateRequest()) {
            // Request hasn't been constructed yet, so build it.
            try {
                buildRemoveRevPtrsRequest();
            } catch (const std::exception& ex) {
                // While unlikely, the build might fail if we have invalid
                // data.  Should that be the case, we need to fail the
                // transaction.
                LOG_ERROR(dctl_logger, DHCP_DDNS_REVERSE_REMOVE_BUILD_FAILURE)
                          .arg(getNcr()->toText())
                          .arg(ex.what());
                transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
                break;
            }
        }

        // Call sendUpdate() to initiate the async send. Note it also sets
        // next event to NOP_EVT.
473
        sendUpdate("Reverse Remove");
474 475 476 477 478 479
        break;

    case IO_COMPLETED_EVT: {
        switch (getDnsUpdateStatus()) {
        case DNSClient::SUCCESS: {
            // We successfully received a response packet from the server.
480 481
            // The RCODE will be based on a value-dependent RRset search,
            // see RFC 2136 section 3.2.3/3.2.4.
482 483
            const dns::Rcode& rcode = getDnsUpdateResponse()->getRcode();
            if ((rcode == dns::Rcode::NOERROR()) ||
484
                (rcode == dns::Rcode::NXRRSET())) {
485 486 487
                // We were able to remove the reverse mapping or they were
                // not there (Rcode of NXRRSET means there are no matching
                // RRsets). In either case, mark it as done.
488 489 490 491 492 493 494
                setReverseChangeCompleted(true);
                transition(PROCESS_TRANS_OK_ST, UPDATE_OK_EVT);
            } else {
                // Per RFC4703 any other value means cease.
                // If we get not authorized should try the next server in
                // the list? @todo  This needs some discussion perhaps.
                LOG_ERROR(dctl_logger, DHCP_DDNS_REVERSE_REMOVE_REJECTED)
495
                          .arg(getCurrentServer()->toText())
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511
                          .arg(getNcr()->getFqdn())
                          .arg(rcode.getCode());
                transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
            }

            break;
        }

        case DNSClient::TIMEOUT:
        case DNSClient::OTHER:
            // We couldn't send to the current server, log it and set up
            // to select the next server for a retry.
            // @note For now we treat OTHER as an IO error like TIMEOUT. It
            // is not entirely clear if this is accurate.
            LOG_ERROR(dctl_logger, DHCP_DDNS_REVERSE_REMOVE_IO_ERROR)
                      .arg(getNcr()->getFqdn())
512
                      .arg(getCurrentServer()->toText());
513 514 515 516 517 518 519 520 521 522

            // If we are out of retries on this server, we go back and start
            // all over on a new server.
            retryTransition(SELECTING_REV_SERVER_ST);
            break;

        case DNSClient::INVALID_RESPONSE:
            // A response was received but was corrupt. Retry it like an IO
            // error.
            LOG_ERROR(dctl_logger, DHCP_DDNS_REVERSE_REMOVE_RESP_CORRUPT)
523
                      .arg(getCurrentServer()->toText())
524 525 526 527 528 529 530 531 532 533 534 535 536 537
                      .arg(getNcr()->getFqdn());

            // If we are out of retries on this server, we go back and start
            // all over on a new server.
            retryTransition(SELECTING_REV_SERVER_ST);
            break;

        default:
            // Any other value and we will fail this transaction, something
            // bigger is wrong.
            LOG_ERROR(dctl_logger,
                      DHCP_DDNS_REVERSE_REMOVE_BAD_DNSCLIENT_STATUS)
                      .arg(getDnsUpdateStatus())
                      .arg(getNcr()->getFqdn())
538
                      .arg(getCurrentServer()->toText());
539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558

            transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
            break;
        } // end switch on dns_status

        break;
    } // end case IO_COMPLETE_EVT

    default:
        // Event is invalid.
        isc_throw(NameRemoveTransactionError,
                  "Wrong event for context: " << getContextStr());
    }
}


void
NameRemoveTransaction::processRemoveOkHandler() {
    switch(getNextEvent()) {
    case UPDATE_OK_EVT:
559 560
        LOG_INFO(dctl_logger, DHCP_DDNS_REMOVE_SUCCEEDED)
                .arg(getNcr()->toText());
561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577
        setNcrStatus(dhcp_ddns::ST_COMPLETED);
        endModel();
        break;
    default:
        // Event is invalid.
        isc_throw(NameRemoveTransactionError,
                  "Wrong event for context: " << getContextStr());
    }
}

void
NameRemoveTransaction::processRemoveFailedHandler() {
    switch(getNextEvent()) {
    case UPDATE_FAILED_EVT:
    case NO_MORE_SERVERS_EVT:
    case SERVER_IO_ERROR_EVT:
        setNcrStatus(dhcp_ddns::ST_FAILED);
578 579
        LOG_ERROR(dctl_logger, DHCP_DDNS_REMOVE_FAILED)
                  .arg(transactionOutcomeString());
580 581 582 583 584 585 586 587 588 589 590 591 592 593
        endModel();
        break;
    default:
        // Event is invalid.
        isc_throw(NameRemoveTransactionError,
                  "Wrong event for context: " << getContextStr());
    }
}

void
NameRemoveTransaction::buildRemoveFwdAddressRequest() {
    // Construct an empty request.
    D2UpdateMessagePtr request = prepNewRequest(getForwardDomain());

594
    // Content on this request is based on RFC 4703, section 5.5, paragraph 4.
595 596
    // Construct dns::Name from NCR fqdn.
    dns::Name fqdn(dns::Name(getNcr()->getFqdn()));
597
    // First build the Prerequisite Section
598

599 600 601 602 603 604
    // Create an DHCID matches prerequisite RR and add it to the
    // pre-requisite section
    // Based on RFC 2136, section 2.4.2.
    dns::RRsetPtr prereq(new dns::RRset(fqdn, dns::RRClass::IN(),
                                        dns::RRType::DHCID(), dns::RRTTL(0)));
    addDhcidRdata(prereq);
605 606
    request->addRRset(D2UpdateMessage::SECTION_PREREQUISITE, prereq);

607
    // Next build the Update Section
608

609
    // Create the FQDN/IP 'delete' RR and add it to the update section.
610
    // Add the RR to update section.
611 612
    // Based on 2136 section 2.5.4
    dns::RRsetPtr update(new dns::RRset(fqdn, dns::RRClass::NONE(),
613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628
                         getAddressRRType(), dns::RRTTL(0)));
    addLeaseAddressRdata(update);
    request->addRRset(D2UpdateMessage::SECTION_UPDATE, update);

    // Set the transaction's update request to the new request.
    setDnsUpdateRequest(request);
}

void
NameRemoveTransaction::buildRemoveFwdRRsRequest() {
    // Construct an empty request.
    D2UpdateMessagePtr request = prepNewRequest(getForwardDomain());

    // Construct dns::Name from NCR fqdn.
    dns::Name fqdn(dns::Name(getNcr()->getFqdn()));

629
    // Content on this request is based on RFC 4703, section 5.5, paragraph 5.
630 631 632 633 634
    // First build the Prerequisite Section.

    // Now create an DHCID matches prerequisite RR.
    // Set the RR's RData to DHCID.
    // Add it to the pre-requisite section.
635 636 637
    // Based on RFC 2136, section 2.4.2.
    dns::RRsetPtr prereq(new dns::RRset(fqdn, dns::RRClass::IN(),
                         dns::RRType::DHCID(), dns::RRTTL(0)));
638 639 640
    addDhcidRdata(prereq);
    request->addRRset(D2UpdateMessage::SECTION_PREREQUISITE, prereq);

641 642 643 644 645 646 647 648 649 650 651 652 653 654
    // Create an assertion that there are no A RRs for the FQDN.
    // Add it to the pre-reqs.
    // Based on RFC 2136, section 2.4.3.
    prereq.reset(new dns::RRset(fqdn, dns::RRClass::NONE(),
                                dns::RRType::A(), dns::RRTTL(0)));
    request->addRRset(D2UpdateMessage::SECTION_PREREQUISITE, prereq);

    // Create an assertion that there are no A RRs for the FQDN.
    // Add it to the pre-reqs.
    // Based on RFC 2136, section 2.4.3.
    prereq.reset(new dns::RRset(fqdn, dns::RRClass::NONE(),
                                dns::RRType::AAAA(), dns::RRTTL(0)));
    request->addRRset(D2UpdateMessage::SECTION_PREREQUISITE, prereq);

655 656
    // Next build the Update Section.

657
    // Create the 'delete' of all RRs for FQDN.
658 659
    // Set the message RData to lease address.
    // Add the RR to update section.
660
    // Based on RFC 2136, section 2.5.3.
661
    dns::RRsetPtr update(new dns::RRset(fqdn, dns::RRClass::ANY(),
662
                         dns::RRType::ANY(), dns::RRTTL(0)));
663 664 665 666 667 668 669 670 671 672 673 674 675 676 677
    request->addRRset(D2UpdateMessage::SECTION_UPDATE, update);

    // Set the transaction's update request to the new request.
    setDnsUpdateRequest(request);
}

void
NameRemoveTransaction::buildRemoveRevPtrsRequest() {
    // Construct an empty request.
    D2UpdateMessagePtr request = prepNewRequest(getReverseDomain());

    // Create the reverse IP address "FQDN".
    std::string rev_addr = D2CfgMgr::reverseIpAddress(getNcr()->getIpAddress());
    dns::Name rev_ip(rev_addr);

678 679 680 681 682 683 684 685 686 687 688 689
    // Content on this request is based on RFC 4703, section 5.5, paragraph 2.
    // First build the Prerequisite Section.
    // (Note that per RFC 4703, section 5.4, there is no need to validate
    // DHCID RR for PTR entries.)

    // Create an assertion that the PTRDNAME in the PTR record matches the
    // client's FQDN for the address that was released.
    // Based on RFC 2136, section 3.2.3
    dns::RRsetPtr prereq(new dns::RRset(rev_ip, dns::RRClass::IN(),
                                        dns::RRType::PTR(), dns::RRTTL(0)));
    addPtrRdata(prereq);
    request->addRRset(D2UpdateMessage::SECTION_PREREQUISITE, prereq);
690

691
    // Now, build the Update section.
692

693 694 695 696
    // Create a delete of any RRs for the FQDN and add it to update section.
    // Based on RFC 2136, section 3.4.2.3
    dns::RRsetPtr update(new dns::RRset(rev_ip, dns::RRClass::ANY(),
                         dns::RRType::ANY(), dns::RRTTL(0)));
697 698 699 700 701 702 703 704
    request->addRRset(D2UpdateMessage::SECTION_UPDATE, update);

    // Set the transaction's update request to the new request.
    setDnsUpdateRequest(request);
}

} // namespace isc::d2
} // namespace isc