dhcp6_srv_unittest.cc 74 KB
Newer Older
1
// Copyright (C) 2011-2014  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/iface_mgr.h>
29
#include <dhcp6/json_config_parser.h>
30
#include <dhcp/dhcp6.h>
31
#include <dhcp/docsis3_option_defs.h>
32
#include <dhcp/tests/iface_mgr_test_config.h>
33 34 35
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/lease_mgr.h>
#include <dhcpsrv/lease_mgr_factory.h>
36
#include <dhcpsrv/utils.h>
Tomek Mrugalski's avatar
Tomek Mrugalski committed
37
#include <util/buffer.h>
Tomek Mrugalski's avatar
Tomek Mrugalski committed
38
#include <util/range_utilities.h>
39
#include <hooks/server_hooks.h>
40

41
#include <dhcp6/tests/dhcp6_test_utils.h>
42
#include <boost/pointer_cast.hpp>
43
#include <boost/scoped_ptr.hpp>
44
#include <gtest/gtest.h>
45
#include <unistd.h>
46 47 48 49
#include <fstream>
#include <iostream>
#include <sstream>

50
using namespace isc;
51 52
using namespace isc::data;
using namespace isc::config;
53
using namespace isc::test;
54
using namespace isc::asiolink;
55
using namespace isc::dhcp;
56
using namespace isc::dhcp::test;
Tomek Mrugalski's avatar
Tomek Mrugalski committed
57
using namespace isc::util;
58
using namespace isc::hooks;
59
using namespace std;
60

61
namespace {
62

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

    Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
    sol->setRemoteAddr(IOAddress("fe80::abcd"));
74
    sol->addOption(generateIA(D6O_IA_NA, 234, 1500, 3000));
75 76 77 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
    checkNakResponse (reply, DHCPV6_ADVERTISE, 1234, STATUS_NoAddrsAvail);
}

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

    // 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
111
    Pkt6Ptr reply = srv.processRequest(req);
112 113 114 115 116 117 118 119

    // check that we get the right NAK
    checkNakResponse (reply, DHCPV6_REPLY, 1234, STATUS_NoAddrsAvail);
}

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

    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
146
    Pkt6Ptr reply = srv.processRenew(req);
147 148 149 150 151 152 153 154

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

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

    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
181
    Pkt6Ptr reply = srv.processRelease(req);
182 183 184 185

    // check that we get the right NAK
    checkNakResponse (reply, DHCPV6_REPLY, 1234, STATUS_NoBinding);
}
186

187

188 189 190
// 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).
191
TEST_F(Dhcpv6SrvTest, basic) {
192 193 194 195
    // srv has stubbed interface detection. It will read
    // interfaces.txt instead. It will pretend to have detected
    // fe80::1234 link-local address on eth0 interface. Obviously
    // an attempt to bind this socket will fail.
196 197
    boost::scoped_ptr<Dhcpv6Srv> srv;

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

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

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

    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) {
236
    case DUID::DUID_LLT: {
Tomek Mrugalski's avatar
Tomek Mrugalski committed
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
        // 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
257
        EXPECT_TRUE(mac != zeros);
Tomek Mrugalski's avatar
Tomek Mrugalski committed
258 259
        break;
    }
260
    case DUID::DUID_EN: {
Tomek Mrugalski's avatar
Tomek Mrugalski committed
261 262 263 264
        // 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
265
        EXPECT_FALSE(isRangeZero(content.begin(), content.end()));
Tomek Mrugalski's avatar
Tomek Mrugalski committed
266 267
        break;
    }
268
    case DUID::DUID_LL: {
Tomek Mrugalski's avatar
Tomek Mrugalski committed
269
        // not supported yet
270 271 272 273 274 275 276
        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
277
    }
278
    case DUID::DUID_UUID: // not supported yet
Tomek Mrugalski's avatar
Tomek Mrugalski committed
279
    default:
280 281
        ADD_FAILURE() << "Not supported duid type=" << duid_type << endl;
        break;
Tomek Mrugalski's avatar
Tomek Mrugalski committed
282 283 284
    }
}

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

    IfaceMgrTestConfig test_config(true);

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

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

325
    // Pass it to the server and get an advertise
326
    Pkt6Ptr adv = srv_.processSolicit(sol);
327 328

    // check if we get response at all
