dhcp6_srv_unittest.cc 86.3 KB
Newer Older
1
// Copyright (C) 2011-2017 Internet Systems Consortium, Inc. ("ISC")
2
//
3 4 5
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6

7
#include <config.h>
8

9
#include <asiolink/io_address.h>
Tomek Mrugalski's avatar
Tomek Mrugalski committed
10
#include <dhcp/dhcp6.h>
11
#include <dhcp/duid.h>
12
#include <dhcp/option.h>
13
#include <dhcp/option6_addrlst.h>
Tomek Mrugalski's avatar
Tomek Mrugalski committed
14
#include <dhcp/option6_ia.h>
15
#include <dhcp/option6_iaaddr.h>
16
#include <dhcp/option_int.h>
17
#include <dhcp/option_int_array.h>
18
#include <dhcp/option_string.h>
19
#include <dhcp/option_vendor.h>
20
#include <dhcp/option_vendor_class.h>
21
#include <dhcp/iface_mgr.h>
22
#include <dhcp6/json_config_parser.h>
23
#include <dhcp/dhcp6.h>
24
#include <dhcp/docsis3_option_defs.h>
25
#include <dhcp/tests/iface_mgr_test_config.h>
26 27 28
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/lease_mgr.h>
#include <dhcpsrv/lease_mgr_factory.h>
29
#include <dhcpsrv/host_mgr.h>
30
#include <dhcpsrv/utils.h>
Tomek Mrugalski's avatar
Tomek Mrugalski committed
31
#include <util/buffer.h>
Tomek Mrugalski's avatar
Tomek Mrugalski committed
32
#include <util/range_utilities.h>
33
#include <util/encode/hex.h>
34
#include <stats/stats_mgr.h>
35

36
#include <dhcp6/tests/dhcp6_test_utils.h>
37
#include <dhcp6/tests/dhcp6_client.h>
Tomek Mrugalski's avatar
Tomek Mrugalski committed
38
#include <dhcp/tests/pkt_captures.h>
39
#include <cc/command_interpreter.h>
40
#include <boost/pointer_cast.hpp>
41
#include <boost/scoped_ptr.hpp>
42
#include <gtest/gtest.h>
43
#include <unistd.h>
44 45 46 47
#include <fstream>
#include <iostream>
#include <sstream>

48
using namespace isc;
49
using namespace isc::data;
50
using namespace isc::asiolink;
51
using namespace isc::dhcp;
52
using namespace isc::dhcp::test;
Tomek Mrugalski's avatar
Tomek Mrugalski committed
53
using namespace isc::util;
54
using namespace std;
55

56
namespace {
57

58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
const char* CONFIGS[] = {
    // Configuration 0:
    // - used in advertiseOptions
    "{ \"interfaces-config\": {"
    "  \"interfaces\": [ \"*\" ]"
    "},"
    "\"preferred-lifetime\": 3000,"
    "\"rebind-timer\": 2000, "
    "\"renew-timer\": 1000, "
    "\"subnet6\": [ { "
    "    \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
    "    \"subnet\": \"2001:db8:1::/48\", "
    "    \"interface\": \"eth0\", "
    "    \"option-data\": [ {"
    "          \"name\": \"dns-servers\","
    "          \"data\": \"2001:db8:1234:FFFF::1, 2001:db8:1234:FFFF::2\""
    "        },"
    "        {"
    "          \"name\": \"subscriber-id\","
    "          \"data\": \"1234\","
78
    "          \"csv-format\": false"
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
    "        } ]"
    " } ],"
    "\"valid-lifetime\": 4000 }",

    // Configuration 1:
    // - a single subnet
    // - MySQL host data source
    "{ \"interfaces-config\": {"
    "  \"interfaces\": [ \"*\" ]"
    "},"
    "\"hosts-database\": {"
    "    \"type\": \"mysql\","
    "    \"name\": \"keatest\","
    "    \"user\": \"keatest\","
    "    \"password\": \"keatest\""
    "},"
    "\"preferred-lifetime\": 3000,"
    "\"rebind-timer\": 2000, "
    "\"renew-timer\": 1000, "
    "\"subnet6\": [ { "
    "    \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
    "    \"subnet\": \"2001:db8:1::/48\" "
    " } ],"
    "\"valid-lifetime\": 4000 }"
};

105
// This test verifies that incoming SOLICIT can be handled properly when
106
// there are no subnets configured.
107
//
108 109
// This test sends a SOLICIT and the expected response
// is an ADVERTISE with STATUS_NoAddrsAvail and no address provided in the
110 111 112 113 114 115
// response
TEST_F(NakedDhcpv6SrvTest, SolicitNoSubnet) {
    NakedDhcpv6Srv srv(0);

    Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
    sol->setRemoteAddr(IOAddress("fe80::abcd"));
116
    sol->addOption(generateIA(D6O_IA_NA, 234, 1500, 3000));
117 118 119 120 121 122 123
    OptionPtr clientid = generateClientId();
    sol->addOption(clientid);

    // Pass it to the server and get an advertise
    Pkt6Ptr reply = srv.processSolicit(sol);

    // check that we get the right NAK
124 125
    checkNakResponse(reply, DHCPV6_ADVERTISE, 1234, STATUS_NoAddrsAvail,
                     0, 0);
126 127
}

128
// This test verifies that incoming REQUEST can be handled properly when
129
// there are no subnets configured.
130
//
131 132
// This test sends a REQUEST and the expected response
// is an REPLY with STATUS_NoAddrsAvail and no address provided in the
133 134 135 136 137 138 139
// response
TEST_F(NakedDhcpv6SrvTest, RequestNoSubnet) {
    NakedDhcpv6Srv srv(0);

    // Let's create a REQUEST
    Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234));
    req->setRemoteAddr(IOAddress("fe80::abcd"));
