Commit 318530ed authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰
Browse files

[2326] RELEASE support implemented.

parent b25d6802
526. [bug] syephen
5XX. [func] tomek
b10-dhcp6: Support for RELEASE message has been added. Clients
are now able to release their non-temporary IPv6 addresses.
(Trac #2326, git TBD)
526. [bug] stephen
Miscellaneous fixes to DHCP code including rationalisation of
some methods in LeaseMgr and resolving some Doxygen/cppcheck
issues.
......
......@@ -65,6 +65,13 @@ This informational message is printed every time DHCPv6 is started.
It indicates what database backend type is being to store lease and
other information.
% DHCP6_DB_ERROR_LEASE6_WITHOUT_DUID database error: DB returns a lease for address %1 without any DUID
This error message indicates database consistency failure. Database has an entry
for a given address and believes it is currently used, but it does not
contain client-id information. This is most likely a software error.
Please contact ISC. As a temporary workaround, please manually remove
lease entry from the database.
% DHCP6_LEASE_ADVERT lease %1 advertised (client duid=%2, iaid=%3)
This debug message indicates that the server successfully advertised
a lease. It is up to the client to choose one server out of othe advertised
......@@ -86,6 +93,27 @@ This message indicates that the server failed to grant (in response to
received REQUEST) a lease for a given client. There may be many reasons for
such failure. Each specific failure is logged in a separate log entry.
% DHCP6_RELEASE Address %1 belonging to client duid=%2, iaid=%3 was released properly.
This debug message indicates that an address was released properly. This
is a normal operation during client shutdown.
% DHCP6_RELEASE_FAIL Database failed to remove lease for address %1 for duid=%2, iaid=%3
This error message incidates that database failed to release a lease.
This indicates a database operation error and likely requires administrator
intervention (e.g. check if DHCP process has sufficient priviledges to update
database).
% DHCP6_RELEASE_FAIL_WRONG_DUID Client (duid=%2) tried to release address %2, but it belongs to client (duid=%3)
This warning message indicates that client tried to release an address that
does belong to a different client. This should not happen in normal circumstances,
but since the client is releasing it will stop using released addresses anyway,
so there is a good chance that the situation will correct itself.
% DHCP6_RELEASE_FAIL_WRONG_IAID Client (duid=%2) tried to release address %2, but it used wrong IAID (expected %4, but got %3)
This warning message indicates that client tried to release an address that
does belong to it, but was expected in a different IA container. This likely
means that the client's support for multiple address is buggy.
% DHCP6_REQUIRED_OPTIONS_CHECK_FAIL %1 message received from %2 failed the following check: %3
This message indicates that received DHCPv6 packet is invalid. This may be due
to a number of reasons, e.g. the mandatory client-id option is missing,
......@@ -216,3 +244,8 @@ recently and does not recognize its well-behaving clients. This is more
probable if you see many such messages. Clients will recover from this,
but they will most likely get a different IP addresses and experience
a brief service interruption.
% DHCP6_UNKNOWN_RELEASE received RELEASE from unknown client (duid=%1, iaid=%2)
This warning message is printed when client attempts to release a lease,
but no such lease is known by the server. See DHCP6_UNKNOWN_RENEW for
possible reasons for such behavior.
......@@ -436,6 +436,8 @@ void Dhcpv6Srv::assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer) {
// We need to allocate addresses for all IA_NA options in the client's
// question (i.e. SOLICIT or REQUEST) message.
// @todo add support for IA_TA
// @todo add support for IA_PD
// We need to select a subnet the client is connected in.
Subnet6Ptr subnet = selectSubnet(question);
......@@ -640,6 +642,8 @@ void Dhcpv6Srv::renewLeases(const Pkt6Ptr& renew, Pkt6Ptr& reply) {
// We need to renew addresses for all IA_NA options in the client's
// RENEW message.
// @todo add support for IA_TA
// @todo add support for IA_PD
// We need to select a subnet the client is connected in.
Subnet6Ptr subnet = selectSubnet(renew);
......@@ -688,11 +692,169 @@ void Dhcpv6Srv::renewLeases(const Pkt6Ptr& renew, Pkt6Ptr& reply) {
break;
}
}
}
void Dhcpv6Srv::releaseLeases(const Pkt6Ptr& release, Pkt6Ptr& reply) {
// We need to release addresses for all IA_NA options in the client's
// RELEASE message.
// @todo Add support for IA_TA
// @todo Add support for IA_PD
// @todo Consider supporting more than one address in a single IA_NA.
// That was envisaged by RFC3315, but it never happened. The only
// software that supports that is Dibbler, but its author seriously doubts
// if anyone is really using it. Clients that want more than one address
// just include more instances of IA_NA options.
// Let's find client's DUID. Client is supposed to include its client-id
// option almost all the time (the only exception is an anonymous inf-request,
// but that is mostly a theoretical case). Our allocation engine needs DUID
// and will refuse to allocate anything to anonymous clients.
OptionPtr opt_duid = release->getOption(D6O_CLIENTID);
if (!opt_duid) {
// This should not happen. We have checked this before.
reply->addOption(createStatusCode(STATUS_UnspecFail,
"You did not include mandatory client-id"));
return;
}
DuidPtr duid(new DUID(opt_duid->getData()));
int general_status = STATUS_Success;
for (Option::OptionCollection::iterator opt = release->options_.begin();
opt != release->options_.end(); ++opt) {
switch (opt->second->getType()) {
case D6O_IA_NA: {
OptionPtr answer_opt = releaseIA_NA(duid, release, general_status,
boost::dynamic_pointer_cast<Option6IA>(opt->second));
if (answer_opt) {
reply->addOption(answer_opt);
}
break;
}
default:
break;
}
}
// To be pedantic, we should also include status code in the top-level
// scope, not just in each IA_NA. See RFC3315, section 18.2.6.
// This behavior will likely go away in RFC3315bis.
reply->addOption(createStatusCode(general_status,
"Summary status for all processed IA_NAs"));
}
OptionPtr Dhcpv6Srv::releaseIA_NA(const DuidPtr& duid, Pkt6Ptr question,
int& general_status,
boost::shared_ptr<Option6IA> ia) {
// Release can be done in one of two ways:
// Approach 1: extract address from client's IA_NA and see if it belongs
// to this particular client.
// Approach 2: find a subnet for this client, get a lease for
// this subnet/duid/iaid and check if its content matches to what the
// client is asking us to release.
//
// This method implements approach 1.
// That's our response
boost::shared_ptr<Option6IA> ia_rsp(new Option6IA(D6O_IA_NA, ia->getIAID()));
boost::shared_ptr<Option6IAAddr> release_addr = boost::dynamic_pointer_cast<Option6IAAddr>
(ia->getOption(D6O_IAADDR));
if (!release_addr) {
ia_rsp->addOption(createStatusCode(STATUS_NoBinding,
"You did not include address in your RELEASE"));
general_status = STATUS_NoBinding;
return (ia_rsp);
}
Lease6Ptr lease = LeaseMgrFactory::instance().getLease6(release_addr->getAddress());
if (!lease) {
// client releasing a lease that we don't know about.
// Insert status code NoAddrsAvail.
ia_rsp->addOption(createStatusCode(STATUS_NoBinding,
"Sorry, no known leases for this duid/iaid, can't release."));
general_status = STATUS_NoBinding;
LOG_WARN(dhcp6_logger, DHCP6_UNKNOWN_RELEASE)
.arg(duid->toText())
.arg(ia->getIAID());
return (ia_rsp);
}
if (!lease->duid_) {
// Something is gravely wrong here. We do have a lease, but it does not
// have mandatory DUID information attached. Someone was messing with our
// database.
LOG_ERROR(dhcp6_logger, DHCP6_DB_ERROR_LEASE6_WITHOUT_DUID)
.arg(release_addr->getAddress().toText());
general_status = STATUS_UnspecFail;
ia_rsp->addOption(createStatusCode(STATUS_UnspecFail,
"Database consistency check failed when trying to RELEASE"));
return (ia_rsp);
}
if (*duid != *(lease->duid_)) {
// Sorry, it's not your address. You can't release it.
LOG_WARN(dhcp6_logger, DHCP6_RELEASE_FAIL_WRONG_DUID)
.arg(release_addr->getAddress().toText())
.arg(duid->toText())
.arg(lease->duid_->toText());
general_status = STATUS_NoBinding;
ia_rsp->addOption(createStatusCode(STATUS_NoBinding,
"This address does not belong to you, you can't release it"));
return (ia_rsp);
}
if (ia->getIAID() != lease->iaid_) {
// This address belongs to this client, but to a different IA
LOG_WARN(dhcp6_logger, DHCP6_RELEASE_FAIL_WRONG_IAID)
.arg(release_addr->getAddress().toText())
.arg(duid->toText())
.arg(ia->getIAID())
.arg(lease->iaid_);
ia_rsp->addOption(createStatusCode(STATUS_NoBinding,
"This is your address, but you used wrong IAID"));
general_status = STATUS_NoBinding;
return (ia_rsp);
}
// It is not necessary if the address matches as we used getLease6(addr)
// method that is supposed to return a proper lease.
// Ok, we've passed all checks. Let's release this address.
if (!LeaseMgrFactory::instance().deleteLease(lease->addr_)) {
ia_rsp->addOption(createStatusCode(STATUS_UnspecFail,
"Server failed to release a lease"));
LOG_ERROR(dhcp6_logger, DHCP6_RELEASE_FAIL)
.arg(lease->addr_.toText())
.arg(duid->toText())
.arg(lease->iaid_);
general_status = STATUS_UnspecFail;
return (ia_rsp);
} else {
LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, DHCP6_RELEASE)
.arg(lease->addr_.toText())
.arg(duid->toText())
.arg(lease->iaid_);
ia_rsp->addOption(createStatusCode(STATUS_Success,
"Lease released. Thank you, please come again."));
return (ia_rsp);
}
}
Pkt6Ptr Dhcpv6Srv::processSolicit(const Pkt6Ptr& solicit) {
sanityCheck(solicit, MANDATORY, FORBIDDEN);
......@@ -751,8 +913,16 @@ Pkt6Ptr Dhcpv6Srv::processConfirm(const Pkt6Ptr& confirm) {
}
Pkt6Ptr Dhcpv6Srv::processRelease(const Pkt6Ptr& release) {
/// @todo: Implement this
sanityCheck(release, MANDATORY, MANDATORY);
Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, release->getTransid()));
copyDefaultOptions(release, reply);
appendDefaultOptions(release, reply);
releaseLeases(release, reply);
return reply;
}
......
......@@ -212,17 +212,39 @@ protected:
/// @brief Renews specific IA_NA option
///
/// Generates response to IA_NA. This typically includes finding a lease that
/// corresponds to the received address. If no such lease is found, an IA_NA
/// response is generated with an appropriate status code.
/// Generates response to IA_NA in Renew. This typically includes finding a
/// lease that corresponds to the received address. If no such lease is
/// found, an IA_NA response is generated with an appropriate status code.
///
/// @param subnet subnet the sender belongs to
/// @param duid client's duid
/// @param question client's message
/// @param ia IA_NA option that is being renewed
/// @return IA_NA option (server's response)
OptionPtr renewIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
Pkt6Ptr question, boost::shared_ptr<Option6IA> ia);
/// @brief Releases specific IA_NA option
///
/// Generates response to IA_NA in Release message. This covers finding and
/// removal of a lease that corresponds to the received address. If no such
/// lease is found, an IA_NA response is generated with an appropriate
/// status code.
///
/// As RFC3315 requires to also send global (one for the whole message),
/// this method may update passed general_status. It is set to SUCCESS
/// when message processing begins, but may be update to some error code
/// if release process fails.
///
/// @param duid client's duid
/// @param question client's message
/// @param general_status a global status (it may be updated in case of errors)
/// @param ia IA_NA option that is being renewed
/// @return IA_NA option (server's response)
OptionPtr releaseIA_NA(const DuidPtr& duid, Pkt6Ptr question,
int& general_status,
boost::shared_ptr<Option6IA> ia);
/// @brief Copies required options from client message to server answer.
///
/// Copies options that must appear in any server response (ADVERTISE, REPLY)
......@@ -271,6 +293,17 @@ protected:
/// @param reply server's response
void renewLeases(const Pkt6Ptr& renew, Pkt6Ptr& reply);
/// @brief Attempts to release received addresses
///
/// It iterates through received IA_NA options and attempts to release
/// received addresses. If no such leases are found, or the lease fails
/// proper checks (e.g. belongs to someone else), a proper status
/// code is added to reply message. Released addresses are not added
/// to REPLY packet, just its IA_NA containers.
/// @param release client's message asking to release
/// @param reply server's response
void releaseLeases(const Pkt6Ptr& release, Pkt6Ptr& reply);
/// @brief Sets server-identifier.
///
/// This method attempts to set server-identifier DUID. It loads it
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment