2011-11-27 19:35:47 +08:00
|
|
|
// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
|
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
|
|
|
|
#include <dhcp/dhcp4.h>
|
|
|
|
#include <dhcp/pkt4.h>
|
2011-11-30 15:32:40 +01:00
|
|
|
#include <dhcp/iface_mgr.h>
|
2011-11-27 19:35:47 +08:00
|
|
|
#include <dhcp4/dhcp4_srv.h>
|
|
|
|
#include <asiolink/io_address.h>
|
2011-12-20 19:59:14 +01:00
|
|
|
#include <dhcp/option4_addrlst.h>
|
2011-11-27 19:35:47 +08:00
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
using namespace isc;
|
|
|
|
using namespace isc::dhcp;
|
|
|
|
using namespace isc::asiolink;
|
|
|
|
|
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.
|
2011-12-23 17:26:24 +01:00
|
|
|
const std::string HARDCODED_LEASE = "192.0.2.222"; // assigned lease
|
2011-12-21 16:37:11 +01:00
|
|
|
const std::string HARDCODED_NETMASK = "255.255.255.0";
|
|
|
|
const uint32_t HARDCODED_LEASE_TIME = 60; // in seconds
|
2011-12-23 17:26:24 +01:00
|
|
|
const std::string HARDCODED_GATEWAY = "192.0.2.1";
|
|
|
|
const std::string HARDCODED_DNS_SERVER = "192.0.2.2";
|
|
|
|
const std::string HARDCODED_DOMAIN_NAME = "isc.example.com";
|
|
|
|
const std::string HARDCODED_SERVER_ID = "192.0.2.1";
|
2011-12-21 16:37:11 +01:00
|
|
|
|
2011-12-05 18:45:44 +01:00
|
|
|
Dhcpv4Srv::Dhcpv4Srv(uint16_t port) {
|
|
|
|
cout << "Initialization: opening sockets on port " << port << endl;
|
2011-11-27 19:35:47 +08:00
|
|
|
|
|
|
|
// first call to instance() will create IfaceMgr (it's a singleton)
|
|
|
|
// it may throw something if things go wrong
|
|
|
|
IfaceMgr::instance();
|
|
|
|
|
|
|
|
/// @todo: instantiate LeaseMgr here once it is imlpemented.
|
2011-12-13 14:33:12 +01:00
|
|
|
IfaceMgr::instance().printIfaces();
|
|
|
|
|
|
|
|
IfaceMgr::instance().openSockets4(port);
|
2011-11-27 19:35:47 +08:00
|
|
|
|
|
|
|
setServerID();
|
|
|
|
|
2011-12-12 18:04:12 +01:00
|
|
|
shutdown_ = false;
|
2011-11-27 19:35:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Dhcpv4Srv::~Dhcpv4Srv() {
|
|
|
|
cout << "DHCPv4 server shutdown." << endl;
|
2011-12-12 19:24:36 +01:00
|
|
|
IfaceMgr::instance().closeSockets();
|
2011-11-27 19:35:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
Dhcpv4Srv::run() {
|
2011-12-12 18:04:12 +01:00
|
|
|
while (!shutdown_) {
|
2011-11-27 19:35:47 +08:00
|
|
|
boost::shared_ptr<Pkt4> query; // client's message
|
|
|
|
boost::shared_ptr<Pkt4> rsp; // server's response
|
|
|
|
|
|
|
|
query = IfaceMgr::instance().receive4();
|
2011-12-07 15:00:37 +01:00
|
|
|
|
2011-11-27 19:35:47 +08:00
|
|
|
if (query) {
|
2011-12-12 19:24:36 +01:00
|
|
|
try {
|
|
|
|
query->unpack();
|
|
|
|
} catch (const std::exception& e) {
|
|
|
|
/// TODO: Printout reasons of failed parsing
|
2011-12-07 15:07:15 +01:00
|
|
|
cout << "Failed to parse incoming packet " << endl;
|
2011-11-27 19:35:47 +08:00
|
|
|
continue;
|
|
|
|
}
|
2011-12-07 15:07:15 +01:00
|
|
|
|
2011-11-27 19:35:47 +08:00
|
|
|
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:
|
|
|
|
cout << "Unknown pkt type received:"
|
|
|
|
<< query->getType() << endl;
|
|
|
|
}
|
|
|
|
|
2011-12-07 15:07:15 +01:00
|
|
|
cout << "Received message type " << int(query->getType()) << endl;
|
2011-11-27 19:35:47 +08:00
|
|
|
|
2011-11-30 19:00:57 +01:00
|
|
|
// TODO: print out received packets only if verbose (or debug)
|
|
|
|
// mode is enabled
|
2011-11-27 19:35:47 +08:00
|
|
|
cout << query->toText();
|
|
|
|
|
|
|
|
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());
|
|
|
|
|
2011-12-12 19:24:36 +01:00
|
|
|
cout << "Replying with message type "
|
|
|
|
<< static_cast<int>(rsp->getType()) << ":" << endl;
|
2011-11-27 19:35:47 +08:00
|
|
|
cout << rsp->toText();
|
|
|
|
cout << "----" << endl;
|
|
|
|
if (rsp->pack()) {
|
2011-11-30 19:00:57 +01:00
|
|
|
cout << "Packet assembled correctly." << endl;
|
2011-11-27 19:35:47 +08:00
|
|
|
}
|
2011-12-07 14:52:07 +01:00
|
|
|
IfaceMgr::instance().send(rsp);
|
2011-11-27 19:35:47 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO add support for config session (see src/bin/auth/main.cc)
|
|
|
|
// so this daemon can be controlled from bob
|
|
|
|
}
|
|
|
|
|
|
|
|
return (true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Dhcpv4Srv::setServerID() {
|
2011-11-30 19:00:57 +01:00
|
|
|
/// TODO implement this for real once interface detection (ticket 1237)
|
|
|
|
/// is done. Use hardcoded server-id for now.
|
|
|
|
|
2011-11-27 19:35:47 +08:00
|
|
|
#if 0
|
2011-11-30 19:00:57 +01:00
|
|
|
// uncomment this once ticket 1350 is merged.
|
2011-11-27 19:35:47 +08:00
|
|
|
IOAddress srvId("127.0.0.1");
|
|
|
|
serverid_ = boost::shared_ptr<Option>(
|
|
|
|
new Option4AddrLst(Option::V4, DHO_DHCP_SERVER_IDENTIFIER, srvId));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2011-12-20 19:59:14 +01:00
|
|
|
|
2011-12-21 16:37:11 +01:00
|
|
|
void Dhcpv4Srv::copyDefaultFields(const boost::shared_ptr<Pkt4>& question,
|
|
|
|
boost::shared_ptr<Pkt4>& answer) {
|
|
|
|
answer->setIface(question->getIface());
|
|
|
|
answer->setIndex(question->getIndex());
|
|
|
|
answer->setCiaddr(question->getCiaddr());
|
2011-12-20 19:59:14 +01:00
|
|
|
|
2011-12-21 16:37:11 +01:00
|
|
|
answer->setSiaddr(IOAddress("0.0.0.0")); // explictly set this to 0
|
|
|
|
answer->setHops(question->getHops());
|
2011-12-20 19:59:14 +01:00
|
|
|
|
|
|
|
// copy MAC address
|
2011-12-27 12:49:43 +01:00
|
|
|
vector<uint8_t> mac(question->getChaddr(),
|
|
|
|
question->getChaddr() + Pkt4::MAX_CHADDR_LEN);
|
2011-12-21 16:37:11 +01:00
|
|
|
answer->setHWAddr(question->getHtype(), question->getHlen(), mac);
|
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
|
|
|
}
|
|
|
|
|
2011-12-21 16:37:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Dhcpv4Srv::appendDefaultOptions(boost::shared_ptr<Pkt4>& msg, uint8_t msg_type) {
|
2011-12-23 17:26:24 +01:00
|
|
|
boost::shared_ptr<Option> opt;
|
2011-12-20 19:59:14 +01:00
|
|
|
|
|
|
|
// add Message Type Option (type 53)
|
|
|
|
std::vector<uint8_t> tmp;
|
2011-12-21 16:37:11 +01:00
|
|
|
tmp.push_back(static_cast<uint8_t>(msg_type));
|
2011-12-20 19:59:14 +01:00
|
|
|
opt = boost::shared_ptr<Option>(new Option(Option::V4, DHO_DHCP_MESSAGE_TYPE, tmp));
|
2011-12-21 16:37:11 +01:00
|
|
|
msg->addOption(opt);
|
|
|
|
|
2011-12-23 17:26:24 +01:00
|
|
|
// DHCP Server Identifier (type 54)
|
|
|
|
opt = boost::shared_ptr<Option>
|
|
|
|
(new Option4AddrLst(DHO_DHCP_SERVER_IDENTIFIER, IOAddress(HARDCODED_SERVER_ID)));
|
|
|
|
msg->addOption(opt);
|
|
|
|
|
2011-12-21 16:37:11 +01:00
|
|
|
// more options will be added here later
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-12-23 17:26:24 +01:00
|
|
|
void Dhcpv4Srv::appendRequestedOptions(boost::shared_ptr<Pkt4>& msg) {
|
2011-12-21 16:37:11 +01:00
|
|
|
boost::shared_ptr<Option> opt;
|
|
|
|
|
2011-12-23 17:26:24 +01:00
|
|
|
// Domain name (type 15)
|
|
|
|
vector<uint8_t> domain(HARDCODED_DOMAIN_NAME.begin(), HARDCODED_DOMAIN_NAME.end());
|
|
|
|
opt = boost::shared_ptr<Option>(new Option(Option::V4, DHO_DOMAIN_NAME, domain));
|
|
|
|
msg->addOption(opt);
|
|
|
|
// TODO: Add Option_String class
|
2011-12-21 16:37:11 +01:00
|
|
|
|
2011-12-23 17:26:24 +01:00
|
|
|
// DNS servers (type 6)
|
|
|
|
opt = boost::shared_ptr<Option>
|
|
|
|
(new Option4AddrLst(DHO_DOMAIN_NAME_SERVERS, IOAddress(HARDCODED_DNS_SERVER)));
|
|
|
|
msg->addOption(opt);
|
|
|
|
}
|
2011-12-21 16:37:11 +01:00
|
|
|
|
2011-12-29 23:22:59 +01:00
|
|
|
void Dhcpv4Srv::tryAssignLease(boost::shared_ptr<Pkt4>& msg) {
|
2011-12-23 17:26:24 +01:00
|
|
|
boost::shared_ptr<Option> opt;
|
2011-12-20 19:59:14 +01:00
|
|
|
|
2011-12-23 17:26:24 +01:00
|
|
|
// TODO: Implement actual lease assignment here
|
|
|
|
msg->setYiaddr(IOAddress(HARDCODED_LEASE));
|
2011-12-20 19:59:14 +01:00
|
|
|
|
|
|
|
// IP Address Lease time (type 51)
|
2011-12-21 16:37:11 +01:00
|
|
|
opt = boost::shared_ptr<Option>(new Option(Option::V4, DHO_DHCP_LEASE_TIME));
|
|
|
|
opt->setUint32(HARDCODED_LEASE_TIME);
|
2011-12-23 17:26:24 +01:00
|
|
|
msg->addOption(opt);
|
2011-12-27 12:49:43 +01:00
|
|
|
// TODO: create Option_IntArray that holds list of integers, similar to Option4_AddrLst
|
2011-12-20 19:59:14 +01:00
|
|
|
|
|
|
|
// Subnet mask (type 1)
|
2011-12-21 16:37:11 +01:00
|
|
|
opt = boost::shared_ptr<Option>
|
|
|
|
(new Option4AddrLst(DHO_SUBNET_MASK, IOAddress(HARDCODED_NETMASK)));
|
2011-12-23 17:26:24 +01:00
|
|
|
msg->addOption(opt);
|
2011-12-20 19:59:14 +01:00
|
|
|
|
|
|
|
// Router (type 3)
|
2011-12-21 16:37:11 +01:00
|
|
|
opt = boost::shared_ptr<Option>
|
|
|
|
(new Option4AddrLst(DHO_ROUTERS, IOAddress(HARDCODED_GATEWAY)));
|
2011-12-23 17:26:24 +01:00
|
|
|
msg->addOption(opt);
|
|
|
|
}
|
2011-12-20 19:59:14 +01:00
|
|
|
|
2011-12-23 17:26:24 +01:00
|
|
|
boost::shared_ptr<Pkt4>
|
|
|
|
Dhcpv4Srv::processDiscover(boost::shared_ptr<Pkt4>& discover) {
|
|
|
|
boost::shared_ptr<Pkt4> offer = boost::shared_ptr<Pkt4>
|
|
|
|
(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);
|
|
|
|
appendRequestedOptions(offer);
|
|
|
|
|
2011-12-29 23:22:59 +01:00
|
|
|
tryAssignLease(offer);
|
2011-12-20 19:59:14 +01:00
|
|
|
|
|
|
|
return (offer);
|
2011-11-27 19:35:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
boost::shared_ptr<Pkt4>
|
2011-12-12 18:04:12 +01:00
|
|
|
Dhcpv4Srv::processRequest(boost::shared_ptr<Pkt4>& request) {
|
2011-12-21 16:37:11 +01:00
|
|
|
boost::shared_ptr<Pkt4> ack = boost::shared_ptr<Pkt4>
|
|
|
|
(new Pkt4(DHCPACK, request->getTransid()));
|
|
|
|
|
|
|
|
copyDefaultFields(request, ack);
|
|
|
|
appendDefaultOptions(ack, DHCPACK);
|
2011-12-23 17:26:24 +01:00
|
|
|
appendRequestedOptions(ack);
|
2011-12-21 16:37:11 +01:00
|
|
|
|
2011-12-29 23:22:59 +01:00
|
|
|
tryAssignLease(ack);
|
2011-12-21 16:37:11 +01:00
|
|
|
|
|
|
|
return (ack);
|
2011-11-27 19:35:47 +08:00
|
|
|
}
|
|
|
|
|
2011-12-12 18:04:12 +01:00
|
|
|
void Dhcpv4Srv::processRelease(boost::shared_ptr<Pkt4>& release) {
|
2011-11-27 19:35:47 +08:00
|
|
|
/// TODO: Implement this.
|
|
|
|
cout << "Received RELEASE on " << release->getIface() << " interface." << endl;
|
|
|
|
}
|
2011-11-30 19:00:57 +01:00
|
|
|
|
2011-12-12 18:04:12 +01:00
|
|
|
void Dhcpv4Srv::processDecline(boost::shared_ptr<Pkt4>& decline) {
|
2011-11-27 19:35:47 +08:00
|
|
|
/// TODO: Implement this.
|
|
|
|
cout << "Received DECLINE on " << decline->getIface() << " interface." << endl;
|
|
|
|
}
|
|
|
|
|
2011-12-12 18:04:12 +01:00
|
|
|
boost::shared_ptr<Pkt4> Dhcpv4Srv::processInform(boost::shared_ptr<Pkt4>& 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);
|
|
|
|
}
|