140
    boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, 234, 1500, 3000);
141 142 143 144 145 146 147 148 149 150 151 152 153

    // with a hint
    IOAddress hint("2001:db8:1:1::dead:beef");
    OptionPtr hint_opt(new Option6IAAddr(D6O_IAADDR, hint, 300, 500));
    ia->addOption(hint_opt);
    req->addOption(ia);
    OptionPtr clientid = generateClientId();
    req->addOption(clientid);

    // server-id is mandatory in REQUEST
    req->addOption(srv.getServerID());

    // Pass it to the server and hope for a REPLY
154
    Pkt6Ptr reply = srv.processRequest(req);
155 156

    // check that we get the right NAK
157 158
    checkNakResponse (reply, DHCPV6_REPLY, 1234, STATUS_NoAddrsAvail,
                      0, 0);
159 160 161 162 163
}

// This test verifies that incoming RENEW can be handled properly, even when
// no subnets are configured.
//
164 165
// This test sends a RENEW and the expected response
// is an REPLY with STATUS_NoBinding and no address provided in the
166 167 168 169 170 171 172 173 174 175 176 177 178
// response
TEST_F(NakedDhcpv6SrvTest, RenewNoSubnet) {
    NakedDhcpv6Srv srv(0);

    const IOAddress addr("2001:db8:1:1::cafe:babe");
    const uint32_t iaid = 234;

    // Generate client-id also duid_
    OptionPtr clientid = generateClientId();

    // Let's create a RENEW
    Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RENEW, 1234));
    req->setRemoteAddr(IOAddress("fe80::abcd"));
179
    boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
180 181 182 183 184 185 186 187 188 189

    OptionPtr renewed_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
    ia->addOption(renewed_addr_opt);
    req->addOption(ia);
    req->addOption(clientid);

    // Server-id is mandatory in RENEW
    req->addOption(srv.getServerID());

    // Pass it to the server and hope for a REPLY
190
    Pkt6Ptr reply = srv.processRenew(req);
191 192

    // check that we get the right NAK
193 194
    checkNakResponse (reply, DHCPV6_REPLY, 1234, STATUS_NoBinding,
                      0, 0);
195 196 197 198 199
}

// This test verifies that incoming RELEASE can be handled properly, even when
// no subnets are configured.
//
200 201
// This test sends a RELEASE and the expected response
// is an REPLY with STATUS_NoBinding and no address provided in the
202 203 204 205 206 207 208 209 210 211 212 213 214
// response
TEST_F(NakedDhcpv6SrvTest, ReleaseNoSubnet) {
    NakedDhcpv6Srv srv(0);

    const IOAddress addr("2001:db8:1:1::cafe:babe");
    const uint32_t iaid = 234;

    // Generate client-id also duid_
    OptionPtr clientid = generateClientId();

    // Let's create a RELEASE
    Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RELEASE, 1234));
    req->setRemoteAddr(IOAddress("fe80::abcd"));
215
    boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
216 217 218 219 220 221 222 223 224 225

    OptionPtr released_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
    ia->addOption(released_addr_opt);
    req->addOption(ia);
    req->addOption(clientid);

    // Server-id is mandatory in RELEASE
    req->addOption(srv.getServerID());

    // Pass it to the server and hope for a REPLY
226
    Pkt6Ptr reply = srv.processRelease(req);
227 228

    // check that we get the right NAK
229
    checkNakResponse (reply, DHCPV6_REPLY, 1234, STATUS_NoBinding, 0, 0);
230
}
231

232 233 234
// Test verifies that the Dhcpv6_srv class can be instantiated. It checks a mode
// without open sockets and with sockets opened on a high port (to not require
// root privileges).
235
TEST_F(Dhcpv6SrvTest, basic) {
236 237
    boost::scoped_ptr<Dhcpv6Srv> srv;

238
    ASSERT_NO_THROW( {
239
        // Skip opening any sockets
240
        srv.reset(new NakedDhcpv6Srv(0));
241
    });
242
    srv.reset();
243
    ASSERT_NO_THROW({
244
        // open an unprivileged port
245
        srv.reset(new NakedDhcpv6Srv(DHCP6_SERVER_PORT + 10000));
Tomek Mrugalski's avatar
Tomek Mrugalski committed
246
    });
247 248
}

