|
@@ -60,15 +60,23 @@ namespace {
|
|
|
|
|
|
/// Structure that holds registered hook indexes
|
|
|
struct Dhcp6Hooks {
|
|
|
+ int hook_index_buffer6_receive_;///< index for "buffer6_receive" hook point
|
|
|
int hook_index_pkt6_receive_; ///< index for "pkt6_receive" hook point
|
|
|
int hook_index_subnet6_select_; ///< index for "subnet6_select" hook point
|
|
|
+ int hook_index_lease6_renew_; ///< index for "lease6_renew" hook point
|
|
|
+ int hook_index_lease6_release_; ///< index for "lease6_release" hook point
|
|
|
int hook_index_pkt6_send_; ///< index for "pkt6_send" hook point
|
|
|
+ int hook_index_buffer6_send_; ///< index for "buffer6_send" hook point
|
|
|
|
|
|
/// Constructor that registers hook points for DHCPv6 engine
|
|
|
Dhcp6Hooks() {
|
|
|
+ hook_index_buffer6_receive_= HooksManager::registerHook("buffer6_receive");
|
|
|
hook_index_pkt6_receive_ = HooksManager::registerHook("pkt6_receive");
|
|
|
hook_index_subnet6_select_ = HooksManager::registerHook("subnet6_select");
|
|
|
+ hook_index_lease6_renew_ = HooksManager::registerHook("lease6_renew");
|
|
|
+ hook_index_lease6_release_ = HooksManager::registerHook("lease6_release");
|
|
|
hook_index_pkt6_send_ = HooksManager::registerHook("pkt6_send");
|
|
|
+ hook_index_buffer6_send_ = HooksManager::registerHook("buffer6_send");
|
|
|
}
|
|
|
};
|
|
|
|
|
@@ -94,8 +102,7 @@ namespace dhcp {
|
|
|
static const char* SERVER_DUID_FILE = "b10-dhcp6-serverid";
|
|
|
|
|
|
Dhcpv6Srv::Dhcpv6Srv(uint16_t port)
|
|
|
-:alloc_engine_(), serverid_(), shutdown_(true), hook_index_pkt6_receive_(-1),
|
|
|
- hook_index_subnet6_select_(-1), hook_index_pkt6_send_(-1), port_(port)
|
|
|
+:alloc_engine_(), serverid_(), shutdown_(true), port_(port)
|
|
|
{
|
|
|
|
|
|
LOG_DEBUG(dhcp6_logger, DBG_DHCP6_START, DHCP6_OPEN_SOCKET).arg(port);
|
|
@@ -129,17 +136,11 @@ Dhcpv6Srv::Dhcpv6Srv(uint16_t port)
|
|
|
LOG_WARN(dhcp6_logger, DHCP6_SERVERID_WRITE_FAIL)
|
|
|
.arg(duid_file);
|
|
|
}
|
|
|
-
|
|
|
}
|
|
|
|
|
|
// Instantiate allocation engine
|
|
|
alloc_engine_.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100));
|
|
|
|
|
|
- // Register hook points
|
|
|
- hook_index_pkt6_receive_ = Hooks.hook_index_pkt6_receive_;
|
|
|
- hook_index_subnet6_select_ = Hooks.hook_index_subnet6_select_;
|
|
|
- hook_index_pkt6_send_ = Hooks.hook_index_pkt6_send_;
|
|
|
-
|
|
|
/// @todo call loadLibraries() when handling configuration changes
|
|
|
|
|
|
} catch (const std::exception &e) {
|
|
@@ -191,146 +192,236 @@ bool Dhcpv6Srv::run() {
|
|
|
LOG_ERROR(dhcp6_logger, DHCP6_PACKET_RECEIVE_FAIL).arg(e.what());
|
|
|
}
|
|
|
|
|
|
- if (query) {
|
|
|
- if (!query->unpack()) {
|
|
|
- LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL,
|
|
|
- DHCP6_PACKET_PARSE_FAIL);
|
|
|
- continue;
|
|
|
- }
|
|
|
- LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, DHCP6_PACKET_RECEIVED)
|
|
|
- .arg(query->getName());
|
|
|
- LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL_DATA, DHCP6_QUERY_DATA)
|
|
|
- .arg(static_cast<int>(query->getType()))
|
|
|
- .arg(query->getBuffer().getLength())
|
|
|
- .arg(query->toText());
|
|
|
-
|
|
|
- // Let's execute all callouts registered for packet_received
|
|
|
- if (HooksManager::getHooksManager().calloutsPresent(hook_index_pkt6_receive_)) {
|
|
|
- CalloutHandlePtr callout_handle = getCalloutHandle(query);
|
|
|
+ // Timeout may be reached or signal received, which breaks select() with no packet received
|
|
|
+ if (!query) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
|
|
|
- // Delete previously set arguments
|
|
|
- callout_handle->deleteAllArguments();
|
|
|
+ bool skip_unpack = false;
|
|
|
|
|
|
- // Pass incoming packet as argument
|
|
|
- callout_handle->setArgument("query6", query);
|
|
|
+ // The packet has just been received so contains the uninterpreted wire
|
|
|
+ // data; execute callouts registered for buffer6_receive.
|
|
|
+ if (HooksManager::getHooksManager().calloutsPresent(Hooks.hook_index_buffer6_receive_)) {
|
|
|
+ CalloutHandlePtr callout_handle = getCalloutHandle(query);
|
|
|
|
|
|
- // Call callouts
|
|
|
- HooksManager::callCallouts(hook_index_pkt6_receive_, *callout_handle);
|
|
|
+ // Delete previously set arguments
|
|
|
+ callout_handle->deleteAllArguments();
|
|
|
|
|
|
- // Callouts decided to skip the next processing step. The next
|
|
|
- // processing step would to process the packet, so skip at this
|
|
|
- // stage means drop.
|
|
|
- if (callout_handle->getSkip()) {
|
|
|
- LOG_DEBUG(dhcp6_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_PACKET_RCVD_SKIP);
|
|
|
- continue;
|
|
|
- }
|
|
|
+ // Pass incoming packet as argument
|
|
|
+ callout_handle->setArgument("query6", query);
|
|
|
|
|
|
- callout_handle->getArgument("query6", query);
|
|
|
+ // Call callouts
|
|
|
+ HooksManager::callCallouts(Hooks.hook_index_buffer6_receive_, *callout_handle);
|
|
|
+
|
|
|
+ // Callouts decided to skip the next processing step. The next
|
|
|
+ // processing step would to parse the packet, so skip at this
|
|
|
+ // stage means that callouts did the parsing already, so server
|
|
|
+ // should skip parsing.
|
|
|
+ if (callout_handle->getSkip()) {
|
|
|
+ LOG_DEBUG(dhcp6_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_BUFFER_RCVD_SKIP);
|
|
|
+ skip_unpack = true;
|
|
|
}
|
|
|
|
|
|
- try {
|
|
|
- switch (query->getType()) {
|
|
|
- case DHCPV6_SOLICIT:
|
|
|
- rsp = processSolicit(query);
|
|
|
- break;
|
|
|
+ callout_handle->getArgument("query6", query);
|
|
|
+ }
|
|
|
|
|
|
- case DHCPV6_REQUEST:
|
|
|
- rsp = processRequest(query);
|
|
|
- break;
|
|
|
+ // Unpack the packet information unless the buffer6_receive callouts
|
|
|
+ // indicated they did it
|
|
|
+ if (!skip_unpack) {
|
|
|
+ if (!query->unpack()) {
|
|
|
+ LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL,
|
|
|
+ DHCP6_PACKET_PARSE_FAIL);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, DHCP6_PACKET_RECEIVED)
|
|
|
+ .arg(query->getName());
|
|
|
+ LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL_DATA, DHCP6_QUERY_DATA)
|
|
|
+ .arg(static_cast<int>(query->getType()))
|
|
|
+ .arg(query->getBuffer().getLength())
|
|
|
+ .arg(query->toText());
|
|
|
+
|
|
|
+ // At this point the information in the packet has been unpacked into
|
|
|
+ // the various packet fields and option objects has been cretated.
|
|
|
+ // Execute callouts registered for packet6_receive.
|
|
|
+ if (HooksManager::getHooksManager().calloutsPresent(Hooks.hook_index_pkt6_receive_)) {
|
|
|
+ CalloutHandlePtr callout_handle = getCalloutHandle(query);
|
|
|
+
|
|
|
+ // Delete previously set arguments
|
|
|
+ callout_handle->deleteAllArguments();
|
|
|
+
|
|
|
+ // Pass incoming packet as argument
|
|
|
+ callout_handle->setArgument("query6", query);
|
|
|
+
|
|
|
+ // Call callouts
|
|
|
+ HooksManager::callCallouts(Hooks.hook_index_pkt6_receive_, *callout_handle);
|
|
|
+
|
|
|
+ // Callouts decided to skip the next processing step. The next
|
|
|
+ // processing step would to process the packet, so skip at this
|
|
|
+ // stage means drop.
|
|
|
+ if (callout_handle->getSkip()) {
|
|
|
+ LOG_DEBUG(dhcp6_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_PACKET_RCVD_SKIP);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
|
|
|
- case DHCPV6_RENEW:
|
|
|
- rsp = processRenew(query);
|
|
|
- break;
|
|
|
+ callout_handle->getArgument("query6", query);
|
|
|
+ }
|
|
|
|
|
|
- case DHCPV6_REBIND:
|
|
|
- rsp = processRebind(query);
|
|
|
+ try {
|
|
|
+ switch (query->getType()) {
|
|
|
+ case DHCPV6_SOLICIT:
|
|
|
+ rsp = processSolicit(query);
|
|
|
break;
|
|
|
|
|
|
- case DHCPV6_CONFIRM:
|
|
|
- rsp = processConfirm(query);
|
|
|
- break;
|
|
|
+ case DHCPV6_REQUEST:
|
|
|
+ rsp = processRequest(query);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case DHCPV6_RENEW:
|
|
|
+ rsp = processRenew(query);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case DHCPV6_REBIND:
|
|
|
+ rsp = processRebind(query);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case DHCPV6_CONFIRM:
|
|
|
+ rsp = processConfirm(query);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case DHCPV6_RELEASE:
|
|
|
+ rsp = processRelease(query);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case DHCPV6_DECLINE:
|
|
|
+ rsp = processDecline(query);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case DHCPV6_INFORMATION_REQUEST:
|
|
|
+ rsp = processInfRequest(query);
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ // We received a packet type that we do not recognize.
|
|
|
+ LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_UNKNOWN_MSG_RECEIVED)
|
|
|
+ .arg(static_cast<int>(query->getType()))
|
|
|
+ .arg(query->getIface());
|
|
|
+ // Only action is to output a message if debug is enabled,
|
|
|
+ // and that will be covered by the debug statement before
|
|
|
+ // the "switch" statement.
|
|
|
+ ;
|
|
|
+ }
|
|
|
|
|
|
- case DHCPV6_RELEASE:
|
|
|
- rsp = processRelease(query);
|
|
|
- break;
|
|
|
+ } catch (const RFCViolation& e) {
|
|
|
+ LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_REQUIRED_OPTIONS_CHECK_FAIL)
|
|
|
+ .arg(query->getName())
|
|
|
+ .arg(query->getRemoteAddr().toText())
|
|
|
+ .arg(e.what());
|
|
|
+
|
|
|
+ } catch (const isc::Exception& e) {
|
|
|
+
|
|
|
+ // Catch-all exception (at least for ones based on the isc
|
|
|
+ // Exception class, which covers more or less all that
|
|
|
+ // are explicitly raised in the BIND 10 code). Just log
|
|
|
+ // the problem and ignore the packet. (The problem is logged
|
|
|
+ // as a debug message because debug is disabled by default -
|
|
|
+ // it prevents a DDOS attack based on the sending of problem
|
|
|
+ // packets.)
|
|
|
+ LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_PACKET_PROCESS_FAIL)
|
|
|
+ .arg(query->getName())
|
|
|
+ .arg(query->getRemoteAddr().toText())
|
|
|
+ .arg(e.what());
|
|
|
+ }
|
|
|
|
|
|
- case DHCPV6_DECLINE:
|
|
|
- rsp = processDecline(query);
|
|
|
- break;
|
|
|
+ if (rsp) {
|
|
|
+ rsp->setRemoteAddr(query->getRemoteAddr());
|
|
|
+ rsp->setLocalAddr(query->getLocalAddr());
|
|
|
+ rsp->setRemotePort(DHCP6_CLIENT_PORT);
|
|
|
+ rsp->setLocalPort(DHCP6_SERVER_PORT);
|
|
|
+ rsp->setIndex(query->getIndex());
|
|
|
+ rsp->setIface(query->getIface());
|
|
|
+
|
|
|
+ // Specifies if server should do the packing
|
|
|
+ bool skip_pack = false;
|
|
|
+
|
|
|
+ // Server's reply packet now has all options and fields set.
|
|
|
+ // Options are represented by individual objects, but the
|
|
|
+ // output wire data has not been prepared yet.
|
|
|
+ // Execute all callouts registered for packet6_send
|
|
|
+ if (HooksManager::getHooksManager().calloutsPresent(Hooks.hook_index_pkt6_send_)) {
|
|
|
+ CalloutHandlePtr callout_handle = getCalloutHandle(query);
|
|
|
|
|
|
- case DHCPV6_INFORMATION_REQUEST:
|
|
|
- rsp = processInfRequest(query);
|
|
|
- break;
|
|
|
+ // Delete all previous arguments
|
|
|
+ callout_handle->deleteAllArguments();
|
|
|
+
|
|
|
+ // Set our response
|
|
|
+ callout_handle->setArgument("response6", rsp);
|
|
|
|
|
|
- default:
|
|
|
- // Only action is to output a message if debug is enabled,
|
|
|
- // and that will be covered by the debug statement before
|
|
|
- // the "switch" statement.
|
|
|
- ;
|
|
|
+ // Call all installed callouts
|
|
|
+ HooksManager::callCallouts(Hooks.hook_index_pkt6_send_, *callout_handle);
|
|
|
+
|
|
|
+ // Callouts decided to skip the next processing step. The next
|
|
|
+ // processing step would to pack the packet (create wire data).
|
|
|
+ // That step will be skipped if any callout sets skip flag.
|
|
|
+ // It essentially means that the callout already did packing,
|
|
|
+ // so the server does not have to do it again.
|
|
|
+ if (callout_handle->getSkip()) {
|
|
|
+ LOG_DEBUG(dhcp6_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_PACKET_SEND_SKIP);
|
|
|
+ skip_pack = true;
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- } catch (const RFCViolation& e) {
|
|
|
- LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_REQUIRED_OPTIONS_CHECK_FAIL)
|
|
|
- .arg(query->getName())
|
|
|
- .arg(query->getRemoteAddr().toText())
|
|
|
- .arg(e.what());
|
|
|
+ LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL_DATA,
|
|
|
+ DHCP6_RESPONSE_DATA)
|
|
|
+ .arg(static_cast<int>(rsp->getType())).arg(rsp->toText());
|
|
|
|
|
|
- } catch (const isc::Exception& e) {
|
|
|
-
|
|
|
- // Catch-all exception (at least for ones based on the isc
|
|
|
- // Exception class, which covers more or less all that
|
|
|
- // are explicitly raised in the BIND 10 code). Just log
|
|
|
- // the problem and ignore the packet. (The problem is logged
|
|
|
- // as a debug message because debug is disabled by default -
|
|
|
- // it prevents a DDOS attack based on the sending of problem
|
|
|
- // packets.)
|
|
|
- LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_PACKET_PROCESS_FAIL)
|
|
|
- .arg(query->getName())
|
|
|
- .arg(query->getRemoteAddr().toText())
|
|
|
- .arg(e.what());
|
|
|
+ if (!skip_pack) {
|
|
|
+ try {
|
|
|
+ rsp->pack();
|
|
|
+ } catch (const std::exception& e) {
|
|
|
+ LOG_ERROR(dhcp6_logger, DHCP6_PACK_FAIL)
|
|
|
+ .arg(e.what());
|
|
|
+ continue;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- if (rsp) {
|
|
|
- rsp->setRemoteAddr(query->getRemoteAddr());
|
|
|
- rsp->setLocalAddr(query->getLocalAddr());
|
|
|
- rsp->setRemotePort(DHCP6_CLIENT_PORT);
|
|
|
- rsp->setLocalPort(DHCP6_SERVER_PORT);
|
|
|
- rsp->setIndex(query->getIndex());
|
|
|
- rsp->setIface(query->getIface());
|
|
|
+ try {
|
|
|
|
|
|
- // Execute all callouts registered for packet6_send
|
|
|
- if (HooksManager::getHooksManager().calloutsPresent(hook_index_pkt6_send_)) {
|
|
|
+ // Now all fields and options are constructed into output wire buffer.
|
|
|
+ // Option objects modification does not make sense anymore. Hooks
|
|
|
+ // can only manipulate wire buffer at this stage.
|
|
|
+ // Let's execute all callouts registered for buffer6_send
|
|
|
+ if (HooksManager::getHooksManager().calloutsPresent(Hooks.hook_index_buffer6_send_)) {
|
|
|
CalloutHandlePtr callout_handle = getCalloutHandle(query);
|
|
|
|
|
|
- // Delete all previous arguments
|
|
|
+ // Delete previously set arguments
|
|
|
callout_handle->deleteAllArguments();
|
|
|
|
|
|
- // Set our response
|
|
|
+ // Pass incoming packet as argument
|
|
|
callout_handle->setArgument("response6", rsp);
|
|
|
-
|
|
|
- // Call all installed callouts
|
|
|
- HooksManager::callCallouts(hook_index_pkt6_send_, *callout_handle);
|
|
|
-
|
|
|
+
|
|
|
+ // Call callouts
|
|
|
+ HooksManager::callCallouts(Hooks.hook_index_buffer6_send_, *callout_handle);
|
|
|
+
|
|
|
// Callouts decided to skip the next processing step. The next
|
|
|
- // processing step would to send the packet, so skip at this
|
|
|
- // stage means "drop response".
|
|
|
+ // processing step would to parse the packet, so skip at this
|
|
|
+ // stage means drop.
|
|
|
if (callout_handle->getSkip()) {
|
|
|
- LOG_DEBUG(dhcp6_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_PACKET_SEND_SKIP);
|
|
|
+ LOG_DEBUG(dhcp6_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_BUFFER_SEND_SKIP);
|
|
|
continue;
|
|
|
}
|
|
|
+
|
|
|
+ callout_handle->getArgument("response6", rsp);
|
|
|
}
|
|
|
|
|
|
LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL_DATA,
|
|
|
DHCP6_RESPONSE_DATA)
|
|
|
.arg(static_cast<int>(rsp->getType())).arg(rsp->toText());
|
|
|
|
|
|
- try {
|
|
|
- rsp->pack();
|
|
|
- sendPacket(rsp);
|
|
|
- } catch (const std::exception& e) {
|
|
|
- LOG_ERROR(dhcp6_logger, DHCP6_PACKET_SEND_FAIL)
|
|
|
- .arg(e.what());
|
|
|
- }
|
|
|
+ sendPacket(rsp);
|
|
|
+ } catch (const std::exception& e) {
|
|
|
+ LOG_ERROR(dhcp6_logger, DHCP6_PACKET_SEND_FAIL)
|
|
|
+ .arg(e.what());
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -648,8 +739,8 @@ Dhcpv6Srv::selectSubnet(const Pkt6Ptr& question) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // Let's execute all callouts registered for packet_received
|
|
|
- if (HooksManager::getHooksManager().calloutsPresent(hook_index_subnet6_select_)) {
|
|
|
+ // Let's execute all callouts registered for subnet6_receive
|
|
|
+ if (HooksManager::getHooksManager().calloutsPresent(Hooks.hook_index_subnet6_select_)) {
|
|
|
CalloutHandlePtr callout_handle = getCalloutHandle(question);
|
|
|
|
|
|
// We're reusing callout_handle from previous calls
|
|
@@ -665,7 +756,7 @@ Dhcpv6Srv::selectSubnet(const Pkt6Ptr& question) {
|
|
|
callout_handle->setArgument("subnet6collection", CfgMgr::instance().getSubnets6());
|
|
|
|
|
|
// Call user (and server-side) callouts
|
|
|
- HooksManager::callCallouts(hook_index_subnet6_select_, *callout_handle);
|
|
|
+ HooksManager::callCallouts(Hooks.hook_index_subnet6_select_, *callout_handle);
|
|
|
|
|
|
// Callouts decided to skip this step. This means that no subnet will be
|
|
|
// selected. Packet processing will continue, but it will be severly limited
|
|
@@ -852,7 +943,7 @@ Dhcpv6Srv::assignIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
|
|
|
|
|
|
OptionPtr
|
|
|
Dhcpv6Srv::renewIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
|
|
|
- Pkt6Ptr /* question */, boost::shared_ptr<Option6IA> ia) {
|
|
|
+ const Pkt6Ptr& query, boost::shared_ptr<Option6IA> ia) {
|
|
|
if (!subnet) {
|
|
|
// There's no subnet select for this client. There's nothing to renew.
|
|
|
boost::shared_ptr<Option6IA> ia_rsp(new Option6IA(D6O_IA_NA, ia->getIAID()));
|
|
@@ -889,14 +980,15 @@ Dhcpv6Srv::renewIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
|
|
|
return (ia_rsp);
|
|
|
}
|
|
|
|
|
|
+ // Keep the old data in case the callout tells us to skip update
|
|
|
+ Lease6 old_data = *lease;
|
|
|
+
|
|
|
lease->preferred_lft_ = subnet->getPreferred();
|
|
|
lease->valid_lft_ = subnet->getValid();
|
|
|
lease->t1_ = subnet->getT1();
|
|
|
lease->t2_ = subnet->getT2();
|
|
|
lease->cltt_ = time(NULL);
|
|
|
|
|
|
- LeaseMgrFactory::instance().updateLease6(lease);
|
|
|
-
|
|
|
// Create empty IA_NA option with IAID matching the request.
|
|
|
boost::shared_ptr<Option6IA> ia_rsp(new Option6IA(D6O_IA_NA, ia->getIAID()));
|
|
|
|
|
@@ -907,6 +999,46 @@ Dhcpv6Srv::renewIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
|
|
|
lease->addr_, lease->preferred_lft_,
|
|
|
lease->valid_lft_));
|
|
|
ia_rsp->addOption(addr);
|
|
|
+
|
|
|
+ bool skip = false;
|
|
|
+ // Execute all callouts registered for packet6_send
|
|
|
+ if (HooksManager::getHooksManager().calloutsPresent(Hooks.hook_index_lease6_renew_)) {
|
|
|
+ CalloutHandlePtr callout_handle = getCalloutHandle(query);
|
|
|
+
|
|
|
+ // Delete all previous arguments
|
|
|
+ callout_handle->deleteAllArguments();
|
|
|
+
|
|
|
+ // Pass the original packet
|
|
|
+ callout_handle->setArgument("query6", query);
|
|
|
+
|
|
|
+ // Pass the lease to be updated
|
|
|
+ callout_handle->setArgument("lease6", lease);
|
|
|
+
|
|
|
+ // Pass the IA option to be sent in response
|
|
|
+ callout_handle->setArgument("ia_na", ia_rsp);
|
|
|
+
|
|
|
+ // Call all installed callouts
|
|
|
+ HooksManager::callCallouts(Hooks.hook_index_lease6_renew_, *callout_handle);
|
|
|
+
|
|
|
+ // Callouts decided to skip the next processing step. The next
|
|
|
+ // processing step would to actually renew the lease, so skip at this
|
|
|
+ // stage means "keep the old lease as it is".
|
|
|
+ if (callout_handle->getSkip()) {
|
|
|
+ skip = true;
|
|
|
+ LOG_DEBUG(dhcp6_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_LEASE6_RENEW_SKIP);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!skip) {
|
|
|
+ LeaseMgrFactory::instance().updateLease6(lease);
|
|
|
+ } else {
|
|
|
+ // Copy back the original date to the lease. For MySQL it doesn't make
|
|
|
+ // much sense, but for memfile, the Lease6Ptr points to the actual lease
|
|
|
+ // in memfile, so the actual update is performed when we manipulate fields
|
|
|
+ // of returned Lease6Ptr, the actual updateLease6() is no-op.
|
|
|
+ *lease = old_data;
|
|
|
+ }
|
|
|
+
|
|
|
return (ia_rsp);
|
|
|
}
|
|
|
|
|
@@ -1025,7 +1157,7 @@ Dhcpv6Srv::releaseLeases(const Pkt6Ptr& release, Pkt6Ptr& reply) {
|
|
|
}
|
|
|
|
|
|
OptionPtr
|
|
|
-Dhcpv6Srv::releaseIA_NA(const DuidPtr& duid, Pkt6Ptr /* question */,
|
|
|
+Dhcpv6Srv::releaseIA_NA(const DuidPtr& duid, const Pkt6Ptr& query,
|
|
|
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
|
|
@@ -1109,9 +1241,43 @@ Dhcpv6Srv::releaseIA_NA(const DuidPtr& duid, Pkt6Ptr /* question */,
|
|
|
// It is not necessary to check if the address matches as we used
|
|
|
// getLease6(addr) method that is supposed to return a proper lease.
|
|
|
|
|
|
+ bool skip = false;
|
|
|
+ // Execute all callouts registered for packet6_send
|
|
|
+ if (HooksManager::getHooksManager().calloutsPresent(Hooks.hook_index_lease6_release_)) {
|
|
|
+ CalloutHandlePtr callout_handle = getCalloutHandle(query);
|
|
|
+
|
|
|
+ // Delete all previous arguments
|
|
|
+ callout_handle->deleteAllArguments();
|
|
|
+
|
|
|
+ // Pass the original packet
|
|
|
+ callout_handle->setArgument("query6", query);
|
|
|
+
|
|
|
+ // Pass the lease to be updated
|
|
|
+ callout_handle->setArgument("lease6", lease);
|
|
|
+
|
|
|
+ // Call all installed callouts
|
|
|
+ HooksManager::callCallouts(Hooks.hook_index_lease6_release_, *callout_handle);
|
|
|
+
|
|
|
+ // Callouts decided to skip the next processing step. The next
|
|
|
+ // processing step would to send the packet, so skip at this
|
|
|
+ // stage means "drop response".
|
|
|
+ if (callout_handle->getSkip()) {
|
|
|
+ skip = true;
|
|
|
+ LOG_DEBUG(dhcp6_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_LEASE6_RELEASE_SKIP);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
// Ok, we've passed all checks. Let's release this address.
|
|
|
+ bool success = false; // was the removal operation succeessful?
|
|
|
+
|
|
|
+ if (!skip) {
|
|
|
+ success = LeaseMgrFactory::instance().deleteLease(lease->addr_);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Here the success should be true if we removed lease successfully
|
|
|
+ // and false if skip flag was set or the removal failed for whatever reason
|
|
|
|
|
|
- if (!LeaseMgrFactory::instance().deleteLease(lease->addr_)) {
|
|
|
+ if (!success) {
|
|
|
ia_rsp->addOption(createStatusCode(STATUS_UnspecFail,
|
|
|
"Server failed to release a lease"));
|
|
|
|