dhcp6_srv_unittest.cc 87.2 KB
Newer Older
1
// Copyright (C) 2011-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
#include <config.h>
16

17
#include <asiolink/io_address.h>
Tomek Mrugalski's avatar
Tomek Mrugalski committed
18
#include <dhcp/dhcp6.h>
19
#include <dhcp/duid.h>
20
#include <dhcp/option.h>
21
#include <dhcp/option6_addrlst.h>
Tomek Mrugalski's avatar
Tomek Mrugalski committed
22
#include <dhcp/option6_ia.h>
23
#include <dhcp/option6_iaaddr.h>
24
#include <dhcp/option_int.h>
25
#include <dhcp/option_int_array.h>
26
#include <dhcp/option_string.h>
27
#include <dhcp/option_vendor.h>
28
#include <dhcp/option_vendor_class.h>
29
#include <dhcp/iface_mgr.h>
30
#include <dhcp6/json_config_parser.h>
31
#include <dhcp/dhcp6.h>
32
#include <dhcp/docsis3_option_defs.h>
33
#include <dhcp/tests/iface_mgr_test_config.h>
34 35 36
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/lease_mgr.h>
#include <dhcpsrv/lease_mgr_factory.h>
37
#include <dhcpsrv/utils.h>
Tomek Mrugalski's avatar
Tomek Mrugalski committed
38
#include <util/buffer.h>
Tomek Mrugalski's avatar
Tomek Mrugalski committed
39
#include <util/range_utilities.h>
40
#include <hooks/server_hooks.h>
41

42
#include <dhcp6/tests/dhcp6_test_utils.h>
43
#include <dhcp6/tests/dhcp6_client.h>
Tomek Mrugalski's avatar
Tomek Mrugalski committed
44
#include <dhcp/tests/pkt_captures.h>
45
#include <cc/command_interpreter.h>
46
#include <boost/pointer_cast.hpp>
47
#include <boost/scoped_ptr.hpp>
48
#include <gtest/gtest.h>
49
#include <unistd.h>
50 51 52 53
#include <fstream>
#include <iostream>
#include <sstream>

54
using namespace isc;
55
using namespace isc::data;
56
using namespace isc::test;
57
using namespace isc::asiolink;
58
using namespace isc::dhcp;
59
using namespace isc::dhcp::test;
Tomek Mrugalski's avatar
Tomek Mrugalski committed
60
using namespace isc::util;
61
using namespace isc::hooks;
62
using namespace std;
63

64
namespace {
65

66
// This test verifies that incoming SOLICIT can be handled properly when
67
// there are no subnets configured.
68
//
69 70
// This test sends a SOLICIT and the expected response
// is an ADVERTISE with STATUS_NoAddrsAvail and no address provided in the
71 72 73 74 75 76
// response
TEST_F(NakedDhcpv6SrvTest, SolicitNoSubnet) {
    NakedDhcpv6Srv srv(0);

    Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
    sol->setRemoteAddr(IOAddress("fe80::abcd"));
77
    sol->addOption(generateIA(D6O_IA_NA, 234, 1500, 3000));
78 79 80 81 82 83 84
    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
85 86
    checkNakResponse(reply, DHCPV6_ADVERTISE, 1234, STATUS_NoAddrsAvail,
                     0, 0);
87 88
}

89
// This test verifies that incoming REQUEST can be handled properly when
90
// there are no subnets configured.
91
//
92 93
// This test sends a REQUEST and the expected response
// is an REPLY with STATUS_NoAddrsAvail and no address provided in the
94 95 96 97 98 99 100
// 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"));
101
    boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, 234, 1500, 3000);
102 103 104 105 106 107 108 109 110 111 112 113 114

    // 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
115
    Pkt6Ptr reply = srv.processRequest(req);
116 117

    // check that we get the right NAK
118 119
    checkNakResponse (reply, DHCPV6_REPLY, 1234, STATUS_NoAddrsAvail,
                      0, 0);
120 121 122 123 124
}

// This test verifies that incoming RENEW can be handled properly, even when
// no subnets are configured.
//
125 126
// This test sends a RENEW and the expected response
// is an REPLY with STATUS_NoBinding and no address provided in the
127 128 129 130 131 132 133 134 135 136 137 138 139
// 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"));
140
    boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