249
// Test checks that DUID is generated properly
Tomek Mrugalski's avatar
Tomek Mrugalski committed
250 251
TEST_F(Dhcpv6SrvTest, DUID) {

252
    boost::scoped_ptr<Dhcpv6Srv> srv;
Tomek Mrugalski's avatar
Tomek Mrugalski committed
253
    ASSERT_NO_THROW( {
254
        srv.reset(new NakedDhcpv6Srv(0));
Tomek Mrugalski's avatar
Tomek Mrugalski committed
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
    });

    OptionPtr srvid = srv->getServerID();
    ASSERT_TRUE(srvid);

    EXPECT_EQ(D6O_SERVERID, srvid->getType());

    OutputBuffer buf(32);
    srvid->pack(buf);

    // length of the actual DUID
    size_t len = buf.getLength() - srvid->getHeaderLen();

    InputBuffer data(buf.getData(), buf.getLength());

    // ignore first four bytes (standard DHCPv6 header)
    data.readUint32();

    uint16_t duid_type = data.readUint16();
    cout << "Duid-type=" << duid_type << endl;
    switch(duid_type) {
276
    case DUID::DUID_LLT: {
Tomek Mrugalski's avatar
Tomek Mrugalski committed
277 278
        // DUID must contain at least 6 bytes long MAC
        // + 8 bytes of fixed header
279
        EXPECT_GE(len, 14);
Tomek Mrugalski's avatar
Tomek Mrugalski committed
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296

        uint16_t hw_type = data.readUint16();
        // there's no real way to find out "correct"
        // hardware type
        EXPECT_GT(hw_type, 0);

        // check that timer is counted since 1.1.2000,
        // not from 1.1.1970.
        uint32_t seconds = data.readUint32();
        EXPECT_LE(seconds, DUID_TIME_EPOCH);
        // this test will start failing after 2030.
        // Hopefully we will be at BIND12 by then.

        // MAC must not be zeros
        vector<uint8_t> mac(len-8);
        vector<uint8_t> zeros(len-8, 0);
        data.readVector(mac, len-8);
Tomek Mrugalski's avatar
Tomek Mrugalski committed
297
        EXPECT_TRUE(mac != zeros);
Tomek Mrugalski's avatar
Tomek Mrugalski committed
298 299
        break;
    }
300
    case DUID::DUID_EN: {
Tomek Mrugalski's avatar
Tomek Mrugalski committed
301 302 303 304
        // there's not much we can check. Just simple
        // check if it is not all zeros
        vector<uint8_t> content(len-2);
        data.readVector(content, len-2);
Tomek Mrugalski's avatar
Tomek Mrugalski committed
305
        EXPECT_FALSE(isRangeZero(content.begin(), content.end()));
Tomek Mrugalski's avatar
Tomek Mrugalski committed
306 307
        break;
    }
308
    case DUID::DUID_LL: {
Tomek Mrugalski's avatar
Tomek Mrugalski committed
309
        // not supported yet
310 311 312 313 314 315 316
        cout << "Test not implemented for DUID-LL." << endl;

        // No failure here. There's really no way for test LL DUID. It doesn't
        // even make sense to check if that Link Layer is actually present on
        // a physical interface. RFC3315 says a server should write its DUID
        // and keep it despite hardware changes.
        break;
Tomek Mrugalski's avatar
Tomek Mrugalski committed
317
    }
318
    case DUID::DUID_UUID: // not supported yet
Tomek Mrugalski's avatar
Tomek Mrugalski committed
319
    default:
320 321
        ADD_FAILURE() << "Not supported duid type=" << duid_type << endl;
        break;
Tomek Mrugalski's avatar
Tomek Mrugalski committed
322 323 324
    }
}

325 326 327
// This test checks if Option Request Option (ORO) is parsed correctly
// and the requested options are actually assigned.
TEST_F(Dhcpv6SrvTest, advertiseOptions) {
328 329 330

    IfaceMgrTestConfig test_config(true);

331
    ConstElementPtr x;
332
    ASSERT_NO_THROW(configure(CONFIGS[0]));
333

Tomek Mrugalski's avatar
Tomek Mrugalski committed
334
    Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
335
    sol->setRemoteAddr(IOAddress("fe80::abcd"));
336
    sol->setIface("eth0");
337
    sol->addOption(generateIA(D6O_IA_NA, 234, 1500, 3000));
338
    OptionPtr clientid = generateClientId();
339 340
    sol->addOption(clientid);

341
    // Pass it to the server and get an advertise
342
    Pkt6Ptr adv = srv_.processSolicit(sol);
343 344

    // check if we get response at all
345
    ASSERT_TRUE(adv);
346

347
    // We have not requested any options so they should not
348
    // be included in the response.
349
    ASSERT_FALSE(adv->getOption(D6O_SUBSCRIBER_ID));
350
    ASSERT_FALSE(adv->getOption(D6O_NAME_SERVERS));
351

352 353
    // Let's now request some options. We expect that the server
    // will include them in its response.
354
    boost::shared_ptr<OptionIntArray<uint16_t> >
355
        option_oro(new OptionIntArray<uint16_t>(Option::V6, D6O_ORO));
356 357
    // Create vector with two option codes.
    std::vector<uint16_t> codes(2);
358
    codes[0] = D6O_SUBSCRIBER_ID;
359
    codes[1] = D6O_NAME_SERVERS;
360 361 362 363 364
    // Pass this code to option.
    option_oro->setValues(codes);
    // Append ORO to SOLICIT message.
    sol->addOption(option_oro);

365
    // Need to process SOLICIT again after requesting new option.
366
    adv = srv_.processSolicit(sol);
367
    ASSERT_TRUE(adv);
368

369
    OptionPtr tmp = adv->getOption(D6O_NAME_SERVERS);
370
    ASSERT_TRUE(tmp);
371

372 373 374 375 376 377 378 379 380 381 382
    boost::shared_ptr<Option6AddrLst> reply_nameservers =
        boost::dynamic_pointer_cast<Option6AddrLst>(tmp);
    ASSERT_TRUE(reply_nameservers);

    Option6AddrLst::AddressContainer addrs = reply_nameservers->getAddresses();
    ASSERT_EQ(2, addrs.size());
    EXPECT_TRUE(addrs[0] == IOAddress("2001:db8:1234:FFFF::1"));
    EXPECT_TRUE(addrs[1] == IOAddress("2001:db8:1234:FFFF::2"));

    // There is a dummy option with code 1000 we requested from a server.
    // Expect that this option is in server's response.
383
    tmp = adv->getOption(D6O_SUBSCRIBER_ID);
384 385 386 387 388 389 390 391 392 393
    ASSERT_TRUE(tmp);

    // Check that the option contains valid data (from configuration).
    std::vector<uint8_t> data = tmp->getData();
    ASSERT_EQ(2, data.size());

    const uint8_t foo_expected[] = {
        0x12, 0x34
    };
    EXPECT_EQ(0, memcmp(&data[0], foo_expected, 2));
394 395

    // more checks to be implemented
396
}
397

