2013-01-15 19:53:58 +01:00
|
|
|
// Copyright (C) 2011-2013 Internet Systems Consortium, Inc. ("ISC")
|
2011-11-27 19:35:47 +08:00
|
|
|
//
|
|
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
|
|
// copyright notice and this permission notice appear in all copies.
|
|
|
|
//
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
|
|
|
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
|
|
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
|
|
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
|
|
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
|
|
|
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
|
|
// PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
|
2012-11-16 14:15:45 +00:00
|
|
|
#include <asiolink/io_address.h>
|
2011-11-27 19:35:47 +08:00
|
|
|
#include <dhcp/dhcp4.h>
|
2011-11-30 15:32:40 +01:00
|
|
|
#include <dhcp/iface_mgr.h>
|
2011-12-20 19:59:14 +01:00
|
|
|
#include <dhcp/option4_addrlst.h>
|
2012-12-31 16:49:37 +01:00
|
|
|
#include <dhcp/option_int.h>
|
2013-01-15 19:53:58 +01:00
|
|
|
#include <dhcp/option_int_array.h>
|
2012-11-16 14:15:45 +00:00
|
|
|
#include <dhcp/pkt4.h>
|
2012-12-31 16:49:37 +01:00
|
|
|
#include <dhcp/duid.h>
|
|
|
|
#include <dhcp/hwaddr.h>
|
2012-11-16 14:15:45 +00:00
|
|
|
#include <dhcp4/dhcp4_log.h>
|
|
|
|
#include <dhcp4/dhcp4_srv.h>
|
2012-12-31 16:49:37 +01:00
|
|
|
#include <dhcpsrv/utils.h>
|
|
|
|
#include <dhcpsrv/cfgmgr.h>
|
|
|
|
#include <dhcpsrv/lease_mgr.h>
|
|
|
|
#include <dhcpsrv/lease_mgr_factory.h>
|
|
|
|
#include <dhcpsrv/subnet.h>
|
|
|
|
#include <dhcpsrv/utils.h>
|
|
|
|
#include <dhcpsrv/addr_utilities.h>
|
2011-11-27 19:35:47 +08:00
|
|
|
|
2013-01-14 17:57:26 +01:00
|
|
|
#include <boost/algorithm/string/erase.hpp>
|
|
|
|
|
|
|
|
#include <iomanip>
|
|
|
|
#include <fstream>
|
|
|
|
|
2011-11-27 19:35:47 +08:00
|
|
|
using namespace isc;
|
|
|
|
using namespace isc::asiolink;
|
2012-09-06 11:18:51 +01:00
|
|
|
using namespace isc::dhcp;
|
|
|
|
using namespace isc::log;
|
|
|
|
using namespace std;
|
2011-11-27 19:35:47 +08:00
|
|
|
|
2013-01-31 12:16:22 +00:00
|
|
|
namespace isc {
|
|
|
|
namespace dhcp {
|
|
|
|
|
|
|
|
/// @brief file name of a server-id file
|
|
|
|
///
|
|
|
|
/// Server must store its server identifier in persistent storage that must not
|
|
|
|
/// change between restarts. This is name of the file that is created in dataDir
|
|
|
|
/// (see isc::dhcp::CfgMgr::getDataDir()). It is a text file that uses
|
|
|
|
/// regular IPv4 address, e.g. 192.0.2.1. Server will create it during
|
|
|
|
/// first run and then use it afterwards.
|
|
|
|
static const char* SERVER_ID_FILE = "b10-dhcp4-serverid";
|
|
|
|
|
2011-12-21 16:37:11 +01:00
|
|
|
// These are hardcoded parameters. Currently this is a skeleton server that only
|
|
|
|
// grants those options and a single, fixed, hardcoded lease.
|
|
|
|
|
2013-04-29 11:00:22 +02:00
|
|
|
Dhcpv4Srv::Dhcpv4Srv(uint16_t port, const char* dbconfig, const bool use_bcast,
|
|
|
|
const bool direct_response_desired) {
|
2012-09-06 11:18:51 +01:00
|
|
|
LOG_DEBUG(dhcp4_logger, DBG_DHCP4_START, DHCP4_OPEN_SOCKET).arg(port);
|
2012-07-23 16:35:54 +02:00
|
|
|
try {
|
2012-09-06 12:58:17 +01:00
|
|
|
// First call to instance() will create IfaceMgr (it's a singleton)
|
2013-04-25 19:32:28 +02:00
|
|
|
// it may throw something if things go wrong.
|
2013-05-21 10:45:22 +02:00
|
|
|
// The 'true' value of the call to setMatchingPacketFilter imposes
|
2013-04-25 19:32:28 +02:00
|
|
|
// that IfaceMgr will try to use the mechanism to respond directly
|
|
|
|
// to the client which doesn't have address assigned. This capability
|
|
|
|
// may be lacking on some OSes, so there is no guarantee that server
|
|
|
|
// will be able to respond directly.
|
2013-04-29 11:00:22 +02:00
|
|
|
IfaceMgr::instance().setMatchingPacketFilter(direct_response_desired);
|
2011-11-27 19:35:47 +08:00
|
|
|
|
2012-12-31 16:49:37 +01:00
|
|
|
if (port) {
|
|
|
|
// open sockets only if port is non-zero. Port 0 is used
|
|
|
|
// for non-socket related testing.
|
2013-04-04 15:17:31 +02:00
|
|
|
IfaceMgr::instance().openSockets4(port, use_bcast);
|
2012-12-31 16:49:37 +01:00
|
|
|
}
|
2011-11-27 19:35:47 +08:00
|
|
|
|
2013-01-14 17:57:26 +01:00
|
|
|
string srvid_file = CfgMgr::instance().getDataDir() + "/" + string(SERVER_ID_FILE);
|
|
|
|
if (loadServerID(srvid_file)) {
|
|
|
|
LOG_DEBUG(dhcp4_logger, DBG_DHCP4_START, DHCP4_SERVERID_LOADED)
|
2013-01-30 09:35:48 -06:00
|
|
|
.arg(srvidToString(getServerID()))
|
2013-01-14 17:57:26 +01:00
|
|
|
.arg(srvid_file);
|
|
|
|
} else {
|
|
|
|
generateServerID();
|
|
|
|
LOG_INFO(dhcp4_logger, DHCP4_SERVERID_GENERATED)
|
|
|
|
.arg(srvidToString(getServerID()))
|
|
|
|
.arg(srvid_file);
|
|
|
|
|
|
|
|
if (!writeServerID(srvid_file)) {
|
|
|
|
LOG_WARN(dhcp4_logger, DHCP4_SERVERID_WRITE_FAIL)
|
|
|
|
.arg(srvid_file);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2012-09-06 11:18:51 +01:00
|
|
|
|
2012-12-31 16:49:37 +01:00
|
|
|
// Instantiate LeaseMgr
|
|
|
|
LeaseMgrFactory::create(dbconfig);
|
|
|
|
LOG_INFO(dhcp4_logger, DHCP4_DB_BACKEND_STARTED)
|
|
|
|
.arg(LeaseMgrFactory::instance().getType())
|
|
|
|
.arg(LeaseMgrFactory::instance().getName());
|
|
|
|
|
|
|
|
// Instantiate allocation engine
|
|
|
|
alloc_engine_.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100));
|
|
|
|
|
2012-07-23 16:35:54 +02:00
|
|
|
} catch (const std::exception &e) {
|
2012-09-06 11:18:51 +01:00
|
|
|
LOG_ERROR(dhcp4_logger, DHCP4_SRV_CONSTRUCT_ERROR).arg(e.what());
|
2012-07-23 16:35:54 +02:00
|
|
|
shutdown_ = true;
|
|
|
|
return;
|
|
|
|
}
|
2011-11-27 19:35:47 +08:00
|
|
|
|
2011-12-12 18:04:12 +01:00
|
|
|
shutdown_ = false;
|
2011-11-27 19:35:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Dhcpv4Srv::~Dhcpv4Srv() {
|
2011-12-12 19:24:36 +01:00
|
|
|
IfaceMgr::instance().closeSockets();
|
2011-11-27 19:35:47 +08:00
|
|
|
}
|
|
|
|
|
2013-01-30 19:07:54 +01:00
|
|
|
void
|
|
|
|
Dhcpv4Srv::shutdown() {
|
2012-09-06 11:18:51 +01:00
|
|
|
LOG_DEBUG(dhcp4_logger, DBG_DHCP4_BASIC, DHCP4_SHUTDOWN_REQUEST);
|
2012-05-30 18:36:58 +02:00
|
|
|
shutdown_ = true;
|
|
|
|
}
|
|
|
|
|
2011-11-27 19:35:47 +08:00
|
|
|
bool
|
|
|
|
Dhcpv4Srv::run() {
|
2011-12-12 18:04:12 +01:00
|
|
|
while (!shutdown_) {
|
2012-05-30 18:36:58 +02:00
|
|
|
/// @todo: calculate actual timeout once we have lease database
|
|
|
|
int timeout = 1000;
|
|
|
|
|
2012-03-08 14:52:46 +01:00
|
|
|
// client's message and server's response
|
2012-09-26 12:01:03 +02:00
|
|
|
Pkt4Ptr query;
|
2012-03-08 14:52:46 +01:00
|
|
|
Pkt4Ptr rsp;
|
2011-12-07 15:00:37 +01:00
|
|
|
|
2012-09-26 12:01:03 +02:00
|
|
|
try {
|
|
|
|
query = IfaceMgr::instance().receive4(timeout);
|
|
|
|
} catch (const std::exception& e) {
|
|
|
|
LOG_ERROR(dhcp4_logger, DHCP4_PACKET_RECEIVE_FAIL).arg(e.what());
|
|
|
|
}
|
|
|
|
|
2011-11-27 19:35:47 +08:00
|
|
|
if (query) {
|
2011-12-12 19:24:36 +01:00
|
|
|
try {
|
|
|
|
query->unpack();
|
2012-09-06 11:18:51 +01:00
|
|
|
|
2011-12-12 19:24:36 +01:00
|
|
|
} catch (const std::exception& e) {
|
2012-09-06 11:18:51 +01:00
|
|
|
// Failed to parse the packet.
|
|
|
|
LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL,
|
|
|
|
DHCP4_PACKET_PARSE_FAIL).arg(e.what());
|
2011-11-27 19:35:47 +08:00
|
|
|
continue;
|
|
|
|
}
|
2012-09-06 15:40:12 +01:00
|
|
|
LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, DHCP4_PACKET_RECEIVED)
|
2012-09-06 12:58:17 +01:00
|
|
|
.arg(serverReceivedPacketName(query->getType()))
|
|
|
|
.arg(query->getType())
|
|
|
|
.arg(query->getIface());
|
2012-09-06 11:18:51 +01:00
|
|
|
LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL_DATA, DHCP4_QUERY_DATA)
|
|
|
|
.arg(query->toText());
|
|
|
|
|
2013-02-07 12:49:56 +00:00
|
|
|
try {
|
|
|
|
switch (query->getType()) {
|
|
|
|
case DHCPDISCOVER:
|
|
|
|
rsp = processDiscover(query);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DHCPREQUEST:
|
|
|
|
rsp = processRequest(query);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DHCPRELEASE:
|
|
|
|
processRelease(query);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DHCPDECLINE:
|
|
|
|
processDecline(query);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DHCPINFORM:
|
|
|
|
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 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.)
|
2013-02-11 13:42:18 +00:00
|
|
|
if (dhcp4_logger.isDebugEnabled(DBG_DHCP4_BASIC)) {
|
|
|
|
std::string source = "unknown";
|
|
|
|
HWAddrPtr hwptr = query->getHWAddr();
|
|
|
|
if (hwptr) {
|
|
|
|
source = hwptr->toText();
|
|
|
|
}
|
|
|
|
LOG_DEBUG(dhcp4_logger, DBG_DHCP4_BASIC,
|
|
|
|
DHCP4_PACKET_PROCESS_FAIL)
|
|
|
|
.arg(source).arg(e.what());
|
|
|
|
}
|
2011-11-27 19:35:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (rsp) {
|
2011-12-20 19:59:14 +01:00
|
|
|
if (rsp->getRemoteAddr().toText() == "0.0.0.0") {
|
|
|
|
rsp->setRemoteAddr(query->getRemoteAddr());
|
|
|
|
}
|
|
|
|
if (!rsp->getHops()) {
|
|
|
|
rsp->setRemotePort(DHCP4_CLIENT_PORT);
|
|
|
|
} else {
|
|
|
|
rsp->setRemotePort(DHCP4_SERVER_PORT);
|
|
|
|
}
|
|
|
|
|
2011-11-30 19:00:57 +01:00
|
|
|
rsp->setLocalAddr(query->getLocalAddr());
|
|
|
|
rsp->setLocalPort(DHCP4_SERVER_PORT);
|
|
|
|
rsp->setIface(query->getIface());
|
|
|
|
rsp->setIndex(query->getIndex());
|
|
|
|
|
2012-09-06 11:18:51 +01:00
|
|
|
LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL_DATA,
|
|
|
|
DHCP4_RESPONSE_DATA)
|
|
|
|
.arg(rsp->getType()).arg(rsp->toText());
|
2012-09-06 15:40:12 +01:00
|
|
|
|
|
|
|
if (rsp->pack()) {
|
2012-09-26 12:01:03 +02:00
|
|
|
try {
|
|
|
|
IfaceMgr::instance().send(rsp);
|
2012-09-26 12:09:25 +02:00
|
|
|
} catch (const std::exception& e) {
|
|
|
|
LOG_ERROR(dhcp4_logger, DHCP4_PACKET_SEND_FAIL).arg(e.what());
|
2012-09-26 12:01:03 +02:00
|
|
|
}
|
2012-09-06 15:40:12 +01:00
|
|
|
} else {
|
2012-09-06 11:18:51 +01:00
|
|
|
LOG_ERROR(dhcp4_logger, DHCP4_PACK_FAIL);
|
2011-11-27 19:35:47 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-01-14 17:57:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return (true);
|
|
|
|
}
|
|
|
|
|
2013-01-30 19:07:54 +01:00
|
|
|
bool
|
|
|
|
Dhcpv4Srv::loadServerID(const std::string& file_name) {
|
2011-11-27 19:35:47 +08:00
|
|
|
|
2013-01-14 17:57:26 +01:00
|
|
|
// load content of the file into a string
|
|
|
|
fstream f(file_name.c_str(), ios::in);
|
|
|
|
if (!f.is_open()) {
|
|
|
|
return (false);
|
|
|
|
}
|
|
|
|
|
|
|
|
string hex_string;
|
|
|
|
f >> hex_string;
|
|
|
|
f.close();
|
|
|
|
|
|
|
|
// remove any spaces
|
|
|
|
boost::algorithm::erase_all(hex_string, " ");
|
|
|
|
|
|
|
|
try {
|
|
|
|
IOAddress addr(hex_string);
|
|
|
|
|
2013-01-17 12:50:14 +01:00
|
|
|
if (!addr.isV4()) {
|
2013-01-14 17:57:26 +01:00
|
|
|
return (false);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now create server-id option
|
|
|
|
serverid_.reset(new Option4AddrLst(DHO_DHCP_SERVER_IDENTIFIER, addr));
|
|
|
|
|
|
|
|
} catch(...) {
|
|
|
|
// any kind of malformed input (empty string, IPv6 address, complete
|
|
|
|
// garbate etc.)
|
|
|
|
return (false);
|
2011-11-27 19:35:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return (true);
|
|
|
|
}
|
|
|
|
|
2013-01-30 19:07:54 +01:00
|
|
|
void
|
|
|
|
Dhcpv4Srv::generateServerID() {
|
2013-01-14 17:57:26 +01:00
|
|
|
|
|
|
|
const IfaceMgr::IfaceCollection& ifaces = IfaceMgr::instance().getIfaces();
|
|
|
|
|
|
|
|
// Let's find suitable interface.
|
|
|
|
for (IfaceMgr::IfaceCollection::const_iterator iface = ifaces.begin();
|
|
|
|
iface != ifaces.end(); ++iface) {
|
|
|
|
|
|
|
|
// Let's don't use loopback.
|
|
|
|
if (iface->flag_loopback_) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Let's skip downed interfaces. It is better to use working ones.
|
|
|
|
if (!iface->flag_up_) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2013-04-03 12:20:40 +02:00
|
|
|
const Iface::AddressCollection addrs = iface->getAddresses();
|
2013-01-14 17:57:26 +01:00
|
|
|
|
2013-04-03 12:20:40 +02:00
|
|
|
for (Iface::AddressCollection::const_iterator addr = addrs.begin();
|
2013-01-14 17:57:26 +01:00
|
|
|
addr != addrs.end(); ++addr) {
|
|
|
|
if (addr->getFamily() != AF_INET) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
serverid_ = OptionPtr(new Option4AddrLst(DHO_DHCP_SERVER_IDENTIFIER,
|
|
|
|
*addr));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_throw(BadValue, "No suitable interfaces for server-identifier found");
|
|
|
|
}
|
|
|
|
|
2013-01-30 19:07:54 +01:00
|
|
|
bool
|
|
|
|
Dhcpv4Srv::writeServerID(const std::string& file_name) {
|
2013-01-14 17:57:26 +01:00
|
|
|
fstream f(file_name.c_str(), ios::out | ios::trunc);
|
|
|
|
if (!f.good()) {
|
|
|
|
return (false);
|
|
|
|
}
|
|
|
|
f << srvidToString(getServerID());
|
|
|
|
f.close();
|
2013-01-30 19:07:54 +01:00
|
|
|
return (true);
|
2013-01-14 17:57:26 +01:00
|
|
|
}
|
|
|
|
|
2013-03-28 16:16:28 +01:00
|
|
|
string
|
2013-01-30 19:07:54 +01:00
|
|
|
Dhcpv4Srv::srvidToString(const OptionPtr& srvid) {
|
2013-01-14 17:57:26 +01:00
|
|
|
if (!srvid) {
|
|
|
|
isc_throw(BadValue, "NULL pointer passed to srvidToString()");
|
|
|
|
}
|
|
|
|
boost::shared_ptr<Option4AddrLst> generated =
|
|
|
|
boost::dynamic_pointer_cast<Option4AddrLst>(srvid);
|
|
|
|
if (!srvid) {
|
|
|
|
isc_throw(BadValue, "Pointer to invalid option passed to srvidToString()");
|
|
|
|
}
|
|
|
|
|
|
|
|
Option4AddrLst::AddressContainer addrs = generated->getAddresses();
|
|
|
|
if (addrs.size() != 1) {
|
|
|
|
isc_throw(BadValue, "Malformed option passed to srvidToString(). "
|
|
|
|
<< "Expected to contain a single IPv4 address.");
|
|
|
|
}
|
|
|
|
|
|
|
|
return (addrs[0].toText());
|
2011-11-27 19:35:47 +08:00
|
|
|
}
|
|
|
|
|
2013-01-30 19:07:54 +01:00
|
|
|
void
|
|
|
|
Dhcpv4Srv::copyDefaultFields(const Pkt4Ptr& question, Pkt4Ptr& answer) {
|
2011-12-21 16:37:11 +01:00
|
|
|
answer->setIface(question->getIface());
|
|
|
|
answer->setIndex(question->getIndex());
|
|
|
|
answer->setCiaddr(question->getCiaddr());
|
2011-12-20 19:59:14 +01:00
|
|
|
|
2013-04-09 08:15:22 -05:00
|
|
|
answer->setSiaddr(IOAddress("0.0.0.0")); // explicitly set this to 0
|
2011-12-21 16:37:11 +01:00
|
|
|
answer->setHops(question->getHops());
|
2011-12-20 19:59:14 +01:00
|
|
|
|
|
|
|
// copy MAC address
|
2012-12-27 19:45:00 +01:00
|
|
|
answer->setHWAddr(question->getHWAddr());
|
2011-12-20 19:59:14 +01:00
|
|
|
|
|
|
|
// relay address
|
2011-12-21 16:37:11 +01:00
|
|
|
answer->setGiaddr(question->getGiaddr());
|
|
|
|
|
|
|
|
if (question->getGiaddr().toText() != "0.0.0.0") {
|
2011-12-20 19:59:14 +01:00
|
|
|
// relayed traffic
|
2011-12-21 16:37:11 +01:00
|
|
|
answer->setRemoteAddr(question->getGiaddr());
|
2011-12-20 19:59:14 +01:00
|
|
|
} else {
|
|
|
|
// direct traffic
|
2011-12-21 16:37:11 +01:00
|
|
|
answer->setRemoteAddr(question->getRemoteAddr());
|
2011-12-20 19:59:14 +01:00
|
|
|
}
|
|
|
|
|
2013-01-08 13:53:34 +01:00
|
|
|
// Let's copy client-id to response. See RFC6842.
|
2012-12-31 16:49:37 +01:00
|
|
|
OptionPtr client_id = question->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
|
|
|
|
if (client_id) {
|
|
|
|
answer->addOption(client_id);
|
|
|
|
}
|
2013-04-29 19:05:22 +02:00
|
|
|
|
|
|
|
// If src/dest HW addresses are used by the packet filtering class
|
2013-05-21 10:45:22 +02:00
|
|
|
// we need to copy them as well. There is a need to check that the
|
|
|
|
// address being set is not-NULL because an attempt to set the NULL
|
|
|
|
// HW would result in exception. If these values are not set, the
|
|
|
|
// the default HW addresses (zeroed) should be generated by the
|
|
|
|
// packet filtering class when creating Ethernet header for
|
|
|
|
// outgoing packet.
|
2013-04-29 19:05:22 +02:00
|
|
|
HWAddrPtr src_hw_addr = question->getLocalHWAddr();
|
|
|
|
if (src_hw_addr) {
|
2013-04-29 19:42:58 +02:00
|
|
|
answer->setLocalHWAddr(src_hw_addr);
|
2013-04-29 19:05:22 +02:00
|
|
|
}
|
2013-04-29 19:42:58 +02:00
|
|
|
HWAddrPtr dst_hw_addr = question->getRemoteHWAddr();
|
2013-04-29 19:05:22 +02:00
|
|
|
if (dst_hw_addr) {
|
2013-04-29 19:42:58 +02:00
|
|
|
answer->setRemoteHWAddr(dst_hw_addr);
|
2013-04-29 19:05:22 +02:00
|
|
|
}
|
2011-12-21 16:37:11 +01:00
|
|
|
}
|
|
|
|
|
2013-01-30 19:07:54 +01:00
|
|
|
void
|
|
|
|
Dhcpv4Srv::appendDefaultOptions(Pkt4Ptr& msg, uint8_t msg_type) {
|
2012-02-03 16:54:41 +01:00
|
|
|
OptionPtr opt;
|
2011-12-20 19:59:14 +01:00
|
|
|
|
|
|
|
// add Message Type Option (type 53)
|
2013-01-08 12:07:07 +01:00
|
|
|
msg->setType(msg_type);
|
2011-12-21 16:37:11 +01:00
|
|
|
|
2011-12-23 17:26:24 +01:00
|
|
|
// DHCP Server Identifier (type 54)
|
2012-12-31 16:49:37 +01:00
|
|
|
msg->addOption(getServerID());
|
2011-12-23 17:26:24 +01:00
|
|
|
|
2011-12-21 16:37:11 +01:00
|
|
|
// more options will be added here later
|
|
|
|
}
|
|
|
|
|
2013-01-30 19:07:54 +01:00
|
|
|
void
|
|
|
|
Dhcpv4Srv::appendRequestedOptions(const Pkt4Ptr& question, Pkt4Ptr& msg) {
|
2013-01-15 19:53:58 +01:00
|
|
|
|
|
|
|
// Get the subnet relevant for the client. We will need it
|
|
|
|
// to get the options associated with it.
|
|
|
|
Subnet4Ptr subnet = selectSubnet(question);
|
|
|
|
// If we can't find the subnet for the client there is no way
|
|
|
|
// to get the options to be sent to a client. We don't log an
|
|
|
|
// error because it will be logged by the assignLease method
|
|
|
|
// anyway.
|
|
|
|
if (!subnet) {
|
|
|
|
return;
|
|
|
|
}
|
2011-12-21 16:37:11 +01:00
|
|
|
|
2013-01-15 19:53:58 +01:00
|
|
|
// try to get the 'Parameter Request List' option which holds the
|
|
|
|
// codes of requested options.
|
|
|
|
OptionUint8ArrayPtr option_prl = boost::dynamic_pointer_cast<
|
|
|
|
OptionUint8Array>(question->getOption(DHO_DHCP_PARAMETER_REQUEST_LIST));
|
|
|
|
// If there is no PRL option in the message from the client then
|
|
|
|
// there is nothing to do.
|
|
|
|
if (!option_prl) {
|
|
|
|
return;
|
|
|
|
}
|
2011-12-21 16:37:11 +01:00
|
|
|
|
2013-01-15 19:53:58 +01:00
|
|
|
// Get the codes of requested options.
|
|
|
|
const std::vector<uint8_t>& requested_opts = option_prl->getValues();
|
|
|
|
// For each requested option code get the instance of the option
|
|
|
|
// to be returned to the client.
|
|
|
|
for (std::vector<uint8_t>::const_iterator opt = requested_opts.begin();
|
|
|
|
opt != requested_opts.end(); ++opt) {
|
|
|
|
Subnet::OptionDescriptor desc =
|
|
|
|
subnet->getOptionDescriptor("dhcp4", *opt);
|
|
|
|
if (desc.option) {
|
|
|
|
msg->addOption(desc.option);
|
|
|
|
}
|
|
|
|
}
|
2011-12-23 17:26:24 +01:00
|
|
|
}
|
2011-12-21 16:37:11 +01:00
|
|
|
|
2013-01-22 18:40:55 +01:00
|
|
|
void
|
|
|
|
Dhcpv4Srv::appendBasicOptions(const Pkt4Ptr& question, Pkt4Ptr& msg) {
|
|
|
|
// Identify options that we always want to send to the
|
|
|
|
// client (if they are configured).
|
|
|
|
static const uint16_t required_options[] = {
|
|
|
|
DHO_SUBNET_MASK,
|
|
|
|
DHO_ROUTERS,
|
|
|
|
DHO_DOMAIN_NAME_SERVERS,
|
|
|
|
DHO_DOMAIN_NAME };
|
2011-12-21 16:37:11 +01:00
|
|
|
|
2013-01-22 18:40:55 +01:00
|
|
|
static size_t required_options_size =
|
|
|
|
sizeof(required_options) / sizeof(required_options[0]);
|
|
|
|
|
|
|
|
// Get the subnet.
|
|
|
|
Subnet4Ptr subnet = selectSubnet(question);
|
|
|
|
if (!subnet) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Try to find all 'required' options in the outgoing
|
|
|
|
// message. Those that are not present will be added.
|
|
|
|
for (int i = 0; i < required_options_size; ++i) {
|
|
|
|
OptionPtr opt = msg->getOption(required_options[i]);
|
|
|
|
if (!opt) {
|
|
|
|
// Check whether option has been configured.
|
|
|
|
Subnet::OptionDescriptor desc =
|
|
|
|
subnet->getOptionDescriptor("dhcp4", required_options[i]);
|
|
|
|
if (desc.option) {
|
|
|
|
msg->addOption(desc.option);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-12-23 17:26:24 +01:00
|
|
|
}
|
2011-12-21 16:37:11 +01:00
|
|
|
|
2013-01-30 19:07:54 +01:00
|
|
|
void
|
|
|
|
Dhcpv4Srv::assignLease(const Pkt4Ptr& question, Pkt4Ptr& answer) {
|
2012-12-31 16:49:37 +01:00
|
|
|
|
|
|
|
// We need to select a subnet the client is connected in.
|
|
|
|
Subnet4Ptr subnet = selectSubnet(question);
|
|
|
|
if (!subnet) {
|
|
|
|
// This particular client is out of luck today. We do not have
|
|
|
|
// information about the subnet he is connected to. This likely means
|
|
|
|
// misconfiguration of the server (or some relays). We will continue to
|
|
|
|
// process this message, but our response will be almost useless: no
|
|
|
|
// addresses or prefixes, no subnet specific configuration etc. The only
|
|
|
|
// thing this client can get is some global information (like DNS
|
|
|
|
// servers).
|
|
|
|
|
|
|
|
// perhaps this should be logged on some higher level? This is most likely
|
|
|
|
// configuration bug.
|
|
|
|
LOG_ERROR(dhcp4_logger, DHCP4_SUBNET_SELECTION_FAILED)
|
|
|
|
.arg(question->getRemoteAddr().toText())
|
|
|
|
.arg(serverReceivedPacketName(question->getType()));
|
2013-01-08 12:07:07 +01:00
|
|
|
answer->setType(DHCPNAK);
|
2012-12-31 16:49:37 +01:00
|
|
|
answer->setYiaddr(IOAddress("0.0.0.0"));
|
|
|
|
return;
|
|
|
|
}
|
2011-12-20 19:59:14 +01:00
|
|
|
|
2013-01-08 13:53:34 +01:00
|
|
|
LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL_DATA, DHCP4_SUBNET_SELECTED)
|
|
|
|
.arg(subnet->toText());
|
|
|
|
|
2012-12-31 16:49:37 +01:00
|
|
|
// Get client-id option
|
|
|
|
ClientIdPtr client_id;
|
|
|
|
OptionPtr opt = question->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
|
|
|
|
if (opt) {
|
|
|
|
client_id = ClientIdPtr(new ClientId(opt->getData()));
|
|
|
|
}
|
|
|
|
// client-id is not mandatory in DHCPv4
|
2011-12-20 19:59:14 +01:00
|
|
|
|
2012-12-31 16:49:37 +01:00
|
|
|
IOAddress hint = question->getYiaddr();
|
2011-12-20 19:59:14 +01:00
|
|
|
|
2012-12-31 16:49:37 +01:00
|
|
|
HWAddrPtr hwaddr = question->getHWAddr();
|
2011-12-20 19:59:14 +01:00
|
|
|
|
2012-12-31 16:49:37 +01:00
|
|
|
// "Fake" allocation is processing of DISCOVER message. We pretend to do an
|
|
|
|
// allocation, but we do not put the lease in the database. That is ok,
|
|
|
|
// because we do not guarantee that the user will get that exact lease. If
|
|
|
|
// the user selects this server to do actual allocation (i.e. sends REQUEST)
|
|
|
|
// it should include this hint. That will help us during the actual lease
|
|
|
|
// allocation.
|
2013-01-08 13:53:34 +01:00
|
|
|
bool fake_allocation = (question->getType() == DHCPDISCOVER);
|
2012-12-31 16:49:37 +01:00
|
|
|
|
|
|
|
// Use allocation engine to pick a lease for this client. Allocation engine
|
|
|
|
// will try to honour the hint, but it is just a hint - some other address
|
|
|
|
// may be used instead. If fake_allocation is set to false, the lease will
|
|
|
|
// be inserted into the LeaseMgr as well.
|
|
|
|
Lease4Ptr lease = alloc_engine_->allocateAddress4(subnet, client_id, hwaddr,
|
|
|
|
hint, fake_allocation);
|
|
|
|
|
|
|
|
if (lease) {
|
2013-01-08 13:53:34 +01:00
|
|
|
// We have a lease! Let's set it in the packet and send it back to
|
|
|
|
// the client.
|
2012-12-31 16:49:37 +01:00
|
|
|
LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, fake_allocation?
|
|
|
|
DHCP4_LEASE_ADVERT:DHCP4_LEASE_ALLOC)
|
2013-01-03 13:33:06 +01:00
|
|
|
.arg(lease->addr_.toText())
|
2012-12-31 16:49:37 +01:00
|
|
|
.arg(client_id?client_id->toText():"(no client-id)")
|
2013-01-03 13:33:06 +01:00
|
|
|
.arg(hwaddr?hwaddr->toText():"(no hwaddr info)");
|
2012-12-31 16:49:37 +01:00
|
|
|
|
|
|
|
answer->setYiaddr(lease->addr_);
|
|
|
|
|
2013-03-28 16:16:28 +01:00
|
|
|
// If remote address is not set, we are dealing with a directly
|
2013-04-09 19:03:50 +02:00
|
|
|
// connected client requesting new lease. We can send response to
|
2013-03-28 16:16:28 +01:00
|
|
|
// the address assigned in the lease, but first we have to make sure
|
|
|
|
// that IfaceMgr supports responding directly to the client when
|
|
|
|
// client doesn't have address assigned to its interface yet.
|
|
|
|
if (answer->getRemoteAddr().toText() == "0.0.0.0") {
|
|
|
|
if (IfaceMgr::instance().isDirectResponseSupported()) {
|
|
|
|
answer->setRemoteAddr(lease->addr_);
|
|
|
|
} else {
|
|
|
|
// Since IfaceMgr does not support direct responses to
|
2013-04-09 19:03:50 +02:00
|
|
|
// clients not having IP addresses, we have to send response
|
|
|
|
// to broadcast. We don't check whether the use_bcast flag
|
|
|
|
// was set in the constructor, because this flag is only used
|
|
|
|
// by unit tests to prevent opening broadcast sockets, as
|
|
|
|
// it requires root privileges. If this function is invoked by
|
|
|
|
// unit tests, we expect that it sets broadcast address if
|
|
|
|
// direct response is not supported, so as a test can verify
|
|
|
|
// function's behavior, regardless of the use_bcast flag's value.
|
2013-03-28 16:16:28 +01:00
|
|
|
answer->setRemoteAddr(IOAddress("255.255.255.255"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-31 16:49:37 +01:00
|
|
|
// IP Address Lease time (type 51)
|
|
|
|
opt = OptionPtr(new Option(Option::V4, DHO_DHCP_LEASE_TIME));
|
|
|
|
opt->setUint32(lease->valid_lft_);
|
|
|
|
answer->addOption(opt);
|
|
|
|
|
|
|
|
// Router (type 3)
|
2013-01-22 18:40:55 +01:00
|
|
|
Subnet::OptionDescriptor opt_routers =
|
|
|
|
subnet->getOptionDescriptor("dhcp4", DHO_ROUTERS);
|
|
|
|
if (opt_routers.option) {
|
|
|
|
answer->addOption(opt_routers.option);
|
|
|
|
}
|
2012-12-31 16:49:37 +01:00
|
|
|
|
|
|
|
// Subnet mask (type 1)
|
|
|
|
answer->addOption(getNetmaskOption(subnet));
|
|
|
|
|
|
|
|
// @todo: send renew timer option (T1, option 58)
|
|
|
|
// @todo: send rebind timer option (T2, option 59)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
// Allocation engine did not allocate a lease. The engine logged
|
|
|
|
// cause of that failure. The only thing left is to insert
|
|
|
|
// status code to pass the sad news to the client.
|
|
|
|
|
|
|
|
LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, fake_allocation?
|
|
|
|
DHCP4_LEASE_ADVERT_FAIL:DHCP4_LEASE_ALLOC_FAIL)
|
|
|
|
.arg(client_id?client_id->toText():"(no client-id)")
|
|
|
|
.arg(hwaddr?hwaddr->toText():"(no hwaddr info)")
|
|
|
|
.arg(hint.toText());
|
|
|
|
|
2013-01-08 12:07:07 +01:00
|
|
|
answer->setType(DHCPNAK);
|
2012-12-31 16:49:37 +01:00
|
|
|
answer->setYiaddr(IOAddress("0.0.0.0"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-30 19:07:54 +01:00
|
|
|
OptionPtr
|
|
|
|
Dhcpv4Srv::getNetmaskOption(const Subnet4Ptr& subnet) {
|
2012-12-31 16:49:37 +01:00
|
|
|
uint32_t netmask = getNetmask4(subnet->get().second);
|
|
|
|
|
|
|
|
OptionPtr opt(new OptionInt<uint32_t>(Option::V4,
|
|
|
|
DHO_SUBNET_MASK, netmask));
|
|
|
|
|
|
|
|
return (opt);
|
|
|
|
}
|
|
|
|
|
2013-01-30 19:07:54 +01:00
|
|
|
Pkt4Ptr
|
|
|
|
Dhcpv4Srv::processDiscover(Pkt4Ptr& discover) {
|
2012-02-03 16:54:41 +01:00
|
|
|
Pkt4Ptr offer = Pkt4Ptr
|
2011-12-23 17:26:24 +01:00
|
|
|
(new Pkt4(DHCPOFFER, discover->getTransid()));
|
2011-12-20 19:59:14 +01:00
|
|
|
|
2011-12-23 17:26:24 +01:00
|
|
|
copyDefaultFields(discover, offer);
|
|
|
|
appendDefaultOptions(offer, DHCPOFFER);
|
2013-01-15 19:53:58 +01:00
|
|
|
appendRequestedOptions(discover, offer);
|
2011-12-23 17:26:24 +01:00
|
|
|
|
2012-12-31 16:49:37 +01:00
|
|
|
assignLease(discover, offer);
|
2011-12-20 19:59:14 +01:00
|
|
|
|
2013-01-22 18:40:55 +01:00
|
|
|
// There are a few basic options that we always want to
|
|
|
|
// include in the response. If client did not request
|
|
|
|
// them we append them for him.
|
|
|
|
appendBasicOptions(discover, offer);
|
|
|
|
|
2011-12-20 19:59:14 +01:00
|
|
|
return (offer);
|
2011-11-27 19:35:47 +08:00
|
|
|
}
|
|
|
|
|
2013-01-30 19:07:54 +01:00
|
|
|
Pkt4Ptr
|
|
|
|
Dhcpv4Srv::processRequest(Pkt4Ptr& request) {
|
2012-02-03 16:54:41 +01:00
|
|
|
Pkt4Ptr ack = Pkt4Ptr
|
2011-12-21 16:37:11 +01:00
|
|
|
(new Pkt4(DHCPACK, request->getTransid()));
|
|
|
|
|
|
|
|
copyDefaultFields(request, ack);
|
|
|
|
appendDefaultOptions(ack, DHCPACK);
|
2013-01-15 19:53:58 +01:00
|
|
|
appendRequestedOptions(request, ack);
|
2011-12-21 16:37:11 +01:00
|
|
|
|
2012-12-31 16:49:37 +01:00
|
|
|
assignLease(request, ack);
|
2011-12-21 16:37:11 +01:00
|
|
|
|
2013-01-22 18:40:55 +01:00
|
|
|
// There are a few basic options that we always want to
|
|
|
|
// include in the response. If client did not request
|
|
|
|
// them we append them for him.
|
|
|
|
appendBasicOptions(request, ack);
|
|
|
|
|
2011-12-21 16:37:11 +01:00
|
|
|
return (ack);
|
2011-11-27 19:35:47 +08:00
|
|
|
}
|
|
|
|
|
2013-01-30 19:07:54 +01:00
|
|
|
void
|
|
|
|
Dhcpv4Srv::processRelease(Pkt4Ptr& release) {
|
2013-01-08 13:53:34 +01:00
|
|
|
|
|
|
|
// Try to find client-id
|
2012-12-31 16:49:37 +01:00
|
|
|
ClientIdPtr client_id;
|
|
|
|
OptionPtr opt = release->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
|
|
|
|
if (opt) {
|
|
|
|
client_id = ClientIdPtr(new ClientId(opt->getData()));
|
|
|
|
}
|
|
|
|
|
2013-01-08 13:53:34 +01:00
|
|
|
try {
|
|
|
|
// Do we have a lease for that particular address?
|
|
|
|
Lease4Ptr lease = LeaseMgrFactory::instance().getLease4(release->getYiaddr());
|
|
|
|
|
|
|
|
if (!lease) {
|
|
|
|
// No such lease - bogus release
|
|
|
|
LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, DHCP4_RELEASE_FAIL_NO_LEASE)
|
|
|
|
.arg(release->getYiaddr().toText())
|
|
|
|
.arg(release->getHWAddr()->toText())
|
|
|
|
.arg(client_id ? client_id->toText() : "(no client-id)");
|
|
|
|
return;
|
|
|
|
}
|
2012-12-31 16:49:37 +01:00
|
|
|
|
2013-01-08 13:53:34 +01:00
|
|
|
// Does the hardware address match? We don't want one client releasing
|
|
|
|
// second client's leases.
|
|
|
|
if (lease->hwaddr_ != release->getHWAddr()->hwaddr_) {
|
|
|
|
// @todo: Print hwaddr from lease as part of ticket #2589
|
|
|
|
LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, DHCP4_RELEASE_FAIL_WRONG_HWADDR)
|
|
|
|
.arg(release->getYiaddr().toText())
|
|
|
|
.arg(client_id ? client_id->toText() : "(no client-id)")
|
|
|
|
.arg(release->getHWAddr()->toText());
|
|
|
|
return;
|
|
|
|
}
|
2012-12-31 16:49:37 +01:00
|
|
|
|
2013-01-08 13:53:34 +01:00
|
|
|
// Does the lease have client-id info? If it has, then check it with what
|
|
|
|
// the client sent us.
|
|
|
|
if (lease->client_id_ && client_id && *lease->client_id_ != *client_id) {
|
|
|
|
LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, DHCP4_RELEASE_FAIL_WRONG_CLIENT_ID)
|
|
|
|
.arg(release->getYiaddr().toText())
|
|
|
|
.arg(client_id->toText())
|
|
|
|
.arg(lease->client_id_->toText());
|
|
|
|
return;
|
|
|
|
}
|
2012-12-31 16:49:37 +01:00
|
|
|
|
2013-01-08 13:53:34 +01:00
|
|
|
// Ok, hw and client-id match - let's release the lease.
|
|
|
|
if (LeaseMgrFactory::instance().deleteLease(lease->addr_)) {
|
|
|
|
|
|
|
|
// Release successful - we're done here
|
|
|
|
LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, DHCP4_RELEASE)
|
|
|
|
.arg(lease->addr_.toText())
|
|
|
|
.arg(client_id ? client_id->toText() : "(no client-id)")
|
|
|
|
.arg(release->getHWAddr()->toText());
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// Release failed -
|
|
|
|
LOG_ERROR(dhcp4_logger, DHCP4_RELEASE_FAIL)
|
|
|
|
.arg(lease->addr_.toText())
|
|
|
|
.arg(client_id ? client_id->toText() : "(no client-id)")
|
|
|
|
.arg(release->getHWAddr()->toText());
|
|
|
|
}
|
|
|
|
} catch (const isc::Exception& ex) {
|
|
|
|
// Rethrow the exception with a bit more data.
|
|
|
|
LOG_ERROR(dhcp4_logger, DHCP4_RELEASE_EXCEPTION)
|
|
|
|
.arg(ex.what())
|
|
|
|
.arg(release->getYiaddr());
|
2012-12-31 16:49:37 +01:00
|
|
|
}
|
|
|
|
|
2011-11-27 19:35:47 +08:00
|
|
|
}
|
2011-11-30 19:00:57 +01:00
|
|
|
|
2013-01-30 19:07:54 +01:00
|
|
|
void
|
2013-01-31 16:03:37 +00:00
|
|
|
Dhcpv4Srv::processDecline(Pkt4Ptr& /* decline */) {
|
2011-11-27 19:35:47 +08:00
|
|
|
/// TODO: Implement this.
|
|
|
|
}
|
|
|
|
|
2013-01-30 19:07:54 +01:00
|
|
|
Pkt4Ptr
|
|
|
|
Dhcpv4Srv::processInform(Pkt4Ptr& inform) {
|
2011-11-30 19:00:57 +01:00
|
|
|
/// TODO: Currently implemented echo mode. Implement this for real
|
2011-11-27 19:35:47 +08:00
|
|
|
return (inform);
|
|
|
|
}
|
2012-09-06 12:58:17 +01:00
|
|
|
|
|
|
|
const char*
|
|
|
|
Dhcpv4Srv::serverReceivedPacketName(uint8_t type) {
|
|
|
|
static const char* DISCOVER = "DISCOVER";
|
|
|
|
static const char* REQUEST = "REQUEST";
|
|
|
|
static const char* RELEASE = "RELEASE";
|
|
|
|
static const char* DECLINE = "DECLINE";
|
|
|
|
static const char* INFORM = "INFORM";
|
|
|
|
static const char* UNKNOWN = "UNKNOWN";
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case DHCPDISCOVER:
|
|
|
|
return (DISCOVER);
|
|
|
|
|
|
|
|
case DHCPREQUEST:
|
|
|
|
return (REQUEST);
|
|
|
|
|
|
|
|
case DHCPRELEASE:
|
|
|
|
return (RELEASE);
|
|
|
|
|
|
|
|
case DHCPDECLINE:
|
|
|
|
return (DECLINE);
|
|
|
|
|
|
|
|
case DHCPINFORM:
|
|
|
|
return (INFORM);
|
|
|
|
|
|
|
|
default:
|
|
|
|
;
|
|
|
|
}
|
|
|
|
return (UNKNOWN);
|
|
|
|
}
|
2012-12-31 16:49:37 +01:00
|
|
|
|
2013-01-30 19:07:54 +01:00
|
|
|
Subnet4Ptr
|
|
|
|
Dhcpv4Srv::selectSubnet(const Pkt4Ptr& question) {
|
2012-12-31 16:49:37 +01:00
|
|
|
|
2013-01-08 12:07:07 +01:00
|
|
|
// Is this relayed message?
|
|
|
|
IOAddress relay = question->getGiaddr();
|
|
|
|
if (relay.toText() == "0.0.0.0") {
|
|
|
|
|
|
|
|
// Yes: Use relay address to select subnet
|
|
|
|
return (CfgMgr::instance().getSubnet4(relay));
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// No: Use client's address to select subnet
|
|
|
|
return (CfgMgr::instance().getSubnet4(question->getRemoteAddr()));
|
|
|
|
}
|
2012-12-31 16:49:37 +01:00
|
|
|
}
|
|
|
|
|
2013-01-30 19:07:54 +01:00
|
|
|
void
|
|
|
|
Dhcpv4Srv::sanityCheck(const Pkt4Ptr& pkt, RequirementLevel serverid) {
|
2012-12-31 16:49:37 +01:00
|
|
|
OptionPtr server_id = pkt->getOption(DHO_DHCP_SERVER_IDENTIFIER);
|
|
|
|
switch (serverid) {
|
|
|
|
case FORBIDDEN:
|
|
|
|
if (server_id) {
|
|
|
|
isc_throw(RFCViolation, "Server-id option was not expected, but "
|
|
|
|
<< "received in " << serverReceivedPacketName(pkt->getType()));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MANDATORY:
|
|
|
|
if (!server_id) {
|
|
|
|
isc_throw(RFCViolation, "Server-id option was expected, but not "
|
|
|
|
" received in message "
|
|
|
|
<< serverReceivedPacketName(pkt->getType()));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OPTIONAL:
|
|
|
|
// do nothing here
|
|
|
|
;
|
|
|
|
}
|
|
|
|
}
|
2013-01-31 12:16:22 +00:00
|
|
|
|
|
|
|
} // namespace dhcp
|
|
|
|
} // namespace isc
|