141 142 143 144 145 146 147 148 149 150

    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
151
    Pkt6Ptr reply = srv.processRenew(req);
152 153

    // check that we get the right NAK
154 155
    checkNakResponse (reply, DHCPV6_REPLY, 1234, STATUS_NoBinding,
                      0, 0);
156 157 158 159 160
}

// This test verifies that incoming RELEASE can be handled properly, even when
// no subnets are configured.
//
161 162
// This test sends a RELEASE and the expected response
// is an REPLY with STATUS_NoBinding and no address provided in the
163 164 165 166 167 168 169 170 171 172 173 174 175
// 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"));
176
    boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
177 178 179 180 181 182 183 184 185 186

    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
187
    Pkt6Ptr reply = srv.processRelease(req);
188 189

    // check that we get the right NAK
190
    checkNakResponse (reply, DHCPV6_REPLY, 1234, STATUS_NoBinding, 0, 0);
191
}
192

193 194 195
// 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).
196
TEST_F(Dhcpv6SrvTest, basic) {
197 198
    boost::scoped_ptr<Dhcpv6Srv> srv;

199
    ASSERT_NO_THROW( {
200
        // Skip opening any sockets
201
        srv.reset(new NakedDhcpv6Srv(0));
202
    });
203
    srv.reset();
204
    ASSERT_NO_THROW({
Tomek Mrugalski's avatar
Tomek Mrugalski committed
205
        // open an unpriviledged port
206
        srv.reset(new NakedDhcpv6Srv(DHCP6_SERVER_PORT + 10000));
Tomek Mrugalski's avatar
Tomek Mrugalski committed
207
    });
208 209
}

210
// Test checks that DUID is generated properly
Tomek Mrugalski's avatar
Tomek Mrugalski committed
211 212
TEST_F(Dhcpv6SrvTest, DUID) {

213
    boost::scoped_ptr<Dhcpv6Srv> srv;
Tomek Mrugalski's avatar
Tomek Mrugalski committed
214
    ASSERT_NO_THROW( {
215
        srv.reset(new NakedDhcpv6Srv(0));
Tomek Mrugalski's avatar
Tomek Mrugalski committed
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
    });

    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) {
237
    case DUID::DUID_LLT: {
Tomek Mrugalski's avatar
Tomek Mrugalski committed
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
        // DUID must contain at least 6 bytes long MAC
        // + 8 bytes of fixed header
        EXPECT_GE(14, len);

        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
258
        EXPECT_TRUE(mac != zeros);
Tomek Mrugalski's avatar
Tomek Mrugalski committed
259 260
        break;
    }
261
    case DUID::DUID_EN: {
Tomek Mrugalski's avatar
Tomek Mrugalski committed
262 263 264 265
        // 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
266
        EXPECT_FALSE(isRangeZero(content.begin(), content.end()));
Tomek Mrugalski's avatar
Tomek Mrugalski committed
267 268
        break;
    }
269
    case DUID::DUID_LL: {
Tomek Mrugalski's avatar
Tomek Mrugalski committed
270
        // not supported yet
271 272 273 274 275 276 277
        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
278
    }
279
    case DUID::DUID_UUID: // not supported yet
Tomek Mrugalski's avatar
Tomek Mrugalski committed
280
    default:
281 282
        ADD_FAILURE() << "Not supported duid type=" << duid_type << endl;
        break;
Tomek Mrugalski's avatar
Tomek Mrugalski committed
283 284 285
    }
}