398

399 400 401
// There are no dedicated tests for Dhcpv6Srv::handleIA_NA and Dhcpv6Srv::assignLeases
// as they are indirectly tested in Solicit and Request tests.

402 403
// This test verifies that incoming SOLICIT can be handled properly, that an
// ADVERTISE is generated, that the response has an address and that address
404 405 406
// really belongs to the configured pool.
//
// This test sends a SOLICIT without any hint in IA_NA.
407 408 409 410 411 412 413 414 415
//
// constructed very simple SOLICIT message with:
// - client-id option (mandatory)
// - IA option (a request for address, without any addresses)
//
// expected returned ADVERTISE message:
// - copy of client-id
// - server-id
// - IA that includes IAADDR
416
TEST_F(Dhcpv6SrvTest, SolicitBasic) {
Tomek Mrugalski's avatar
Tomek Mrugalski committed
417
    NakedDhcpv6Srv srv(0);
418

Tomek Mrugalski's avatar
Tomek Mrugalski committed
419
    Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
420
    sol->setRemoteAddr(IOAddress("fe80::abcd"));
421
    sol->setIface("eth0");
422
    sol->addOption(generateIA(D6O_IA_NA, 234, 1500, 3000));
423 424
    OptionPtr clientid = generateClientId();
    sol->addOption(clientid);
425

426
    // Pass it to the server and get an advertise
Tomek Mrugalski's avatar
Tomek Mrugalski committed
427
    Pkt6Ptr reply = srv.processSolicit(sol);
428

429 430
    // check if we get response at all
    checkResponse(reply, DHCPV6_ADVERTISE, 1234);
431

432
    // check that IA_NA was returned and that there's an address included
433
    boost::shared_ptr<Option6IAAddr> addr = checkIA_NA(reply, 234, subnet_->getT1(),
434
                                                subnet_->getT2());
435
    ASSERT_TRUE(addr);
436

437
    // Check that the assigned address is indeed from the configured pool
438
    checkIAAddr(addr, addr->getAddress(), Lease::TYPE_NA);
439 440

    // check DUIDs
Tomek Mrugalski's avatar
Tomek Mrugalski committed
441
    checkServerId(reply, srv.getServerID());
442 443 444
    checkClientId(reply, clientid);
}

445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
// This test verifies that incoming SOLICIT can be handled properly, that an
// ADVERTISE is generated, that the response has a prefix and that prefix
// really belongs to the configured pool.
//
// This test sends a SOLICIT without any hint in IA_PD.
//
// constructed very simple SOLICIT message with:
// - client-id option (mandatory)
// - IA option (a request for address, without any addresses)
//
// expected returned ADVERTISE message:
// - copy of client-id
// - server-id
// - IA that includes IAPREFIX
TEST_F(Dhcpv6SrvTest, pdSolicitBasic) {

    NakedDhcpv6Srv srv(0);

    Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
    sol->setRemoteAddr(IOAddress("fe80::abcd"));
465
    sol->setIface("eth0");
466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481
    sol->addOption(generateIA(D6O_IA_PD, 234, 1500, 3000));
    OptionPtr clientid = generateClientId();
    sol->addOption(clientid);

    // Pass it to the server and get an advertise
    Pkt6Ptr reply = srv.processSolicit(sol);

    // check if we get response at all
    checkResponse(reply, DHCPV6_ADVERTISE, 1234);

    // check that IA_NA was returned and that there's an address included
    boost::shared_ptr<Option6IAPrefix> prefix = checkIA_PD(reply, 234, subnet_->getT1(),
                                                           subnet_->getT2());
    ASSERT_TRUE(prefix);

    // Check that the assigned prefix is indeed from the configured pool
482
    checkIAAddr(prefix, prefix->getAddress(), Lease::TYPE_PD);
483 484 485 486 487 488 489
    EXPECT_EQ(pd_pool_->getLength(), prefix->getLength());

    // check DUIDs
    checkServerId(reply, srv.getServerID());
    checkClientId(reply, clientid);
}

490 491
// This test verifies that incoming SOLICIT can be handled properly, that an
// ADVERTISE is generated, that the response has an address and that address
492 493 494 495 496 497 498 499 500 501 502 503 504 505
// really belongs to the configured pool.
//
// This test sends a SOLICIT with IA_NA that contains a valid hint.
//
// constructed very simple SOLICIT message with:
// - client-id option (mandatory)
// - IA option (a request for address, with an address that belongs to the
//              configured pool, i.e. is valid as hint)
//
// expected returned ADVERTISE message:
// - copy of client-id
// - server-id
// - IA that includes IAADDR
TEST_F(Dhcpv6SrvTest, SolicitHint) {
Tomek Mrugalski's avatar
Tomek Mrugalski committed
506
    NakedDhcpv6Srv srv(0);
507 508 509 510

    // Let's create a SOLICIT
    Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
    sol->setRemoteAddr(IOAddress("fe80::abcd"));
511
    sol->setIface("eth0");
512
    boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, 234, 1500, 3000);