329
    ASSERT_TRUE(adv);
330

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

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

349
    // Need to process SOLICIT again after requesting new option.
350
    adv = srv_.processSolicit(sol);
351
    ASSERT_TRUE(adv);
352

353
    OptionPtr tmp = adv->getOption(D6O_NAME_SERVERS);
354
    ASSERT_TRUE(tmp);
355

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

    // more checks to be implemented
380
}
381

382

383 384 385
// There are no dedicated tests for Dhcpv6Srv::handleIA_NA and Dhcpv6Srv::assignLeases
// as they are indirectly tested in Solicit and Request tests.

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

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

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

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

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

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

    // check DUIDs
Tomek Mrugalski's avatar
Tomek Mrugalski committed
425
    checkServerId(reply, srv.getServerID());
426 427 428
    checkClientId(reply, clientid);
}

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

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

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

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

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

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

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

513
    OptionPtr tmp = reply->getOption(D6O_IA_NA);
514
    ASSERT_TRUE(tmp);
515

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

521
    // check that we've got the address we requested
522
    checkIAAddr(addr, hint, Lease::TYPE_NA);
523

524
    // check DUIDs
Tomek Mrugalski's avatar
Tomek Mrugalski committed
525
    checkServerId(reply, srv.getServerID());
526 527
    checkClientId(reply, clientid);
}
528

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

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

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

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

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

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

575
    // check DUIDs
Tomek Mrugalski's avatar
Tomek Mrugalski committed
576
    checkServerId(reply, srv.getServerID());
577
    checkClientId(reply, clientid);
578
}
579

580 581 582
/// @todo: Add a test that client sends hint that is in pool, but currently
/// being used by a different client.

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

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

601 602 603 604
    sol1->setIface("eth0");
    sol2->setIface("eth0");
    sol3->setIface("eth0");

605 606 607
    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));
608 609 610 611 612 613 614 615 616 617 618

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

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

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

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

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

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

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

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

694
    // server-id is mandatory in REQUEST
Tomek Mrugalski's avatar
Tomek Mrugalski committed
695
    req->addOption(srv.getServerID());
696

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

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

703
    OptionPtr tmp = reply->getOption(D6O_IA_NA);
704
    ASSERT_TRUE(tmp);
705

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

712
    // check that we've got the address we requested
713
    checkIAAddr(addr, hint, Lease::TYPE_NA);
714

715
    // check DUIDs
Tomek Mrugalski's avatar
Tomek Mrugalski committed
716
    checkServerId(reply, srv.getServerID());
717
    checkClientId(reply, clientid);
718

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

725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746
// 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"));
747
    req->setIface("eth0");
748 749 750 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
    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
778
    checkIAAddr(prf, hint, Lease::TYPE_PD);
779 780 781 782 783 784 785 786 787 788 789 790
    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()));
}

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

801 802
    ASSERT_TRUE(subnet_);

803 804 805
    Pkt6Ptr req1 = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234));
    Pkt6Ptr req2 = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 2345));
    Pkt6Ptr req3 = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 3456));
806

807 808 809 810
    req1->setRemoteAddr(IOAddress("fe80::abcd"));
    req2->setRemoteAddr(IOAddress("fe80::1223"));
    req3->setRemoteAddr(IOAddress("fe80::3467"));

811 812 813 814
    req1->setIface("eth0");
    req2->setIface("eth0");
    req3->setIface("eth0");

815 816 817
    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));
818 819 820 821 822 823 824 825 826 827

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

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

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

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

851 852 853 854
    ASSERT_TRUE(addr1);
    ASSERT_TRUE(addr2);
    ASSERT_TRUE(addr3);

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

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

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

877 878 879 880 881 882 883
// 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
884
// - returned REPLY message has IA_NA that includes IAADDR
885
// - lease is actually renewed in LeaseMgr
886 887
TEST_F(Dhcpv6SrvTest, renewBasic) {
    testRenewBasic(Lease::TYPE_NA, "2001:db8:1:1::cafe:babe",
888
                   "2001:db8:1:1::cafe:babe", 128);
889
}
890

891 892 893 894 895 896 897 898 899 900
// 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) {
901 902
    testRenewBasic(Lease::TYPE_PD, "2001:db8:1:2::",
                   "2001:db8:1:2::", pd_pool_->getLength());