286 287 288
// This test checks if Option Request Option (ORO) is parsed correctly
// and the requested options are actually assigned.
TEST_F(Dhcpv6SrvTest, advertiseOptions) {
289 290 291

    IfaceMgrTestConfig test_config(true);

292
    ConstElementPtr x;
293 294 295
    string config = "{ \"interfaces-config\": {"
        "  \"interfaces\": [ \"*\" ]"
        "},"
296 297 298 299
        "\"preferred-lifetime\": 3000,"
        "\"rebind-timer\": 2000, "
        "\"renew-timer\": 1000, "
        "\"subnet6\": [ { "
300
        "    \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
301
        "    \"subnet\": \"2001:db8:1::/48\", "
302
        "    \"interface\": \"eth0\", "
303
        "    \"option-data\": [ {"
304 305
        "          \"name\": \"dns-servers\","
        "          \"space\": \"dhcp6\","
306
        "          \"code\": 23,"
307 308
        "          \"data\": \"2001:db8:1234:FFFF::1, 2001:db8:1234:FFFF::2\","
        "          \"csv-format\": True"
309 310
        "        },"
        "        {"
311 312 313
        "          \"name\": \"subscriber-id\","
        "          \"space\": \"dhcp6\","
        "          \"code\": 38,"
314 315
        "          \"data\": \"1234\","
        "          \"csv-format\": False"
316 317 318
        "        } ]"
        " } ],"
        "\"valid-lifetime\": 4000 }";
319
    ASSERT_NO_THROW(configure(config));
320

Tomek Mrugalski's avatar
Tomek Mrugalski committed
321
    Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
322
    sol->setRemoteAddr(IOAddress("fe80::abcd"));
323
    sol->setIface("eth0");
324
    sol->addOption(generateIA(D6O_IA_NA, 234, 1500, 3000));
325
    OptionPtr clientid = generateClientId();
326 327
    sol->addOption(clientid);

328
    // Pass it to the server and get an advertise
329
    Pkt6Ptr adv = srv_.processSolicit(sol);
330 331

    // check if we get response at all
332
    ASSERT_TRUE(adv);
333

334
    // We have not requested any options so they should not
335
    // be included in the response.
336
    ASSERT_FALSE(adv->getOption(D6O_SUBSCRIBER_ID));
337
    ASSERT_FALSE(adv->getOption(D6O_NAME_SERVERS));
338

339 340
    // Let's now request some options. We expect that the server
    // will include them in its response.
341
    boost::shared_ptr<OptionIntArray<uint16_t> >
342
        option_oro(new OptionIntArray<uint16_t>(Option::V6, D6O_ORO));
343 344
    // Create vector with two option codes.
    std::vector<uint16_t> codes(2);
345
    codes[0] = D6O_SUBSCRIBER_ID;
346
    codes[1] = D6O_NAME_SERVERS;
347 348 349 350 351
    // Pass this code to option.
    option_oro->setValues(codes);
    // Append ORO to SOLICIT message.
    sol->addOption(option_oro);

352
    // Need to process SOLICIT again after requesting new option.
353
    adv = srv_.processSolicit(sol);
354
    ASSERT_TRUE(adv);
355

356
    OptionPtr tmp = adv->getOption(D6O_NAME_SERVERS);
357
    ASSERT_TRUE(tmp);
358

359 360 361 362 363 364 365 366 367 368 369
    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.
370
    tmp = adv->getOption(D6O_SUBSCRIBER_ID);
371 372 373 374 375 376 377 378 379 380
    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));
381 382

    // more checks to be implemented
383
}
384

385

386 387 388
// There are no dedicated tests for Dhcpv6Srv::handleIA_NA and Dhcpv6Srv::assignLeases
// as they are indirectly tested in Solicit and Request tests.

389 390
// This test verifies that incoming SOLICIT can be handled properly, that an
// ADVERTISE is generated, that the response has an address and that address
391 392 393
// really belongs to the configured pool.
//
// This test sends a SOLICIT without any hint in IA_NA.
394 395 396 397 398 399 400 401 402
//
// 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
403
TEST_F(Dhcpv6SrvTest, SolicitBasic) {
Tomek Mrugalski's avatar
Tomek Mrugalski committed
404
    NakedDhcpv6Srv srv(0);
405

Tomek Mrugalski's avatar
Tomek Mrugalski committed
406
    Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
407
    sol->setRemoteAddr(IOAddress("fe80::abcd"));
408
    sol->setIface("eth0");
409
    sol->addOption(generateIA(D6O_IA_NA, 234, 1500, 3000));
410 411
    OptionPtr clientid = generateClientId();
    sol->addOption(clientid);
412

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

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

419
    // check that IA_NA was returned and that there's an address included
420
    boost::shared_ptr<Option6IAAddr> addr = checkIA_NA(reply, 234, subnet_->getT1(),
421
                                                subnet_->getT2());
422
    ASSERT_TRUE(addr);
423

424
    // Check that the assigned address is indeed from the configured pool
425
    checkIAAddr(addr, addr->getAddress(), Lease::TYPE_NA);
426 427

    // check DUIDs
Tomek Mrugalski's avatar
Tomek Mrugalski committed
428
    checkServerId(reply, srv.getServerID());
429 430 431
    checkClientId(reply, clientid);
}