513 514 515

    // with a valid hint
    IOAddress hint("2001:db8:1:1::dead:beef");
516
    ASSERT_TRUE(subnet_->inPool(Lease::TYPE_NA, hint));
517 518
    OptionPtr hint_opt(new Option6IAAddr(D6O_IAADDR, hint, 300, 500));
    ia->addOption(hint_opt);
519
    sol->addOption(ia);
520
    OptionPtr clientid = generateClientId();
521 522
    sol->addOption(clientid);

523
    // Pass it to the server and get an advertise
Tomek Mrugalski's avatar
Tomek Mrugalski committed
524
    Pkt6Ptr reply = srv.processSolicit(sol);
525 526

    // check if we get response at all
527
    checkResponse(reply, DHCPV6_ADVERTISE, 1234);
528

529
    OptionPtr tmp = reply->getOption(D6O_IA_NA);
530
    ASSERT_TRUE(tmp);
531

532
    // check that IA_NA was returned and that there's an address included
533
    boost::shared_ptr<Option6IAAddr> addr = checkIA_NA(reply, 234, subnet_->getT1(),
534
                                                subnet_->getT2());
535
    ASSERT_TRUE(addr);
536

537
    // check that we've got the address we requested
538
    checkIAAddr(addr, hint, Lease::TYPE_NA);
539

540
    // check DUIDs
Tomek Mrugalski's avatar
Tomek Mrugalski committed
541
    checkServerId(reply, srv.getServerID());
542 543
    checkClientId(reply, clientid);
}
544

545 546
// This test verifies that incoming SOLICIT can be handled properly, that an
// ADVERTISE is generated, that the response has an address and that address
547 548 549 550 551 552 553 554 555 556 557 558 559 560
// really belongs to the configured pool.
//
// This test sends a SOLICIT with IA_NA that contains an invalid hint.
//
// constructed very simple SOLICIT message with:
// - client-id option (mandatory)
// - IA option (a request for address, with an address that does not
//              belong to the configured pool, i.e. is valid as hint)
//
// expected returned ADVERTISE message:
// - copy of client-id
// - server-id
// - IA that includes IAADDR
TEST_F(Dhcpv6SrvTest, SolicitInvalidHint) {
Tomek Mrugalski's avatar
Tomek Mrugalski committed
561
    NakedDhcpv6Srv srv(0);
562 563 564 565

    // Let's create a SOLICIT
    Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
    sol->setRemoteAddr(IOAddress("fe80::abcd"));
566
    sol->setIface("eth0");
567
    boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, 234, 1500, 3000);
568
    IOAddress hint("2001:db8:1::cafe:babe");
569
    ASSERT_FALSE(subnet_->inPool(Lease::TYPE_NA, hint));
570 571 572 573
    OptionPtr hint_opt(new Option6IAAddr(D6O_IAADDR, hint, 300, 500));
    ia->addOption(hint_opt);
    sol->addOption(ia);
    OptionPtr clientid = generateClientId();
574 575
    sol->addOption(clientid);

576
    // Pass it to the server and get an advertise
Tomek Mrugalski's avatar
Tomek Mrugalski committed
577
    Pkt6Ptr reply = srv.processSolicit(sol);
578

579 580
    // check if we get response at all
    checkResponse(reply, DHCPV6_ADVERTISE, 1234);
581

582
    // check that IA_NA was returned and that there's an address included
583
    boost::shared_ptr<Option6IAAddr> addr = checkIA_NA(reply, 234, subnet_->getT1(),
584
                                                subnet_->getT2());
585
    ASSERT_TRUE(addr);
586

587
    // Check that the assigned address is indeed from the configured pool
588
    checkIAAddr(addr, addr->getAddress(), Lease::TYPE_NA);
589
    EXPECT_TRUE(subnet_->inPool(Lease::TYPE_NA, addr->getAddress()));
590

591
    // check DUIDs
Tomek Mrugalski's avatar
Tomek Mrugalski committed
592
    checkServerId(reply, srv.getServerID());
593
    checkClientId(reply, clientid);
594
}
595

596 597 598
/// @todo: Add a test that client sends hint that is in pool, but currently
/// being used by a different client.

599 600
// This test checks that the server is offering different addresses to different
// clients in ADVERTISEs. Please note that ADVERTISE is not a guarantee that such
Tomek Mrugalski's avatar
Tomek Mrugalski committed
601
// an address will be assigned. Had the pool was very small and contained only
602
// 2 addresses, the third client would get the same advertise as the first one
603
// and this is a correct behavior. It is REQUEST that will fail for the third
604 605 606
// client. ADVERTISE is basically saying "if you send me a request, you will
// probably get an address like this" (there are no guarantees).
TEST_F(Dhcpv6SrvTest, ManySolicits) {
Tomek Mrugalski's avatar
Tomek Mrugalski committed
607
    NakedDhcpv6Srv srv(0);
608 609 610 611 612 613 614 615 616

    Pkt6Ptr sol1 = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
    Pkt6Ptr sol2 = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 2345));
    Pkt6Ptr sol3 = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 3456));

    sol1->setRemoteAddr(IOAddress("fe80::abcd"));
    sol2->setRemoteAddr(IOAddress("fe80::1223"));
    sol3->setRemoteAddr(IOAddress("fe80::3467"));

617 618 619 620
    sol1->setIface("eth0");
    sol2->setIface("eth0");
    sol3->setIface("eth0");

