Commit 60b979b7 authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰
Browse files

[master] Merge branch 'trac2326' (DHCPv6 release)

Conflicts:
	ChangeLog
	src/bin/dhcp6/dhcp6_messages.mes
parents bef01123 09743185
537. [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 0974318566abe08d0702ddd185156842c6642424)
536. [build] jinmei
Detect a build issue on FreeBSD with g++ 4.2 and Boost installed via
FreeBSD ports at ./configure time. This seems to be a bug of
......
......@@ -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_LEASE_WITHOUT_DUID lease for address %1 does not have a DUID
This error message indicates a database consistency failure. The lease
database has an entry indicating that the given address is in use,
but the lease does not contain any client identification. This is most
likely due to a software error: please raise a bug report. As a temporary
workaround, manually remove the 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 the
......@@ -86,6 +93,37 @@ 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. It
is a normal operation during client shutdown.
% DHCP6_RELEASE_FAIL failed to remove lease for address %1 for duid=%2, iaid=%3
This error message indicates that the software failed to remove a
lease from the lease database. It probably due to an error during a
database operation: resolution will most likely require administrator
intervention (e.g. check if DHCP process has sufficient privileges to
update the database). It may also be triggered if a lease was manually
removed from the database during RELEASE message processing.
% DHCP6_RELEASE_FAIL_WRONG_DUID client (duid=%1) tried to release address %2, but it belongs to client (duid=%3)
This warning message indicates that client tried to release an address
that belongs to a different client. This should not happen in normal
circumstances and may indicate a misconfiguration of the client. However,
since the client releasing the address will stop using it anyway, there
is a good chance that the situation will correct itself.
% DHCP6_RELEASE_FAIL_WRONG_IAID client (duid=%1) tried to release address %2, but it used wrong IAID (expected %3, but got %4)
This warning message indicates that client tried to release an address
that does belong to it, but the address was expected to be in a different
IA (identity association) container. This probably means that the client's
support for multiple addresses is flawed.
% DHCP6_RELEASE_MISSING_CLIENTID client (address=%1) sent RELEASE message without mandatory client-id
This warning message indicates that client sent RELEASE message without
mandatory client-id option. This is most likely caused by a buggy client
(or a relay that malformed forwarded message). This request will not be
processed and a response with error status code will be sent back.
% DHCP6_NOT_RUNNING IPv6 DHCP server is not running
A warning message is issued when an attempt is made to shut down the
IPv6 DHCP server but it is not running.
......@@ -216,3 +254,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);
......@@ -604,7 +606,7 @@ OptionPtr Dhcpv6Srv::renewIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
boost::shared_ptr<Option6IA> ia_rsp(new Option6IA(D6O_IA_NA, ia->getIAID()));
// Insert status code NoAddrsAvail.
ia_rsp->addOption(createStatusCode(STATUS_NoAddrsAvail,
ia_rsp->addOption(createStatusCode(STATUS_NoBinding,
"Sorry, no known leases for this duid/iaid."));
LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, DHCP6_UNKNOWN_RENEW)
......@@ -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,176 @@ 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.
// see sanityCheck() called from processRelease()
LOG_WARN(dhcp6_logger, DHCP6_RELEASE_MISSING_CLIENTID)
.arg(release->getRemoteAddr().toText());
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;
}
// @todo: add support for IA_PD
// @todo: add support for IA_TA
default:
// remaining options are stateless and thus ignored in this context
;
}
}
// 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_INFO(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_LEASE_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_INFO(dhcp6_logger, DHCP6_RELEASE_FAIL_WRONG_DUID)
.arg(duid->toText())
.arg(release_addr->getAddress().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(duid->toText())
.arg(release_addr->getAddress().toText())
.arg(lease->iaid_)
.arg(ia->getIAID());
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 to check 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 +920,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 RFC 3315 requires that a single status code be sent for the whole message,
/// this method may update the passed general_status: it is set to SUCCESS when
/// message processing begins, but may be updated to some error code if the
/// 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
......
This diff is collapsed.
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