432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451
// 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"));
452
    sol->setIface("eth0");
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468
    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
469
    checkIAAddr(prefix, prefix->getAddress(), Lease::TYPE_PD);
470 471 472 473 474 475 476
    EXPECT_EQ(pd_pool_->getLength(), prefix->getLength());

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

477 478
// This test verifies that incoming SOLICIT can be handled properly, that an
// ADVERTISE is generated, that the response has an address and that address
479 480 481 482 483 484 485 486 487 488 489 490 491 492
// 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
493
    NakedDhcpv6Srv srv(0);
494 495 496 497

    // Let's create a SOLICIT
    Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
    sol->setRemoteAddr(IOAddress("fe80::abcd"));
498
    sol->setIface("eth0");
499
    boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, 234, 1500, 3000);
500 501 502

    // with a valid hint
    IOAddress hint("2001:db8:1:1::dead:beef");
503
    ASSERT_TRUE(subnet_->inPool(Lease::TYPE_NA, hint));
504 505
    OptionPtr hint_opt(new Option6IAAddr(D6O_IAADDR, hint, 300, 500));
    ia->addOption(hint_opt);
506
    sol->addOption(ia);
507
    OptionPtr clientid = generateClientId();
508 509
    sol->addOption(clientid);

510
    // Pass it to the server and get an advertise
Tomek Mrugalski's avatar
Tomek Mrugalski committed
511
    Pkt6Ptr reply = srv.processSolicit(sol);
512 513

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

516
    OptionPtr tmp = reply->getOption(D6O_IA_NA);
517
    ASSERT_TRUE(tmp);
518

519
    // check that IA_NA was returned and that there's an address included
520
    boost::shared_ptr<Option6IAAddr> addr = checkIA_NA(reply, 234, subnet_->getT1(),
521
                                                subnet_->getT2());
522
    ASSERT_TRUE(addr);
523

524
    // check that we've got the address we requested
525
    checkIAAddr(addr, hint, Lease::TYPE_NA);
526

527
    // check DUIDs
Tomek Mrugalski's avatar
Tomek Mrugalski committed
528
    checkServerId(reply, srv.getServerID());
529 530
    checkClientId(reply, clientid);
}
531

532 533
// This test verifies that incoming SOLICIT can be handled properly, that an
// ADVERTISE is generated, that the response has an address and that address
534 535 536 537 538 539 540 541 542 543 544 545 546 547
// 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
548
    NakedDhcpv6Srv srv(0);
549 550 551 552

    // Let's create a SOLICIT
    Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
    sol->setRemoteAddr(IOAddress("fe80::abcd"));
553
    sol->setIface("eth0");
554
    boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, 234, 1500, 3000);
555
    IOAddress hint("2001:db8:1::cafe:babe");
556
    ASSERT_FALSE(subnet_->inPool(Lease::TYPE_NA, hint));
557 558 559 560
    OptionPtr hint_opt(new Option6IAAddr(D6O_IAADDR, hint, 300, 500));
    ia->addOption(hint_opt);
    sol->addOption(ia);
    OptionPtr clientid = generateClientId();
561 562
    sol->addOption(clientid);

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

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

569
    // check that IA_NA was returned and that there's an address included
570
    boost::shared_ptr<Option6IAAddr> addr = checkIA_NA(reply, 234, subnet_->getT1(),
571
                                                subnet_->getT2());
572
    ASSERT_TRUE(addr);
573

574
    // Check that the assigned address is indeed from the configured pool
575
    checkIAAddr(addr, addr->getAddress(), Lease::TYPE_NA);
576
    EXPECT_TRUE(subnet_->inPool(Lease::TYPE_NA, addr->getAddress()));
577

578
    // check DUIDs