621 622 623
    sol1->addOption(generateIA(D6O_IA_NA, 1, 1500, 3000));
    sol2->addOption(generateIA(D6O_IA_NA, 2, 1500, 3000));
    sol3->addOption(generateIA(D6O_IA_NA, 3, 1500, 3000));
624 625 626 627 628 629 630 631 632 633 634

    // different client-id sizes
    OptionPtr clientid1 = generateClientId(12);
    OptionPtr clientid2 = generateClientId(14);
    OptionPtr clientid3 = generateClientId(16);

    sol1->addOption(clientid1);
    sol2->addOption(clientid2);
    sol3->addOption(clientid3);

    // Pass it to the server and get an advertise
Tomek Mrugalski's avatar
Tomek Mrugalski committed
635 636 637
    Pkt6Ptr reply1 = srv.processSolicit(sol1);
    Pkt6Ptr reply2 = srv.processSolicit(sol2);
    Pkt6Ptr reply3 = srv.processSolicit(sol3);
638 639

    // check if we get response at all
640 641 642 643 644
    checkResponse(reply1, DHCPV6_ADVERTISE, 1234);
    checkResponse(reply2, DHCPV6_ADVERTISE, 2345);
    checkResponse(reply3, DHCPV6_ADVERTISE, 3456);

    // check that IA_NA was returned and that there's an address included
645
    boost::shared_ptr<Option6IAAddr> addr1 = checkIA_NA(reply1, 1, subnet_->getT1(),
646
                                                subnet_->getT2());
647
    boost::shared_ptr<Option6IAAddr> addr2 = checkIA_NA(reply2, 2, subnet_->getT1(),
648
                                                subnet_->getT2());
649
    boost::shared_ptr<Option6IAAddr> addr3 = checkIA_NA(reply3, 3, subnet_->getT1(),
650
                                                subnet_->getT2());
651 652 653
    ASSERT_TRUE(addr1);
    ASSERT_TRUE(addr2);
    ASSERT_TRUE(addr3);
654 655

    // Check that the assigned address is indeed from the configured pool
656 657 658
    checkIAAddr(addr1, addr1->getAddress(), Lease::TYPE_NA);
    checkIAAddr(addr2, addr2->getAddress(), Lease::TYPE_NA);
    checkIAAddr(addr3, addr3->getAddress(), Lease::TYPE_NA);
659 660

    // check DUIDs
Tomek Mrugalski's avatar
Tomek Mrugalski committed
661 662 663
    checkServerId(reply1, srv.getServerID());
    checkServerId(reply2, srv.getServerID());
    checkServerId(reply3, srv.getServerID());
664 665 666 667 668
    checkClientId(reply1, clientid1);
    checkClientId(reply2, clientid2);
    checkClientId(reply3, clientid3);

    // Finally check that the addresses offered are different
669 670 671 672 673 674
    EXPECT_NE(addr1->getAddress(), addr2->getAddress());
    EXPECT_NE(addr2->getAddress(), addr3->getAddress());
    EXPECT_NE(addr3->getAddress(), addr1->getAddress());
    cout << "Offered address to client1=" << addr1->getAddress() << endl;
    cout << "Offered address to client2=" << addr2->getAddress() << endl;
    cout << "Offered address to client3=" << addr3->getAddress() << endl;
675 676 677 678
}

// This test verifies that incoming REQUEST can be handled properly, that a
// REPLY is generated, that the response has an address and that address
679 680
// really belongs to the configured pool.
//
681
// This test sends a REQUEST with IA_NA that contains a valid hint.
682
//
683
// constructed very simple REQUEST message with:
684 685 686 687
// - client-id option (mandatory)
// - IA option (a request for address, with an address that belongs to the
//              configured pool, i.e. is valid as hint)
//
688
// expected returned REPLY message:
689 690 691 692
// - copy of client-id
// - server-id
// - IA that includes IAADDR
TEST_F(Dhcpv6SrvTest, RequestBasic) {
Tomek Mrugalski's avatar
Tomek Mrugalski committed
693
    NakedDhcpv6Srv srv(0);
694

695 696 697
    // Let's create a REQUEST
    Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234));
    req->setRemoteAddr(IOAddress("fe80::abcd"));
698
    req->setIface("eth0");
699
    boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, 234, 1500, 3000);
700 701 702

    // with a valid hint
    IOAddress hint("2001:db8:1:1::dead:beef");
703
    ASSERT_TRUE(subnet_->inPool(Lease::TYPE_NA, hint));
704 705
    OptionPtr hint_opt(new Option6IAAddr(D6O_IAADDR, hint, 300, 500));
    ia->addOption(hint_opt);
706
    req->addOption(ia);
707
    OptionPtr clientid = generateClientId();
708
    req->addOption(clientid);
709

710
    // server-id is mandatory in REQUEST
Tomek Mrugalski's avatar
Tomek Mrugalski committed
711
    req->addOption(srv.getServerID());
712

713
    // Pass it to the server and hope for a REPLY
714
    Pkt6Ptr reply = srv.processRequest(req);
715 716

    // check if we get response at all
717
    checkResponse(reply, DHCPV6_REPLY, 1234);
718

719
    OptionPtr tmp = reply->getOption(D6O_IA_NA);
720
    ASSERT_TRUE(tmp);
721

722
    // check that IA_NA was returned and that there's an address included
723 724 725
    boost::shared_ptr<Option6IAAddr> addr = checkIA_NA(reply, 234,
                                                       subnet_->getT1(),
                                                       subnet_->getT2());
