dhcp4_test_utils.cc 22 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
//
// 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.

#include <config.h>

#include <asiolink/io_address.h>
#include <config/ccsession.h>
#include <dhcp4/tests/dhcp4_test_utils.h>
#include <dhcp/option4_addrlst.h>
#include <dhcp/option_int_array.h>
#include <dhcp/option_custom.h>
#include <dhcp/iface_mgr.h>
#include <dhcpsrv/cfgmgr.h>
25
#include <dhcpsrv/lease.h>
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
#include <dhcpsrv/lease_mgr.h>
#include <dhcpsrv/lease_mgr_factory.h>

using namespace std;
using namespace isc::asiolink;


namespace isc {
namespace dhcp {
namespace test {

/// dummy server-id file location
static const char* SRVID_FILE = "server-id-test.txt";

Dhcpv4SrvTest::Dhcpv4SrvTest()
:rcode_(-1) {
    subnet_ = Subnet4Ptr(new Subnet4(IOAddress("192.0.2.0"), 24, 1000,
                                     2000, 3000));
    pool_ = Pool4Ptr(new Pool4(IOAddress("192.0.2.100"), IOAddress("192.0.2.110")));
    subnet_->addPool(pool_);

47
    CfgMgr::instance().deleteActiveIfaces();
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 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
    CfgMgr::instance().deleteSubnets4();
    CfgMgr::instance().addSubnet4(subnet_);

    // Add Router option.
    Option4AddrLstPtr opt_routers(new Option4AddrLst(DHO_ROUTERS));
    opt_routers->setAddress(IOAddress("192.0.2.2"));
    subnet_->addOption(opt_routers, false, "dhcp4");

    // it's ok if that fails. There should not be such a file anyway
    unlink(SRVID_FILE);
}

void Dhcpv4SrvTest::addPrlOption(Pkt4Ptr& pkt) {

    OptionUint8ArrayPtr option_prl =
        OptionUint8ArrayPtr(new OptionUint8Array(Option::V4,
                                                 DHO_DHCP_PARAMETER_REQUEST_LIST));

    // Let's request options that have been configured for the subnet.
    option_prl->addValue(DHO_DOMAIN_NAME_SERVERS);
    option_prl->addValue(DHO_DOMAIN_NAME);
    option_prl->addValue(DHO_LOG_SERVERS);
    option_prl->addValue(DHO_COOKIE_SERVERS);
    // Let's also request the option that hasn't been configured. In such
    // case server should ignore request for this particular option.
    option_prl->addValue(DHO_LPR_SERVERS);
    // And add 'Parameter Request List' option into the DISCOVER packet.
    pkt->addOption(option_prl);
}

void Dhcpv4SrvTest::configureRequestedOptions() {
    // dns-servers
    Option4AddrLstPtr
        option_dns_servers(new Option4AddrLst(DHO_DOMAIN_NAME_SERVERS));
    option_dns_servers->addAddress(IOAddress("192.0.2.1"));
    option_dns_servers->addAddress(IOAddress("192.0.2.100"));
    ASSERT_NO_THROW(subnet_->addOption(option_dns_servers, false, "dhcp4"));

    // domain-name
    OptionDefinition def("domain-name", DHO_DOMAIN_NAME, OPT_FQDN_TYPE);
    OptionCustomPtr option_domain_name(new OptionCustom(def, Option::V4));
    option_domain_name->writeFqdn("example.com");
    subnet_->addOption(option_domain_name, false, "dhcp4");

    // log-servers
    Option4AddrLstPtr option_log_servers(new Option4AddrLst(DHO_LOG_SERVERS));
    option_log_servers->addAddress(IOAddress("192.0.2.2"));
    option_log_servers->addAddress(IOAddress("192.0.2.10"));
    ASSERT_NO_THROW(subnet_->addOption(option_log_servers, false, "dhcp4"));

    // cookie-servers
    Option4AddrLstPtr option_cookie_servers(new Option4AddrLst(DHO_COOKIE_SERVERS));
    option_cookie_servers->addAddress(IOAddress("192.0.2.1"));
    ASSERT_NO_THROW(subnet_->addOption(option_cookie_servers, false, "dhcp4"));
}

void Dhcpv4SrvTest::messageCheck(const Pkt4Ptr& q, const Pkt4Ptr& a) {
    ASSERT_TRUE(q);
    ASSERT_TRUE(a);

    EXPECT_EQ(q->getHops(),   a->getHops());
    EXPECT_EQ(q->getIface(),  a->getIface());
    EXPECT_EQ(q->getIndex(),  a->getIndex());
    EXPECT_EQ(q->getGiaddr(), a->getGiaddr());
    // When processing an incoming packet the remote address
    // is copied as a src address, and the source address is
    // copied as a remote address to the response.
    EXPECT_TRUE(q->getLocalHWAddr() == a->getLocalHWAddr());
    EXPECT_TRUE(q->getRemoteHWAddr() == a->getRemoteHWAddr());

118 119
    // Check that the server identifier is present in the response.
    // Presence (or absence) of other options is checked elsewhere.
120 121 122 123 124 125
    EXPECT_TRUE(a->getOption(DHO_DHCP_SERVER_IDENTIFIER));

    // Check that something is offered
    EXPECT_TRUE(a->getYiaddr().toText() != "0.0.0.0");
}

126 127 128 129 130
::testing::AssertionResult
Dhcpv4SrvTest::basicOptionsPresent(const Pkt4Ptr& pkt) {
    std::ostringstream errmsg;
    errmsg << "option missing in the response";
    if (!pkt->getOption(DHO_DOMAIN_NAME)) {
131 132
        return (::testing::AssertionFailure(::testing::Message()
                                            << "domain-name " << errmsg));
133 134

    } else if (!pkt->getOption(DHO_DOMAIN_NAME_SERVERS)) {
135 136
        return (::testing::AssertionFailure(::testing::Message()
                                            << "dns-servers " << errmsg));
137 138

    } else if (!pkt->getOption(DHO_SUBNET_MASK)) {
139 140
        return (::testing::AssertionFailure(::testing::Message()
                                            << "subnet-mask " << errmsg));
141 142

    } else if (!pkt->getOption(DHO_ROUTERS)) {
143 144
        return (::testing::AssertionFailure(::testing::Message() << "routers "
                                            << errmsg));
145 146

    } else if (!pkt->getOption(DHO_DHCP_LEASE_TIME)) {
147 148
        return (::testing::AssertionFailure(::testing::Message() <<
                                            "dhcp-lease-time " << errmsg));
149 150 151 152

    }
    return (::testing::AssertionSuccess());

153 154
}

155 156 157 158 159
::testing::AssertionResult
Dhcpv4SrvTest::noBasicOptions(const Pkt4Ptr& pkt) {
    std::ostringstream errmsg;
    errmsg << "option present in the response";
    if (pkt->getOption(DHO_DOMAIN_NAME)) {
160 161
        return (::testing::AssertionFailure(::testing::Message()
                                            << "domain-name " << errmsg));
162 163

    } else if (pkt->getOption(DHO_DOMAIN_NAME_SERVERS)) {
164 165
        return (::testing::AssertionFailure(::testing::Message()
                                            << "dns-servers " << errmsg));
166 167

    } else if (pkt->getOption(DHO_SUBNET_MASK)) {
168 169
        return (::testing::AssertionFailure(::testing::Message()
                                            << "subnet-mask " << errmsg));
170 171

    } else if (pkt->getOption(DHO_ROUTERS)) {
172 173
        return (::testing::AssertionFailure(::testing::Message() << "routers "
                                            << errmsg));
174 175

    } else if (pkt->getOption(DHO_DHCP_LEASE_TIME)) {
176 177
        return (::testing::AssertionFailure(::testing::Message()
                                            << "dhcp-lease-time " << errmsg));
178 179 180 181 182 183 184 185 186 187

    }
    return (::testing::AssertionSuccess());
}

::testing::AssertionResult
Dhcpv4SrvTest::requestedOptionsPresent(const Pkt4Ptr& pkt) {
    std::ostringstream errmsg;
    errmsg << "option missing in the response";
    if (!pkt->getOption(DHO_LOG_SERVERS)) {
188 189
        return (::testing::AssertionFailure(::testing::Message()
                                            << "log-servers " << errmsg));
190 191

    } else if (!pkt->getOption(DHO_COOKIE_SERVERS)) {
192 193
        return (::testing::AssertionFailure(::testing::Message()
                                            << "cookie-servers " << errmsg));
194 195 196 197 198 199 200 201 202 203

    }
    return (::testing::AssertionSuccess());
}

::testing::AssertionResult
Dhcpv4SrvTest::noRequestedOptions(const Pkt4Ptr& pkt) {
    std::ostringstream errmsg;
    errmsg << "option present in the response";
    if (pkt->getOption(DHO_LOG_SERVERS)) {
204 205
        return (::testing::AssertionFailure(::testing::Message()
                                            << "log-servers " << errmsg));
206 207

    } else if (pkt->getOption(DHO_COOKIE_SERVERS)) {
208 209
        return (::testing::AssertionFailure(::testing::Message()
                                            << "cookie-servers " << errmsg));
210 211 212

    }
    return (::testing::AssertionSuccess());
213 214
}

215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 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 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
OptionPtr Dhcpv4SrvTest::generateClientId(size_t size /*= 4*/) {

    OptionBuffer clnt_id(size);
    for (int i = 0; i < size; i++) {
        clnt_id[i] = 100 + i;
    }

    client_id_ = ClientIdPtr(new ClientId(clnt_id));

    return (OptionPtr(new Option(Option::V4, DHO_DHCP_CLIENT_IDENTIFIER,
                                 clnt_id.begin(),
                                 clnt_id.begin() + size)));
}

HWAddrPtr Dhcpv4SrvTest::generateHWAddr(size_t size /*= 6*/) {
    const uint8_t hw_type = 123; // Just a fake number (typically 6=HTYPE_ETHER, see dhcp4.h)
    OptionBuffer mac(size);
    for (int i = 0; i < size; ++i) {
        mac[i] = 50 + i;
    }
    return (HWAddrPtr(new HWAddr(mac, hw_type)));
}

void Dhcpv4SrvTest::checkAddressParams(const Pkt4Ptr& rsp, const SubnetPtr subnet,
                                       bool t1_mandatory /*= false*/,
                                       bool t2_mandatory /*= false*/) {

    // Technically inPool implies inRange, but let's be on the safe
    // side and check both.
    EXPECT_TRUE(subnet->inRange(rsp->getYiaddr()));
    EXPECT_TRUE(subnet->inPool(Lease::TYPE_V4, rsp->getYiaddr()));

    // Check lease time
    OptionPtr opt = rsp->getOption(DHO_DHCP_LEASE_TIME);
    if (!opt) {
        ADD_FAILURE() << "Lease time option missing in response";
    } else {
        EXPECT_EQ(opt->getUint32(), subnet->getValid());
    }

    // Check T1 timer
    opt = rsp->getOption(DHO_DHCP_RENEWAL_TIME);
    if (opt) {
        EXPECT_EQ(opt->getUint32(), subnet->getT1());
    } else {
        if (t1_mandatory) {
            ADD_FAILURE() << "Required T1 option missing";
        }
    }

    // Check T2 timer
    opt = rsp->getOption(DHO_DHCP_REBINDING_TIME);
    if (opt) {
        EXPECT_EQ(opt->getUint32(), subnet->getT2());
    } else {
        if (t2_mandatory) {
            ADD_FAILURE() << "Required T2 option missing";
        }
    }
}

void Dhcpv4SrvTest::checkResponse(const Pkt4Ptr& rsp, uint8_t expected_message_type,
                                  uint32_t expected_transid) {
    ASSERT_TRUE(rsp);
    EXPECT_EQ(expected_message_type, rsp->getType());
    EXPECT_EQ(expected_transid, rsp->getTransid());
}

Lease4Ptr Dhcpv4SrvTest::checkLease(const Pkt4Ptr& rsp,
                                    const OptionPtr& client_id,
                                    const HWAddrPtr&,
                                    const IOAddress& expected_addr) {

    ClientIdPtr id;
    if (client_id) {
        OptionBuffer data = client_id->getData();
        id.reset(new ClientId(data));
    }

    Lease4Ptr lease = LeaseMgrFactory::instance().getLease4(expected_addr);
    if (!lease) {
        cout << "Lease for " << expected_addr.toText()
             << " not found in the database backend.";
        return (Lease4Ptr());
    }

    EXPECT_EQ(rsp->getYiaddr().toText(), expected_addr.toText());

    EXPECT_EQ(expected_addr.toText(), lease->addr_.toText());
    if (client_id) {
        EXPECT_TRUE(*lease->client_id_ == *id);
    }
    EXPECT_EQ(subnet_->getID(), lease->subnet_id_);

    return (lease);
}

void Dhcpv4SrvTest::checkServerId(const Pkt4Ptr& rsp, const OptionPtr& expected_srvid) {
    // Check that server included its server-id
    OptionPtr opt = rsp->getOption(DHO_DHCP_SERVER_IDENTIFIER);
    ASSERT_TRUE(opt);
    EXPECT_EQ(opt->getType(), expected_srvid->getType() );
    EXPECT_EQ(opt->len(), expected_srvid->len() );
    EXPECT_TRUE(opt->getData() == expected_srvid->getData());
}

void Dhcpv4SrvTest::checkClientId(const Pkt4Ptr& rsp, const OptionPtr& expected_clientid) {
    // check that server included our own client-id
    OptionPtr opt = rsp->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
    ASSERT_TRUE(opt);
    EXPECT_EQ(expected_clientid->getType(), opt->getType());
    EXPECT_EQ(expected_clientid->len(), opt->len());
    EXPECT_TRUE(expected_clientid->getData() == opt->getData());
}

330 331 332 333 334 335 336 337 338
::testing::AssertionResult
Dhcpv4SrvTest::createPacketFromBuffer(const Pkt4Ptr& src_pkt,
                                      Pkt4Ptr& dst_pkt) {
    // Create on-wire format of the packet. If pack() has been called
    // on this instance of the packet already, the next call to pack()
    // should remove all contents of the output buffer.
    try {
        src_pkt->pack();
    } catch (const Exception& ex) {
339 340 341
        return (::testing::AssertionFailure(::testing::Message()
                                            << "Failed to parse source packet: "
                                            << ex.what()));
342 343 344 345 346 347 348 349 350
    }
    // Get the output buffer from the source packet.
    const util::OutputBuffer& buf = src_pkt->getBuffer();
    // Create a copy of the packet using the output buffer from the source
    // packet.
    try {
        dst_pkt.reset(new Pkt4(static_cast<const uint8_t*>(buf.getData()),
                               buf.getLength()));
    } catch (const Exception& ex) {
351 352 353 354 355
        return (::testing::AssertionFailure(::testing::Message()
                                            << "Failed to create a"
                                            " destination packet from"
                                            " the buffer: "
                                            << ex.what()));
356 357 358 359 360 361
    }

    try {
        // Parse the new packet and return to the caller.
        dst_pkt->unpack();
    } catch (const Exception& ex) {
362 363 364 365
        return (::testing::AssertionFailure(::testing::Message()
                                            << "Failed to parse a"
                                            << " destination packet: "
                                            << ex.what()));
366 367 368 369 370
    }

    return (::testing::AssertionSuccess());
}

371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401
void Dhcpv4SrvTest::TearDown() {

    CfgMgr::instance().deleteSubnets4();

    // Let's clean up if there is such a file.
    unlink(SRVID_FILE);

    // Close all open sockets.
    IfaceMgr::instance().closeSockets();

    // Some unit tests override the default packet filtering class, used
    // by the IfaceMgr. The dummy class, called PktFilterTest, reports the
    // capability to directly respond to the clients without IP address
    // assigned. This capability is not supported by the default packet
    // filtering class: PktFilterInet. Therefore setting the dummy class
    // allows to test scenarios, when server responds to the broadcast address
    // on client's request, despite having support for direct response.
    // The following call restores the use of original packet filtering class
    // after the test.
    try {
        IfaceMgr::instance().setPacketFilter(PktFilterPtr(new PktFilterInet()));

    } catch (const Exception& ex) {
        FAIL() << "Failed to restore the default (PktFilterInet) packet filtering"
               << " class after the test. Exception has been caught: "
               << ex.what();
    }

}

Dhcpv4SrvFakeIfaceTest::Dhcpv4SrvFakeIfaceTest()
402
: Dhcpv4SrvTest(), current_pkt_filter_() {
403 404 405 406 407 408 409 410 411 412 413 414 415 416
    // Remove current interface configuration. Instead we want to add
    // a couple of fake interfaces.
    IfaceMgr& ifacemgr = IfaceMgr::instance();
    ifacemgr.closeSockets();
    ifacemgr.clearIfaces();

    // Add fake interfaces.
    ifacemgr.addInterface(createIface("lo", 0, "127.0.0.1"));
    ifacemgr.addInterface(createIface("eth0", 1, "192.0.3.1"));
    ifacemgr.addInterface(createIface("eth1", 2, "10.0.0.1"));

    // In order to use fake interfaces we have to supply the custom
    // packet filtering class, which can mimic opening sockets on
    // fake interafaces.
417 418
    current_pkt_filter_.reset(new PktFilterTest());
    ifacemgr.setPacketFilter(current_pkt_filter_);
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
    ifacemgr.openSockets4();
}

void
Dhcpv4SrvFakeIfaceTest::TearDown() {
    // The base class function restores the original packet filtering class.
    Dhcpv4SrvTest::TearDown();
    // The base class however, doesn't re-detect real interfaces.
    try {
        IfaceMgr::instance().clearIfaces();
        IfaceMgr::instance().detectIfaces();

    } catch (const Exception& ex) {
        FAIL() << "Failed to restore interface configuration after using"
            " fake interfaces";
    }
}

Iface
Dhcpv4SrvFakeIfaceTest::createIface(const std::string& name, const int ifindex,
                                    const std::string& addr) {
    Iface iface(name, ifindex);
    iface.addAddress(IOAddress(addr));
    if (name == "lo") {
        iface.flag_loopback_ = true;
    }
    iface.flag_up_ = true;
    iface.flag_running_ = true;
    iface.inactive4_ = false;
    return (iface);
}
450

451 452
void
Dhcpv4SrvFakeIfaceTest::testDiscoverRequest(const uint8_t msg_type) {
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486
    // Create an instance of the tested class.
    boost::scoped_ptr<NakedDhcpv4Srv> srv(new NakedDhcpv4Srv(0));

    // Initialize the source HW address.
    vector<uint8_t> mac(6);
    for (int i = 0; i < 6; ++i) {
        mac[i] = i * 10;
    }
    // Initialized the destination HW address.
    vector<uint8_t> dst_mac(6);
    for (int i = 0; i < 6; ++i) {
        dst_mac[i] = i * 20;
    }
    // Create a DHCP message. It will be used to simulate the
    // incoming message.
    boost::shared_ptr<Pkt4> req(new Pkt4(msg_type, 1234));
    // Create a response message. It will hold a reponse packet.
    // Initially, set it to NULL.
    boost::shared_ptr<Pkt4> rsp;
    // Set the name of the interface on which packet is received.
    req->setIface("eth0");
    // Set the interface index. It is just a dummy value and will
    // not be interpreted.
    req->setIndex(17);
    // Set the target HW address. This value is normally used to
    // construct the data link layer header.
    req->setRemoteHWAddr(1, 6, dst_mac);
    // Set the HW address. This value is set on DHCP level (in chaddr).
    req->setHWAddr(1, 6, mac);
    // Set local HW address. It is used to construct the data link layer
    // header.
    req->setLocalHWAddr(1, 6, mac);
    // Set target IP address.
    req->setRemoteAddr(IOAddress("192.0.2.55"));
487
    // Set relay address and hops.
488
    req->setGiaddr(IOAddress("192.0.2.10"));
489
    req->setHops(1);
490 491 492 493 494 495 496

    // We are going to test that certain options are returned
    // in the response message when requested using 'Parameter
    // Request List' option. Let's configure those options that
    // are returned when requested.
    configureRequestedOptions();

497 498 499 500 501
    // Create a copy of the original packet by parsing its wire format.
    // This simulates the real life scenario when we process the packet
    // which was parsed from its wire format.
    Pkt4Ptr received;
    ASSERT_TRUE(createPacketFromBuffer(req, received));
502 503
    // Set interface. It is required for the server to generate server id.
    received->setIface("eth0");
504 505
    if (msg_type == DHCPDISCOVER) {
        ASSERT_NO_THROW(
506
            rsp = srv->processDiscover(received);
507
        );
508 509 510 511 512 513

        // Should return OFFER
        ASSERT_TRUE(rsp);
        EXPECT_EQ(DHCPOFFER, rsp->getType());

    } else {
514
        ASSERT_NO_THROW(rsp = srv->processRequest(received));
515 516 517 518 519 520 521

        // Should return ACK
        ASSERT_TRUE(rsp);
        EXPECT_EQ(DHCPACK, rsp->getType());

    }

522
    messageCheck(received, rsp);
523

524 525
    // Basic options should be present when we got the lease.
    EXPECT_TRUE(basicOptionsPresent(rsp));
526 527
    // We did not request any options so these should not be present
    // in the RSP.
528
    EXPECT_TRUE(noRequestedOptions(rsp));
529 530 531 532 533

    // Repeat the test but request some options.
    // Add 'Parameter Request List' option.
    addPrlOption(req);

534 535 536
    ASSERT_TRUE(createPacketFromBuffer(req, received));
    ASSERT_TRUE(received->getOption(DHO_DHCP_PARAMETER_REQUEST_LIST));

537 538 539
    // Set interface. It is required for the server to generate server id.
    received->setIface("eth0");

540
    if (msg_type == DHCPDISCOVER) {
541
        ASSERT_NO_THROW(rsp = srv->processDiscover(received));
542 543 544 545 546 547

        // Should return non-NULL packet.
        ASSERT_TRUE(rsp);
        EXPECT_EQ(DHCPOFFER, rsp->getType());

    } else {
548
        ASSERT_NO_THROW(rsp = srv->processRequest(received));
549 550 551 552 553 554 555

        // Should return non-NULL packet.
        ASSERT_TRUE(rsp);
        EXPECT_EQ(DHCPACK, rsp->getType());
    }

    // Check that the requested options are returned.
556 557
    EXPECT_TRUE(basicOptionsPresent(rsp));
    EXPECT_TRUE(requestedOptionsPresent(rsp));
558 559 560 561 562 563 564 565 566 567 568 569 570 571 572

    // The following part of the test will test that the NAK is sent when
    // there is no address pool configured. In the same time, we expect
    // that the requested options are not included in NAK message, but that
    // they are only included when yiaddr is set to non-zero value.
    ASSERT_NO_THROW(subnet_->delPools(Lease::TYPE_V4));

    // There has been a lease allocated for the particular client. So,
    // even though we deleted the subnet, the client would get the
    // existing lease (not a NAK). Therefore, we have to change the chaddr
    // in the packet so as the existing lease is not returned.
    req->setHWAddr(1, 6, std::vector<uint8_t>(2, 6));
    ASSERT_TRUE(createPacketFromBuffer(req, received));
    ASSERT_TRUE(received->getOption(DHO_DHCP_PARAMETER_REQUEST_LIST));

573 574 575
    // Set interface. It is required for the server to generate server id.
    received->setIface("eth0");

576 577 578 579 580 581 582 583 584 585 586 587 588 589
    if (msg_type == DHCPDISCOVER) {
        ASSERT_NO_THROW(rsp = srv->processDiscover(received));
        // Should return non-NULL packet.
        ASSERT_TRUE(rsp);
    } else {
        ASSERT_NO_THROW(rsp = srv->processRequest(received));
        // Should return non-NULL packet.
        ASSERT_TRUE(rsp);
    }
    // We should get the NAK packet with yiaddr set to 0.
    EXPECT_EQ(DHCPNAK, rsp->getType());
    ASSERT_EQ("0.0.0.0", rsp->getYiaddr().toText());

    // Make sure that none of the requested options is returned in NAK.
590 591 592 593
    // Also options such as Routers or Subnet Mask should not be there,
    // because lease hasn't been acquired.
    EXPECT_TRUE(noRequestedOptions(rsp));
    EXPECT_TRUE(noBasicOptions(rsp));
594 595 596 597 598
}

}; // end of isc::dhcp::test namespace
}; // end of isc::dhcp namespace
}; // end of isc namespace