Tomek Mrugalski's avatar
Tomek Mrugalski committed
579
    checkServerId(reply, srv.getServerID());
580
    checkClientId(reply, clientid);
581
}
582

583 584 585
/// @todo: Add a test that client sends hint that is in pool, but currently
/// being used by a different client.

586 587
// 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
588
// an address will be assigned. Had the pool was very small and contained only
589
// 2 addresses, the third client would get the same advertise as the first one
590
// and this is a correct behavior. It is REQUEST that will fail for the third
591 592 593
// 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
594
    NakedDhcpv6Srv srv(0);
595 596 597 598 599 600 601 602 603

    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"));

604 605 606 607
    sol1->setIface("eth0");
    sol2->setIface("eth0");
    sol3->setIface("eth0");

608 609 610
    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));
611 612 613 614 615 616 617 618 619 620 621

    // 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
622 623 624
    Pkt6Ptr reply1 = srv.processSolicit(sol1);
    Pkt6Ptr reply2 = srv.processSolicit(sol2);
    Pkt6Ptr reply3 = srv.processSolicit(sol3);
625 626

    // check if we get response at all
627 628 629 630 631
    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
632
    boost::shared_ptr<Option6IAAddr> addr1 = checkIA_NA(reply1, 1, subnet_->getT1(),
633
                                                subnet_->getT2());
634
    boost::shared_ptr<Option6IAAddr> addr2 = checkIA_NA(reply2, 2, subnet_->getT1(),
635
                                                subnet_->getT2());
636
    boost::shared_ptr<Option6IAAddr> addr3 = checkIA_NA(reply3, 3, subnet_->getT1(),
637
                                                subnet_->getT2());
638 639 640
    ASSERT_TRUE(addr1);
    ASSERT_TRUE(addr2);
    ASSERT_TRUE(addr3);
641 642

    // Check that the assigned address is indeed from the configured pool
643 644 645
    checkIAAddr(addr1, addr1->getAddress(), Lease::TYPE_NA);
    checkIAAddr(addr2, addr2->getAddress(), Lease::TYPE_NA);
    checkIAAddr(addr3, addr3->getAddress(), Lease::TYPE_NA);
646 647

    // check DUIDs
Tomek Mrugalski's avatar
Tomek Mrugalski committed
648 649 650
    checkServerId(reply1, srv.getServerID());
    checkServerId(reply2, srv.getServerID());
    checkServerId(reply3, srv.getServerID());
651 652 653 654 655
    checkClientId(reply1, clientid1);
    checkClientId(reply2, clientid2);
    checkClientId(reply3, clientid3);

    // Finally check that the addresses offered are different
656 657 658 659 660 661
    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;
662 663 664 665
}

// This test verifies that incoming REQUEST can be handled properly, that a
// REPLY is generated, that the response has an address and that address
666 667
// really belongs to the configured pool.
//
668
// This test sends a REQUEST with IA_NA that contains a valid hint.
669
//
670
// constructed very simple REQUEST message with:
671 672 673 674
// - 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)
//
675
// expected returned REPLY message:
676 677 678 679
// - copy of client-id
// - server-id
// - IA that includes IAADDR
TEST_F(Dhcpv6SrvTest, RequestBasic) {
Tomek Mrugalski's avatar
Tomek Mrugalski committed
680
    NakedDhcpv6Srv srv(0);
681

682 683 684
    // Let's create a REQUEST
    Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234));
    req->setRemoteAddr(IOAddress("fe80::abcd"));
685
    req->setIface("eth0");
686
    boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, 234, 1500, 3000);
687 688 689

    // with a valid hint
    IOAddress hint("2001:db8:1:1::dead:beef");
690
    ASSERT_TRUE(subnet_->inPool(Lease::TYPE_NA, hint));
691 692
    OptionPtr hint_opt(new Option6IAAddr(D6O_IAADDR, hint, 300, 500));
    ia->addOption(hint_opt);
693
    req->addOption(ia);
694
    OptionPtr clientid = generateClientId();
695
    req->addOption(clientid);
696

697
    // server-id is mandatory in REQUEST
Tomek Mrugalski's avatar
Tomek Mrugalski committed
698
    req->addOption(srv.getServerID());
699

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

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