726
    ASSERT_TRUE(addr);
727

728
    // check that we've got the address we requested
729
    checkIAAddr(addr, hint, Lease::TYPE_NA);
730

731
    // check DUIDs
Tomek Mrugalski's avatar
Tomek Mrugalski committed
732
    checkServerId(reply, srv.getServerID());
733
    checkClientId(reply, clientid);
734

735 736 737
    // check that the lease is really in the database
    Lease6Ptr l = checkLease(duid_, reply->getOption(D6O_IA_NA), addr);
    EXPECT_TRUE(l);
738
    LeaseMgrFactory::instance().deleteLease(addr->getAddress());
739
}
740

741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762
// This test verifies that incoming REQUEST can be handled properly, that a
// REPLY is generated, that the response has a prefix and that prefix
// really belongs to the configured pool.
//
// This test sends a REQUEST with IA_PD that contains a valid hint.
//
// constructed very simple REQUEST message with:
// - client-id option (mandatory)
// - IA option (a request for address, with an address that belongs to the
//              configured pool, i.e. is valid as hint)
//
// expected returned REPLY message:
// - copy of client-id
// - server-id
// - IA that includes IAPREFIX
TEST_F(Dhcpv6SrvTest, pdRequestBasic) {

    NakedDhcpv6Srv srv(0);

    // Let's create a REQUEST
    Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234));
    req->setRemoteAddr(IOAddress("fe80::abcd"));
763
    req->setIface("eth0");
764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793
    boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_PD, 234, 1500, 3000);

    // with a valid hint
    IOAddress hint("2001:db8:1:2:f::");
    ASSERT_TRUE(subnet_->inPool(Lease::TYPE_PD, hint));
    OptionPtr hint_opt(new Option6IAPrefix(D6O_IAPREFIX, hint, 64, 300, 500));
    ia->addOption(hint_opt);
    req->addOption(ia);
    OptionPtr clientid = generateClientId();
    req->addOption(clientid);

    // server-id is mandatory in REQUEST
    req->addOption(srv.getServerID());

    // Pass it to the server and hope for a REPLY
    Pkt6Ptr reply = srv.processRequest(req);

    // check if we get response at all
    checkResponse(reply, DHCPV6_REPLY, 1234);

    OptionPtr tmp = reply->getOption(D6O_IA_PD);
    ASSERT_TRUE(tmp);

    // check that IA_NA was returned and that there's an address included
    boost::shared_ptr<Option6IAPrefix> prf = checkIA_PD(reply, 234,
                                                        subnet_->getT1(),
                                                        subnet_->getT2());
    ASSERT_TRUE(prf);

    // check that we've got the address we requested
794
    checkIAAddr(prf, hint, Lease::TYPE_PD);
795 796 797 798 799 800 801 802 803 804 805 806
    EXPECT_EQ(pd_pool_->getLength(), prf->getLength());

    // check DUIDs
    checkServerId(reply, srv.getServerID());
    checkClientId(reply, clientid);

    // check that the lease is really in the database
    Lease6Ptr l = checkPdLease(duid_, reply->getOption(D6O_IA_PD), prf);
    EXPECT_TRUE(l);
    EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease(prf->getAddress()));
}

807 808 809 810
// This test checks that the server is offering different addresses to different
// clients in REQUEST. Please note that ADVERTISE is not a guarantee that such
// and address will be assigned. Had the pool was very small and contained only
// 2 addresses, the third client would get the same advertise as the first one
811
// and this is a correct behavior. It is REQUEST that will fail for the third
812 813 814
// client. ADVERTISE is basically saying "if you send me a request, you will
// probably get an address like this" (there are no guarantees).
TEST_F(Dhcpv6SrvTest, ManyRequests) {
Tomek Mrugalski's avatar
Tomek Mrugalski committed
815
    NakedDhcpv6Srv srv(0);
816

817 818
    ASSERT_TRUE(subnet_);

819 820 821
    Pkt6Ptr req1 = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234));
    Pkt6Ptr req2 = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 2345));
    Pkt6Ptr req3 = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 3456));
822

823 824 825 826
    req1->setRemoteAddr(IOAddress("fe80::abcd"));
    req2->setRemoteAddr(IOAddress("fe80::1223"));
    req3->setRemoteAddr(IOAddress("fe80::3467"));

827 828 829 830
    req1->setIface("eth0");
    req2->setIface("eth0");
    req3->setIface("eth0");

831 832 833
    req1->addOption(generateIA(D6O_IA_NA, 1, 1500, 3000));
    req2->addOption(generateIA(D6O_IA_NA, 2, 1500, 3000));
    req3->addOption(generateIA(D6O_IA_NA, 3, 1500, 3000));
834 835 836 837 838 839 840 841 842 843

    // different client-id sizes
    OptionPtr clientid1 = generateClientId(12);
    OptionPtr clientid2 = generateClientId(14);
    OptionPtr clientid3 = generateClientId(16);

    req1->addOption(clientid1);
    req2->addOption(clientid2);
    req3->addOption(clientid3);

844
    // server-id is mandatory in REQUEST
Tomek Mrugalski's avatar
Tomek Mrugalski committed
845 846 847
    req1->addOption(srv.getServerID());
    req2->addOption(srv.getServerID());
    req3->addOption(srv.getServerID());
848

849
    // Pass it to the server and get an advertise
850 851 852
    Pkt6Ptr reply1 = srv.processRequest(req1);
    Pkt6Ptr reply2 = srv.processRequest(req2);
    Pkt6Ptr reply3 = srv.processRequest(req3);
