mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-29 04:57:52 +00:00
[master] Merged trac4267 (final run_one())
This commit is contained in:
commit
2047a44ad5
1
AUTHORS
1
AUTHORS
@ -89,6 +89,7 @@ We have received the following contributions:
|
||||
|
||||
- Jinmei Tatuya
|
||||
2015-10: Pkt4o6 class improvements
|
||||
2015-11: split Dhcpv4Srv::run() into run() and processPacket()
|
||||
|
||||
- Sebastien Couture, Ubity Inc
|
||||
2015-12: Fixes to MySQL schema creation
|
||||
|
@ -449,10 +449,17 @@ This error message is issued when preparing an on-wire format of the packet
|
||||
has failed. The first argument identifies the client and the DHCP transaction.
|
||||
The second argument includes the error string.
|
||||
|
||||
% DHCP4_PACKET_PROCESS_EXCEPTION exception occurred during packet processing: %1
|
||||
This error message indicates that an exception was raised during packet processing
|
||||
that was not caught by other, more specific exception handlers. This packet will
|
||||
be dropped and the server will continue operation.
|
||||
% DHCP4_PACKET_PROCESS_EXCEPTION exception occurred during packet processing
|
||||
This error message indicates that a non-standard exception was raised
|
||||
during packet processing that was not caught by other, more specific
|
||||
exception handlers. This packet will be dropped and the server will
|
||||
continue operation.
|
||||
|
||||
% DHCP4_PACKET_PROCESS_STD_EXCEPTION exception occurred during packet processing: %1
|
||||
This error message indicates that a standard exception was raised
|
||||
during packet processing that was not caught by other, more specific
|
||||
exception handlers. This packet will be dropped and the server will
|
||||
continue operation.
|
||||
|
||||
% DHCP4_PACKET_RECEIVED %1: %2 (type %3) received from %4 to %5 on interface %6
|
||||
A debug message noting that the server has received the specified type of
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC")
|
||||
// Copyright (C) 2011-2016 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
@ -418,390 +418,403 @@ Dhcpv4Srv::sendPacket(const Pkt4Ptr& packet) {
|
||||
bool
|
||||
Dhcpv4Srv::run() {
|
||||
while (!shutdown_) {
|
||||
// client's message and server's response
|
||||
Pkt4Ptr query;
|
||||
Pkt4Ptr rsp;
|
||||
|
||||
try {
|
||||
|
||||
try {
|
||||
uint32_t timeout = 1000;
|
||||
LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL, DHCP4_BUFFER_WAIT).arg(timeout);
|
||||
query = receivePacket(timeout);
|
||||
|
||||
// Log if packet has arrived. We can't log the detailed information
|
||||
// about the DHCP message because it hasn't been unpacked/parsed
|
||||
// yet, and it can't be parsed at this point because hooks will
|
||||
// have to process it first. The only information available at this
|
||||
// point are: the interface, source address and destination addresses
|
||||
// and ports.
|
||||
if (query) {
|
||||
LOG_DEBUG(packet4_logger, DBG_DHCP4_BASIC, DHCP4_BUFFER_RECEIVED)
|
||||
.arg(query->getRemoteAddr().toText())
|
||||
.arg(query->getRemotePort())
|
||||
.arg(query->getLocalAddr().toText())
|
||||
.arg(query->getLocalPort())
|
||||
.arg(query->getIface());
|
||||
|
||||
} else {
|
||||
LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL, DHCP4_BUFFER_WAIT_INTERRUPTED)
|
||||
.arg(timeout);
|
||||
}
|
||||
|
||||
} catch (const SignalInterruptOnSelect) {
|
||||
// Packet reception interrupted because a signal has been received.
|
||||
// This is not an error because we might have received a SIGTERM,
|
||||
// SIGINT, SIGHUP or SIGCHILD which are handled by the server. For
|
||||
// signals that are not handled by the server we rely on the default
|
||||
// behavior of the system.
|
||||
LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL, DHCP4_BUFFER_WAIT_SIGNAL)
|
||||
.arg(signal_set_->getNext());
|
||||
} catch (const std::exception& e) {
|
||||
// Log all other errors.
|
||||
LOG_ERROR(packet4_logger, DHCP4_BUFFER_RECEIVE_FAIL).arg(e.what());
|
||||
}
|
||||
|
||||
// Handle next signal received by the process. It must be called after
|
||||
// an attempt to receive a packet to properly handle server shut down.
|
||||
// The SIGTERM or SIGINT will be received prior to, or during execution
|
||||
// of select() (select is invoked by receivePacket()). When that
|
||||
// happens, select will be interrupted. The signal handler will be
|
||||
// invoked immediately after select(). The handler will set the
|
||||
// shutdown flag and cause the process to terminate before the next
|
||||
// select() function is called. If the function was called before
|
||||
// receivePacket the process could wait up to the duration of timeout
|
||||
// of select() to terminate.
|
||||
try {
|
||||
handleSignal();
|
||||
} catch (const std::exception& e) {
|
||||
// Standard exception occurred. Let's be on the safe side to
|
||||
// catch std::exception.
|
||||
LOG_ERROR(dhcp4_logger, DHCP4_HANDLE_SIGNAL_EXCEPTION)
|
||||
.arg(e.what());
|
||||
}
|
||||
|
||||
// Timeout may be reached or signal received, which breaks select()
|
||||
// with no reception occurred. No need to log anything here because
|
||||
// we have logged right after the call to receivePacket().
|
||||
if (!query) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Log reception of the packet. We need to increase it early, as any
|
||||
// failures in unpacking will cause the packet to be dropped. We
|
||||
// will increase type specific packets further down the road.
|
||||
// See processStatsReceived().
|
||||
isc::stats::StatsMgr::instance().addValue("pkt4-received",
|
||||
static_cast<int64_t>(1));
|
||||
|
||||
// In order to parse the DHCP options, the server needs to use some
|
||||
// configuration information such as: existing option spaces, option
|
||||
// definitions etc. This is the kind of information which is not
|
||||
// available in the libdhcp, so we need to supply our own implementation
|
||||
// of the option parsing function here, which would rely on the
|
||||
// configuration data.
|
||||
query->setCallback(boost::bind(&Dhcpv4Srv::unpackOptions, this,
|
||||
_1, _2, _3));
|
||||
|
||||
bool skip_unpack = false;
|
||||
|
||||
// The packet has just been received so contains the uninterpreted wire
|
||||
// data; execute callouts registered for buffer4_receive.
|
||||
if (HooksManager::calloutsPresent(Hooks.hook_index_buffer4_receive_)) {
|
||||
CalloutHandlePtr callout_handle = getCalloutHandle(query);
|
||||
|
||||
// Delete previously set arguments
|
||||
callout_handle->deleteAllArguments();
|
||||
|
||||
// Pass incoming packet as argument
|
||||
callout_handle->setArgument("query4", query);
|
||||
|
||||
// Call callouts
|
||||
HooksManager::callCallouts(Hooks.hook_index_buffer4_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->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
|
||||
LOG_DEBUG(hooks_logger, DBG_DHCP4_DETAIL, DHCP4_HOOK_BUFFER_RCVD_SKIP)
|
||||
.arg(query->getRemoteAddr().toText())
|
||||
.arg(query->getLocalAddr().toText())
|
||||
.arg(query->getIface());
|
||||
skip_unpack = true;
|
||||
}
|
||||
|
||||
callout_handle->getArgument("query4", query);
|
||||
|
||||
/// @todo: add support for DROP status
|
||||
}
|
||||
|
||||
// Unpack the packet information unless the buffer4_receive callouts
|
||||
// indicated they did it
|
||||
if (!skip_unpack) {
|
||||
try {
|
||||
LOG_DEBUG(options4_logger, DBG_DHCP4_DETAIL, DHCP4_BUFFER_UNPACK)
|
||||
.arg(query->getRemoteAddr().toText())
|
||||
.arg(query->getLocalAddr().toText())
|
||||
.arg(query->getIface());
|
||||
query->unpack();
|
||||
} catch (const std::exception& e) {
|
||||
// Failed to parse the packet.
|
||||
LOG_DEBUG(bad_packet4_logger, DBG_DHCP4_DETAIL,
|
||||
DHCP4_PACKET_DROP_0001)
|
||||
.arg(query->getRemoteAddr().toText())
|
||||
.arg(query->getLocalAddr().toText())
|
||||
.arg(query->getIface())
|
||||
.arg(e.what());
|
||||
|
||||
// Increase the statistics of parse failues and dropped packets.
|
||||
isc::stats::StatsMgr::instance().addValue("pkt4-parse-failed",
|
||||
static_cast<int64_t>(1));
|
||||
isc::stats::StatsMgr::instance().addValue("pkt4-receive-drop",
|
||||
static_cast<int64_t>(1));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Update statistics accordingly for received packet.
|
||||
processStatsReceived(query);
|
||||
|
||||
// Assign this packet to one or more classes if needed. We need to do
|
||||
// this before calling accept(), because getSubnet4() may need client
|
||||
// class information.
|
||||
classifyPacket(query);
|
||||
|
||||
// Check whether the message should be further processed or discarded.
|
||||
// There is no need to log anything here. This function logs by itself.
|
||||
if (!accept(query)) {
|
||||
// Increase the statistic of dropped packets.
|
||||
isc::stats::StatsMgr::instance().addValue("pkt4-receive-drop",
|
||||
static_cast<int64_t>(1));
|
||||
continue;
|
||||
}
|
||||
|
||||
// We have sanity checked (in accept() that the Message Type option
|
||||
// exists, so we can safely get it here.
|
||||
int type = query->getType();
|
||||
LOG_DEBUG(packet4_logger, DBG_DHCP4_BASIC_DATA, DHCP4_PACKET_RECEIVED)
|
||||
.arg(query->getLabel())
|
||||
.arg(query->getName())
|
||||
.arg(type)
|
||||
.arg(query->getRemoteAddr())
|
||||
.arg(query->getLocalAddr())
|
||||
.arg(query->getIface());
|
||||
LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL_DATA, DHCP4_QUERY_DATA)
|
||||
.arg(query->getLabel())
|
||||
.arg(query->toText());
|
||||
|
||||
// Let's execute all callouts registered for pkt4_receive
|
||||
if (HooksManager::calloutsPresent(hook_index_pkt4_receive_)) {
|
||||
CalloutHandlePtr callout_handle = getCalloutHandle(query);
|
||||
|
||||
// Delete previously set arguments
|
||||
callout_handle->deleteAllArguments();
|
||||
|
||||
// Pass incoming packet as argument
|
||||
callout_handle->setArgument("query4", query);
|
||||
|
||||
// Call callouts
|
||||
HooksManager::callCallouts(hook_index_pkt4_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->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
|
||||
LOG_DEBUG(hooks_logger, DBG_DHCP4_HOOKS, DHCP4_HOOK_PACKET_RCVD_SKIP)
|
||||
.arg(query->getLabel());
|
||||
continue;
|
||||
}
|
||||
|
||||
/// @todo: Add support for DROP status
|
||||
|
||||
callout_handle->getArgument("query4", query);
|
||||
}
|
||||
|
||||
try {
|
||||
switch (query->getType()) {
|
||||
case DHCPDISCOVER:
|
||||
rsp = processDiscover(query);
|
||||
break;
|
||||
|
||||
case DHCPREQUEST:
|
||||
// Note that REQUEST is used for many things in DHCPv4: for
|
||||
// requesting new leases, renewing existing ones and even
|
||||
// for rebinding.
|
||||
rsp = processRequest(query);
|
||||
break;
|
||||
|
||||
case DHCPRELEASE:
|
||||
processRelease(query);
|
||||
break;
|
||||
|
||||
case DHCPDECLINE:
|
||||
processDecline(query);
|
||||
break;
|
||||
|
||||
case DHCPINFORM:
|
||||
rsp = processInform(query);
|
||||
break;
|
||||
|
||||
default:
|
||||
// Only action is to output a message if debug is enabled,
|
||||
// and that is covered by the debug statement before the
|
||||
// "switch" statement.
|
||||
;
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
|
||||
// Catch-all exception (we used to call only isc::Exception, but
|
||||
// std::exception could potentially be raised and if we don't catch
|
||||
// it here, it would be caught in main() and the process would
|
||||
// terminate). 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(bad_packet4_logger, DBG_DHCP4_BASIC,
|
||||
DHCP4_PACKET_DROP_0007)
|
||||
.arg(query->getLabel())
|
||||
.arg(e.what());
|
||||
|
||||
// Increase the statistic of dropped packets.
|
||||
isc::stats::StatsMgr::instance().addValue("pkt4-receive-drop",
|
||||
static_cast<int64_t>(1));
|
||||
}
|
||||
|
||||
if (!rsp) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Specifies if server should do the packing
|
||||
bool skip_pack = false;
|
||||
|
||||
// Execute all callouts registered for pkt4_send
|
||||
if (HooksManager::calloutsPresent(hook_index_pkt4_send_)) {
|
||||
CalloutHandlePtr callout_handle = getCalloutHandle(query);
|
||||
|
||||
// Delete all previous arguments
|
||||
callout_handle->deleteAllArguments();
|
||||
|
||||
// Clear skip flag if it was set in previous callouts
|
||||
callout_handle->setStatus(CalloutHandle::NEXT_STEP_CONTINUE);
|
||||
|
||||
// Set our response
|
||||
callout_handle->setArgument("response4", rsp);
|
||||
|
||||
// Also pass the corresponding query packet as argument
|
||||
callout_handle->setArgument("query4", query);
|
||||
|
||||
// Call all installed callouts
|
||||
HooksManager::callCallouts(hook_index_pkt4_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".
|
||||
if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
|
||||
LOG_DEBUG(hooks_logger, DBG_DHCP4_HOOKS, DHCP4_HOOK_PACKET_SEND_SKIP)
|
||||
.arg(query->getLabel());
|
||||
skip_pack = true;
|
||||
}
|
||||
|
||||
/// @todo: Add support for DROP status
|
||||
}
|
||||
|
||||
if (!skip_pack) {
|
||||
try {
|
||||
LOG_DEBUG(options4_logger, DBG_DHCP4_DETAIL, DHCP4_PACKET_PACK)
|
||||
.arg(rsp->getLabel());
|
||||
rsp->pack();
|
||||
} catch (const std::exception& e) {
|
||||
LOG_ERROR(options4_logger, DHCP4_PACKET_PACK_FAIL)
|
||||
.arg(rsp->getLabel())
|
||||
.arg(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// 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 buffer4_send
|
||||
if (HooksManager::calloutsPresent(Hooks.hook_index_buffer4_send_)) {
|
||||
CalloutHandlePtr callout_handle = getCalloutHandle(query);
|
||||
|
||||
// Delete previously set arguments
|
||||
callout_handle->deleteAllArguments();
|
||||
|
||||
// Pass incoming packet as argument
|
||||
callout_handle->setArgument("response4", rsp);
|
||||
|
||||
// Call callouts
|
||||
HooksManager::callCallouts(Hooks.hook_index_buffer4_send_,
|
||||
*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 drop.
|
||||
if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
|
||||
LOG_DEBUG(hooks_logger, DBG_DHCP4_HOOKS,
|
||||
DHCP4_HOOK_BUFFER_SEND_SKIP)
|
||||
.arg(rsp->getLabel());
|
||||
continue;
|
||||
}
|
||||
|
||||
/// @todo: Add support for DROP status.
|
||||
|
||||
callout_handle->getArgument("response4", rsp);
|
||||
}
|
||||
|
||||
LOG_DEBUG(packet4_logger, DBG_DHCP4_BASIC, DHCP4_PACKET_SEND)
|
||||
.arg(rsp->getLabel())
|
||||
.arg(rsp->getName())
|
||||
.arg(static_cast<int>(rsp->getType()))
|
||||
.arg(rsp->getLocalAddr())
|
||||
.arg(rsp->getLocalPort())
|
||||
.arg(rsp->getRemoteAddr())
|
||||
.arg(rsp->getRemotePort())
|
||||
.arg(rsp->getIface());
|
||||
|
||||
LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL_DATA,
|
||||
DHCP4_RESPONSE_DATA)
|
||||
.arg(rsp->getLabel())
|
||||
.arg(rsp->getName())
|
||||
.arg(static_cast<int>(rsp->getType()))
|
||||
.arg(rsp->toText());
|
||||
sendPacket(rsp);
|
||||
|
||||
// Update statistics accordingly for sent packet.
|
||||
processStatsSent(rsp);
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
LOG_ERROR(packet4_logger, DHCP4_PACKET_SEND_FAIL)
|
||||
.arg(rsp->getLabel())
|
||||
.arg(e.what());
|
||||
}
|
||||
|
||||
run_one();
|
||||
} catch (const std::exception& e) {
|
||||
// General catch-all exception that are not caught by more specific
|
||||
// catches. This one is for exceptions derived from std::exception.
|
||||
LOG_ERROR(packet4_logger, DHCP4_PACKET_PROCESS_EXCEPTION)
|
||||
LOG_ERROR(packet4_logger, DHCP4_PACKET_PROCESS_STD_EXCEPTION)
|
||||
.arg(e.what());
|
||||
} catch (...) {
|
||||
// General catch-all exception that are not caught by more specific
|
||||
// catches. This one is for other exceptions, not derived from
|
||||
// std::exception.
|
||||
LOG_ERROR(packet4_logger, DHCP4_PACKET_PROCESS_EXCEPTION)
|
||||
.arg("an unknown exception not derived from std::exception");
|
||||
LOG_ERROR(packet4_logger, DHCP4_PACKET_PROCESS_EXCEPTION);
|
||||
}
|
||||
}
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
void
|
||||
Dhcpv4Srv::run_one() {
|
||||
// client's message and server's response
|
||||
Pkt4Ptr query;
|
||||
Pkt4Ptr rsp;
|
||||
|
||||
try {
|
||||
uint32_t timeout = 1000;
|
||||
LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL, DHCP4_BUFFER_WAIT).arg(timeout);
|
||||
query = receivePacket(timeout);
|
||||
|
||||
// Log if packet has arrived. We can't log the detailed information
|
||||
// about the DHCP message because it hasn't been unpacked/parsed
|
||||
// yet, and it can't be parsed at this point because hooks will
|
||||
// have to process it first. The only information available at this
|
||||
// point are: the interface, source address and destination addresses
|
||||
// and ports.
|
||||
if (query) {
|
||||
LOG_DEBUG(packet4_logger, DBG_DHCP4_BASIC, DHCP4_BUFFER_RECEIVED)
|
||||
.arg(query->getRemoteAddr().toText())
|
||||
.arg(query->getRemotePort())
|
||||
.arg(query->getLocalAddr().toText())
|
||||
.arg(query->getLocalPort())
|
||||
.arg(query->getIface());
|
||||
|
||||
} else {
|
||||
LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL, DHCP4_BUFFER_WAIT_INTERRUPTED)
|
||||
.arg(timeout);
|
||||
}
|
||||
|
||||
} catch (const SignalInterruptOnSelect) {
|
||||
// Packet reception interrupted because a signal has been received.
|
||||
// This is not an error because we might have received a SIGTERM,
|
||||
// SIGINT, SIGHUP or SIGCHILD which are handled by the server. For
|
||||
// signals that are not handled by the server we rely on the default
|
||||
// behavior of the system.
|
||||
LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL, DHCP4_BUFFER_WAIT_SIGNAL)
|
||||
.arg(signal_set_->getNext());
|
||||
} catch (const std::exception& e) {
|
||||
// Log all other errors.
|
||||
LOG_ERROR(packet4_logger, DHCP4_BUFFER_RECEIVE_FAIL).arg(e.what());
|
||||
}
|
||||
|
||||
// Handle next signal received by the process. It must be called after
|
||||
// an attempt to receive a packet to properly handle server shut down.
|
||||
// The SIGTERM or SIGINT will be received prior to, or during execution
|
||||
// of select() (select is invoked by receivePacket()). When that
|
||||
// happens, select will be interrupted. The signal handler will be
|
||||
// invoked immediately after select(). The handler will set the
|
||||
// shutdown flag and cause the process to terminate before the next
|
||||
// select() function is called. If the function was called before
|
||||
// receivePacket the process could wait up to the duration of timeout
|
||||
// of select() to terminate.
|
||||
try {
|
||||
handleSignal();
|
||||
} catch (const std::exception& e) {
|
||||
// Standard exception occurred. Let's be on the safe side to
|
||||
// catch std::exception.
|
||||
LOG_ERROR(dhcp4_logger, DHCP4_HANDLE_SIGNAL_EXCEPTION)
|
||||
.arg(e.what());
|
||||
}
|
||||
|
||||
// Timeout may be reached or signal received, which breaks select()
|
||||
// with no reception occurred. No need to log anything here because
|
||||
// we have logged right after the call to receivePacket().
|
||||
if (!query) {
|
||||
return;
|
||||
}
|
||||
|
||||
processPacket(query, rsp);
|
||||
|
||||
if (!rsp) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 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 buffer4_send
|
||||
if (HooksManager::calloutsPresent(Hooks.hook_index_buffer4_send_)) {
|
||||
CalloutHandlePtr callout_handle = getCalloutHandle(query);
|
||||
|
||||
// Delete previously set arguments
|
||||
callout_handle->deleteAllArguments();
|
||||
|
||||
// Pass incoming packet as argument
|
||||
callout_handle->setArgument("response4", rsp);
|
||||
|
||||
// Call callouts
|
||||
HooksManager::callCallouts(Hooks.hook_index_buffer4_send_,
|
||||
*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 drop.
|
||||
if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
|
||||
LOG_DEBUG(hooks_logger, DBG_DHCP4_HOOKS,
|
||||
DHCP4_HOOK_BUFFER_SEND_SKIP)
|
||||
.arg(rsp->getLabel());
|
||||
return;
|
||||
}
|
||||
|
||||
/// @todo: Add support for DROP status.
|
||||
|
||||
callout_handle->getArgument("response4", rsp);
|
||||
}
|
||||
|
||||
LOG_DEBUG(packet4_logger, DBG_DHCP4_BASIC, DHCP4_PACKET_SEND)
|
||||
.arg(rsp->getLabel())
|
||||
.arg(rsp->getName())
|
||||
.arg(static_cast<int>(rsp->getType()))
|
||||
.arg(rsp->getLocalAddr())
|
||||
.arg(rsp->getLocalPort())
|
||||
.arg(rsp->getRemoteAddr())
|
||||
.arg(rsp->getRemotePort())
|
||||
.arg(rsp->getIface());
|
||||
|
||||
LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL_DATA,
|
||||
DHCP4_RESPONSE_DATA)
|
||||
.arg(rsp->getLabel())
|
||||
.arg(rsp->getName())
|
||||
.arg(static_cast<int>(rsp->getType()))
|
||||
.arg(rsp->toText());
|
||||
sendPacket(rsp);
|
||||
|
||||
// Update statistics accordingly for sent packet.
|
||||
processStatsSent(rsp);
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
LOG_ERROR(packet4_logger, DHCP4_PACKET_SEND_FAIL)
|
||||
.arg(rsp->getLabel())
|
||||
.arg(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Dhcpv4Srv::processPacket(Pkt4Ptr& query, Pkt4Ptr& rsp) {
|
||||
// Log reception of the packet. We need to increase it early, as any
|
||||
// failures in unpacking will cause the packet to be dropped. We
|
||||
// will increase type specific statistic further down the road.
|
||||
// See processStatsReceived().
|
||||
isc::stats::StatsMgr::instance().addValue("pkt4-received",
|
||||
static_cast<int64_t>(1));
|
||||
|
||||
// In order to parse the DHCP options, the server needs to use some
|
||||
// configuration information such as: existing option spaces, option
|
||||
// definitions etc. This is the kind of information which is not
|
||||
// available in the libdhcp, so we need to supply our own implementation
|
||||
// of the option parsing function here, which would rely on the
|
||||
// configuration data.
|
||||
query->setCallback(boost::bind(&Dhcpv4Srv::unpackOptions, this,
|
||||
_1, _2, _3));
|
||||
|
||||
bool skip_unpack = false;
|
||||
|
||||
// The packet has just been received so contains the uninterpreted wire
|
||||
// data; execute callouts registered for buffer4_receive.
|
||||
if (HooksManager::calloutsPresent(Hooks.hook_index_buffer4_receive_)) {
|
||||
CalloutHandlePtr callout_handle = getCalloutHandle(query);
|
||||
|
||||
// Delete previously set arguments
|
||||
callout_handle->deleteAllArguments();
|
||||
|
||||
// Pass incoming packet as argument
|
||||
callout_handle->setArgument("query4", query);
|
||||
|
||||
// Call callouts
|
||||
HooksManager::callCallouts(Hooks.hook_index_buffer4_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->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
|
||||
LOG_DEBUG(hooks_logger, DBG_DHCP4_DETAIL,
|
||||
DHCP4_HOOK_BUFFER_RCVD_SKIP)
|
||||
.arg(query->getRemoteAddr().toText())
|
||||
.arg(query->getLocalAddr().toText())
|
||||
.arg(query->getIface());
|
||||
skip_unpack = true;
|
||||
}
|
||||
|
||||
callout_handle->getArgument("query4", query);
|
||||
|
||||
/// @todo: add support for DROP status
|
||||
}
|
||||
|
||||
// Unpack the packet information unless the buffer4_receive callouts
|
||||
// indicated they did it
|
||||
if (!skip_unpack) {
|
||||
try {
|
||||
LOG_DEBUG(options4_logger, DBG_DHCP4_DETAIL, DHCP4_BUFFER_UNPACK)
|
||||
.arg(query->getRemoteAddr().toText())
|
||||
.arg(query->getLocalAddr().toText())
|
||||
.arg(query->getIface());
|
||||
query->unpack();
|
||||
} catch (const std::exception& e) {
|
||||
// Failed to parse the packet.
|
||||
LOG_DEBUG(bad_packet4_logger, DBG_DHCP4_DETAIL,
|
||||
DHCP4_PACKET_DROP_0001)
|
||||
.arg(query->getRemoteAddr().toText())
|
||||
.arg(query->getLocalAddr().toText())
|
||||
.arg(query->getIface())
|
||||
.arg(e.what());
|
||||
|
||||
// Increase the statistics of parse failues and dropped packets.
|
||||
isc::stats::StatsMgr::instance().addValue("pkt4-parse-failed",
|
||||
static_cast<int64_t>(1));
|
||||
isc::stats::StatsMgr::instance().addValue("pkt4-receive-drop",
|
||||
static_cast<int64_t>(1));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Update statistics accordingly for received packet.
|
||||
processStatsReceived(query);
|
||||
|
||||
// Assign this packet to one or more classes if needed. We need to do
|
||||
// this before calling accept(), because getSubnet4() may need client
|
||||
// class information.
|
||||
classifyPacket(query);
|
||||
|
||||
// Check whether the message should be further processed or discarded.
|
||||
// There is no need to log anything here. This function logs by itself.
|
||||
if (!accept(query)) {
|
||||
// Increase the statistic of dropped packets.
|
||||
isc::stats::StatsMgr::instance().addValue("pkt4-receive-drop",
|
||||
static_cast<int64_t>(1));
|
||||
return;
|
||||
}
|
||||
|
||||
// We have sanity checked (in accept() that the Message Type option
|
||||
// exists, so we can safely get it here.
|
||||
int type = query->getType();
|
||||
LOG_DEBUG(packet4_logger, DBG_DHCP4_BASIC_DATA, DHCP4_PACKET_RECEIVED)
|
||||
.arg(query->getLabel())
|
||||
.arg(query->getName())
|
||||
.arg(type)
|
||||
.arg(query->getRemoteAddr())
|
||||
.arg(query->getLocalAddr())
|
||||
.arg(query->getIface());
|
||||
LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL_DATA, DHCP4_QUERY_DATA)
|
||||
.arg(query->getLabel())
|
||||
.arg(query->toText());
|
||||
|
||||
// Let's execute all callouts registered for pkt4_receive
|
||||
if (HooksManager::calloutsPresent(hook_index_pkt4_receive_)) {
|
||||
CalloutHandlePtr callout_handle = getCalloutHandle(query);
|
||||
|
||||
// Delete previously set arguments
|
||||
callout_handle->deleteAllArguments();
|
||||
|
||||
// Pass incoming packet as argument
|
||||
callout_handle->setArgument("query4", query);
|
||||
|
||||
// Call callouts
|
||||
HooksManager::callCallouts(hook_index_pkt4_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->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
|
||||
LOG_DEBUG(hooks_logger, DBG_DHCP4_HOOKS,
|
||||
DHCP4_HOOK_PACKET_RCVD_SKIP)
|
||||
.arg(query->getLabel());
|
||||
return;
|
||||
}
|
||||
|
||||
/// @todo: Add support for DROP status
|
||||
|
||||
callout_handle->getArgument("query4", query);
|
||||
}
|
||||
|
||||
try {
|
||||
switch (query->getType()) {
|
||||
case DHCPDISCOVER:
|
||||
rsp = processDiscover(query);
|
||||
break;
|
||||
|
||||
case DHCPREQUEST:
|
||||
// Note that REQUEST is used for many things in DHCPv4: for
|
||||
// requesting new leases, renewing existing ones and even
|
||||
// for rebinding.
|
||||
rsp = processRequest(query);
|
||||
break;
|
||||
|
||||
case DHCPRELEASE:
|
||||
processRelease(query);
|
||||
break;
|
||||
|
||||
case DHCPDECLINE:
|
||||
processDecline(query);
|
||||
break;
|
||||
|
||||
case DHCPINFORM:
|
||||
rsp = processInform(query);
|
||||
break;
|
||||
|
||||
default:
|
||||
// Only action is to output a message if debug is enabled,
|
||||
// and that is covered by the debug statement before the
|
||||
// "switch" statement.
|
||||
;
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
|
||||
// Catch-all exception (we used to call only isc::Exception, but
|
||||
// std::exception could potentially be raised and if we don't catch
|
||||
// it here, it would be caught in main() and the process would
|
||||
// terminate). 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(bad_packet4_logger, DBG_DHCP4_BASIC,
|
||||
DHCP4_PACKET_DROP_0007)
|
||||
.arg(query->getLabel())
|
||||
.arg(e.what());
|
||||
|
||||
// Increase the statistic of dropped packets.
|
||||
isc::stats::StatsMgr::instance().addValue("pkt4-receive-drop",
|
||||
static_cast<int64_t>(1));
|
||||
}
|
||||
|
||||
if (!rsp) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Specifies if server should do the packing
|
||||
bool skip_pack = false;
|
||||
|
||||
// Execute all callouts registered for pkt4_send
|
||||
if (HooksManager::calloutsPresent(hook_index_pkt4_send_)) {
|
||||
CalloutHandlePtr callout_handle = getCalloutHandle(query);
|
||||
|
||||
// Delete all previous arguments
|
||||
callout_handle->deleteAllArguments();
|
||||
|
||||
// Clear skip flag if it was set in previous callouts
|
||||
callout_handle->setStatus(CalloutHandle::NEXT_STEP_CONTINUE);
|
||||
|
||||
// Set our response
|
||||
callout_handle->setArgument("response4", rsp);
|
||||
|
||||
// Also pass the corresponding query packet as argument
|
||||
callout_handle->setArgument("query4", query);
|
||||
|
||||
// Call all installed callouts
|
||||
HooksManager::callCallouts(hook_index_pkt4_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".
|
||||
if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
|
||||
LOG_DEBUG(hooks_logger, DBG_DHCP4_HOOKS,
|
||||
DHCP4_HOOK_PACKET_SEND_SKIP)
|
||||
.arg(query->getLabel());
|
||||
skip_pack = true;
|
||||
}
|
||||
|
||||
/// @todo: Add support for DROP status
|
||||
}
|
||||
|
||||
if (!skip_pack) {
|
||||
try {
|
||||
LOG_DEBUG(options4_logger, DBG_DHCP4_DETAIL, DHCP4_PACKET_PACK)
|
||||
.arg(rsp->getLabel());
|
||||
rsp->pack();
|
||||
} catch (const std::exception& e) {
|
||||
LOG_ERROR(options4_logger, DHCP4_PACKET_PACK_FAIL)
|
||||
.arg(rsp->getLabel())
|
||||
.arg(e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string
|
||||
Dhcpv4Srv::srvidToString(const OptionPtr& srvid) {
|
||||
if (!srvid) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC")
|
||||
// Copyright (C) 2011-2016 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
@ -208,14 +208,28 @@ public:
|
||||
|
||||
/// @brief Main server processing loop.
|
||||
///
|
||||
/// Main server processing loop. Receives incoming packets, verifies
|
||||
/// their correctness, generates appropriate answer (if needed) and
|
||||
/// transmits responses.
|
||||
/// Main server processing loop. Call the processing step routine
|
||||
/// until shut down.
|
||||
///
|
||||
/// @return true, if being shut down gracefully, fail if experienced
|
||||
/// critical error.
|
||||
/// @return true, if being shut down gracefully, never fail.
|
||||
bool run();
|
||||
|
||||
/// @brief Main server processing step.
|
||||
///
|
||||
/// Main server processing step. Receives one incoming packet, calls
|
||||
/// the processing packet routing and (if necessary) transmits
|
||||
/// a response.
|
||||
void run_one();
|
||||
|
||||
/// @brief Process a single incoming DHCPv4 packet.
|
||||
///
|
||||
/// It verifies correctness of the passed packet, call per-type processXXX
|
||||
/// methods, generates appropriate answer.
|
||||
///
|
||||
/// @param query A pointer to the packet to be processed.
|
||||
/// @param rsp A pointer to the response
|
||||
void processPacket(Pkt4Ptr& query, Pkt4Ptr& rsp);
|
||||
|
||||
/// @brief Instructs the server to shut down.
|
||||
void shutdown();
|
||||
|
||||
|
@ -425,16 +425,23 @@ because packets of this type must be sent to multicast. The first argument
|
||||
specifies the client and transaction identification information, the
|
||||
second argument specifies packet type.
|
||||
|
||||
% DHCP6_PACKET_PROCESS_EXCEPTION exception occurred during packet processing: %1
|
||||
This error message indicates that an exception was raised during packet processing
|
||||
that was not caught by other, more specific exception handlers. This packet will
|
||||
be dropped and the server will continue operation.
|
||||
% DHCP6_PACKET_PROCESS_EXCEPTION exception occurred during packet processing
|
||||
This error message indicates that a non-standard exception was raised
|
||||
during packet processing that was not caught by other, more specific
|
||||
exception handlers. This packet will be dropped and the server will
|
||||
continue operation.
|
||||
|
||||
% DHCP6_PACKET_PROCESS_FAIL processing of %1 message received from %2 failed: %3
|
||||
This is a general catch-all message indicating that the processing of the
|
||||
specified packet type from the indicated address failed. The reason is given in the
|
||||
message. The server will not send a response but will instead ignore the packet.
|
||||
|
||||
% DHCP6_PACKET_PROCESS_STD_EXCEPTION exception occurred during packet processing: %1
|
||||
This error message indicates that a standard exception was raised
|
||||
during packet processing that was not caught by other, more specific
|
||||
exception handlers. This packet will be dropped and the server will
|
||||
continue operation.
|
||||
|
||||
% DHCP6_PACKET_RECEIVED %1: %2 (type %3) received from %4 to %5 on interface %6
|
||||
A debug message noting that the server has received the specified type of
|
||||
packet on the specified interface. The first argument specifies the
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC")
|
||||
// Copyright (C) 2011-2016 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
@ -288,422 +288,430 @@ Dhcpv6Srv::createContext(const Pkt6Ptr& pkt) {
|
||||
|
||||
bool Dhcpv6Srv::run() {
|
||||
while (!shutdown_) {
|
||||
// client's message and server's response
|
||||
Pkt6Ptr query;
|
||||
Pkt6Ptr rsp;
|
||||
|
||||
try {
|
||||
|
||||
try {
|
||||
uint32_t timeout = 1000;
|
||||
LOG_DEBUG(packet6_logger, DBG_DHCP6_DETAIL, DHCP6_BUFFER_WAIT).arg(timeout);
|
||||
query = receivePacket(timeout);
|
||||
|
||||
// Log if packet has arrived. We can't log the detailed information
|
||||
// about the DHCP message because it hasn't been unpacked/parsed
|
||||
// yet, and it can't be parsed at this point because hooks will
|
||||
// have to process it first. The only information available at this
|
||||
// point are: the interface, source address and destination addresses
|
||||
// and ports.
|
||||
if (query) {
|
||||
LOG_DEBUG(packet6_logger, DBG_DHCP6_BASIC, DHCP6_BUFFER_RECEIVED)
|
||||
.arg(query->getRemoteAddr().toText())
|
||||
.arg(query->getRemotePort())
|
||||
.arg(query->getLocalAddr().toText())
|
||||
.arg(query->getLocalPort())
|
||||
.arg(query->getIface());
|
||||
|
||||
// Log reception of the packet. We need to increase it early, as
|
||||
// any failures in unpacking will cause the packet to be dropped.
|
||||
// we will increase type specific packets further down the road.
|
||||
// See processStatsReceived().
|
||||
StatsMgr::instance().addValue("pkt6-received", static_cast<int64_t>(1));
|
||||
|
||||
} else {
|
||||
LOG_DEBUG(packet6_logger, DBG_DHCP6_DETAIL, DHCP6_BUFFER_WAIT_INTERRUPTED)
|
||||
.arg(timeout);
|
||||
}
|
||||
|
||||
} catch (const SignalInterruptOnSelect) {
|
||||
// Packet reception interrupted because a signal has been received.
|
||||
// This is not an error because we might have received a SIGTERM,
|
||||
// SIGINT or SIGHUP which are handled by the server. For signals
|
||||
// that are not handled by the server we rely on the default
|
||||
// behavior of the system.
|
||||
LOG_DEBUG(packet6_logger, DBG_DHCP6_DETAIL, DHCP6_BUFFER_WAIT_SIGNAL)
|
||||
.arg(signal_set_->getNext());
|
||||
} catch (const std::exception& e) {
|
||||
LOG_ERROR(packet6_logger, DHCP6_PACKET_RECEIVE_FAIL).arg(e.what());
|
||||
}
|
||||
|
||||
// Handle next signal received by the process. It must be called after
|
||||
// an attempt to receive a packet to properly handle server shut down.
|
||||
// The SIGTERM or SIGINT will be received prior to, or during execution
|
||||
// of select() (select is invoked by receivePacket()). When that happens,
|
||||
// select will be interrupted. The signal handler will be invoked
|
||||
// immediately after select(). The handler will set the shutdown flag
|
||||
// and cause the process to terminate before the next select() function
|
||||
// is called. If the function was called before receivePacket the
|
||||
// process could wait up to the duration of timeout of select() to
|
||||
// terminate.
|
||||
try {
|
||||
handleSignal();
|
||||
} catch (const std::exception& e) {
|
||||
// An (a standard or ISC) exception occurred.
|
||||
LOG_ERROR(dhcp6_logger, DHCP6_HANDLE_SIGNAL_EXCEPTION)
|
||||
.arg(e.what());
|
||||
}
|
||||
|
||||
// Timeout may be reached or signal received, which breaks select()
|
||||
// with no packet received
|
||||
if (!query) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// In order to parse the DHCP options, the server needs to use some
|
||||
// configuration information such as: existing option spaces, option
|
||||
// definitions etc. This is the kind of information which is not
|
||||
// available in the libdhcp, so we need to supply our own implementation
|
||||
// of the option parsing function here, which would rely on the
|
||||
// configuration data.
|
||||
query->setCallback(boost::bind(&Dhcpv6Srv::unpackOptions, this, _1, _2,
|
||||
_3, _4, _5));
|
||||
|
||||
bool skip_unpack = false;
|
||||
|
||||
// The packet has just been received so contains the uninterpreted wire
|
||||
// data; execute callouts registered for buffer6_receive.
|
||||
if (HooksManager::calloutsPresent(Hooks.hook_index_buffer6_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_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->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
|
||||
LOG_DEBUG(hooks_logger, DBG_DHCP6_DETAIL, DHCP6_HOOK_BUFFER_RCVD_SKIP)
|
||||
.arg(query->getRemoteAddr().toText())
|
||||
.arg(query->getLocalAddr().toText())
|
||||
.arg(query->getIface());
|
||||
skip_unpack = true;
|
||||
}
|
||||
|
||||
/// @todo: Add support for DROP status.
|
||||
|
||||
callout_handle->getArgument("query6", query);
|
||||
}
|
||||
|
||||
// Unpack the packet information unless the buffer6_receive callouts
|
||||
// indicated they did it
|
||||
if (!skip_unpack) {
|
||||
try {
|
||||
LOG_DEBUG(options6_logger, DBG_DHCP6_DETAIL, DHCP6_BUFFER_UNPACK)
|
||||
.arg(query->getRemoteAddr().toText())
|
||||
.arg(query->getLocalAddr().toText())
|
||||
.arg(query->getIface());
|
||||
query->unpack();
|
||||
} catch (const std::exception &e) {
|
||||
// Failed to parse the packet.
|
||||
LOG_DEBUG(bad_packet6_logger, DBG_DHCP6_DETAIL,
|
||||
DHCP6_PACKET_DROP_PARSE_FAIL)
|
||||
.arg(query->getRemoteAddr().toText())
|
||||
.arg(query->getLocalAddr().toText())
|
||||
.arg(query->getIface())
|
||||
.arg(e.what());
|
||||
|
||||
// Increase the statistics of parse failures and dropped packets.
|
||||
StatsMgr::instance().addValue("pkt6-parse-failed",
|
||||
static_cast<int64_t>(1));
|
||||
StatsMgr::instance().addValue("pkt6-receive-drop",
|
||||
static_cast<int64_t>(1));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Update statistics accordingly for received packet.
|
||||
processStatsReceived(query);
|
||||
|
||||
// Check if received query carries server identifier matching
|
||||
// server identifier being used by the server.
|
||||
if (!testServerID(query)) {
|
||||
|
||||
// Increase the statistic of dropped packets.
|
||||
StatsMgr::instance().addValue("pkt6-receive-drop", static_cast<int64_t>(1));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if the received query has been sent to unicast or multicast.
|
||||
// The Solicit, Confirm, Rebind and Information Request will be
|
||||
// discarded if sent to unicast address.
|
||||
if (!testUnicast(query)) {
|
||||
|
||||
// Increase the statistic of dropped packets.
|
||||
StatsMgr::instance().addValue("pkt6-receive-drop", static_cast<int64_t>(1));
|
||||
continue;
|
||||
}
|
||||
|
||||
LOG_DEBUG(packet6_logger, DBG_DHCP6_BASIC_DATA, DHCP6_PACKET_RECEIVED)
|
||||
.arg(query->getLabel())
|
||||
.arg(query->getName())
|
||||
.arg(static_cast<int>(query->getType()))
|
||||
.arg(query->getRemoteAddr())
|
||||
.arg(query->getLocalAddr())
|
||||
.arg(query->getIface());
|
||||
LOG_DEBUG(packet6_logger, DBG_DHCP6_DETAIL_DATA, DHCP6_QUERY_DATA)
|
||||
.arg(query->getLabel())
|
||||
.arg(query->toText());
|
||||
|
||||
// At this point the information in the packet has been unpacked into
|
||||
// the various packet fields and option objects has been created.
|
||||
// Execute callouts registered for packet6_receive.
|
||||
if (HooksManager::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->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
|
||||
LOG_DEBUG(hooks_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_PACKET_RCVD_SKIP)
|
||||
.arg(query->getLabel());
|
||||
continue;
|
||||
}
|
||||
|
||||
/// @todo: Add support for DROP status.
|
||||
|
||||
callout_handle->getArgument("query6", query);
|
||||
}
|
||||
|
||||
// Assign this packet to a class, if possible
|
||||
classifyPacket(query);
|
||||
|
||||
try {
|
||||
NameChangeRequestPtr ncr;
|
||||
|
||||
switch (query->getType()) {
|
||||
case DHCPV6_SOLICIT:
|
||||
rsp = processSolicit(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(bad_packet6_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.
|
||||
;
|
||||
}
|
||||
|
||||
} catch (const RFCViolation& e) {
|
||||
LOG_DEBUG(bad_packet6_logger, DBG_DHCP6_BASIC, DHCP6_REQUIRED_OPTIONS_CHECK_FAIL)
|
||||
.arg(query->getName())
|
||||
.arg(query->getRemoteAddr().toText())
|
||||
.arg(e.what());
|
||||
|
||||
// Increase the statistic of dropped packets.
|
||||
StatsMgr::instance().addValue("pkt6-receive-drop", static_cast<int64_t>(1));
|
||||
|
||||
} catch (const std::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 Kea code), but also the standard one, which may possibly be
|
||||
// thrown from boost 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(bad_packet6_logger, DBG_DHCP6_BASIC, DHCP6_PACKET_PROCESS_FAIL)
|
||||
.arg(query->getName())
|
||||
.arg(query->getRemoteAddr().toText())
|
||||
.arg(e.what());
|
||||
|
||||
// Increase the statistic of dropped packets.
|
||||
StatsMgr::instance().addValue("pkt6-receive-drop", static_cast<int64_t>(1));
|
||||
}
|
||||
|
||||
if (rsp) {
|
||||
|
||||
// Process relay-supplied options. It is important to call this very
|
||||
// late in the process, because we now have all the options the
|
||||
// server wanted to send already set. This is important, because
|
||||
// RFC6422, section 6 states:
|
||||
//
|
||||
// The server SHOULD discard any options that appear in the RSOO
|
||||
// for which it already has one or more candidates.
|
||||
//
|
||||
// So we ignore any RSOO options if there's an option with the same
|
||||
// code already present.
|
||||
processRSOO(query, rsp);
|
||||
|
||||
rsp->setRemoteAddr(query->getRemoteAddr());
|
||||
rsp->setLocalAddr(query->getLocalAddr());
|
||||
|
||||
if (rsp->relay_info_.empty()) {
|
||||
// Direct traffic, send back to the client directly
|
||||
rsp->setRemotePort(DHCP6_CLIENT_PORT);
|
||||
} else {
|
||||
// Relayed traffic, send back to the relay agent
|
||||
rsp->setRemotePort(DHCP6_SERVER_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::calloutsPresent(Hooks.hook_index_pkt6_send_)) {
|
||||
CalloutHandlePtr callout_handle = getCalloutHandle(query);
|
||||
|
||||
// Delete all previous arguments
|
||||
callout_handle->deleteAllArguments();
|
||||
|
||||
// Set our response
|
||||
callout_handle->setArgument("response6", rsp);
|
||||
|
||||
// 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->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
|
||||
LOG_DEBUG(hooks_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_PACKET_SEND_SKIP)
|
||||
.arg(rsp->getLabel());
|
||||
skip_pack = true;
|
||||
}
|
||||
|
||||
/// @todo: Add support for DROP status
|
||||
}
|
||||
|
||||
if (!skip_pack) {
|
||||
try {
|
||||
rsp->pack();
|
||||
} catch (const std::exception& e) {
|
||||
LOG_ERROR(options6_logger, DHCP6_PACK_FAIL)
|
||||
.arg(e.what());
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
// 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::calloutsPresent(Hooks.hook_index_buffer6_send_)) {
|
||||
CalloutHandlePtr callout_handle = getCalloutHandle(query);
|
||||
|
||||
// Delete previously set arguments
|
||||
callout_handle->deleteAllArguments();
|
||||
|
||||
// Pass incoming packet as argument
|
||||
callout_handle->setArgument("response6", rsp);
|
||||
|
||||
// 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 parse the packet, so skip at this
|
||||
// stage means drop.
|
||||
if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
|
||||
LOG_DEBUG(hooks_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_BUFFER_SEND_SKIP)
|
||||
.arg(rsp->getLabel());
|
||||
continue;
|
||||
}
|
||||
|
||||
/// @todo: Add support for DROP status
|
||||
|
||||
callout_handle->getArgument("response6", rsp);
|
||||
}
|
||||
|
||||
LOG_DEBUG(packet6_logger, DBG_DHCP6_DETAIL_DATA,
|
||||
DHCP6_RESPONSE_DATA)
|
||||
.arg(static_cast<int>(rsp->getType())).arg(rsp->toText());
|
||||
|
||||
sendPacket(rsp);
|
||||
|
||||
// Update statistics accordingly for sent packet.
|
||||
processStatsSent(rsp);
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
LOG_ERROR(packet6_logger, DHCP6_PACKET_SEND_FAIL)
|
||||
.arg(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
run_one();
|
||||
} catch (const std::exception& e) {
|
||||
// General catch-all standard exceptions that are not caught by more
|
||||
// specific catches.
|
||||
LOG_ERROR(packet6_logger, DHCP6_PACKET_PROCESS_EXCEPTION)
|
||||
LOG_ERROR(packet6_logger, DHCP6_PACKET_PROCESS_STD_EXCEPTION)
|
||||
.arg(e.what());
|
||||
} catch (...) {
|
||||
// General catch-all non-standard exception that are not caught
|
||||
// by more specific catches.
|
||||
LOG_ERROR(packet6_logger, DHCP6_PACKET_PROCESS_EXCEPTION)
|
||||
.arg("an unknown exception not derived from std::exception");
|
||||
LOG_ERROR(packet6_logger, DHCP6_PACKET_PROCESS_EXCEPTION);
|
||||
}
|
||||
}
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
void Dhcpv6Srv::run_one() {
|
||||
// client's message and server's response
|
||||
Pkt6Ptr query;
|
||||
Pkt6Ptr rsp;
|
||||
|
||||
try {
|
||||
uint32_t timeout = 1000;
|
||||
LOG_DEBUG(packet6_logger, DBG_DHCP6_DETAIL, DHCP6_BUFFER_WAIT).arg(timeout);
|
||||
query = receivePacket(timeout);
|
||||
|
||||
// Log if packet has arrived. We can't log the detailed information
|
||||
// about the DHCP message because it hasn't been unpacked/parsed
|
||||
// yet, and it can't be parsed at this point because hooks will
|
||||
// have to process it first. The only information available at this
|
||||
// point are: the interface, source address and destination addresses
|
||||
// and ports.
|
||||
if (query) {
|
||||
LOG_DEBUG(packet6_logger, DBG_DHCP6_BASIC, DHCP6_BUFFER_RECEIVED)
|
||||
.arg(query->getRemoteAddr().toText())
|
||||
.arg(query->getRemotePort())
|
||||
.arg(query->getLocalAddr().toText())
|
||||
.arg(query->getLocalPort())
|
||||
.arg(query->getIface());
|
||||
|
||||
// Log reception of the packet. We need to increase it early, as
|
||||
// any failures in unpacking will cause the packet to be dropped.
|
||||
// we will increase type specific packets further down the road.
|
||||
// See processStatsReceived().
|
||||
StatsMgr::instance().addValue("pkt6-received", static_cast<int64_t>(1));
|
||||
|
||||
} else {
|
||||
LOG_DEBUG(packet6_logger, DBG_DHCP6_DETAIL, DHCP6_BUFFER_WAIT_INTERRUPTED)
|
||||
.arg(timeout);
|
||||
}
|
||||
|
||||
} catch (const SignalInterruptOnSelect) {
|
||||
// Packet reception interrupted because a signal has been received.
|
||||
// This is not an error because we might have received a SIGTERM,
|
||||
// SIGINT or SIGHUP which are handled by the server. For signals
|
||||
// that are not handled by the server we rely on the default
|
||||
// behavior of the system.
|
||||
LOG_DEBUG(packet6_logger, DBG_DHCP6_DETAIL, DHCP6_BUFFER_WAIT_SIGNAL)
|
||||
.arg(signal_set_->getNext());
|
||||
} catch (const std::exception& e) {
|
||||
LOG_ERROR(packet6_logger, DHCP6_PACKET_RECEIVE_FAIL).arg(e.what());
|
||||
}
|
||||
|
||||
// Handle next signal received by the process. It must be called after
|
||||
// an attempt to receive a packet to properly handle server shut down.
|
||||
// The SIGTERM or SIGINT will be received prior to, or during execution
|
||||
// of select() (select is invoked by receivePacket()). When that happens,
|
||||
// select will be interrupted. The signal handler will be invoked
|
||||
// immediately after select(). The handler will set the shutdown flag
|
||||
// and cause the process to terminate before the next select() function
|
||||
// is called. If the function was called before receivePacket the
|
||||
// process could wait up to the duration of timeout of select() to
|
||||
// terminate.
|
||||
try {
|
||||
handleSignal();
|
||||
} catch (const std::exception& e) {
|
||||
// An (a standard or ISC) exception occurred.
|
||||
LOG_ERROR(dhcp6_logger, DHCP6_HANDLE_SIGNAL_EXCEPTION)
|
||||
.arg(e.what());
|
||||
}
|
||||
|
||||
// Timeout may be reached or signal received, which breaks select()
|
||||
// with no packet received
|
||||
if (!query) {
|
||||
return;
|
||||
}
|
||||
|
||||
processPacket(query, rsp);
|
||||
|
||||
if (!rsp) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
// 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::calloutsPresent(Hooks.hook_index_buffer6_send_)) {
|
||||
CalloutHandlePtr callout_handle = getCalloutHandle(query);
|
||||
|
||||
// Delete previously set arguments
|
||||
callout_handle->deleteAllArguments();
|
||||
|
||||
// Pass incoming packet as argument
|
||||
callout_handle->setArgument("response6", rsp);
|
||||
|
||||
// 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 parse the packet, so skip at this
|
||||
// stage means drop.
|
||||
if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
|
||||
LOG_DEBUG(hooks_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_BUFFER_SEND_SKIP)
|
||||
.arg(rsp->getLabel());
|
||||
return;
|
||||
}
|
||||
|
||||
/// @todo: Add support for DROP status
|
||||
|
||||
callout_handle->getArgument("response6", rsp);
|
||||
}
|
||||
|
||||
LOG_DEBUG(packet6_logger, DBG_DHCP6_DETAIL_DATA, DHCP6_RESPONSE_DATA)
|
||||
.arg(static_cast<int>(rsp->getType())).arg(rsp->toText());
|
||||
|
||||
sendPacket(rsp);
|
||||
|
||||
// Update statistics accordingly for sent packet.
|
||||
processStatsSent(rsp);
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
LOG_ERROR(packet6_logger, DHCP6_PACKET_SEND_FAIL).arg(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Dhcpv6Srv::processPacket(Pkt6Ptr& query, Pkt6Ptr& rsp) {
|
||||
// In order to parse the DHCP options, the server needs to use some
|
||||
// configuration information such as: existing option spaces, option
|
||||
// definitions etc. This is the kind of information which is not
|
||||
// available in the libdhcp, so we need to supply our own implementation
|
||||
// of the option parsing function here, which would rely on the
|
||||
// configuration data.
|
||||
query->setCallback(boost::bind(&Dhcpv6Srv::unpackOptions, this, _1, _2,
|
||||
_3, _4, _5));
|
||||
|
||||
bool skip_unpack = false;
|
||||
|
||||
// The packet has just been received so contains the uninterpreted wire
|
||||
// data; execute callouts registered for buffer6_receive.
|
||||
if (HooksManager::calloutsPresent(Hooks.hook_index_buffer6_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_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->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
|
||||
LOG_DEBUG(hooks_logger, DBG_DHCP6_DETAIL, DHCP6_HOOK_BUFFER_RCVD_SKIP)
|
||||
.arg(query->getRemoteAddr().toText())
|
||||
.arg(query->getLocalAddr().toText())
|
||||
.arg(query->getIface());
|
||||
skip_unpack = true;
|
||||
}
|
||||
|
||||
/// @todo: Add support for DROP status.
|
||||
|
||||
callout_handle->getArgument("query6", query);
|
||||
}
|
||||
|
||||
// Unpack the packet information unless the buffer6_receive callouts
|
||||
// indicated they did it
|
||||
if (!skip_unpack) {
|
||||
try {
|
||||
LOG_DEBUG(options6_logger, DBG_DHCP6_DETAIL, DHCP6_BUFFER_UNPACK)
|
||||
.arg(query->getRemoteAddr().toText())
|
||||
.arg(query->getLocalAddr().toText())
|
||||
.arg(query->getIface());
|
||||
query->unpack();
|
||||
} catch (const std::exception &e) {
|
||||
// Failed to parse the packet.
|
||||
LOG_DEBUG(bad_packet6_logger, DBG_DHCP6_DETAIL,
|
||||
DHCP6_PACKET_DROP_PARSE_FAIL)
|
||||
.arg(query->getRemoteAddr().toText())
|
||||
.arg(query->getLocalAddr().toText())
|
||||
.arg(query->getIface())
|
||||
.arg(e.what());
|
||||
|
||||
// Increase the statistics of parse failures and dropped packets.
|
||||
StatsMgr::instance().addValue("pkt6-parse-failed",
|
||||
static_cast<int64_t>(1));
|
||||
StatsMgr::instance().addValue("pkt6-receive-drop",
|
||||
static_cast<int64_t>(1));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Update statistics accordingly for received packet.
|
||||
processStatsReceived(query);
|
||||
|
||||
// Check if received query carries server identifier matching
|
||||
// server identifier being used by the server.
|
||||
if (!testServerID(query)) {
|
||||
|
||||
// Increase the statistic of dropped packets.
|
||||
StatsMgr::instance().addValue("pkt6-receive-drop", static_cast<int64_t>(1));
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the received query has been sent to unicast or multicast.
|
||||
// The Solicit, Confirm, Rebind and Information Request will be
|
||||
// discarded if sent to unicast address.
|
||||
if (!testUnicast(query)) {
|
||||
|
||||
// Increase the statistic of dropped packets.
|
||||
StatsMgr::instance().addValue("pkt6-receive-drop", static_cast<int64_t>(1));
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_DEBUG(packet6_logger, DBG_DHCP6_BASIC_DATA, DHCP6_PACKET_RECEIVED)
|
||||
.arg(query->getLabel())
|
||||
.arg(query->getName())
|
||||
.arg(static_cast<int>(query->getType()))
|
||||
.arg(query->getRemoteAddr())
|
||||
.arg(query->getLocalAddr())
|
||||
.arg(query->getIface());
|
||||
LOG_DEBUG(packet6_logger, DBG_DHCP6_DETAIL_DATA, DHCP6_QUERY_DATA)
|
||||
.arg(query->getLabel())
|
||||
.arg(query->toText());
|
||||
|
||||
// At this point the information in the packet has been unpacked into
|
||||
// the various packet fields and option objects has been created.
|
||||
// Execute callouts registered for packet6_receive.
|
||||
if (HooksManager::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->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
|
||||
LOG_DEBUG(hooks_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_PACKET_RCVD_SKIP)
|
||||
.arg(query->getLabel());
|
||||
return;
|
||||
}
|
||||
|
||||
/// @todo: Add support for DROP status.
|
||||
|
||||
callout_handle->getArgument("query6", query);
|
||||
}
|
||||
|
||||
// Assign this packet to a class, if possible
|
||||
classifyPacket(query);
|
||||
|
||||
try {
|
||||
NameChangeRequestPtr ncr;
|
||||
|
||||
switch (query->getType()) {
|
||||
case DHCPV6_SOLICIT:
|
||||
rsp = processSolicit(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(bad_packet6_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.
|
||||
;
|
||||
}
|
||||
|
||||
} catch (const RFCViolation& e) {
|
||||
LOG_DEBUG(bad_packet6_logger, DBG_DHCP6_BASIC, DHCP6_REQUIRED_OPTIONS_CHECK_FAIL)
|
||||
.arg(query->getName())
|
||||
.arg(query->getRemoteAddr().toText())
|
||||
.arg(e.what());
|
||||
|
||||
// Increase the statistic of dropped packets.
|
||||
StatsMgr::instance().addValue("pkt6-receive-drop", static_cast<int64_t>(1));
|
||||
|
||||
} catch (const std::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 Kea code), but also the standard one, which may possibly be
|
||||
// thrown from boost 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(bad_packet6_logger, DBG_DHCP6_BASIC, DHCP6_PACKET_PROCESS_FAIL)
|
||||
.arg(query->getName())
|
||||
.arg(query->getRemoteAddr().toText())
|
||||
.arg(e.what());
|
||||
|
||||
// Increase the statistic of dropped packets.
|
||||
StatsMgr::instance().addValue("pkt6-receive-drop", static_cast<int64_t>(1));
|
||||
}
|
||||
|
||||
if (!rsp) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Process relay-supplied options. It is important to call this very
|
||||
// late in the process, because we now have all the options the
|
||||
// server wanted to send already set. This is important, because
|
||||
// RFC6422, section 6 states:
|
||||
//
|
||||
// The server SHOULD discard any options that appear in the RSOO
|
||||
// for which it already has one or more candidates.
|
||||
//
|
||||
// So we ignore any RSOO options if there's an option with the same
|
||||
// code already present.
|
||||
processRSOO(query, rsp);
|
||||
|
||||
rsp->setRemoteAddr(query->getRemoteAddr());
|
||||
rsp->setLocalAddr(query->getLocalAddr());
|
||||
|
||||
if (rsp->relay_info_.empty()) {
|
||||
// Direct traffic, send back to the client directly
|
||||
rsp->setRemotePort(DHCP6_CLIENT_PORT);
|
||||
} else {
|
||||
// Relayed traffic, send back to the relay agent
|
||||
rsp->setRemotePort(DHCP6_SERVER_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::calloutsPresent(Hooks.hook_index_pkt6_send_)) {
|
||||
CalloutHandlePtr callout_handle = getCalloutHandle(query);
|
||||
|
||||
// Delete all previous arguments
|
||||
callout_handle->deleteAllArguments();
|
||||
|
||||
// Set our response
|
||||
callout_handle->setArgument("response6", rsp);
|
||||
|
||||
// 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->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
|
||||
LOG_DEBUG(hooks_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_PACKET_SEND_SKIP)
|
||||
.arg(rsp->getLabel());
|
||||
skip_pack = true;
|
||||
}
|
||||
|
||||
/// @todo: Add support for DROP status
|
||||
}
|
||||
|
||||
if (!skip_pack) {
|
||||
try {
|
||||
rsp->pack();
|
||||
} catch (const std::exception& e) {
|
||||
LOG_ERROR(options6_logger, DHCP6_PACK_FAIL).arg(e.what());
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
Dhcpv6Srv::duidToString(const OptionPtr& opt) {
|
||||
stringstream tmp;
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC")
|
||||
// Copyright (C) 2011-2016 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
@ -89,14 +89,28 @@ public:
|
||||
|
||||
/// @brief Main server processing loop.
|
||||
///
|
||||
/// Main server processing loop. Receives incoming packets, verifies
|
||||
/// their correctness, generates appropriate answer (if needed) and
|
||||
/// transmits responses.
|
||||
/// Main server processing loop. Call the processing step routine
|
||||
/// until shut down.
|
||||
///
|
||||
/// @return true, if being shut down gracefully, fail if experienced
|
||||
/// critical error.
|
||||
/// @return true, if being shut down gracefully, never fail.
|
||||
bool run();
|
||||
|
||||
/// @brief Main server processing step.
|
||||
///
|
||||
/// Main server processing step. Receives one incoming packet, calls
|
||||
/// the processing packet routing and (if necessary) transmits
|
||||
/// a response.
|
||||
void run_one();
|
||||
|
||||
/// @brief Process a single incoming DHCPv6 packet.
|
||||
///
|
||||
/// It verifies correctness of the passed packet, call per-type processXXX
|
||||
/// methods, generates appropriate answer.
|
||||
///
|
||||
/// @param query A pointer to the packet to be processed.
|
||||
/// @param rsp A pointer to the response
|
||||
void processPacket(Pkt6Ptr& query, Pkt6Ptr& rsp);
|
||||
|
||||
/// @brief Instructs the server to shut down.
|
||||
void shutdown();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user