706
    OptionPtr tmp = reply->getOption(D6O_IA_NA);
707
    ASSERT_TRUE(tmp);
708

709
    // check that IA_NA was returned and that there's an address included
710 711 712
    boost::shared_ptr<Option6IAAddr> addr = checkIA_NA(reply, 234,
                                                       subnet_->getT1(),
                                                       subnet_->getT2());
713
    ASSERT_TRUE(addr);
714

715
    // check that we've got the address we requested
716
    checkIAAddr(addr, hint, Lease::TYPE_NA);
717

718
    // check DUIDs
Tomek Mrugalski's avatar
Tomek Mrugalski committed
719
    checkServerId(reply, srv.getServerID());
720
    checkClientId(reply, clientid);
721

722 723 724
    // check that the lease is really in the database
    Lease6Ptr l = checkLease(duid_, reply->getOption(D6O_IA_NA), addr);
    EXPECT_TRUE(l);
725
    LeaseMgrFactory::instance().deleteLease(addr->getAddress());
726
}
727

728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749
// 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"));
750
    req->setIface("eth0");
751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780
    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
781
    checkIAAddr(prf, hint, Lease::TYPE_PD);
782 783 784 785 786 787 788 789 790 791 792 793
    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()));
}

794 795 796 797
// 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
798
// and this is a correct behavior. It is REQUEST that will fail for the third
799 800 801
// 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
802
    NakedDhcpv6Srv srv(0);
803

804 805
    ASSERT_TRUE(subnet_);

806 807 808
    Pkt6Ptr req1 = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234));
    Pkt6Ptr req2 = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 2345));
    Pkt6Ptr req3 = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 3456));
809

810 811 812 813
    req1->setRemoteAddr(IOAddress("fe80::abcd"));
    req2->setRemoteAddr(IOAddress("fe80::1223"));
    req3->setRemoteAddr(IOAddress("fe80::3467"));

814 815 816 817
    req1->setIface("eth0");
    req2->setIface("eth0");
    req3->setIface("eth0");

818 819 820
    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));
821 822 823 824 825 826 827 828 829 830

    // 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);

831
    // server-id is mandatory in REQUEST
Tomek Mrugalski's avatar
Tomek Mrugalski committed
832 833 834
    req1->addOption(srv.getServerID());
    req2->addOption(srv.getServerID());
    req3->addOption(srv.getServerID());
835

836
    // Pass it to the server and get an advertise
837 838 839
    Pkt6Ptr reply1 = srv.processRequest(req1);
    Pkt6Ptr reply2 = srv.processRequest(req2);
    Pkt6Ptr reply3 = srv.processRequest(req3);
840 841 842 843 844 845 846

    // 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
847
    boost::shared_ptr<Option6IAAddr> addr1 = checkIA_NA(reply1, 1, subnet_->getT1(),
848
                                                subnet_->getT2());
849
    boost::shared_ptr<Option6IAAddr> addr2 = checkIA_NA(reply2, 2, subnet_->getT1(),
850
                                                subnet_->getT2());
851
    boost::shared_ptr<Option6IAAddr> addr3 = checkIA_NA(reply3, 3, subnet_->getT1(),
852 853
                                                subnet_->getT2());

854 855 856 857
    ASSERT_TRUE(addr1);
    ASSERT_TRUE(addr2);
    ASSERT_TRUE(addr3);

858
    // Check that the assigned address is indeed from the configured pool
859 860 861
    checkIAAddr(addr1, addr1->getAddress(), Lease::TYPE_NA);
    checkIAAddr(addr2, addr2->getAddress(), Lease::TYPE_NA);
    checkIAAddr(addr3, addr3->getAddress(), Lease::TYPE_NA);
862 863

    // check DUIDs
Tomek Mrugalski's avatar
Tomek Mrugalski committed
864 865 866
    checkServerId(reply1, srv.getServerID());
    checkServerId(reply2, srv.getServerID());
    checkServerId(reply3, srv.getServerID());
867 868 869 870 871
    checkClientId(reply1, clientid1);
    checkClientId(reply2, clientid2);
    checkClientId(reply3, clientid3);

    // Finally check that the addresses offered are different
872 873 874 875 876 877
    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;
878
}
879

880 881 882