853 854 855 856 857 858 859

    // check if we get response at all
    checkResponse(reply1, DHCPV6_REPLY, 1234);
    checkResponse(reply2, DHCPV6_REPLY, 2345);
    checkResponse(reply3, DHCPV6_REPLY, 3456);

    // check that IA_NA was returned and that there's an address included
860
    boost::shared_ptr<Option6IAAddr> addr1 = checkIA_NA(reply1, 1, subnet_->getT1(),
861
                                                subnet_->getT2());
862
    boost::shared_ptr<Option6IAAddr> addr2 = checkIA_NA(reply2, 2, subnet_->getT1(),
863
                                                subnet_->getT2());
864
    boost::shared_ptr<Option6IAAddr> addr3 = checkIA_NA(reply3, 3, subnet_->getT1(),
865 866
                                                subnet_->getT2());

867 868 869 870
    ASSERT_TRUE(addr1);
    ASSERT_TRUE(addr2);
    ASSERT_TRUE(addr3);

871
    // Check that the assigned address is indeed from the configured pool
872 873 874
    checkIAAddr(addr1, addr1->getAddress(), Lease::TYPE_NA);
    checkIAAddr(addr2, addr2->getAddress(), Lease::TYPE_NA);
    checkIAAddr(addr3, addr3->getAddress(), Lease::TYPE_NA);
875 876

    // check DUIDs
Tomek Mrugalski's avatar
Tomek Mrugalski committed
877 878 879
    checkServerId(reply1, srv.getServerID());
    checkServerId(reply2, srv.getServerID());
    checkServerId(reply3, srv.getServerID());
880 881 882 883 884
    checkClientId(reply1, clientid1);
    checkClientId(reply2, clientid2);
    checkClientId(reply3, clientid3);

    // Finally check that the addresses offered are different
885 886 887 888 889 890
    EXPECT_NE(addr1->getAddress(), addr2->getAddress());
    EXPECT_NE(addr2->getAddress(), addr3->getAddress());
    EXPECT_NE(addr3->getAddress(), addr1->getAddress());
    cout << "Assigned address to client1=" << addr1->getAddress() << endl;
    cout << "Assigned address to client2=" << addr2->getAddress() << endl;
    cout << "Assigned address to client3=" << addr3->getAddress() << endl;
891
}
892

893 894 895 896 897 898 899
// This test verifies that incoming (positive) RENEW can be handled properly, that a
// REPLY is generated, that the response has an address and that address
// really belongs to the configured pool and that lease is actually renewed.
//
// expected:
// - returned REPLY message has copy of client-id
// - returned REPLY message has server-id
900
// - returned REPLY message has IA_NA that includes IAADDR
901
// - lease is actually renewed in LeaseMgr
902 903
TEST_F(Dhcpv6SrvTest, renewBasic) {
    testRenewBasic(Lease::TYPE_NA, "2001:db8:1:1::cafe:babe",
904
                   "2001:db8:1:1::cafe:babe", 128);
905
}
906

907 908 909 910 911 912 913 914 915 916
// This test verifies that incoming (positive) PD RENEW can be handled properly,
// that a REPLY is generated, that the response has a prefix and that prefix
// really belongs to the configured pool and that lease is actually renewed.
//
// expected:
// - returned REPLY message has copy of client-id
// - returned REPLY message has server-id
// - returned REPLY message has IA_PD that includes IAPREFIX
// - lease is actually renewed in LeaseMgr
TEST_F(Dhcpv6SrvTest, pdRenewBasic) {
917 918
    testRenewBasic(Lease::TYPE_PD, "2001:db8:1:2::",
                   "2001:db8:1:2::", pd_pool_->getLength());
919 920
}

921
// This test verifies that incoming (invalid) RENEW with an address
922 923 924
// can be handled properly. This has changed with #3565. The server
// is now able to allocate a lease in Renew if it's available.
// Previous testRenewReject is now split into 3 tests.
925
//
926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953
// This test checks the first scenario: There is no lease at all.
// The server will try to assign it. Since it is not used by anyone else,
// the server will assign it. This is convenient for various types
// of recoveries, e.g. when the server lost its database.
TEST_F(Dhcpv6SrvTest, RenewUnknown) {
    // False means that the lease should not be created before renewal attempt
    testRenewBasic(Lease::TYPE_NA, "2001:db8:1:1::abc", "2001:db8:1:1::abc",
                   128, false);
}

// This test checks that a client that renews existing lease, but uses
// a wrong IAID, will be processed correctly. As there is no lease for
// this (duid, type, iaid) tuple, this is treated as a new IA, regardless
// if the client inserted an address that is used in a different IA.
// After #3565 was implemented, the server will attempt to assign a lease.
// The one that client requested is already used with different IAID, so
// it will just pick a different lease. This is the second out of three
// scenarios tests by old RenewReject test.
TEST_F(Dhcpv6SrvTest, RenewWrongIAID) {
    testRenewWrongIAID(Lease::TYPE_NA, IOAddress("2001:db8:1:1::abc"));
}

// This test checks whether client A can renew an address that is currently
// leased by client B. The server should detect that the lease belong to
// someone else and assign a different lease. This is the third out of three
// scenarios tests by old RenewReject test.
TEST_F(Dhcpv6SrvTest, RenewSomeoneElesesLease) {
    testRenewSomeoneElsesLease(Lease::TYPE_NA, IOAddress("2001:db8::1"));