return (addr);
}
+ // Checks that server rejected IA_NA, i.e. that it has no addresses and
+ // that expected status code really appears there.
+ // Status code indicates type of error encountered (in theory it can also
+ // indicate success, but servers typically don't send success status
+ // as this is the default result and it saves bandwidth)
+ void checkRejectedIA_NA(const boost::shared_ptr<Option6IA>& ia,
+ uint16_t expected_status_code) {
+ // Make sure there is no address assigned.
+ EXPECT_FALSE(ia->getOption(D6O_IAADDR));
+
+ // T1, T2 should be zeroed
+ EXPECT_EQ(0, ia->getT1());
+ EXPECT_EQ(0, ia->getT2());
+
+ OptionPtr status = ia->getOption(D6O_STATUS_CODE);
+ EXPECT_TRUE(status);
+
+ if (status) {
+ // We don't have dedicated class for status code, so let's just interpret
+ // first 2 bytes as status. Remainder of the status code option content is
+ // just a text explanation what went wrong.
+ EXPECT_EQ(static_cast<uint16_t>(expected_status_code), status->getUint16());
+ }
+ }
+
// Check that generated IAADDR option contains expected address.
void checkIAAddr(const boost::shared_ptr<Option6IAAddr>& addr,
const IOAddress& expected_addr,
// 1 >= difference between cltt and expected
EXPECT_GE(1, abs(cltt - expected));
- LeaseMgrFactory::instance().deleteLease6(addr_opt->getAddress());
+ EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease6(addr_opt->getAddress()));
}
-// This test verifies that incoming (negative) RENEW can be handled properly.
-// Client tries to RENEW an address that was never assigned to him.
+// This test verifies that incoming (invalid) RENEW can be handled properly.
+//
+// This test checks 3 scenarios:
+// 1. there is no such lease at all
+// 2. there is such a lease, but it is assigned to a different IAID
+// 3. there is such a lease, but it belongs to a different client
+//
// expected:
// - returned REPLY message has copy of client-id
// - returned REPLY message has server-id
// - returned REPLY message has IA that includes STATUS-CODE
// - No lease in LeaseMgr
-TEST_F(Dhcpv6SrvTest, RenewNoLease) {
+TEST_F(Dhcpv6SrvTest, RenewReject) {
boost::scoped_ptr<NakedDhcpv6Srv> srv;
ASSERT_NO_THROW( srv.reset(new NakedDhcpv6Srv(0)) );
IOAddress addr("2001:db8:1:1::dead");
- const uint32_t iaid = 234;
+ const uint32_t transid = 1234;
+ const uint32_t valid_iaid = 234;
+ const uint32_t bogus_iaid = 456;
// generate client-id also duid_
OptionPtr clientid = generateClientId();
ASSERT_FALSE(l);
// Let's create a RENEW
- Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RENEW, 1234));
+ Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RENEW, transid));
req->setRemoteAddr(IOAddress("fe80::abcd"));
- boost::shared_ptr<Option6IA> ia = generateIA(iaid, 1500, 3000);
+ boost::shared_ptr<Option6IA> ia = generateIA(bogus_iaid, 1500, 3000);
ASSERT_TRUE(subnet_->inPool(addr));
OptionPtr renewed_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
// server-id is mandatory in RENEW
req->addOption(srv->getServerID());
+ // Case 1: No lease known to server
+
// Pass it to the server and hope for a REPLY
Pkt6Ptr reply = srv->processRenew(req);
- // check if we get response at all
- checkResponse(reply, DHCPV6_REPLY, 1234);
-
+ // Check if we get response at all
+ checkResponse(reply, DHCPV6_REPLY, transid);
OptionPtr tmp = reply->getOption(D6O_IA_NA);
ASSERT_TRUE(tmp);
+ // Check that IA_NA was returned and that there's an address included
+ ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
+ ASSERT_TRUE(ia);
+ checkRejectedIA_NA(ia, STATUS_NoAddrsAvail);
- // check that IA_NA was returned and that there's an address included
+ // Check that there is no lease added
+ l = LeaseMgrFactory::instance().getLease6(addr);
+ ASSERT_FALSE(l);
+
+ // CASE 2: Lease is known and belongs to this client, but to a different IAID
+
+ // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
+ // value on purpose. They should be updated during RENEW.
+ Lease6Ptr lease(new Lease6(Lease6::LEASE_IA_NA, addr, duid_, valid_iaid,
+ 501, 502, 503, 504, subnet_->getID(), 0));
+ lease->cltt_ = 123; // Let's use it as an indicator that the lease
+ // was NOT updated.
+ ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
+
+ // Pass it to the server and hope for a REPLY
+ reply = srv->processRenew(req);
+ checkResponse(reply, DHCPV6_REPLY, transid);
+ tmp = reply->getOption(D6O_IA_NA);
+ ASSERT_TRUE(tmp);
+ // Check that IA_NA was returned and that there's an address included
ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
ASSERT_TRUE(ia);
+ checkRejectedIA_NA(ia, STATUS_NoAddrsAvail);
- // Make sure there is no address assigned.
- EXPECT_FALSE(ia->getOption(D6O_IAADDR));
+ // There is a iaid mis-match, so server should respond that there is
+ // no such address to renew.
- // T1, T2 should be zeroed
- EXPECT_EQ(0, ia->getT1());
- EXPECT_EQ(0, ia->getT2());
+ // CASE 3: Lease belongs to a client with different client-id
+ req->delOption(D6O_CLIENTID);
+ ia = boost::dynamic_pointer_cast<Option6IA>(req->getOption(D6O_IA_NA));
+ ia->setIAID(valid_iaid); // Now iaid in renew matches that in leasemgr
+ req->addOption(generateClientId(13)); // generate different DUID
+ // (with length 13)
+
+ reply = srv->processRenew(req);
+ checkResponse(reply, DHCPV6_REPLY, transid);
+ tmp = reply->getOption(D6O_IA_NA);
+ ASSERT_TRUE(tmp);
+ // Check that IA_NA was returned and that there's an address included
+ ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
+ ASSERT_TRUE(ia);
+ checkRejectedIA_NA(ia, STATUS_NoAddrsAvail);
- OptionPtr status = ia->getOption(D6O_STATUS_CODE);
- ASSERT_TRUE(status);
- // We don't have dedicated class for status code, so let's just interpret
- // first 2 bytes as status. Remainder of the status code option is just
- // a text explanation what went wrong.
- EXPECT_EQ(static_cast<uint16_t>(STATUS_NoAddrsAvail), status->getUint16());
+ lease = LeaseMgrFactory::instance().getLease6(addr);
+ ASSERT_TRUE(lease);
+ // Verify that the lease was not updated.
+ EXPECT_EQ(123, lease->cltt_);
- l = LeaseMgrFactory::instance().getLease6(addr);
- ASSERT_FALSE(l);
+ EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease6(addr));
}
// This test verifies if the status code option is generated properly.